@nielspeter/eess-md 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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/dist/builders/docs.d.ts +28 -0
  4. package/dist/builders/docs.d.ts.map +1 -0
  5. package/dist/builders/docs.js +44 -0
  6. package/dist/builders/docs.js.map +1 -0
  7. package/dist/builders/links.d.ts +26 -0
  8. package/dist/builders/links.d.ts.map +1 -0
  9. package/dist/builders/links.js +42 -0
  10. package/dist/builders/links.js.map +1 -0
  11. package/dist/builders/pointers.d.ts +26 -0
  12. package/dist/builders/pointers.d.ts.map +1 -0
  13. package/dist/builders/pointers.js +43 -0
  14. package/dist/builders/pointers.js.map +1 -0
  15. package/dist/builders/rows.d.ts +36 -0
  16. package/dist/builders/rows.d.ts.map +1 -0
  17. package/dist/builders/rows.js +42 -0
  18. package/dist/builders/rows.js.map +1 -0
  19. package/dist/builders/task-items.d.ts +21 -0
  20. package/dist/builders/task-items.d.ts.map +1 -0
  21. package/dist/builders/task-items.js +33 -0
  22. package/dist/builders/task-items.js.map +1 -0
  23. package/dist/builders/vocabulary.d.ts +66 -0
  24. package/dist/builders/vocabulary.d.ts.map +1 -0
  25. package/dist/builders/vocabulary.js +118 -0
  26. package/dist/builders/vocabulary.js.map +1 -0
  27. package/dist/conditions/pointer-resolve.d.ts +51 -0
  28. package/dist/conditions/pointer-resolve.d.ts.map +1 -0
  29. package/dist/conditions/pointer-resolve.js +164 -0
  30. package/dist/conditions/pointer-resolve.js.map +1 -0
  31. package/dist/conditions/resolve.d.ts +36 -0
  32. package/dist/conditions/resolve.d.ts.map +1 -0
  33. package/dist/conditions/resolve.js +108 -0
  34. package/dist/conditions/resolve.js.map +1 -0
  35. package/dist/conditions/structure.d.ts +13 -0
  36. package/dist/conditions/structure.d.ts.map +1 -0
  37. package/dist/conditions/structure.js +42 -0
  38. package/dist/conditions/structure.js.map +1 -0
  39. package/dist/conditions/table-rows.d.ts +28 -0
  40. package/dist/conditions/table-rows.d.ts.map +1 -0
  41. package/dist/conditions/table-rows.js +25 -0
  42. package/dist/conditions/table-rows.js.map +1 -0
  43. package/dist/corpus.d.ts +40 -0
  44. package/dist/corpus.d.ts.map +1 -0
  45. package/dist/corpus.js +73 -0
  46. package/dist/corpus.js.map +1 -0
  47. package/dist/index.d.ts +26 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +22 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/model/document.d.ts +78 -0
  52. package/dist/model/document.d.ts.map +1 -0
  53. package/dist/model/document.js +68 -0
  54. package/dist/model/document.js.map +1 -0
  55. package/dist/model/links.d.ts +32 -0
  56. package/dist/model/links.d.ts.map +1 -0
  57. package/dist/model/links.js +53 -0
  58. package/dist/model/links.js.map +1 -0
  59. package/dist/model/pointers.d.ts +29 -0
  60. package/dist/model/pointers.d.ts.map +1 -0
  61. package/dist/model/pointers.js +65 -0
  62. package/dist/model/pointers.js.map +1 -0
  63. package/dist/model/query.d.ts +6 -0
  64. package/dist/model/query.d.ts.map +1 -0
  65. package/dist/model/query.js +15 -0
  66. package/dist/model/query.js.map +1 -0
  67. package/dist/model/rows.d.ts +52 -0
  68. package/dist/model/rows.d.ts.map +1 -0
  69. package/dist/model/rows.js +42 -0
  70. package/dist/model/rows.js.map +1 -0
  71. package/dist/model/task-items.d.ts +28 -0
  72. package/dist/model/task-items.d.ts.map +1 -0
  73. package/dist/model/task-items.js +47 -0
  74. package/dist/model/task-items.js.map +1 -0
  75. package/dist/model/violation.d.ts +23 -0
  76. package/dist/model/violation.d.ts.map +1 -0
  77. package/dist/model/violation.js +22 -0
  78. package/dist/model/violation.js.map +1 -0
  79. package/dist/predicates/document.d.ts +8 -0
  80. package/dist/predicates/document.d.ts.map +1 -0
  81. package/dist/predicates/document.js +22 -0
  82. package/dist/predicates/document.js.map +1 -0
  83. package/dist/rules/adr.d.ts +34 -0
  84. package/dist/rules/adr.d.ts.map +1 -0
  85. package/dist/rules/adr.js +103 -0
  86. package/dist/rules/adr.js.map +1 -0
  87. package/dist/rules/ledger.d.ts +44 -0
  88. package/dist/rules/ledger.d.ts.map +1 -0
  89. package/dist/rules/ledger.js +119 -0
  90. package/dist/rules/ledger.js.map +1 -0
  91. package/package.json +60 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-rows.js","sourceRoot":"","sources":["../../src/conditions/table-rows.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,cAAc,EAA+B,MAAM,kBAAkB,CAAA;AAkB9E;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAA0B;IAChE,OAAO;QACL,WAAW,EAAE,8CAA8C;QAC3D,QAAQ,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAC3B,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CACxB,cAAc,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC,OAAO,CACpF,CAAC,GAAG,EAAE,EAAE,CACN,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5B,WAAW,CAAC;YACV,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,QAAQ,GAAG,CAAC,GAAG;YACpG,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI;YACpB,OAAO;YACP,UAAU,EAAE,GAAG,CAAC,IAAI;YACpB,OAAO,EAAE,GAAG;SACb,CAAC,CACH,CACJ,CACF;KACJ,CAAA;AACH,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { type MdDocument } from './model/document.js';
