@timiagama/ecr 0.0.1 → 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 (138) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +16 -0
  3. package/README.md +411 -7
  4. package/dist/bin.d.ts +20 -0
  5. package/dist/bin.d.ts.map +1 -0
  6. package/dist/bin.js +26 -0
  7. package/dist/bin.js.map +1 -0
  8. package/dist/cli/corpus-loader.d.ts +198 -0
  9. package/dist/cli/corpus-loader.d.ts.map +1 -0
  10. package/dist/cli/corpus-loader.js +351 -0
  11. package/dist/cli/corpus-loader.js.map +1 -0
  12. package/dist/cli/corpus-statistics.d.ts +113 -0
  13. package/dist/cli/corpus-statistics.d.ts.map +1 -0
  14. package/dist/cli/corpus-statistics.js +119 -0
  15. package/dist/cli/corpus-statistics.js.map +1 -0
  16. package/dist/cli/diagnostic-reporter.d.ts +103 -0
  17. package/dist/cli/diagnostic-reporter.d.ts.map +1 -0
  18. package/dist/cli/diagnostic-reporter.js +254 -0
  19. package/dist/cli/diagnostic-reporter.js.map +1 -0
  20. package/dist/cli/project-ignore.d.ts +113 -0
  21. package/dist/cli/project-ignore.d.ts.map +1 -0
  22. package/dist/cli/project-ignore.js +199 -0
  23. package/dist/cli/project-ignore.js.map +1 -0
  24. package/dist/cli/safe-text.d.ts +25 -0
  25. package/dist/cli/safe-text.d.ts.map +1 -0
  26. package/dist/cli/safe-text.js +34 -0
  27. package/dist/cli/safe-text.js.map +1 -0
  28. package/dist/cli/supervisor.d.ts +108 -0
  29. package/dist/cli/supervisor.d.ts.map +1 -0
  30. package/dist/cli/supervisor.js +139 -0
  31. package/dist/cli/supervisor.js.map +1 -0
  32. package/dist/cli.d.ts +247 -0
  33. package/dist/cli.d.ts.map +1 -0
  34. package/dist/cli.js +591 -0
  35. package/dist/cli.js.map +1 -0
  36. package/dist/corpus-validator.d.ts +183 -0
  37. package/dist/corpus-validator.d.ts.map +1 -0
  38. package/dist/corpus-validator.js +479 -0
  39. package/dist/corpus-validator.js.map +1 -0
  40. package/dist/document-identity-rule.d.ts +198 -0
  41. package/dist/document-identity-rule.d.ts.map +1 -0
  42. package/dist/document-identity-rule.js +244 -0
  43. package/dist/document-identity-rule.js.map +1 -0
  44. package/dist/ecr.d.ts +103 -0
  45. package/dist/ecr.d.ts.map +1 -0
  46. package/dist/ecr.js +216 -0
  47. package/dist/ecr.js.map +1 -0
  48. package/dist/glob-pattern.d.ts +94 -0
  49. package/dist/glob-pattern.d.ts.map +1 -0
  50. package/dist/glob-pattern.js +188 -0
  51. package/dist/glob-pattern.js.map +1 -0
  52. package/dist/heading-source-form.d.ts +77 -0
  53. package/dist/heading-source-form.d.ts.map +1 -0
  54. package/dist/heading-source-form.js +129 -0
  55. package/dist/heading-source-form.js.map +1 -0
  56. package/dist/identifier-grammar.d.ts +212 -0
  57. package/dist/identifier-grammar.d.ts.map +1 -0
  58. package/dist/identifier-grammar.js +273 -0
  59. package/dist/identifier-grammar.js.map +1 -0
  60. package/dist/index.d.ts +19 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +11 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/inline-reference-rule.d.ts +557 -0
  65. package/dist/inline-reference-rule.d.ts.map +1 -0
  66. package/dist/inline-reference-rule.js +802 -0
  67. package/dist/inline-reference-rule.js.map +1 -0
  68. package/dist/meta-documents.d.ts +91 -0
  69. package/dist/meta-documents.d.ts.map +1 -0
  70. package/dist/meta-documents.js +133 -0
  71. package/dist/meta-documents.js.map +1 -0
  72. package/dist/per-document-visitor.d.ts +510 -0
  73. package/dist/per-document-visitor.d.ts.map +1 -0
  74. package/dist/per-document-visitor.js +1032 -0
  75. package/dist/per-document-visitor.js.map +1 -0
  76. package/dist/references-section-rule.d.ts +482 -0
  77. package/dist/references-section-rule.d.ts.map +1 -0
  78. package/dist/references-section-rule.js +777 -0
  79. package/dist/references-section-rule.js.map +1 -0
  80. package/dist/section-hierarchy-rule.d.ts +299 -0
  81. package/dist/section-hierarchy-rule.d.ts.map +1 -0
  82. package/dist/section-hierarchy-rule.js +482 -0
  83. package/dist/section-hierarchy-rule.js.map +1 -0
  84. package/dist/source-alignment.d.ts +41 -0
  85. package/dist/source-alignment.d.ts.map +1 -0
  86. package/dist/source-alignment.js +166 -0
  87. package/dist/source-alignment.js.map +1 -0
  88. package/dist/source-lines.d.ts +69 -0
  89. package/dist/source-lines.d.ts.map +1 -0
  90. package/dist/source-lines.js +104 -0
  91. package/dist/source-lines.js.map +1 -0
  92. package/dist/spec-version.d.ts +19 -0
  93. package/dist/spec-version.d.ts.map +1 -0
  94. package/dist/spec-version.js +19 -0
  95. package/dist/spec-version.js.map +1 -0
  96. package/dist/types.d.ts +219 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +11 -0
  99. package/dist/types.js.map +1 -0
  100. package/examples/docs/0. Orientation/0.0 - System Overview.md +34 -0
  101. package/examples/docs/0. Orientation/0.0.1 - Glossary.md +21 -0
  102. package/examples/docs/0. Orientation/0.0.2 - Quality Gates.md +22 -0
  103. package/examples/docs/3. Ingestion/3.1 - Ingestion - Validation Rules.md +33 -0
  104. package/examples/docs/4. Payments/4.10 - Settlement.md +22 -0
  105. package/examples/docs/4. Payments/4.2 - Payment Processing Contract.md +33 -0
  106. package/examples/docs/8. Orchestration/8.1 - Workflow Orchestration Contract.md +38 -0
  107. package/examples/docs/8. Orchestration/8.1.3 - Retry Policy.md +17 -0
  108. package/examples/docs/8. Orchestration/8.10 - Dead Letter Queue.md +20 -0
  109. package/examples/docs/README.md +7 -0
  110. package/package.json +65 -7
  111. package/protocol/navigation-protocol.md +223 -0
  112. package/spec/v2/1 - ECR - Structural Specification.md +1467 -0
  113. package/spec/v2/2 - ECR - User Guide.md +845 -0
  114. package/spec/v2/3 - Design Rationale - The Section Separator.md +243 -0
  115. package/src/bin.ts +30 -0
  116. package/src/cli/corpus-loader.ts +482 -0
  117. package/src/cli/corpus-statistics.ts +196 -0
  118. package/src/cli/diagnostic-reporter.ts +344 -0
  119. package/src/cli/project-ignore.ts +238 -0
  120. package/src/cli/safe-text.ts +39 -0
  121. package/src/cli/supervisor.ts +204 -0
  122. package/src/cli.ts +836 -0
  123. package/src/corpus-validator.ts +642 -0
  124. package/src/document-identity-rule.ts +422 -0
  125. package/src/ecr.ts +298 -0
  126. package/src/glob-pattern.ts +242 -0
  127. package/src/heading-source-form.ts +173 -0
  128. package/src/identifier-grammar.ts +380 -0
  129. package/src/index.ts +78 -0
  130. package/src/inline-reference-rule.ts +1235 -0
  131. package/src/meta-documents.ts +159 -0
  132. package/src/per-document-visitor.ts +1528 -0
  133. package/src/references-section-rule.ts +1182 -0
  134. package/src/section-hierarchy-rule.ts +705 -0
  135. package/src/source-alignment.ts +209 -0
  136. package/src/source-lines.ts +123 -0
  137. package/src/spec-version.ts +19 -0
  138. package/src/types.ts +267 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Meta-Document Filtering
