mirror of
https://github.com/larvit/adf-codec.git
synced 2026-11-13 04:08:29 +01:00
Refuse an attribute value JSON does not hold, and push a folded callout's title leaves one at a time
This commit is contained in:
@@ -75,6 +75,16 @@ test('names the attribute nesting past the levels the parser reads one at, and s
|
||||
test('accepts the JSON values an attribute may hold', () => {
|
||||
assert.equal(isAdfDocument({ content: [{ attrs: { a: [1, 'x', null, true, { b: 2 }] }, type: 'paragraph' }], type: 'doc', version: 1 }), true)
|
||||
assert.equal(isAdfDocument({ content: [{ attrs: { a: [() => 1] }, type: 'paragraph' }], type: 'doc', version: 1 }), false)
|
||||
assert.equal(isAdfDocument({ content: [{ attrs: { a: Object.assign(Object.create(null), { b: 1 }) }, type: 'paragraph' }], type: 'doc', version: 1 }), true)
|
||||
})
|
||||
|
||||
test('refuses an attribute value that is an object JSON does not hold', () => {
|
||||
class Point { x = 1 }
|
||||
for (const value of [new Date(0), new Map([['b', 1]]), new Set([1]), new Uint8Array([1, 2]), new Point(), [new Map()], { b: new Set() }]) {
|
||||
assert.equal(isAdfDocument({ content: [{ attrs: { a: value }, type: 'paragraph' }], type: 'doc', version: 1 }), false, String(value))
|
||||
}
|
||||
assert.equal(isAdfDocument({ content: [{ attrs: new Map(), type: 'paragraph' }], type: 'doc', version: 1 }), false)
|
||||
assert.equal(isAdfDocument({ content: [{ marks: [{ attrs: { href: new URL('https://x.test') }, type: 'link' }], text: 'x', type: 'text' }], type: 'doc', version: 1 }), false)
|
||||
})
|
||||
|
||||
test("reads a node's siblings as a walk rather than as one call's arguments", () => {
|
||||
|
||||
+8
-1
@@ -13,12 +13,19 @@ export function isJsonValue(value: unknown): value is JsonValue {
|
||||
}
|
||||
// A hole is not a JSON value, and Array.prototype methods skip holes — spreading materialises them.
|
||||
if (Array.isArray(item)) for (const child of [...item]) pending.push(child)
|
||||
else if (typeof item === 'object') for (const child of Object.values(item)) pending.push(child)
|
||||
else if (isPlainObject(item)) for (const child of Object.values(item)) pending.push(child)
|
||||
else return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// A Date, Map or class instance passes typeof but JSON writes it as {} or a key per element.
|
||||
function isPlainObject(value: unknown): value is object {
|
||||
if (typeof value !== 'object' || value === null) return false
|
||||
const prototype: unknown = Object.getPrototypeOf(value)
|
||||
return prototype === Object.prototype || prototype === null
|
||||
}
|
||||
|
||||
export function nestingDepth(value: unknown): number {
|
||||
const pending: { depth: number; item: unknown }[] = [{ depth: 0, item: value }]
|
||||
let deepest = 0
|
||||
|
||||
@@ -154,7 +154,7 @@ function quoteNode(blocks: readonly Block[], reading: Reading, path: ConvertErro
|
||||
for (const [index, node] of title.value.nodes.entries()) {
|
||||
const held = node.text === undefined ? inlineLeaves([node], 'paragraph', [...path, 'content', index], depth) : success([node])
|
||||
if (!held.ok) return held
|
||||
leaves.push(...held.value)
|
||||
for (const leaf of held.value) leaves.push(leaf)
|
||||
}
|
||||
const text = titleText(leaves)
|
||||
const type = reading.inExpand ? 'nestedExpand' : 'expand'
|
||||
|
||||
@@ -124,6 +124,12 @@ test('reads a folded callout to an expand titled by the rest of its marker line,
|
||||
assert.deepEqual(read('> [!NOTE]-\n>\n> Line.\n'), [bare('expand', said('Line.'))])
|
||||
})
|
||||
|
||||
test("reads a folded callout's title leaves as a walk rather than as one call's arguments", () => {
|
||||
const children = Array.from({ length: 130000 }, () => '{\\"text\\":\\"a\\",\\"type\\":\\"text\\"}').join(',')
|
||||
const parsed = plainMarkdownToAdf(`> [!NOTE]- !adf:carry{json="{\\"content\\":[${children}],\\"type\\":\\"unknownInline\\"}"}\n`)
|
||||
assert.equal(parsed.ok && parsed.value.content?.[0]?.attrs?.['title'], 'a'.repeat(130000))
|
||||
})
|
||||
|
||||
test('reads a folded callout inside an expand to a nested expand', () => {
|
||||
const markdown = '> [!NOTE]- Outer\n>\n> > [!NOTE]- Inner\n> >\n> > Deep.\n>\n> > [!TIP]\n> >\n> > > [!NOTE]-\n'
|
||||
assert.deepEqual(read(markdown), [node('expand', { title: 'Outer' }, node('nestedExpand', { title: 'Inner' }, said('Deep.')), panel('tip', bare('nestedExpand', paragraph())))])
|
||||
|
||||
Reference in New Issue
Block a user