diff --git a/src/Tokenizer.ts b/src/Tokenizer.ts index 3f3a9855df..e6f900d457 100644 --- a/src/Tokenizer.ts +++ b/src/Tokenizer.ts @@ -414,17 +414,16 @@ export class _Tokenizer { for (const item of list.items) { this.lexer.state.top = false; item.tokens = this.lexer.blockTokens(item.text, []); - if (item.task) { + const itemToken = item.tokens[0]; + if (item.task && (itemToken?.type === 'text' || itemToken?.type === 'paragraph')) { // Remove checkbox markdown from item tokens item.text = item.text.replace(this.rules.other.listReplaceTask, ''); - if (item.tokens[0]?.type === 'text' || item.tokens[0]?.type === 'paragraph') { - item.tokens[0].raw = item.tokens[0].raw.replace(this.rules.other.listReplaceTask, ''); - item.tokens[0].text = item.tokens[0].text.replace(this.rules.other.listReplaceTask, ''); - for (let i = this.lexer.inlineQueue.length - 1; i >= 0; i--) { - if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[i].src)) { - this.lexer.inlineQueue[i].src = this.lexer.inlineQueue[i].src.replace(this.rules.other.listReplaceTask, ''); - break; - } + itemToken.raw = itemToken.raw.replace(this.rules.other.listReplaceTask, ''); + itemToken.text = itemToken.text.replace(this.rules.other.listReplaceTask, ''); + for (let i = this.lexer.inlineQueue.length - 1; i >= 0; i--) { + if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[i].src)) { + this.lexer.inlineQueue[i].src = this.lexer.inlineQueue[i].src.replace(this.rules.other.listReplaceTask, ''); + break; } } @@ -453,6 +452,8 @@ export class _Tokenizer { item.tokens.unshift(checkboxToken); } } + } else if (item.task) { + item.task = false; } if (!list.loose) { diff --git a/test/specs/new/tasklist_setext_heading.html b/test/specs/new/tasklist_setext_heading.html new file mode 100644 index 0000000000..56fc079410 --- /dev/null +++ b/test/specs/new/tasklist_setext_heading.html @@ -0,0 +1,18 @@ +

tight

+ +

unchecked

+ +

loose

+ diff --git a/test/specs/new/tasklist_setext_heading.md b/test/specs/new/tasklist_setext_heading.md new file mode 100644 index 0000000000..448dd74b9d --- /dev/null +++ b/test/specs/new/tasklist_setext_heading.md @@ -0,0 +1,17 @@ +# tight + +- [x] title + --- + +# unchecked + +- [ ] title + --- + +# loose + +- [x] title + --- + + body +- second diff --git a/test/unit/Lexer.test.js b/test/unit/Lexer.test.js index fe5c0cd80e..19f267177b 100644 --- a/test/unit/Lexer.test.js +++ b/test/unit/Lexer.test.js @@ -1297,6 +1297,123 @@ paragraph }); }); + it('does not parse setext heading text as a task checkbox', () => { + expectTokens({ + md: '- [x] title\n ---', + tokens: [ + { + type: 'list', + raw: '- [x] title\n ---', + ordered: false, + start: '', + loose: false, + items: [ + { + type: 'list_item', + raw: '- [x] title\n ---', + task: false, + loose: false, + text: '[x] title\n---', + tokens: [ + { + type: 'heading', + raw: '[x] title\n---', + depth: 2, + text: '[x] title', + tokens: [ + { + type: 'text', + raw: '[x] title', + text: '[x] title', + }, + ], + }, + ], + }, + ], + }, + ], + }); + }); + + it('keeps setext heading task candidates loose when separated by blank lines', () => { + expectTokens({ + md: '- [x] title\n ---\n\n body\n- second', + tokens: [ + { + type: 'list', + raw: '- [x] title\n ---\n\n body\n- second', + ordered: false, + start: '', + loose: true, + items: [ + { + type: 'list_item', + raw: '- [x] title\n ---\n\n body\n', + task: false, + loose: true, + text: '[x] title\n---\n\nbody', + tokens: [ + { + type: 'heading', + raw: '[x] title\n---', + depth: 2, + text: '[x] title', + tokens: [ + { + type: 'text', + raw: '[x] title', + text: '[x] title', + }, + ], + }, + { + type: 'space', + raw: '\n\n', + }, + { + type: 'paragraph', + raw: 'body', + text: 'body', + tokens: [ + { + type: 'text', + raw: 'body', + text: 'body', + escaped: false, + }, + ], + }, + ], + }, + { + type: 'list_item', + raw: '- second', + task: false, + loose: true, + text: 'second', + tokens: [ + { + type: 'paragraph', + raw: 'second', + text: 'second', + tokens: [ + { + type: 'text', + raw: 'second', + text: 'second', + escaped: false, + }, + ], + }, + ], + }, + ], + }, + ], + }); + }); + it('multiline', () => { expectTokens({ md: `