Pin the two scans the narrowing left alone, and name what stays raw
CI / gate (push) Successful in 5s
CI / gate (push) Successful in 5s
This commit is contained in:
@@ -43,7 +43,7 @@
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"url": "b](c"
|
||||
"url": "b](c)"
|
||||
},
|
||||
"type": "inlineCard"
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ a `b :inlineCard{url="c\u0060d"}
|
||||
|
||||
::extension {extensionKey=jira parameters="{\"jql\":\"a\u007cb \u0060c\u0060 \u0026 d \u003c e\"}"}
|
||||
|
||||
[a:inlineCard{url="b](c"}
|
||||
[a:inlineCard{url="b](c)"}
|
||||
|
||||
+6
-5
@@ -94,9 +94,10 @@ container is open, a named error otherwise.
|
||||
valid — no attributes. A bare value matches `[A-Za-z0-9_-]+`; any other value is double-quoted
|
||||
with JSON string escaping (`\"` `\\` `\n` `\t` `\uXXXX`, …) — total over
|
||||
Unicode, and raw newlines never appear inside quotes. A quoted value also escapes `` ` ``, `&`,
|
||||
`<` and `|` as `\u0060`, `\u0026`, `\u003c` and `\u007c`; `*`, `_`, `~`, `[` and `(` resolve after a
|
||||
directive binds and stay raw. The closing `}` is the first one outside quotes, since a quoted value
|
||||
holds `}` unescaped. All values are strings at the grammar level; each node's section assigns types.
|
||||
`<` and `|` as `\u0060`, `\u0026`, `\u003c` and `\u007c`; `*`, `_`, `~`, `[`, `]` and `(` resolve
|
||||
after a directive binds and stay raw. The closing `}` is the first one outside quotes, since a
|
||||
quoted value holds `}` unescaped. All values are strings at the grammar level; each node's section
|
||||
assigns types.
|
||||
Canonical form orders keys alphabetically, spells values bare wherever allowed, escapes inside
|
||||
quotes in the shortest form each escape has, and omits empty `{attrs}` except where the `{` itself
|
||||
claims the directive (`:hardBreak{}`).
|
||||
@@ -220,8 +221,8 @@ One header row plus plain inline cells is a pipe table; anything richer is the d
|
||||
and every cell carry no attrs and no marks, the first row is all `tableHeader` and the rest all
|
||||
`tableCell`, every row has the header's cell count, and every cell holds exactly one attr-less,
|
||||
mark-less paragraph — an empty cell holds one empty paragraph — with no `|` anywhere the
|
||||
inline layer spells as syntax — a code span, a link destination or title: pipe form cannot spell
|
||||
that pipe and the table takes the directive form. A pipe table parses back to exactly that shape.
|
||||
inline layer spells as syntax: a code span, an autolink, a link destination or title. A `|` there
|
||||
takes the directive form instead. A pipe table parses back to exactly that shape.
|
||||
|
||||
```
|
||||
| Part | Qty |
|
||||
|
||||
@@ -255,6 +255,11 @@ test('escapes a literal delimiter that would merge with an emitted one', () => {
|
||||
assert.equal(code(adfToMarkdown(document(paragraph({ text: 'x', type: 'text' }, marked('~a', { type: 'strike' }))))), 'unspellable-mark')
|
||||
assert.equal(emitted({ text: '`', type: 'text' }, marked('x', { type: 'code' })), '\\``x`\n')
|
||||
assert.equal(emitted(marked('x', { type: 'code' }), { text: '`', type: 'text' }), '`x`\\`\n')
|
||||
assert.equal(emitted({ text: '`a', type: 'text' }, marked('b', { type: 'code' })), '\\`a`b`\n')
|
||||
assert.equal(
|
||||
emitted({ text: '<https://example.com/', type: 'text' }, { attrs: { url: 'x>' }, type: 'inlineCard' }),
|
||||
'\\<https://example.com/:inlineCard{url="x>"}\n',
|
||||
)
|
||||
assert.equal(emitted({ text: '!', type: 'text' }, marked('x', { attrs: { href: 'https://example.com/' }, type: 'link' })), '\\\n')
|
||||
assert.equal(emitted({ text: '[a', type: 'text' }, marked('x', { attrs: { href: 'https://example.com/' }, type: 'link' })), '[a[x](https://example.com/)\n')
|
||||
assert.equal(emitted({ text: '[a](b)', type: 'text' }), '\\[a](b)\n')
|
||||
|
||||
@@ -19,7 +19,7 @@ const delimiters = ['*', '_', '`', '~']
|
||||
const asciiPunctuation = /[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/
|
||||
const htmlConstructs = [/^<[!?]/, /^<\/?[A-Za-z][A-Za-z0-9-]*(?:[\s/>]|$)/, /^<[^\s<>@]+@[^\s<>@]+>/]
|
||||
const inlineDirectiveOpener = /^:[a-z][A-Za-z0-9]*[[{]/
|
||||
const linkTextCloser = /[([:]/
|
||||
const followsLinkText = /[([:]/
|
||||
const unicodePunctuation = /[\p{P}\p{S}]/u
|
||||
|
||||
export function assembleInlineLine(segments: readonly InlineSegment[], container: LineContainer): AssembledLine {
|
||||
@@ -179,11 +179,11 @@ function claimsCharacter(
|
||||
return false
|
||||
}
|
||||
|
||||
// A `]` the emitter spelled closes the construct it belongs to, which binds first — never link text.
|
||||
// A `]` the emitter spelled sits inside a construct that binds before link text does.
|
||||
function opensLink(scan: string, escapings: readonly (InlineEscaping | undefined)[], index: number): boolean {
|
||||
for (let cursor = index + 1; cursor < scan.length; cursor += 1) {
|
||||
if (scan.charAt(cursor) !== ']' || isSyntax(escapings[cursor])) continue
|
||||
if (linkTextCloser.test(scan.charAt(cursor + 1))) return true
|
||||
if (followsLinkText.test(scan.charAt(cursor + 1))) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user