@c4a/context-cli 0.5.38-beta.1 → 0.5.38-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +130 -22
- package/package.json +1 -1
- package/templates/aspect-runtime/aspectRunnerSdk.js +67 -1
- package/templates/aspects/README.md +3 -1
package/cli.js
CHANGED
|
@@ -33106,18 +33106,76 @@ function renderSummaryText(value) {
|
|
|
33106
33106
|
function escapeRawComment(value) {
|
|
33107
33107
|
return value.replace(/-->/gu, "--\\>");
|
|
33108
33108
|
}
|
|
33109
|
-
function renderRawBlock(section) {
|
|
33109
|
+
function renderRawBlock(section, renderedContent) {
|
|
33110
33110
|
const raw = section.raw?.trim();
|
|
33111
|
-
if (raw === undefined || raw.length === 0 || raw ===
|
|
33111
|
+
if (raw === undefined || raw.length === 0 || raw === renderedContent.trim())
|
|
33112
33112
|
return [];
|
|
33113
33113
|
return ["", "<!-- c4a:raw", escapeRawComment(raw), "/c4a:raw -->"];
|
|
33114
33114
|
}
|
|
33115
|
-
function
|
|
33115
|
+
function plainHeadingText(value) {
|
|
33116
|
+
return value.replace(/\[([^\]]+)\]\([^)]+\)/gu, "$1").replace(/`([^`]+)`/gu, "$1").replace(/\*\*([^*]+)\*\*/gu, "$1").replace(/\*([^*]+)\*/gu, "$1").replace(/_([^_]+)_/gu, "$1").replace(/<[^>]+>/gu, "").replace(/[ \t]+/gu, " ").trim().toLowerCase();
|
|
33117
|
+
}
|
|
33118
|
+
function collectHeadingLines(lines) {
|
|
33119
|
+
const headings = [];
|
|
33120
|
+
let fence;
|
|
33121
|
+
for (const [index2, line] of lines.entries()) {
|
|
33122
|
+
const fenceMatch = line.match(/^\s*(```|~~~)/u);
|
|
33123
|
+
if (fenceMatch) {
|
|
33124
|
+
const marker = fenceMatch[1];
|
|
33125
|
+
fence = fence === undefined ? marker : fence === marker ? undefined : fence;
|
|
33126
|
+
continue;
|
|
33127
|
+
}
|
|
33128
|
+
if (fence !== undefined)
|
|
33129
|
+
continue;
|
|
33130
|
+
const heading2 = line.match(/^(#{1,6})[ \t]+(.+?)(?:[ \t]+#+[ \t]*)?$/u);
|
|
33131
|
+
if (!heading2)
|
|
33132
|
+
continue;
|
|
33133
|
+
headings.push({
|
|
33134
|
+
index: index2,
|
|
33135
|
+
level: heading2[1]?.length ?? 1,
|
|
33136
|
+
text: heading2[2]?.trim() ?? ""
|
|
33137
|
+
});
|
|
33138
|
+
}
|
|
33139
|
+
return headings;
|
|
33140
|
+
}
|
|
33141
|
+
function normalizeSectionContentHeadings(input) {
|
|
33142
|
+
const trimmed = input.content.trim();
|
|
33143
|
+
if (trimmed.length === 0)
|
|
33144
|
+
return trimmed;
|
|
33145
|
+
const lines = trimmed.split(/\r?\n/u);
|
|
33146
|
+
const headings = collectHeadingLines(lines);
|
|
33147
|
+
const removableTitleSet = new Set(input.removableTitles.map(plainHeadingText).filter((title) => title.length > 0));
|
|
33148
|
+
const firstHeading = headings[0];
|
|
33149
|
+
if (firstHeading !== undefined && removableTitleSet.has(plainHeadingText(firstHeading.text)) && lines.slice(0, firstHeading.index).every((line) => line.trim().length === 0)) {
|
|
33150
|
+
lines.splice(firstHeading.index, 1);
|
|
33151
|
+
}
|
|
33152
|
+
const remainingHeadings = collectHeadingLines(lines);
|
|
33153
|
+
const minDepth = remainingHeadings.reduce((current, heading2) => current === undefined ? heading2.level : Math.min(current, heading2.level), undefined);
|
|
33154
|
+
const offset = minDepth === undefined ? 0 : Math.max(0, input.minHeadingLevel - minDepth);
|
|
33155
|
+
if (offset === 0)
|
|
33156
|
+
return lines.join(`
|
|
33157
|
+
`).trim();
|
|
33158
|
+
const headingByLine = new Map(remainingHeadings.map((heading2) => [heading2.index, heading2]));
|
|
33159
|
+
return lines.map((line, index2) => {
|
|
33160
|
+
const heading2 = headingByLine.get(index2);
|
|
33161
|
+
if (heading2 === undefined)
|
|
33162
|
+
return line;
|
|
33163
|
+
const level = Math.min(6, heading2.level + offset);
|
|
33164
|
+
return `${"#".repeat(level)} ${heading2.text}`;
|
|
33165
|
+
}).join(`
|
|
33166
|
+
`).trim();
|
|
33167
|
+
}
|
|
33168
|
+
function renderSectionBody(section, minHeadingLevel, groupTitle) {
|
|
33169
|
+
const content3 = normalizeSectionContentHeadings({
|
|
33170
|
+
content: section.content,
|
|
33171
|
+
minHeadingLevel,
|
|
33172
|
+
removableTitles: [section.summary ?? "", groupTitle]
|
|
33173
|
+
});
|
|
33116
33174
|
return [
|
|
33117
33175
|
renderSectionComment(section),
|
|
33118
33176
|
...section.summary !== undefined ? ["<!-- c4a:summary -->", renderSummaryText(section.summary), "<!-- /c4a:summary -->", ""] : [],
|
|
33119
|
-
|
|
33120
|
-
...renderRawBlock(section),
|
|
33177
|
+
content3,
|
|
33178
|
+
...renderRawBlock(section, content3),
|
|
33121
33179
|
"<!-- /c4a:section -->"
|
|
33122
33180
|
].join(`
|
|
33123
33181
|
`);
|
|
@@ -33140,7 +33198,7 @@ function renderSectionGroups(sections, headingLevel) {
|
|
|
33140
33198
|
const groupSections2 = grouped.get(title) ?? [];
|
|
33141
33199
|
if (groupSections2.length === 0)
|
|
33142
33200
|
continue;
|
|
33143
|
-
const renderedSections = groupSections2.map(renderSectionBody);
|
|
33201
|
+
const renderedSections = groupSections2.map((section) => renderSectionBody(section, headingLevel + 1, title));
|
|
33144
33202
|
parts.push([`${hashes} ${title}`, "", renderedSections.join(`
|
|
33145
33203
|
|
|
33146
33204
|
`)].join(`
|
|
@@ -51606,12 +51664,34 @@ function isMeaningfulTerm(term) {
|
|
|
51606
51664
|
return compacted.length >= 4;
|
|
51607
51665
|
}
|
|
51608
51666
|
function uniqueTerms(node3) {
|
|
51609
|
-
|
|
51667
|
+
const out2 = [];
|
|
51668
|
+
const seen = new Set;
|
|
51669
|
+
const push2 = (kind, term) => {
|
|
51670
|
+
if (typeof term !== "string")
|
|
51671
|
+
return;
|
|
51672
|
+
const value = term.trim();
|
|
51673
|
+
if (!isMeaningfulTerm(value))
|
|
51674
|
+
return;
|
|
51675
|
+
const key = `${kind}:${value}`;
|
|
51676
|
+
if (seen.has(key))
|
|
51677
|
+
return;
|
|
51678
|
+
seen.add(key);
|
|
51679
|
+
out2.push({ value, kind });
|
|
51680
|
+
};
|
|
51681
|
+
push2("slug", node3.slug);
|
|
51682
|
+
push2("title", node3.title);
|
|
51683
|
+
for (const alias of node3.aliases ?? [])
|
|
51684
|
+
push2("alias", alias);
|
|
51685
|
+
return out2;
|
|
51610
51686
|
}
|
|
51611
51687
|
function containsAsciiLikeTerm(text5, term) {
|
|
51612
51688
|
const pattern = new RegExp(`(^|${ASCII_BOUNDARY})${escapeRegExp(term.toLowerCase())}($|${ASCII_BOUNDARY})`, "iu");
|
|
51613
51689
|
return pattern.test(text5);
|
|
51614
51690
|
}
|
|
51691
|
+
function containsAsciiLikeNameTerm(text5, term) {
|
|
51692
|
+
const pattern = new RegExp(`(^|${ASCII_NAME_BOUNDARY})${escapeRegExp(term.toLowerCase())}($|${ASCII_NAME_BOUNDARY})`, "iu");
|
|
51693
|
+
return pattern.test(text5);
|
|
51694
|
+
}
|
|
51615
51695
|
function containsCjkTerm(text5, term) {
|
|
51616
51696
|
const normalized = term.toLowerCase();
|
|
51617
51697
|
let index2 = text5.indexOf(normalized);
|
|
@@ -51634,16 +51714,35 @@ function containsStrongTerm(text5, compactText, term) {
|
|
|
51634
51714
|
const compacted = compact(normalized);
|
|
51635
51715
|
return compacted.length >= 6 && compactText.includes(compacted);
|
|
51636
51716
|
}
|
|
51717
|
+
function containsTerm(text5, compactText, term) {
|
|
51718
|
+
if (term.kind === "slug")
|
|
51719
|
+
return containsStrongTerm(text5, compactText, term.value);
|
|
51720
|
+
const normalized = term.value.normalize("NFKC").toLowerCase();
|
|
51721
|
+
if (CJK_RE2.test(normalized))
|
|
51722
|
+
return containsCjkTerm(text5, normalized);
|
|
51723
|
+
return containsAsciiLikeNameTerm(text5, normalized);
|
|
51724
|
+
}
|
|
51725
|
+
function currentCodePackage(input) {
|
|
51726
|
+
return input.currentCodePackage ?? input.knownNodes.find((node3) => node3.slug === input.currentNodeSlug)?.codePackage;
|
|
51727
|
+
}
|
|
51728
|
+
function canInferFromTerm(input) {
|
|
51729
|
+
if (input.term.kind === "slug")
|
|
51730
|
+
return true;
|
|
51731
|
+
if (input.currentCodePackage === undefined || input.targetCodePackage === undefined)
|
|
51732
|
+
return true;
|
|
51733
|
+
return input.currentCodePackage === input.targetCodePackage;
|
|
51734
|
+
}
|
|
51637
51735
|
function inferRefersToNodes(input) {
|
|
51638
51736
|
const existing = input.existing ?? [];
|
|
51639
51737
|
const output = [...existing];
|
|
51640
51738
|
const seen = new Set(output);
|
|
51641
51739
|
const text5 = input.text.normalize("NFKC").toLowerCase();
|
|
51642
51740
|
const compactText = compact(input.text);
|
|
51741
|
+
const currentPackage = currentCodePackage(input);
|
|
51643
51742
|
for (const node3 of input.knownNodes) {
|
|
51644
51743
|
if (node3.slug === input.currentNodeSlug || seen.has(node3.slug))
|
|
51645
51744
|
continue;
|
|
51646
|
-
if (uniqueTerms(node3).some((term) =>
|
|
51745
|
+
if (uniqueTerms(node3).some((term) => canInferFromTerm({ term, currentCodePackage: currentPackage, targetCodePackage: node3.codePackage }) && containsTerm(text5, compactText, term))) {
|
|
51647
51746
|
output.push(node3.slug);
|
|
51648
51747
|
seen.add(node3.slug);
|
|
51649
51748
|
}
|
|
@@ -51661,7 +51760,8 @@ async function collectKnownRefersToNodes(ctxDir) {
|
|
|
51661
51760
|
bySlug.set(node3.parsed.node.id, {
|
|
51662
51761
|
slug: node3.parsed.node.id,
|
|
51663
51762
|
title: node3.parsed.node.title,
|
|
51664
|
-
aliases: node3.parsed.node.aliases ?? []
|
|
51763
|
+
aliases: node3.parsed.node.aliases ?? [],
|
|
51764
|
+
...node3.parsed.node.code_package !== undefined ? { codePackage: node3.parsed.node.code_package } : {}
|
|
51665
51765
|
});
|
|
51666
51766
|
}
|
|
51667
51767
|
let activeSources = new Set;
|
|
@@ -51680,7 +51780,7 @@ async function collectKnownRefersToNodes(ctxDir) {
|
|
|
51680
51780
|
}
|
|
51681
51781
|
return [...bySlug.values()];
|
|
51682
51782
|
}
|
|
51683
|
-
var ASCII_BOUNDARY = "[^\\p{Letter}\\p{Number}_]", CJK_RE2;
|
|
51783
|
+
var ASCII_BOUNDARY = "[^\\p{Letter}\\p{Number}_]", ASCII_NAME_BOUNDARY = "[^\\p{Letter}\\p{Number}_/-]", CJK_RE2;
|
|
51684
51784
|
var init_refersToInference = __esm(() => {
|
|
51685
51785
|
init_alignPlan();
|
|
51686
51786
|
init_sources();
|
|
@@ -58354,11 +58454,12 @@ function sectionText(section) {
|
|
|
58354
58454
|
return [section.summary, section.content, section.detail].filter((value) => typeof value === "string").join(`
|
|
58355
58455
|
`);
|
|
58356
58456
|
}
|
|
58357
|
-
async function withInferredRefersToNodes(ctxDir, nodeSlug, input) {
|
|
58457
|
+
async function withInferredRefersToNodes(ctxDir, nodeSlug, currentCodePackage2, input) {
|
|
58358
58458
|
const inferred = inferRefersToNodes({
|
|
58359
58459
|
text: [input.summary, input.content, input.detail].filter((value) => typeof value === "string").join(`
|
|
58360
58460
|
`),
|
|
58361
58461
|
currentNodeSlug: nodeSlug,
|
|
58462
|
+
currentCodePackage: currentCodePackage2,
|
|
58362
58463
|
knownNodes: await collectKnownRefersToNodes(ctxDir),
|
|
58363
58464
|
existing: input.refers_to_nodes
|
|
58364
58465
|
});
|
|
@@ -58366,7 +58467,7 @@ async function withInferredRefersToNodes(ctxDir, nodeSlug, input) {
|
|
|
58366
58467
|
}
|
|
58367
58468
|
async function mdriveSectionAdd(input) {
|
|
58368
58469
|
const located = await locateNode(input.ctxDir, input.nodeSlug);
|
|
58369
|
-
const sectionInput = await withInferredRefersToNodes(input.ctxDir, input.nodeSlug, input.input);
|
|
58470
|
+
const sectionInput = await withInferredRefersToNodes(input.ctxDir, input.nodeSlug, located.parsed.node.code_package, input.input);
|
|
58370
58471
|
const section = createSection(input.nodeSlug, sectionInput, nextSectionId(located.parsed.sections), located.parsed.node.type);
|
|
58371
58472
|
reassignSections(located.parsed, [...located.parsed.sections, section]);
|
|
58372
58473
|
await atomicRewriteRootFile(located.filePath, located.root);
|
|
@@ -58457,6 +58558,7 @@ async function mdriveSectionUpdate(input) {
|
|
|
58457
58558
|
const inferred = inferRefersToNodes({
|
|
58458
58559
|
text: sectionText(section),
|
|
58459
58560
|
currentNodeSlug: input.nodeSlug,
|
|
58561
|
+
currentCodePackage: located.parsed.node.code_package,
|
|
58460
58562
|
knownNodes: await collectKnownRefersToNodes(input.ctxDir),
|
|
58461
58563
|
existing: section.refers_to_nodes
|
|
58462
58564
|
});
|
|
@@ -58492,7 +58594,7 @@ async function mdriveSectionSupersede(input) {
|
|
|
58492
58594
|
const oldSection = findSection(input.nodeSlug, located.parsed, input.oldSectionId);
|
|
58493
58595
|
oldSection.status = SectionStatus.deprecated;
|
|
58494
58596
|
const nextId = nextSectionId(located.parsed.sections);
|
|
58495
|
-
const sectionInput = await withInferredRefersToNodes(input.ctxDir, input.nodeSlug, input.input);
|
|
58597
|
+
const sectionInput = await withInferredRefersToNodes(input.ctxDir, input.nodeSlug, located.parsed.node.code_package, input.input);
|
|
58496
58598
|
const added = createSection(input.nodeSlug, sectionInput, nextId, located.parsed.node.type);
|
|
58497
58599
|
added.relations = [
|
|
58498
58600
|
...added.relations ?? [],
|
|
@@ -98471,6 +98573,7 @@ function inferredRefersToNodes(input) {
|
|
|
98471
98573
|
const inferred = inferRefersToNodes({
|
|
98472
98574
|
text: input.text,
|
|
98473
98575
|
currentNodeSlug: input.nodeSlug,
|
|
98576
|
+
currentCodePackage: input.currentCodePackage,
|
|
98474
98577
|
knownNodes: input.knownNodes,
|
|
98475
98578
|
existing: input.existing
|
|
98476
98579
|
});
|
|
@@ -98491,6 +98594,7 @@ function createProjectionSection(input) {
|
|
|
98491
98594
|
const inferred = inferredRefersToNodes({
|
|
98492
98595
|
knownNodes: input.knownNodes,
|
|
98493
98596
|
nodeSlug: input.row.node_slug,
|
|
98597
|
+
currentCodePackage: input.node.parsed.node.code_package,
|
|
98494
98598
|
text: sectionText2(section)
|
|
98495
98599
|
});
|
|
98496
98600
|
if (inferred !== undefined)
|
|
@@ -98524,15 +98628,19 @@ function updateProjectionSection(input) {
|
|
|
98524
98628
|
input.section.status = SectionStatus.active;
|
|
98525
98629
|
changed = true;
|
|
98526
98630
|
}
|
|
98527
|
-
|
|
98528
|
-
|
|
98529
|
-
|
|
98530
|
-
|
|
98531
|
-
|
|
98532
|
-
|
|
98533
|
-
|
|
98534
|
-
if (inferred
|
|
98631
|
+
const inferred = inferredRefersToNodes({
|
|
98632
|
+
knownNodes: input.knownNodes,
|
|
98633
|
+
nodeSlug: input.row.node_slug,
|
|
98634
|
+
currentCodePackage: input.node.parsed.node.code_package,
|
|
98635
|
+
text: sectionText2(input.section)
|
|
98636
|
+
});
|
|
98637
|
+
if (JSON.stringify(input.section.refers_to_nodes ?? undefined) !== JSON.stringify(inferred)) {
|
|
98638
|
+
if (inferred === undefined) {
|
|
98639
|
+
delete input.section.refers_to_nodes;
|
|
98640
|
+
} else {
|
|
98535
98641
|
input.section.refers_to_nodes = inferred;
|
|
98642
|
+
}
|
|
98643
|
+
changed = true;
|
|
98536
98644
|
}
|
|
98537
98645
|
const issues = validateSection(input.section);
|
|
98538
98646
|
if (issues.length > 0) {
|
|
@@ -98775,7 +98883,7 @@ function applyProjectableRows(input) {
|
|
|
98775
98883
|
input.touchedNodes.add(node3);
|
|
98776
98884
|
input.touchedFiles.add(node3.filePath);
|
|
98777
98885
|
added += 1;
|
|
98778
|
-
} else if (updateProjectionSection({ section: current.section, row, sourceRef, knownNodes: input.knownNodes })) {
|
|
98886
|
+
} else if (updateProjectionSection({ section: current.section, node: node3, row, sourceRef, knownNodes: input.knownNodes })) {
|
|
98779
98887
|
input.touchedNodes.add(node3);
|
|
98780
98888
|
input.touchedFiles.add(node3.filePath);
|
|
98781
98889
|
updated += 1;
|
package/package.json
CHANGED
|
@@ -441,6 +441,12 @@ function cloneNode(node, children) {
|
|
|
441
441
|
cloned.children = children;
|
|
442
442
|
return cloned;
|
|
443
443
|
}
|
|
444
|
+
function cloneMarkdownNode(node) {
|
|
445
|
+
return {
|
|
446
|
+
...node,
|
|
447
|
+
...node.children !== undefined ? { children: node.children.map(cloneMarkdownNode) } : {}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
444
450
|
function mdxAttrValueText(value) {
|
|
445
451
|
if (value === null || value === undefined)
|
|
446
452
|
return;
|
|
@@ -622,6 +628,14 @@ function plainText(node) {
|
|
|
622
628
|
return node.value;
|
|
623
629
|
return (node.children ?? []).map(plainText).join("");
|
|
624
630
|
}
|
|
631
|
+
function normalizedHeadingLabel(value) {
|
|
632
|
+
return compactWhitespace(value).toLowerCase();
|
|
633
|
+
}
|
|
634
|
+
function headingMatchesTitle(node, title) {
|
|
635
|
+
if (title === undefined || node.type !== "heading")
|
|
636
|
+
return false;
|
|
637
|
+
return normalizedHeadingLabel(plainText(node)) === normalizedHeadingLabel(title);
|
|
638
|
+
}
|
|
625
639
|
function firstHeadingText(nodes) {
|
|
626
640
|
for (const node of nodes) {
|
|
627
641
|
if (node.type === "heading") {
|
|
@@ -651,6 +665,56 @@ function stripYamlFrontmatter(raw) {
|
|
|
651
665
|
}
|
|
652
666
|
return raw;
|
|
653
667
|
}
|
|
668
|
+
function clampHeadingLevel(value) {
|
|
669
|
+
return Math.min(6, Math.max(1, Math.trunc(value)));
|
|
670
|
+
}
|
|
671
|
+
function minHeadingDepth(nodes) {
|
|
672
|
+
let out;
|
|
673
|
+
function visit(node) {
|
|
674
|
+
if (node.type === "heading" && typeof node.depth === "number") {
|
|
675
|
+
out = out === undefined ? node.depth : Math.min(out, node.depth);
|
|
676
|
+
}
|
|
677
|
+
for (const child of node.children ?? [])
|
|
678
|
+
visit(child);
|
|
679
|
+
}
|
|
680
|
+
for (const node of nodes)
|
|
681
|
+
visit(node);
|
|
682
|
+
return out;
|
|
683
|
+
}
|
|
684
|
+
function shiftHeadingDepths(nodes, offset) {
|
|
685
|
+
return nodes.map((node) => {
|
|
686
|
+
const next = cloneMarkdownNode(node);
|
|
687
|
+
if (next.type === "heading" && typeof next.depth === "number") {
|
|
688
|
+
next.depth = clampHeadingLevel(next.depth + offset);
|
|
689
|
+
}
|
|
690
|
+
if (next.children !== undefined) {
|
|
691
|
+
next.children = shiftHeadingDepths(next.children, offset);
|
|
692
|
+
}
|
|
693
|
+
return next;
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
function sectionBodyMarkdownFromTree(tree, options) {
|
|
697
|
+
const minHeadingLevel = clampHeadingLevel(options.minHeadingLevel ?? 3);
|
|
698
|
+
const removeTitleHeading = options.removeTitleHeading ?? true;
|
|
699
|
+
const children = (tree.children ?? []).map(cloneMarkdownNode);
|
|
700
|
+
const withoutTitle = removeTitleHeading && children[0] !== undefined && headingMatchesTitle(children[0], options.title) ? children.slice(1) : children;
|
|
701
|
+
const minDepth = minHeadingDepth(withoutTitle);
|
|
702
|
+
const headingOffset = minDepth === undefined ? 0 : Math.max(0, minHeadingLevel - minDepth);
|
|
703
|
+
return normalizeMarkdown(mdxProcessor.stringify({
|
|
704
|
+
...tree,
|
|
705
|
+
children: shiftHeadingDepths(withoutTitle, headingOffset)
|
|
706
|
+
}));
|
|
707
|
+
}
|
|
708
|
+
function normalizeSectionMarkdown(markdown, options = {}) {
|
|
709
|
+
const source = stripYamlFrontmatter(markdown);
|
|
710
|
+
const tree = mdxProcessor.parse(source);
|
|
711
|
+
const normalized = mdxProcessor.runSync(tree);
|
|
712
|
+
const title = options.title ?? firstHeadingText(normalized.children ?? []);
|
|
713
|
+
return sectionBodyMarkdownFromTree(normalized, {
|
|
714
|
+
...options,
|
|
715
|
+
...title !== undefined ? { title } : {}
|
|
716
|
+
});
|
|
717
|
+
}
|
|
654
718
|
function parseMdxDocument(raw, fallbackTitle) {
|
|
655
719
|
const source = stripYamlFrontmatter(raw);
|
|
656
720
|
const tree = mdxProcessor.parse(source);
|
|
@@ -658,7 +722,8 @@ function parseMdxDocument(raw, fallbackTitle) {
|
|
|
658
722
|
const markdown = normalizeMarkdown(mdxProcessor.stringify(normalized));
|
|
659
723
|
const blocks = markdownBlocks(markdown);
|
|
660
724
|
const title = firstHeadingText(normalized.children ?? []) ?? fallbackTitle;
|
|
661
|
-
|
|
725
|
+
const bodyMarkdown = sectionBodyMarkdownFromTree(normalized, { title });
|
|
726
|
+
return { title, markdown, bodyMarkdown, blocks };
|
|
662
727
|
}
|
|
663
728
|
|
|
664
729
|
// src/aspect-runtime/index.ts
|
|
@@ -697,6 +762,7 @@ export {
|
|
|
697
762
|
parseMdxDocument,
|
|
698
763
|
parseJsLikeTokenNames,
|
|
699
764
|
normalizeSymbolSlug,
|
|
765
|
+
normalizeSectionMarkdown,
|
|
700
766
|
normalizeComponentSlug,
|
|
701
767
|
markdownFence,
|
|
702
768
|
inferComponentName,
|
|
@@ -199,7 +199,7 @@ export default defineAspect({
|
|
|
199
199
|
node_slug: "target-node",
|
|
200
200
|
kind: "description",
|
|
201
201
|
summary: doc.title,
|
|
202
|
-
content: doc.
|
|
202
|
+
content: doc.bodyMarkdown,
|
|
203
203
|
source: file,
|
|
204
204
|
artifact: artifactFromRelPath(file.path),
|
|
205
205
|
});
|
|
@@ -208,6 +208,8 @@ export default defineAspect({
|
|
|
208
208
|
});
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
+
Use `doc.bodyMarkdown` for Section content. It removes a leading document title when it matches `doc.title`, then shifts remaining headings under the rendered Section container. The renderer applies the final heading offset again from the actual node depth, so nested child-node Sections stay structurally valid. `doc.markdown` remains available when a plugin needs the full normalized document.
|
|
212
|
+
|
|
211
213
|
---
|
|
212
214
|
|
|
213
215
|
## Section Projection Protocol (`section-projection.v2`)
|