-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(marshal): cheap capData stringify and parse #1558
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,57 @@ | ||||||
/** @template S @typedef {import('./types.js').CapData<S>} CapData */ | ||||||
|
||||||
const { Fail, quote: q } = assert; | ||||||
|
||||||
/** @typedef {string} SimpleString */ | ||||||
|
||||||
/** | ||||||
* A SimpleString is one where JSON.strigify-ing the string just | ||||||
* puts quotes around the contents, and it contains no close square | ||||||
* brackets. Many slot encodings use slot strings that | ||||||
* obey these rules, which is why they are useful. | ||||||
* | ||||||
* @param {unknown} str | ||||||
* @returns {asserts str is SimpleString} | ||||||
*/ | ||||||
export const assertSimpleString = str => { | ||||||
assert(typeof str === 'string'); | ||||||
const stringified = JSON.stringify(str); | ||||||
const expected = `"${str}"`; | ||||||
stringified === expected || | ||||||
Fail`Expected to stringify to ${q(expected)}, not ${q(stringified)}}`; | ||||||
assert(str.indexOf(']') === -1); | ||||||
}; | ||||||
harden(assertSimpleString); | ||||||
|
||||||
/** | ||||||
* @param {CapData<SimpleString>} capData | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since if you want to ensure that |
||||||
* @returns {string} | ||||||
*/ | ||||||
export const stringifyCapData = capData => { | ||||||
const { | ||||||
body, | ||||||
slots: [...slots], | ||||||
} = capData; | ||||||
assert(typeof body === 'string'); | ||||||
assert(body.startsWith('#')); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we do this, I hope it's in a way that expands the definition of "CapData" from |
||||||
const scBody = body.slice(1); | ||||||
JSON.parse(scBody); // Just asserts that it parses as JSON | ||||||
slots.forEach(assertSimpleString); | ||||||
return `{"slots":${JSON.stringify(slots)},"#body":${scBody}}`; | ||||||
}; | ||||||
harden(stringifyCapData); | ||||||
|
||||||
const DSL = /^\{"slots":(\[[^\]]*\]),"#body":(.*)\}$/; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would recommend to move to a less greedy search and string boundaries if possible There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had never seen But good point about newlines. Where the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Imposing an ordering constraint on the entries of a JSON object (which is defined to be unordered) would definitely merit explanation, as would the existence of this regular expression—I assume it's in anticipation of being able to look at slots without even parsing the body? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For checking the
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
|
||||||
export const parseCapData = str => { | ||||||
assert(typeof str === 'string'); | ||||||
const matches = DSL.exec(str); | ||||||
assert(matches && matches.length === 3); | ||||||
const slots = JSON.parse(matches[1]); | ||||||
slots.forEach(assertSimpleString); | ||||||
const scBody = matches[2]; | ||||||
JSON.parse(scBody); // Just asserts that it parses as JSON | ||||||
const body = `#${scBody}`; | ||||||
return harden({ body, slots }); | ||||||
}; | ||||||
harden(parseCapData); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { test } from './prepare-test-env-ava.js'; | ||
|
||
import { | ||
assertSimpleString, | ||
parseCapData, | ||
stringifyCapData, | ||
} from '../src/stringify-capdata.js'; | ||
|
||
test('test assertSimpleString', t => { | ||
t.notThrows(() => assertSimpleString('x')); | ||
t.throws(() => assertSimpleString('x"'), { | ||
message: 'Expected to stringify to "\\"x\\"\\"", not "\\"x\\\\\\"\\""}', | ||
}); | ||
t.throws(() => assertSimpleString('[x]'), { | ||
message: 'Check failed', | ||
}); | ||
}); | ||
|
||
const roundTrips = (t, capData, str) => { | ||
t.is(stringifyCapData(capData), str); | ||
t.deepEqual(parseCapData(str), capData); | ||
}; | ||
|
||
test('test capData roundTrips', t => { | ||
roundTrips(t, { body: '#[]', slots: ['a'] }, '{"slots":["a"],"#body":[]}'); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.