@oa-sdk/spec-bundler 0.1.0
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/LICENSE +201 -0
- package/README.md +240 -0
- package/dist/archiver.d.ts +22 -0
- package/dist/archiver.js +155 -0
- package/dist/category-parser.d.ts +15 -0
- package/dist/category-parser.js +115 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +760 -0
- package/dist/context-generator.d.ts +14 -0
- package/dist/context-generator.js +297 -0
- package/dist/freshness.d.ts +41 -0
- package/dist/freshness.js +365 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +705 -0
- package/dist/link-rewriter.d.ts +65 -0
- package/dist/link-rewriter.js +777 -0
- package/dist/resolver.d.ts +27 -0
- package/dist/resolver.js +276 -0
- package/dist/schema.d.ts +563 -0
- package/dist/schema.js +670 -0
- package/dist/section-slicer.d.ts +12 -0
- package/dist/section-slicer.js +114 -0
- package/dist/topic.d.ts +62 -0
- package/dist/topic.js +262 -0
- package/dist/tree-shaker.d.ts +40 -0
- package/dist/tree-shaker.js +523 -0
- package/dist/types.d.ts +369 -0
- package/dist/types.js +2 -0
- package/package.json +29 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { sliceMarkdownBySections } from "./section-slicer.js";
|
|
2
|
+
export const STANDARD_CONTRACT_HEADINGS = [
|
|
3
|
+
"Contract*",
|
|
4
|
+
"Interface*",
|
|
5
|
+
"Overview*",
|
|
6
|
+
"Preconditions*",
|
|
7
|
+
"Guarantees*",
|
|
8
|
+
"API*",
|
|
9
|
+
"Specification*",
|
|
10
|
+
"Rules*",
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Parses the document category from YAML frontmatter or infers it from path heuristics.
|
|
14
|
+
*/
|
|
15
|
+
export function parseDocumentCategory(content, filePath) {
|
|
16
|
+
const normPath = filePath.replace(/\\/g, "/").toLowerCase();
|
|
17
|
+
// 1. Try YAML frontmatter parsing
|
|
18
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
19
|
+
if (frontmatterMatch) {
|
|
20
|
+
const fm = frontmatterMatch[1];
|
|
21
|
+
const catMatch = fm.match(/^(?:category|type|kind)\s*:\s*["']?([a-zA-Z_-]+)["']?/m);
|
|
22
|
+
if (catMatch) {
|
|
23
|
+
const rawCat = catMatch[1].toLowerCase().trim();
|
|
24
|
+
if (rawCat === "feature" || rawCat === "features")
|
|
25
|
+
return "feature";
|
|
26
|
+
if (rawCat === "mechanism" || rawCat === "mechanisms" || rawCat === "tech" || rawCat === "strategy")
|
|
27
|
+
return "mechanism";
|
|
28
|
+
if (rawCat === "error" || rawCat === "errors")
|
|
29
|
+
return "error";
|
|
30
|
+
if (rawCat === "issue" || rawCat === "issues" || rawCat === "adr" || rawCat === "rfc")
|
|
31
|
+
return "issue";
|
|
32
|
+
if (rawCat === "convention" || rawCat === "conventions" || rawCat === "rule" || rawCat === "rules")
|
|
33
|
+
return "convention";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// 2. Path-based heuristics
|
|
37
|
+
if (normPath.includes("/features/") || normPath.includes("/feature/"))
|
|
38
|
+
return "feature";
|
|
39
|
+
if (normPath.includes("/mechanisms/") || normPath.includes("/mechanism/") || normPath.includes("/tech/") || normPath.includes("/strategies/"))
|
|
40
|
+
return "mechanism";
|
|
41
|
+
if (normPath.includes("/errors/") || normPath.includes("/error/"))
|
|
42
|
+
return "error";
|
|
43
|
+
if (normPath.includes("/issues/") || normPath.includes("/issue/") || normPath.includes("/adr/") || normPath.includes("/rfc/"))
|
|
44
|
+
return "issue";
|
|
45
|
+
if (normPath.includes("/conventions/") || normPath.includes("/convention/") || normPath.includes("/rules/"))
|
|
46
|
+
return "convention";
|
|
47
|
+
// 3. Extension fallback
|
|
48
|
+
if (normPath.endsWith(".tsp"))
|
|
49
|
+
return "mechanism";
|
|
50
|
+
return "feature";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Extracts document content according to requested fidelity level (full, contract-only, summary).
|
|
54
|
+
* Prevents bundle bloat by stripping non-contract details for background/upstream documents.
|
|
55
|
+
*/
|
|
56
|
+
export function extractDocumentFidelity(content, category, fidelity = "full", customSections) {
|
|
57
|
+
if (fidelity === "full") {
|
|
58
|
+
if (customSections && customSections.length > 0) {
|
|
59
|
+
const sliceResult = sliceMarkdownBySections(content, customSections);
|
|
60
|
+
return { content: sliceResult.sliced, isModified: sliceResult.isSliced };
|
|
61
|
+
}
|
|
62
|
+
return { content, isModified: false };
|
|
63
|
+
}
|
|
64
|
+
if (fidelity === "contract-only") {
|
|
65
|
+
const headingsToExtract = customSections && customSections.length > 0
|
|
66
|
+
? customSections
|
|
67
|
+
: STANDARD_CONTRACT_HEADINGS;
|
|
68
|
+
const sliceResult = sliceMarkdownBySections(content, headingsToExtract);
|
|
69
|
+
if (sliceResult.isSliced) {
|
|
70
|
+
return { content: sliceResult.sliced, isModified: true };
|
|
71
|
+
}
|
|
72
|
+
// If no contract headings explicitly matched, fallback to preamble + frontmatter
|
|
73
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
74
|
+
const frontmatter = frontmatterMatch ? frontmatterMatch[0] : "";
|
|
75
|
+
const body = content.slice(frontmatter.length);
|
|
76
|
+
const bodyLines = body.split(/\r?\n/);
|
|
77
|
+
const preambleLines = [];
|
|
78
|
+
for (const line of bodyLines) {
|
|
79
|
+
if (/^#{2,6}\s+/.test(line))
|
|
80
|
+
break; // Stop at first H2+ section
|
|
81
|
+
preambleLines.push(line);
|
|
82
|
+
}
|
|
83
|
+
const fallbackContent = `${frontmatter}${preambleLines.join("\n").trim()}\n`;
|
|
84
|
+
return { content: fallbackContent, isModified: true };
|
|
85
|
+
}
|
|
86
|
+
if (fidelity === "summary") {
|
|
87
|
+
// 1. Separate frontmatter
|
|
88
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
89
|
+
const frontmatter = frontmatterMatch ? frontmatterMatch[0] : "";
|
|
90
|
+
// 2. Extract summary field if declared in frontmatter
|
|
91
|
+
let summaryText = "";
|
|
92
|
+
if (frontmatterMatch) {
|
|
93
|
+
const sumMatch = frontmatterMatch[1].match(/^summary\s*:\s*["']?([^"'\r\n]+)["']?/m);
|
|
94
|
+
if (sumMatch) {
|
|
95
|
+
summaryText = sumMatch[1].trim();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 3. Extract title and first body paragraph
|
|
99
|
+
const body = content.slice(frontmatter.length);
|
|
100
|
+
const lines = body.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
101
|
+
const titleLine = lines.find((l) => l.startsWith("# ")) || `# Document (${category})`;
|
|
102
|
+
const firstParagraph = lines.find((l) => !l.startsWith("#") && !l.startsWith("-")) || "";
|
|
103
|
+
const summaryContent = `${frontmatter}
|
|
104
|
+
${titleLine}
|
|
105
|
+
|
|
106
|
+
*(Category: \`${category}\` | Fidelity: \`summary\`)*
|
|
107
|
+
|
|
108
|
+
> [!NOTE]
|
|
109
|
+
> ${summaryText || firstParagraph || "No detailed summary declared."}
|
|
110
|
+
`;
|
|
111
|
+
return { content: summaryContent, isModified: true };
|
|
112
|
+
}
|
|
113
|
+
return { content, isModified: false };
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=category-parser.js.map
|
package/dist/cli.d.ts
ADDED