@c4a/context-cli 0.5.38-beta.1 → 0.5.38-beta.2
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
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(`
|
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`)
|