2
+ /**
3
+ * Configuration for a markdown corpus.
4
+ */
5
+ export interface CorpusOptions {
6
+ /** Globs (repo-relative, POSIX) selecting the markdown files to load, e.g. `['docs/**']`. */
7
+ readonly roots: readonly string[];
8
+ /**
9
+ * Globs marking frozen folders — historical records whose drift is reported
10
+ * but never failed. Defaults to the near-universal `completed`/`archived`;
11
+ * extend for your project's lifecycle folders (`delivered`, `wont-do`, …).
12
+ */
13
+ readonly frozen?: readonly string[];
14
+ /**
15
+ * Directories/globs never walked (build output, deps, VCS). Merged with a
16
+ * built-in set (`node_modules`, `.git`, `dist`, `coverage`).
17
+ */
18
+ readonly ignore?: readonly string[];
19
+ /** Repo root the globs and pointers resolve against. Defaults to `process.cwd()`. */
20
+ readonly cwd?: string;
21
+ }
22
+ /**
23
+ * A loaded markdown corpus — the "project" handle passed to `docs()`, `links()`,
24
+ * and `pointers()`. Analogous to `project()` (TS) and `diagram()` (Mermaid).
25
+ */
26
+ export interface Corpus {
27
+ /** All loaded documents. */
28
+ documents(): MdDocument[];
29
+ /** Repo root the corpus resolves against. */
30
+ readonly root: string;
31
+ /** Every file path under the repo root (repo-relative, POSIX) — for pointer/link resolution. */
32
+ readonly fileIndex: ReadonlySet<string>;
33
+ }
34
+ /**
35
+ * Load a markdown corpus. Walks `roots` from `cwd`, parses each `.md` file with
36
+ * GFM enabled, and records frozen membership per file. The full repo file tree
37
+ * is indexed so later phases can resolve code pointers and cross-links.
38
+ */
39
+ export declare function corpus(options: CorpusOptions): Corpus;
40
+ //# sourceMappingURL=corpus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../src/corpus.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEpE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,6FAA6F;IAC7F,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,qFAAqF;IACrF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,4BAA4B;IAC5B,SAAS,IAAI,UAAU,EAAE,CAAA;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,gGAAgG;IAChG,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CACxC;AA4BD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAuCrD"}
package/dist/corpus.js ADDED
@@ -0,0 +1,73 @@
1
+ import { readFileSync, readdirSync } from 'node:fs';
2
+ import { join, relative, sep } from 'node:path';
3
+ import { fromMarkdown } from 'mdast-util-from-markdown';
4
+ import { gfm } from 'micromark-extension-gfm';
5
+ import { gfmFromMarkdown } from 'mdast-util-gfm';
6
+ import picomatch from 'picomatch';
7
+ import { buildDocument } from './model/document.js';
8
+ const DEFAULT_FROZEN = ['**/completed/**', '**/archived/**'];
9
+ const BUILTIN_IGNORE = ['node_modules', '.git', 'dist', 'coverage', '.output', '.nuxt', '.vercel'];
10
+ function toPosix(p) {
11
+ return sep === '/' ? p : p.split(sep).join('/');
12
+ }
13
+ function walk(dir, root, ignoreDirs, acc) {
14
+ let entries;
15
+ try {
16
+ entries = readdirSync(dir, { withFileTypes: true });
17
+ }
18
+ catch (err) {
19
+ void err; // unreadable dir (permissions, dangling symlink) — deliberately skipped
20
+ return;
21
+ }
22
+ for (const e of entries) {
23
+ const abs = join(dir, e.name);
24
+ if (e.isDirectory()) {
25
+ if (ignoreDirs.has(e.name))
26
+ continue;
27
+ walk(abs, root, ignoreDirs, acc);
28
+ }
29
+ else if (e.isFile()) {
30
+ acc.push(toPosix(relative(root, abs)));
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Load a markdown corpus. Walks `roots` from `cwd`, parses each `.md` file with
36
+ * GFM enabled, and records frozen membership per file. The full repo file tree
37
+ * is indexed so later phases can resolve code pointers and cross-links.
38
+ */
39
+ export function corpus(options) {
40
+ const root = options.cwd ?? process.cwd();
41
+ const ignoreDirs = new Set(BUILTIN_IGNORE);
42
+ const allFiles = [];
43
+ walk(root, root, ignoreDirs, allFiles);
44
+ const matchesRoot = picomatch([...options.roots]);
45
+ const matchesFrozen = picomatch([...(options.frozen ?? DEFAULT_FROZEN)]);
46
+ const matchesIgnore = options.ignore && options.ignore.length > 0 ? picomatch([...options.ignore]) : () => false;
47
+ const fileIndex = new Set(allFiles);
48
+ const gfmExt = gfm();
49
+ const gfmMdast = gfmFromMarkdown();
50
+ const documents = allFiles
51
+ .filter((rel) => rel.endsWith('.md') && matchesRoot(rel) && !matchesIgnore(rel))
52
+ .map((rel) => {
53
+ const abs = join(root, rel);
54
+ const text = readFileSync(abs, 'utf8');
55
+ const tree = fromMarkdown(text, {
56
+ extensions: [gfmExt],
57
+ mdastExtensions: [gfmMdast],
58
+ });
59
+ return buildDocument({
60
+ file: abs,
61
+ relPath: rel,
62
+ frozen: matchesFrozen(rel),
63
+ text,
64
+ root: tree,
65
+ });
66
+ });
67
+ return {
68
+ documents: () => documents,
69
+ root,
70
+ fileIndex,
71
+ };
72
+ }
73
+ //# sourceMappingURL=corpus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus.js","sourceRoot":"","sources":["../src/corpus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export { corpus } from './corpus.js';
2
+ export type { CorpusOptions, Corpus } from './corpus.js';
3
+ export type { MdDocument, MdSection, MdTable, MdCodeBlock } from './model/document.js';
4
+ export type { MdRow, ColumnSpec, RowMatchOptions, RowMatchMode } from './model/rows.js';
5
+ export { matchTableRows } from './model/rows.js';
6
+ export type { ArchViolation } from './model/violation.js';
7
+ export { docs, DocsRuleBuilder } from './builders/docs.js';
8
+ export { links, LinkRuleBuilder } from './builders/links.js';
9
+ export type { MdLink } from './builders/links.js';
10
+ export type { LinkResolveOptions } from './conditions/resolve.js';
11
+ export { pointers, PointerRuleBuilder } from './builders/pointers.js';
12
+ export type { MdPointer } from './builders/pointers.js';
13
+ export { presentExternalRoots } from './conditions/pointer-resolve.js';
14
+ export type { PointerResolveOptions } from './conditions/pointer-resolve.js';
15
+ export { rows, RowsRuleBuilder } from './builders/rows.js';
16
+ export { taskItems, TaskItemRuleBuilder } from './builders/task-items.js';
17
+ export type { MdTaskItem } from './builders/task-items.js';
18
+ export { collectTaskItems } from './model/task-items.js';
19
+ export type { MdTaskItemRef } from './model/task-items.js';
20
+ export { vocabulary, terms, TermRuleBuilder } from './builders/vocabulary.js';
21
+ export type { Vocabulary, VocabularyOptions, MdTerm, TermsOptions } from './builders/vocabulary.js';
22
+ export { haveSection, haveTable } from './conditions/structure.js';
23
+ export type { HaveTableOptions } from './conditions/structure.js';
24
+ export { haveTableRowsSatisfying } from './conditions/table-rows.js';
25
+ export type { HaveTableRowsOptions, TableRowContext } from './conditions/table-rows.js';
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGxD,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtF,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGzD,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC5D,YAAY,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACrE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAA;AACtE,YAAY,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAC5E,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACzE,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC7E,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGnG,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAClE,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AACpE,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ // @nielspeter/eess-md — the Markdown dialect of the eess family.
2
+ //
3
+ // Validates a repo's markdown corpus against the shared @nielspeter/eess kernel:
4
+ // documents have the sections/tables they should, cross-links resolve, and code
5
+ // pointers ground against real files. The opinionated ADR gate ships separately
6
+ // from `@nielspeter/eess-md/rules/adr`.
7
+ // Corpus loader
8
+ export { corpus } from './corpus.js';
9
+ export { matchTableRows } from './model/rows.js';
10
+ // Entry points
11
+ export { docs, DocsRuleBuilder } from './builders/docs.js';
12
+ export { links, LinkRuleBuilder } from './builders/links.js';
13
+ export { pointers, PointerRuleBuilder } from './builders/pointers.js';
14
+ export { presentExternalRoots } from './conditions/pointer-resolve.js';
15
+ export { rows, RowsRuleBuilder } from './builders/rows.js';
16
+ export { taskItems, TaskItemRuleBuilder } from './builders/task-items.js';
17
+ export { collectTaskItems } from './model/task-items.js';
18
+ export { vocabulary, terms, TermRuleBuilder } from './builders/vocabulary.js';
19
+ // Conditions (for composing custom rules / presets)
20
+ export { haveSection, haveTable } from './conditions/structure.js';
21
+ export { haveTableRowsSatisfying } from './conditions/table-rows.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,gFAAgF;AAChF,wCAAwC;AAExC,gBAAgB;AAChB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAMpC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGhD,eAAe;AACf,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAG5D,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAErE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAA;AAEtE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAG7E,oDAAoD;AACpD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAElE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,78 @@
1
+ import type { Root } from 'mdast';
2
+ /**
3
+ * A heading in a markdown document.
4
+ */
5
+ export interface MdSection {
6
+ /** Heading text, e.g. "Enforcement" */
7
+ readonly name: string;
8
+ /** Heading level (1 = `#`, 2 = `##`, …) */
9
+ readonly depth: number;
10
+ /** 1-based line where the heading starts */
11
+ readonly line: number;
12
+ }
13
+ /**
14
+ * A GFM table in a markdown document.
15
+ */
16
+ export interface MdTable {
17
+ /** Header cell texts, trimmed */
18
+ readonly header: readonly string[];
19
+ /** Body rows, each an array of trimmed cell texts */
20
+ readonly rows: readonly (readonly string[])[];
21
+ /**
22
+ * 1-based source line of each body row, parallel to `rows` (real mdast
23
+ * positions, not derived — the file:line a diagnostic points at must be
24
+ * exact). `rowLines[i]` is the line of `rows[i]`.
25
+ */
26
+ readonly rowLines: readonly number[];
27
+ /** 1-based line where the table starts */
28
+ readonly line: number;
29
+ /** Names of the enclosing headings, outermost first (nearest section is last) */
30
+ readonly sectionPath: readonly string[];
31
+ }
32
+ /** A fenced code block in a markdown document. */
33
+ export interface MdCodeBlock {
34
+ /** The info-string language, e.g. `mermaid`, `typescript`, or `null`. */
35
+ readonly lang: string | null;
36
+ /** The block's contents. */
37
+ readonly value: string;
38
+ /** 1-based line where the fence starts. */
39
+ readonly line: number;
40
+ }
41
+ /**
42
+ * One markdown document in the corpus — the element type of `docs()`.
43
+ *
44
+ * The underlying mdast `Root` is exposed for advanced use, but the dialect's
45
+ * own abstractions (`sections`, `tables`, and — in later phases — links and
46
+ * pointers) are the intended surface.
47
+ */
48
+ export interface MdDocument {
49
+ /** Absolute file path */
50
+ readonly file: string;
51
+ /** Repo-relative path (POSIX separators), e.g. `docs/adr/0001-x.md` */
52
+ readonly relPath: string;
53
+ /** In a frozen folder — historical record; drift is reported, never failed */
54
+ readonly frozen: boolean;
55
+ /** Raw source text */
56
+ readonly text: string;
57
+ readonly sections: readonly MdSection[];
58
+ readonly tables: readonly MdTable[];
59
+ /** Fenced code blocks (e.g. embedded `mermaid` diagrams). */
60
+ readonly codeBlocks: readonly MdCodeBlock[];
61
+ /** mdast root (internal / advanced) */
62
+ readonly root: Root;
63
+ }
64
+ /**
65
+ * Build an `MdDocument` from a parsed mdast `Root`.
66
+ *
67
+ * Walks top-level nodes once, collecting headings (as sections) and GFM tables.
68
+ * Tables record the heading path they sit under so a rule can scope to
69
+ * "the table in the `## Enforcement` section".
70
+ */
71
+ export declare function buildDocument(args: {
72
+ file: string;
73
+ relPath: string;
74
+ frozen: boolean;
75
+ text: string;
76
+ root: Root;
77
+ }): MdDocument;
78
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/model/document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,OAAO,CAAA;AAE9C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAA;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;AAED,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,sBAAsB;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;IACnC,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,SAAS,WAAW,EAAE,CAAA;IAC3C,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CACpB;AAsBD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,IAAI,CAAA;CACX,GAAG,UAAU,CAwCb"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Recursively concatenate the text content of an mdast node. Inline code keeps
3
+ * its backticks, because a backtick-delimited `path.ts` or `it('…')` inside a
4
+ * table cell is a meaningful code citation, not plain prose.
5
+ */
6
+ function nodeText(node) {
7
+ if (node.type === 'inlineCode' && typeof node.value === 'string') {
8
+ return '`' + node.value + '`';
9
+ }
10
+ if ('value' in node && typeof node.value === 'string')
11
+ return node.value;
12
+ if ('children' in node && Array.isArray(node.children)) {
13
+ return node.children.map((c) => nodeText(c)).join('');
14
+ }
15
+ return '';
16
+ }
17
+ function lineOf(node) {
18
+ return node.position?.start.line ?? 0;
19
+ }
20
+ /**
21
+ * Build an `MdDocument` from a parsed mdast `Root`.
22
+ *
23
+ * Walks top-level nodes once, collecting headings (as sections) and GFM tables.
24
+ * Tables record the heading path they sit under so a rule can scope to
25
+ * "the table in the `## Enforcement` section".
26
+ */
27
+ export function buildDocument(args) {
28
+ const sections = [];
29
+ const tables = [];
30
+ const codeBlocks = [];
31
+ // Running heading stack: index i holds the current heading at depth i+1.
32
+ const headingStack = [];
33
+ for (const node of args.root.children) {
34
+ if (node.type === 'heading') {
35
+ const name = nodeText(node).trim();
36
+ sections.push({ name, depth: node.depth, line: lineOf(node) });
37
+ headingStack.length = node.depth - 1;
38
+ headingStack[node.depth - 1] = name;
39
+ }
40
+ else if (node.type === 'table') {
41
+ const rowsText = node.children.map((row) => row.children.map((cell) => nodeText(cell).trim()));
42
+ const [header = [], ...rows] = rowsText;
43
+ // Real per-row source lines (header row excluded), parallel to `rows`.
44
+ const rowLines = node.children.slice(1).map((row) => lineOf(row));
45
+ tables.push({
46
+ header,
47
+ rows,
48
+ rowLines,
49
+ line: lineOf(node),
50
+ sectionPath: headingStack.filter((h) => h !== undefined),
51
+ });
52
+ }
53
+ else if (node.type === 'code') {
54
+ codeBlocks.push({ lang: node.lang ?? null, value: node.value, line: lineOf(node) });
55
+ }
56
+ }
57
+ return {
58
+ file: args.file,
59
+ relPath: args.relPath,
60
+ frozen: args.frozen,
61
+ text: args.text,
62
+ sections,
63
+ tables,
64
+ codeBlocks,
65
+ root: args.root,
66
+ };
67
+ }
68
+ //# sourceMappingURL=document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/model/document.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Root } from 'mdast';
2
+ import type { MdDocument } from './document.js';
3
+ /** A markdown link occurrence within a document (before doc back-reference). */
4
+ export interface MdLinkRef {
5
+ /** Raw URL as written, e.g. `./other.md#section` or `https://example.com`. */
6
+ readonly url: string;
7
+ /** Link text. */
8
+ readonly text: string;
9
+ /** 1-based line in the source document. */
10
+ readonly line: number;
11
+ /** True for `scheme:` / protocol-relative URLs (http, https, mailto, //…). */
12
+ readonly external: boolean;
13
+ /**
14
+ * Char offset span of the URL within the document source, for autofix
15
+ * (plan 0066). Present only when the URL is locatable in the raw source
16
+ * (plain paths; percent-encoded/entity URLs may be absent) — a fix is emitted
17
+ * only when the exact span is known.
18
+ */
19
+ readonly urlStart?: number;
20
+ readonly urlEnd?: number;
21
+ }
22
+ /**
23
+ * Collect inline markdown links (`[text](url)`) from a document tree. Links
24
+ * inside fenced code are not parsed as `link` nodes by mdast, so they are
25
+ * naturally excluded.
26
+ */
27
+ export declare function collectLinks(root: Root, source?: string): MdLinkRef[];
28
+ /** A link with its owning document attached — the element the builders and conditions operate on. */
29
+ export interface MdLink extends MdLinkRef {
30
+ readonly doc: MdDocument;
31
+ }
32
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/model/links.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAS,MAAM,OAAO,CAAA;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,gFAAgF;AAChF,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,iBAAiB;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAWD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAoCrE;AAED,qGAAqG;AACrG,MAAM,WAAW,MAAO,SAAQ,SAAS;IACvC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACzB"}
@@ -0,0 +1,53 @@
1
+ // A URL is external if it has a scheme (`https:`, `mailto:`) or is protocol-relative.
2
+ const EXTERNAL_RE = /^([a-z][a-z0-9+.-]*:|\/\/)/i;
3
+ function textOf(node) {
4
+ if ('value' in node && typeof node.value === 'string')
5
+ return node.value;
6
+ if ('children' in node)
7
+ return node.children.map((c) => textOf(c)).join('');
8
+ return '';
9
+ }
10
+ /**
11
+ * Collect inline markdown links (`[text](url)`) from a document tree. Links
12
+ * inside fenced code are not parsed as `link` nodes by mdast, so they are
13
+ * naturally excluded.
14
+ */
15
+ export function collectLinks(root, source) {
16
+ const out = [];
17
+ const visit = (node) => {
18
+ if (node.type === 'link') {
19
+ // Locate the URL's exact char span in the source (for autofix). The link
20
+ // node's raw text is `[text](url …)`; the URL is the last occurrence of
21
+ // `node.url` within it (a URL in the link text would come earlier). If the
22
+ // source form differs from the decoded `node.url`, leave the span absent —
23
+ // no fix is emitted without an exact span.
24
+ let urlStart;
25
+ let urlEnd;
26
+ const startOff = node.position?.start.offset;
27
+ const endOff = node.position?.end.offset;
28
+ if (source !== undefined && startOff !== undefined && endOff !== undefined) {
29
+ const raw = source.slice(startOff, endOff);
30
+ const rel = raw.lastIndexOf(node.url);
31
+ if (rel >= 0) {
32
+ urlStart = startOff + rel;
33
+ urlEnd = urlStart + node.url.length;
34
+ }
35
+ }
36
+ out.push({
37
+ url: node.url,
38
+ text: textOf(node),
39
+ line: node.position?.start.line ?? 0,
40
+ external: EXTERNAL_RE.test(node.url),
41
+ urlStart,
42
+ urlEnd,
43
+ });
44
+ }
45
+ if ('children' in node) {
46
+ for (const child of node.children)
47
+ visit(child);
48
+ }
49
+ };
50
+ visit(root);
51
+ return out;
52
+ }
53
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/model/links.ts"],"names":[],"mappings":"AAuBA,sFAAsF;AACtF,MAAM,WAAW,GAAG,6BAA6B,CAAA;AAEjD,SAAS,MAAM,CAAC,IAAW;IACzB,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,KAAK,CAAA;IACxE,IAAI,UAAU,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC3E,OAAO,EAAE,CAAA;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAU,EAAE,MAAe;IACtD,MAAM,GAAG,GAAgB,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAG,CAAC,IAAW,EAAQ,EAAE;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,yEAAyE;YACzE,wEAAwE;YACxE,2EAA2E;YAC3E,2EAA2E;YAC3E,2CAA2C;YAC3C,IAAI,QAA4B,CAAA;YAChC,IAAI,MAA0B,CAAA;YAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAA;YAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAA;YACxC,IAAI,MAAM,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC3E,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;gBAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACrC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;oBACb,QAAQ,GAAG,QAAQ,GAAG,GAAG,CAAA;oBACzB,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAA;gBACrC,CAAC;YACH,CAAC;YACD,GAAG,CAAC,IAAI,CAAC;gBACP,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;gBAClB,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;gBACpC,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBACpC,QAAQ;gBACR,MAAM;aACP,CAAC,CAAA;QACJ,CAAC;QACD,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;gBAAE,KAAK,CAAC,KAAK,CAAC,CAAA;QACjD,CAAC;IACH,CAAC,CAAA;IACD,KAAK,CAAC,IAAI,CAAC,CAAA;IACX,OAAO,GAAG,CAAA;AACZ,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { Root } from 'mdast';
2
+ import type { MdDocument } from './document.js';
3
+ /** A `path.ext:line[-end]` code pointer occurrence within a document. */
4
+ export interface MdPointerRef {
5
+ /** The cited path, e.g. `server/routers/admin.ts` or `[id].vue`. */
6
+ readonly path: string;
7
+ /** First referenced code line. */
8
+ readonly startLine: number;
9
+ /** Last referenced code line (== startLine when no range). */
10
+ readonly endLine: number;
11
+ /** Verbatim pointer text, e.g. `admin.ts:493-495`. */
12
+ readonly raw: string;
13
+ /** 1-based line in the source document where the pointer appears. */
14
+ readonly line: number;
15
+ /** Char offset span of the `path` portion within the document source (for autofix, plan 0066). */
16
+ readonly pathStart: number;
17
+ readonly pathEnd: number;
18
+ }
19
+ /**
20
+ * Extract code pointers from a document. Pointers inside fenced/indented code
21
+ * are ignored (illustrative, not live claims); pointers in prose and inline
22
+ * code are collected.
23
+ */
24
+ export declare function extractPointers(text: string, root: Root): MdPointerRef[];
25
+ /** A pointer with its owning document attached — the element the builders and conditions operate on. */
26
+ export interface MdPointer extends MdPointerRef {
27
+ readonly doc: MdDocument;
28
+ }
29
+ //# sourceMappingURL=pointers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointers.d.ts","sourceRoot":"","sources":["../../src/model/pointers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAS,MAAM,OAAO,CAAA;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,kCAAkC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,sDAAsD;IACtD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,kGAAkG;IAClG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AA4BD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,YAAY,EAAE,CAkCxE;AAED,wGAAwG;AACxG,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACzB"}
@@ -0,0 +1,65 @@
1
+ /** Code file extensions a pointer may target — web stack plus the JVM/legacy
2
+ * languages an external-root traceability matrix cites (plan 0069 Phase 5). */
3
+ const CODE_EXT = 'ts|tsx|js|mjs|cjs|vue|json|sql|sh|ya?ml|groovy|java|kt|kts|cs|py|rb|go|rs|php';
4
+ // `path.ext:line` or `path.ext:start-end`. Path class includes `[` `]` so Nuxt
5
+ // dynamic routes like `[id].vue` match. Backticks aren't in the class, so
6
+ // `` `admin.ts:493` `` delimits naturally.
7
+ const POINTER_RE = new RegExp(String.raw `([A-Za-z0-9_./\[\]-]+\.(?:${CODE_EXT})):(\d+)(?:-(\d+))?`, 'g');
8
+ /** Line ranges [start,end] of fenced/indented code blocks (inline code kept). */
9
+ function fencedRanges(root) {
10
+ const ranges = [];
11
+ const visit = (node) => {
12
+ if (node.type === 'code' && node.position) {
13
+ ranges.push([node.position.start.line, node.position.end.line]);
14
+ }
15
+ if ('children' in node) {
16
+ for (const child of node.children)
17
+ visit(child);
18
+ }
19
+ };
20
+ visit(root);
21
+ return ranges;
22
+ }
23
+ /**
24
+ * Extract code pointers from a document. Pointers inside fenced/indented code
25
+ * are ignored (illustrative, not live claims); pointers in prose and inline
26
+ * code are collected.
27
+ */
28
+ export function extractPointers(text, root) {
29
+ const ranges = fencedRanges(root);
30
+ const inFence = (line) => ranges.some(([s, e]) => line >= s && line <= e);
31
+ const out = [];
32
+ const lines = text.split('\n');
33
+ let lineStartOffset = 0;
34
+ for (let i = 0; i < lines.length; i++) {
35
+ const lineNo = i + 1;
36
+ const lineText = lines[i];
37
+ if (lineText === undefined)
38
+ continue;
39
+ if (!inFence(lineNo)) {
40
+ for (const m of lineText.matchAll(POINTER_RE)) {
41
+ const path = m[1];
42
+ const startStr = m[2];
43
+ if (path === undefined || startStr === undefined || m.index === undefined)
44
+ continue;
45
+ const startLine = Number(startStr);
46
+ const endLine = m[3] !== undefined ? Number(m[3]) : startLine;
47
+ // The match begins with the path (group 1), so its doc offset is the
48
+ // line's start offset plus the match index.
49
+ const pathStart = lineStartOffset + m.index;
50
+ out.push({
51
+ path,
52
+ startLine,
53
+ endLine,
54
+ raw: m[0],
55
+ line: lineNo,
56
+ pathStart,
57
+ pathEnd: pathStart + path.length,
58
+ });
59
+ }
60
+ }
61
+ lineStartOffset += lineText.length + 1; // + the '\n'
62
+ }
63
+ return out;
64
+ }
65
+ //# sourceMappingURL=pointers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointers.js","sourceRoot":"","sources":["../../src/model/pointers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { MdDocument, MdTable } from './document.js';
2
+ /** Does the document have a heading matching `name`? */
3
+ export declare function hasSection(doc: MdDocument, name: string | RegExp): boolean;
4
+ /** Is the table under a heading matching `section` (or is no section required)? */
5
+ export declare function tableInSection(table: MdTable, section?: string | RegExp): boolean;
6
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/model/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAOxD,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAE1E;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAGjF"}
@@ -0,0 +1,15 @@
1
+ /** Match a string against a name matcher (exact string or regex). */
2
+ function matchName(value, name) {
3
+ return typeof name === 'string' ? value === name : name.test(value);
4
+ }
5
+ /** Does the document have a heading matching `name`? */
6
+ export function hasSection(doc, name) {
7
+ return doc.sections.some((s) => matchName(s.name, name));
8
+ }
9
+ /** Is the table under a heading matching `section` (or is no section required)? */
10
+ export function tableInSection(table, section) {
11
+ if (section === undefined)
12
+ return true;
13
+ return table.sectionPath.some((h) => matchName(h, section));
14
+ }
15
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/model/query.ts"],"names":[],"mappings":"AAEA,qEAAqE;AACrE,SAAS,SAAS,CAAC,KAAa,EAAE,IAAqB;IACrD,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACrE,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,UAAU,CAAC,GAAe,EAAE,IAAqB;IAC/D,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,KAAc,EAAE,OAAyB;IACtE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACtC,OAAO,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAA;AAC7D,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { MdDocument, MdTable } from './document.js';
2
+ /**
3
+ * A single body row of a GFM table, as a first-class element.
4
+ *
5
+ * This is the element type of the `rows()` entry point and the context passed
6
+ * to `haveTableRowsSatisfying`'s row validator — one type, two consumers. A row
7
+ * carries its located-column accessor (`get`), its real source line, and back
8
+ * references to the document and table it came from.
9
+ */
10
+ export interface MdRow {
11
+ /** The row's cells, trimmed. */
12
+ readonly cells: readonly string[];
13
+ /** Cell text for a located column role (`''` if the role's column wasn't found). */
14
+ readonly get: (role: string) => string;
15
+ /** 0-based data-row index within its table (header excluded). */
16
+ readonly rowIndex: number;
17
+ /** 1-based source line of this row — the exact file:line for diagnostics. */
18
+ readonly line: number;
19
+ /** The document this row belongs to. */
20
+ readonly doc: MdDocument;
21
+ /** The table this row belongs to. */
22
+ readonly table: MdTable;
23
+ }
24
+ /** How role names map to header-column patterns. Every role must be present. */
25
+ export type ColumnSpec = Readonly<Record<string, RegExp>>;
26
+ /** Options shared by `rows()` and `haveTableRowsSatisfying`. */
27
+ export interface RowMatchOptions {
28
+ /** Restrict to tables under a heading matching this. */
29
+ readonly section?: string | RegExp;
30
+ /**
31
+ * role → header pattern. A table participates only if its header matches
32
+ * every pattern; the row's `get(role)` then reads the located cell.
33
+ */
34
+ readonly columns: ColumnSpec;
35
+ }
36
+ /**
37
+ * How many matching tables to draw rows from:
38
+ * - `all` (default) — every matching table contributes rows. A correspondence
39
+ * source (`rows()`) must not silently ignore a second matching table.
40
+ * - `first` — only the first matching table, preserving the historical
41
+ * `haveTableRowsSatisfying` semantics.
42
+ */
43
+ export type RowMatchMode = 'all' | 'first';
44
+ /**
45
+ * Extract table rows as first-class `MdRow` elements.
46
+ *
47
+ * Finds the tables in the document that sit under the requested section (if
48
+ * any) and have all the requested columns (`mode` decides all vs. first), then
49
+ * yields one `MdRow` per body row with its real source line.
50
+ */
51
+ export declare function matchTableRows(doc: MdDocument, opts: RowMatchOptions, mode?: RowMatchMode): MdRow[];
52
+ //# sourceMappingURL=rows.d.ts.map