3
+ *
4
+ * ECR governs *architectural* documents — those that carry a DocID and
5
+ * participate in the reference graph. A corpus also contains documents that
6
+ * deliberately sit outside that graph: READMEs, agent instruction files,
7
+ * contributing guides, changelogs and licences. These have no DocID by design
8
+ * and must not be reported as structurally invalid.
9
+ *
10
+ * File discovery is the host's responsibility (spec 1#3.2), so this module is
11
+ * offered for hosts to apply when assembling a corpus rather than being
12
+ * enforced inside the rules themselves.
13
+ */
14
+
15
+ import { GlobPattern } from './glob-pattern.js';
16
+
17
+ /**
18
+ * Filenames that are conventionally outside the ECR reference graph.
19
+ *
20
+ * Matching is case-insensitive and ignores the file extension, so `README.md`,
21
+ * `readme.MD` and `Readme` are all treated alike.
22
+ */
23
+ export const DEFAULT_META_DOCUMENT_NAMES: readonly string[] = [
24
+ // The name `ecr init` once gave the navigation protocol when it wrote it into
25
+ // a corpus. The protocol carries no DocID by design, so a copy kept in a
26
+ // corpus under that name must not be reported as an invalid document.
27
+ 'ecr-navigation-protocol',
28
+ 'readme',
29
+ 'claude',
30
+ 'agents',
31
+ 'contributing',
32
+ 'changelog',
33
+ 'license',
34
+ 'licence',
35
+ 'code_of_conduct',
36
+ 'security',
37
+ 'authors',
38
+ 'notice',
39
+ ];
40
+
41
+ /**
42
+ * Decides which documents in a corpus are meta-documents and therefore exempt
43
+ * from ECR structural validation.
44
+ *
45
+ * A document is exempt when its filename matches a known meta-document name, or
46
+ * when its path matches one of the caller-supplied ignore patterns.
47
+ *
48
+ * Ignore patterns use a minimal glob syntax: `*` matches any run of characters
49
+ * except `/`, and `**` matches any run of characters including `/`. Patterns are
50
+ * matched against the document's corpus-relative path using forward slashes.
51
+ */
52
+ export class MetaDocumentFilter {
53
+ /** Lower-cased filenames treated as meta-documents. */
54
+ private readonly metaDocumentNames: ReadonlySet<string>;
55
+
56
+ /** Compiled ignore patterns supplied by the caller. */
57
+ private readonly ignorePatterns: readonly GlobPattern[];
58
+
59
+ /**
60
+ * Compiled directory parts of the ignore patterns that exclude everything
61
+ * beneath a directory: those ending in slash-double-star, and `**` itself.
62
+ */
63
+ private readonly ignoredDirectoryPatterns: readonly GlobPattern[];
64
+
65
+ /**
66
+ * Creates a filter.
67
+ *
68
+ * @param ignorePatterns - Additional glob patterns to exclude, matched against the corpus-relative path
69
+ * @param metaDocumentNames - Filenames treated as meta-documents; defaults to {@link DEFAULT_META_DOCUMENT_NAMES}
70
+ */
71
+ public constructor(
72
+ ignorePatterns: readonly string[] = [],
73
+ metaDocumentNames: readonly string[] = DEFAULT_META_DOCUMENT_NAMES,
74
+ ) {
75
+ this.metaDocumentNames = new Set(
76
+ metaDocumentNames.map((name: string): string => name.toLowerCase()),
77
+ );
78
+ this.ignorePatterns = ignorePatterns.map(
79
+ (pattern: string): GlobPattern => new GlobPattern(pattern),
80
+ );
81
+ this.ignoredDirectoryPatterns = ignorePatterns
82
+ .map((pattern: string): string | undefined => MetaDocumentFilter.readIgnoredDirectory(pattern))
83
+ .filter((directory: string | undefined): directory is string => directory !== undefined)
84
+ .map((directory: string): GlobPattern => new GlobPattern(directory));
85
+ }
86
+
87
+ /**
88
+ * Determines whether a document should be excluded from ECR validation.
89
+ *
90
+ * @param corpusRelativePath - The document's path relative to the corpus root, using forward slashes
91
+ * @returns `true` when the document is a meta-document or matches an ignore pattern
92
+ */
93
+ public shouldExclude(corpusRelativePath: string): boolean {
94
+ return (
95
+ this.isMetaDocument(corpusRelativePath) ||
96
+ this.matchesIgnorePattern(corpusRelativePath)
97
+ );
98
+ }
99
+
100
+ /**
101
+ * Determines whether a path names a conventional meta-document.
102
+ *
103
+ * @param corpusRelativePath - The document's path relative to the corpus root
104
+ * @returns `true` when the filename, without extension, is a known meta-document name
105
+ */
106
+ public isMetaDocument(corpusRelativePath: string): boolean {
107
+ const lastSlashIndex: number = corpusRelativePath.lastIndexOf('/');
108
+ const fileName: string = corpusRelativePath.substring(lastSlashIndex + 1);
109
+ const lastDotIndex: number = fileName.lastIndexOf('.');
110
+ const baseName: string =
111
+ lastDotIndex > 0 ? fileName.substring(0, lastDotIndex) : fileName;
112
+
113
+ return this.metaDocumentNames.has(baseName.toLowerCase());
114
+ }
115
+
116
+ /**
117
+ * Determines whether a path matches any caller-supplied ignore pattern.
118
+ *
119
+ * @param corpusRelativePath - The document's path relative to the corpus root
120
+ * @returns `true` when at least one ignore pattern matches
121
+ */
122
+ public matchesIgnorePattern(corpusRelativePath: string): boolean {
123
+ return this.ignorePatterns.some((pattern: GlobPattern): boolean =>
124
+ pattern.matches(corpusRelativePath),
125
+ );
126
+ }
127
+
128
+ /**
129
+ * Determines whether an ignore pattern excludes every path beneath a
130
+ * directory, so that the directory need not be walked at all.
131
+ *
132
+ * Only a pattern ending in slash-double-star (or `**` alone) says so: `vendor/**`
133
+ * excludes all of `vendor`, but `vendor/*` excludes only the files directly
134
+ * inside it, so `vendor` must still be walked for `vendor/a/b.md`.
135
+ *
136
+ * @param corpusRelativeDirectory - The directory's path relative to the corpus root, using forward slashes, without a trailing slash
137
+ * @returns `true` when no path beneath the directory could be included
138
+ */
139
+ public excludesDirectory(corpusRelativeDirectory: string): boolean {
140
+ return this.ignoredDirectoryPatterns.some((pattern: GlobPattern): boolean =>
141
+ pattern.matches(corpusRelativeDirectory),
142
+ );
143
+ }
144
+
145
+ /**
146
+ * Reads the directory part of an ignore pattern that excludes a whole
147
+ * directory.
148
+ *
149
+ * @param pattern - An ignore pattern
150
+ * @returns The pattern for the excluded directories, or `undefined` when the pattern does not exclude whole directories
151
+ */
152
+ private static readIgnoredDirectory(pattern: string): string | undefined {
153
+ if (pattern === '**') {
154
+ return pattern;
155
+ }
156
+
157
+ return pattern.endsWith('/**') ? pattern.slice(0, -'/**'.length) : undefined;
158
+ }
159
+ }