mirror of
https://github.com/Jeuners/ECC.git
synced 2026-09-09 15:02:30 +02:00
fix(plan-canvas): stop dropping list items when a block's first item is over-indented (#2501)
* fix(plan-canvas): stop dropping list items when a block's first item is over-indented * fix: address greptile findings for PR #2501 - list-type detection and outdent nesting - plan-canvas markdown: fix nested list rendering where outdented runs (indent 6→4) create duplicate sibling UL blocks instead of sharing parent (#2501) - transcript-context: add LARGE_WINDOW_NATIVE_MODEL_IDS array for models whose default context window is 1M but do NOT carry the [1m] marker (fixes #2497) - Add test coverage for transcript-context and shell-substitution modules - Add test coverage for project-detect module (#2498) * fix(plan-canvas): handle outdented list runs * fix(plan-canvas): start a new list when marker type changes at the same indent CommonMark treats a marker-type change (bullet to ordered or back) at the same indentation as the start of a new list. buildList previously absorbed the run into the current list, so mixed runs rendered under a single wrong tag. Stop the run on a tag change and let buildListBlock render the next run as a sibling list with its own tag.
This commit is contained in:
parent
fb98726d0a
commit
5d68ef3617
2 changed files with 62 additions and 2 deletions
|
|
@ -132,8 +132,12 @@ function renderListItem(text) {
|
|||
return '<li>' + renderInline(text) + '</li>';
|
||||
}
|
||||
|
||||
function listTag(marker) {
|
||||
return /^\d/.test(marker) ? 'ol' : 'ul';
|
||||
}
|
||||
|
||||
function buildList(items, start, indent) {
|
||||
const tag = /^\d/.test(items[start].marker) ? 'ol' : 'ul';
|
||||
const tag = listTag(items[start].marker);
|
||||
const parts = [];
|
||||
let i = start;
|
||||
while (i < items.length && items[i].indent >= indent) {
|
||||
|
|
@ -148,6 +152,10 @@ function buildList(items, start, indent) {
|
|||
}
|
||||
i = nested.end;
|
||||
} else {
|
||||
// A marker-type change at the same indent starts a new list
|
||||
// (CommonMark); stop here so the caller renders the next run with
|
||||
// its own tag instead of absorbing it into this one.
|
||||
if (listTag(items[i].marker) !== tag) break;
|
||||
parts.push(renderListItem(items[i].text));
|
||||
i += 1;
|
||||
}
|
||||
|
|
@ -155,6 +163,17 @@ function buildList(items, start, indent) {
|
|||
return { html: '<' + tag + '>\n' + parts.join('\n') + '\n</' + tag + '>', end: i };
|
||||
}
|
||||
|
||||
function buildListBlock(items) {
|
||||
let lists = [];
|
||||
let i = 0;
|
||||
while (i < items.length) {
|
||||
const list = buildList(items, i, items[i].indent);
|
||||
lists = [...lists, list.html];
|
||||
i = list.end;
|
||||
}
|
||||
return lists.join('\n');
|
||||
}
|
||||
|
||||
function startsBlock(line, nextLine) {
|
||||
return /^```/.test(line) ||
|
||||
/^#{1,6}\s/.test(line) ||
|
||||
|
|
@ -257,7 +276,10 @@ function renderMarkdown(text) {
|
|||
items.push({ indent: m[1].length, marker: m[2], text: m[3] });
|
||||
i += 1;
|
||||
}
|
||||
out.push(buildList(items, 0, items[0].indent).html);
|
||||
// An outdent below the first item's indentation ends that list. Render
|
||||
// the remaining run as a sibling list so malformed indentation cannot
|
||||
// silently drop content or create an empty parent item.
|
||||
out.push(buildListBlock(items));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,44 @@ function runTests() {
|
|||
assert.strictEqual(renderMarkdown('* a\n* b'), '<ul>\n<li>a</li>\n<li>b</li>\n</ul>');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('preserves items that outdent below the first item', () => {
|
||||
assert.strictEqual(
|
||||
renderMarkdown(' - alpha\n- beta\n- gamma'),
|
||||
'<ul>\n<li>alpha</li>\n</ul>\n<ul>\n<li>beta</li>\n<li>gamma</li>\n</ul>'
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('uses each outdented run marker for its list type', () => {
|
||||
assert.strictEqual(
|
||||
renderMarkdown(' - prep\n1. phase one\n2. phase two'),
|
||||
'<ul>\n<li>prep</li>\n</ul>\n<ol>\n<li>phase one</li>\n<li>phase two</li>\n</ol>'
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('marker type change at the same indent starts a new list', () => {
|
||||
assert.strictEqual(
|
||||
renderMarkdown('- prep\n1. phase one\n2. phase two'),
|
||||
'<ul>\n<li>prep</li>\n</ul>\n<ol>\n<li>phase one</li>\n<li>phase two</li>\n</ol>'
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('switching back to bullets after a numbered run starts a third list', () => {
|
||||
assert.strictEqual(
|
||||
renderMarkdown('1. one\n- bullet\n2. two'),
|
||||
'<ol>\n<li>one</li>\n</ol>\n<ul>\n<li>bullet</li>\n</ul>\n<ol>\n<li>two</li>\n</ol>'
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('renders repeated outdents without empty parent items', () => {
|
||||
const out = renderMarkdown(' - deep one\n - deep two\n - middle\n- shallow');
|
||||
assert.strictEqual(
|
||||
out,
|
||||
'<ul>\n<li>deep one</li>\n<li>deep two</li>\n</ul>\n' +
|
||||
'<ul>\n<li>middle</li>\n</ul>\n<ul>\n<li>shallow</li>\n</ul>'
|
||||
);
|
||||
assert.ok(!out.includes('<li>\n<ul>'), `No empty parent item expected, got ${out}`);
|
||||
})) passed++; else failed++;
|
||||
|
||||
// Table tests
|
||||
console.log('\nTables:');
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue