@golden-frijoles/kit 0.16.0 → 0.17.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/dist/doc-format.mjs +51 -0
- package/package.json +1 -1
package/dist/doc-format.mjs
CHANGED
|
@@ -110,8 +110,57 @@ export function siblingDocs(readmeRelPath) {
|
|
|
110
110
|
|
|
111
111
|
// ── Individual checkers — each returns a list of { rule, detail } offenses for one file's content ──
|
|
112
112
|
|
|
113
|
+
// An HTML comment that never closes hides EVERYTHING after it when the doc renders — the whole epic README, its
|
|
114
|
+
// architecture lock included (think-skills and sketch-specs both shipped one, 2026-09-30, from an edit anchored on a
|
|
115
|
+
// heading the old template's comment named). Code is skipped first: a `<!-- jev:` inside backticks or a fence is an
|
|
116
|
+
// example, not a comment, and several sprint docs quote one.
|
|
117
|
+
// A code span opens with a run of backticks and closes with the same run (``<!-- x`` included).
|
|
118
|
+
const CODE_SPAN = /(`+)[\s\S]*?\1/g;
|
|
119
|
+
|
|
120
|
+
// A later `-->` closes an open comment wherever it appears (a mermaid `A --> B` included) — that is what CommonMark
|
|
121
|
+
// renders, so the rule agrees with the page; the text in between is still hidden, and only reading it shows that.
|
|
122
|
+
export function unclosedComments(content) {
|
|
123
|
+
const lines = content.split('\n');
|
|
124
|
+
let fence = null;
|
|
125
|
+
let open = null; // the line an unclosed <!-- started on, while we are inside one
|
|
126
|
+
for (let i = 0; i < lines.length; i++) {
|
|
127
|
+
// The whole run of marks: a ```` fence is closed only by ```` or longer, never by the ``` it quotes.
|
|
128
|
+
const fenceMark = lines[i].match(/^ {0,3}(`{3,}|~{3,})/);
|
|
129
|
+
if (open === null && fenceMark) {
|
|
130
|
+
const mark = fenceMark[1];
|
|
131
|
+
if (fence === null) fence = mark;
|
|
132
|
+
else if (mark[0] === fence[0] && mark.length >= fence.length) fence = null;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (fence !== null) continue;
|
|
136
|
+
let rest = open === null ? lines[i].replace(CODE_SPAN, '') : lines[i];
|
|
137
|
+
for (;;) {
|
|
138
|
+
if (open === null) {
|
|
139
|
+
const at = rest.indexOf('<!--');
|
|
140
|
+
if (at === -1) break;
|
|
141
|
+
open = i;
|
|
142
|
+
rest = rest.slice(at + 4);
|
|
143
|
+
} else {
|
|
144
|
+
const at = rest.indexOf('-->');
|
|
145
|
+
if (at === -1) break;
|
|
146
|
+
open = null;
|
|
147
|
+
rest = rest.slice(at + 3).replace(CODE_SPAN, '');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return open === null
|
|
152
|
+
? []
|
|
153
|
+
: [
|
|
154
|
+
{
|
|
155
|
+
rule: 'unclosed-html-comment',
|
|
156
|
+
detail: `line ${open + 1} opens <!-- and nothing closes it — everything after it is hidden when the doc renders`,
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
|
|
113
161
|
export function checkEpicReadme(content, { slug, exists = existsRelative } = {}) {
|
|
114
162
|
const offenses = [];
|
|
163
|
+
offenses.push(...unclosedComments(content));
|
|
115
164
|
// Many epics predate the seeds/ convention and genuinely have no seed file to link — that's an
|
|
116
165
|
// accepted state (Sprint 2 sweep decision), not drift. Only require a **Scope seed:** field when a
|
|
117
166
|
// real seed file exists for this epic's slug; a seed that exists but isn't linked IS still flagged.
|
|
@@ -230,6 +279,7 @@ export function bodyStartIndex(lines) {
|
|
|
230
279
|
|
|
231
280
|
export function checkSprintDoc(content) {
|
|
232
281
|
const offenses = [];
|
|
282
|
+
offenses.push(...unclosedComments(content));
|
|
233
283
|
const all = content.split('\n');
|
|
234
284
|
const statusLine = all
|
|
235
285
|
.slice(bodyStartIndex(all))
|
|
@@ -331,6 +381,7 @@ export const RETRO_SECTION_STEMS = [
|
|
|
331
381
|
// same date — that is fixing drift, not relaxing the check.
|
|
332
382
|
export function checkRetrospective(content) {
|
|
333
383
|
const offenses = [];
|
|
384
|
+
offenses.push(...unclosedComments(content));
|
|
334
385
|
const closedLine = content.split('\n').find((l) => /closed/i.test(l) && l.trim() !== '');
|
|
335
386
|
if (!closedLine) {
|
|
336
387
|
offenses.push({ rule: 'retro-closed-missing', detail: 'no "Closed" date line found near the top' });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@golden-frijoles/kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "The scripts the Golden Frijoles skills run, packaged so they work in any repo: planning, build-order, reporting and verification rails. Zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|