@nielspeter/eess 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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/dist/ansi.d.ts +7 -0
  4. package/dist/ansi.d.ts.map +1 -0
  5. package/dist/ansi.js +16 -0
  6. package/dist/ansi.js.map +1 -0
  7. package/dist/apply-fixes.d.ts +25 -0
  8. package/dist/apply-fixes.d.ts.map +1 -0
  9. package/dist/apply-fixes.js +52 -0
  10. package/dist/apply-fixes.js.map +1 -0
  11. package/dist/baseline-generator.d.ts +18 -0
  12. package/dist/baseline-generator.d.ts.map +1 -0
  13. package/dist/baseline-generator.js +29 -0
  14. package/dist/baseline-generator.js.map +1 -0
  15. package/dist/baseline.d.ts +83 -0
  16. package/dist/baseline.d.ts.map +1 -0
  17. package/dist/baseline.js +115 -0
  18. package/dist/baseline.js.map +1 -0
  19. package/dist/check-options.d.ts +47 -0
  20. package/dist/check-options.d.ts.map +1 -0
  21. package/dist/check-options.js +2 -0
  22. package/dist/check-options.js.map +1 -0
  23. package/dist/code-frame.d.ts +17 -0
  24. package/dist/code-frame.d.ts.map +1 -0
  25. package/dist/code-frame.js +32 -0
  26. package/dist/code-frame.js.map +1 -0
  27. package/dist/combinators.d.ts +55 -0
  28. package/dist/combinators.d.ts.map +1 -0
  29. package/dist/combinators.js +43 -0
  30. package/dist/combinators.js.map +1 -0
  31. package/dist/condition.d.ts +56 -0
  32. package/dist/condition.d.ts.map +1 -0
  33. package/dist/condition.js +2 -0
  34. package/dist/condition.js.map +1 -0
  35. package/dist/correspondence.d.ts +78 -0
  36. package/dist/correspondence.d.ts.map +1 -0
  37. package/dist/correspondence.js +127 -0
  38. package/dist/correspondence.js.map +1 -0
  39. package/dist/define.d.ts +41 -0
  40. package/dist/define.d.ts.map +1 -0
  41. package/dist/define.js +42 -0
  42. package/dist/define.js.map +1 -0
  43. package/dist/diff-aware.d.ts +37 -0
  44. package/dist/diff-aware.d.ts.map +1 -0
  45. package/dist/diff-aware.js +69 -0
  46. package/dist/diff-aware.js.map +1 -0
  47. package/dist/environment.d.ts +14 -0
  48. package/dist/environment.d.ts.map +1 -0
  49. package/dist/environment.js +20 -0
  50. package/dist/environment.js.map +1 -0
  51. package/dist/errors.d.ts +14 -0
  52. package/dist/errors.d.ts.map +1 -0
  53. package/dist/errors.js +21 -0
  54. package/dist/errors.js.map +1 -0
  55. package/dist/exclusion-comments.d.ts +52 -0
  56. package/dist/exclusion-comments.d.ts.map +1 -0
  57. package/dist/exclusion-comments.js +183 -0
  58. package/dist/exclusion-comments.js.map +1 -0
  59. package/dist/execute-rule.d.ts +31 -0
  60. package/dist/execute-rule.d.ts.map +1 -0
  61. package/dist/execute-rule.js +119 -0
  62. package/dist/execute-rule.js.map +1 -0
  63. package/dist/format-github.d.ts +25 -0
  64. package/dist/format-github.d.ts.map +1 -0
  65. package/dist/format-github.js +44 -0
  66. package/dist/format-github.js.map +1 -0
  67. package/dist/format-json.d.ts +12 -0
  68. package/dist/format-json.d.ts.map +1 -0
  69. package/dist/format-json.js +30 -0
  70. package/dist/format-json.js.map +1 -0
  71. package/dist/format.d.ts +25 -0
  72. package/dist/format.d.ts.map +1 -0
  73. package/dist/format.js +66 -0
  74. package/dist/format.js.map +1 -0
  75. package/dist/index.d.ts +42 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +40 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/matching.d.ts +31 -0
  80. package/dist/matching.d.ts.map +1 -0
  81. package/dist/matching.js +64 -0
  82. package/dist/matching.js.map +1 -0
  83. package/dist/predicate.d.ts +11 -0
  84. package/dist/predicate.d.ts.map +1 -0
  85. package/dist/predicate.js +2 -0
  86. package/dist/predicate.js.map +1 -0
  87. package/dist/preset-dispatch.d.ts +46 -0
  88. package/dist/preset-dispatch.d.ts.map +1 -0
  89. package/dist/preset-dispatch.js +48 -0
  90. package/dist/preset-dispatch.js.map +1 -0
  91. package/dist/report.d.ts +38 -0
  92. package/dist/report.d.ts.map +1 -0
  93. package/dist/report.js +45 -0
  94. package/dist/report.js.map +1 -0
  95. package/dist/rule-builder.d.ts +188 -0
  96. package/dist/rule-builder.d.ts.map +1 -0
  97. package/dist/rule-builder.js +323 -0
  98. package/dist/rule-builder.js.map +1 -0
  99. package/dist/rule-description.d.ts +12 -0
  100. package/dist/rule-description.d.ts.map +1 -0
  101. package/dist/rule-description.js +2 -0
  102. package/dist/rule-description.js.map +1 -0
  103. package/dist/rule-metadata.d.ts +17 -0
  104. package/dist/rule-metadata.d.ts.map +1 -0
  105. package/dist/rule-metadata.js +2 -0
  106. package/dist/rule-metadata.js.map +1 -0
  107. package/dist/silent-exclusion.d.ts +38 -0
  108. package/dist/silent-exclusion.d.ts.map +1 -0
  109. package/dist/silent-exclusion.js +30 -0
  110. package/dist/silent-exclusion.js.map +1 -0
  111. package/dist/terminal-builder.d.ts +83 -0
  112. package/dist/terminal-builder.d.ts.map +1 -0
  113. package/dist/terminal-builder.js +134 -0
  114. package/dist/terminal-builder.js.map +1 -0
  115. package/dist/violation.d.ts +51 -0
  116. package/dist/violation.d.ts.map +1 -0
  117. package/dist/violation.js +2 -0
  118. package/dist/violation.js.map +1 -0
  119. package/package.json +40 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Niels Peter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @nielspeter/eess
2
+
3
+ The dialect-independent **kernel** of the [eess](../../README.md) family — _Executable Enforceable Specification System._
4
+
5
+ This package is the engine every eess dialect runs on. It knows nothing about TypeScript, Mermaid, or any specific artifact format; it is generic over the element type being validated.
6
+
7
+ ## What's in here
8
+
9
+ - `RuleBuilder<T, P>` — the fluent `.that().should().check()` chain, generic over element type `T` and project handle `P`
10
+ - `Predicate<T>`, `Condition<T>`, `Matcher<V>` — the interfaces dialects implement
11
+ - `ArchViolation` — the violation model; each dialect supplies its own element→violation adapter
12
+ - Baseline mode, diff-aware filtering, exclusions, and the terminal/GitHub/JSON formatters
13
+ - `definePredicate` / `defineCondition` — extension points for advanced users
14
+
15
+ ## Who uses it
16
+
17
+ You normally don't install this directly — you install a dialect:
18
+
19
+ - [`@nielspeter/eess-ts`](../ts) — TypeScript
20
+ - [`@nielspeter/eess-mermaid`](../mermaid) — Mermaid class diagrams
21
+
22
+ Install `@nielspeter/eess` directly only when authoring a new dialect or a cross-dialect tool on top of the kernel.
23
+
24
+ ## License
25
+
26
+ MIT
package/dist/ansi.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export declare const bold: (text: string) => string;
2
+ export declare const dim: (text: string) => string;
3
+ export declare const red: (text: string) => string;
4
+ export declare const yellow: (text: string) => string;
5
+ export declare const cyan: (text: string) => string;
6
+ export declare const gray: (text: string) => string;
7
+ //# sourceMappingURL=ansi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.d.ts","sourceRoot":"","sources":["../src/ansi.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,IAAI,SALsC,MAAM,KAAK,MAKnC,CAAA;AAC/B,eAAO,MAAM,GAAG,SANuC,MAAM,KAAK,MAMpC,CAAA;AAC9B,eAAO,MAAM,GAAG,SAPuC,MAAM,KAAK,MAOnC,CAAA;AAC/B,eAAO,MAAM,MAAM,SARoC,MAAM,KAAK,MAQhC,CAAA;AAClC,eAAO,MAAM,IAAI,SATsC,MAAM,KAAK,MASlC,CAAA;AAChC,eAAO,MAAM,IAAI,SAVsC,MAAM,KAAK,MAUlC,CAAA"}
package/dist/ansi.js ADDED
@@ -0,0 +1,16 @@
1
+ const enabled = typeof process !== 'undefined' &&
2
+ !process.env['NO_COLOR'] &&
3
+ ((process.env['FORCE_COLOR'] !== undefined && process.env['FORCE_COLOR'] !== '0') ||
4
+ process.stdout?.isTTY === true);
5
+ function wrap(code, resetCode) {
6
+ if (!enabled)
7
+ return (text) => text;
8
+ return (text) => `\x1b[${String(code)}m${text}\x1b[${String(resetCode)}m`;
9
+ }
10
+ export const bold = wrap(1, 22);
11
+ export const dim = wrap(2, 22);
12
+ export const red = wrap(31, 39);
13
+ export const yellow = wrap(33, 39);
14
+ export const cyan = wrap(36, 39);
15
+ export const gray = wrap(90, 39);
16
+ //# sourceMappingURL=ansi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.js","sourceRoot":"","sources":["../src/ansi.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GACX,OAAO,OAAO,KAAK,WAAW;IAC9B,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACxB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,GAAG,CAAC;QAC/E,OAAO,CAAC,MAAM,EAAE,KAAK,KAAK,IAAI,CAAC,CAAA;AAEnC,SAAS,IAAI,CAAC,IAAY,EAAE,SAAiB;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAA;IACnC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,QAAQ,MAAM,CAAC,SAAS,CAAC,GAAG,CAAA;AAC3E,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAC/B,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAC9B,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;AAC/B,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;AAClC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;AAChC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA"}
@@ -0,0 +1,25 @@
1
+ import type { ArchViolation } from './violation.js';
2
+ /** Outcome of an `applyFixes` run. */
3
+ export interface ApplyResult {
4
+ /** Number of fixes applied (or, in dry-run, that would apply). */
5
+ readonly applied: number;
6
+ /** Number of fixes skipped because they overlapped another fix. */
7
+ readonly skipped: number;
8
+ /** Absolute paths of the files edited (or that would be edited). */
9
+ readonly files: readonly string[];
10
+ /** One-line descriptions of the applied fixes, in file/offset order. */
11
+ readonly descriptions: readonly string[];
12
+ }
13
+ /**
14
+ * Apply the deterministic fixes carried by `violations` (plan 0066).
15
+ *
16
+ * Fixes are grouped by file and applied end-to-start so earlier offsets stay
17
+ * valid. Overlapping fixes on a file are **all skipped** — a fix is only ever
18
+ * applied when it is unambiguous, so a collision is reported, never guessed.
19
+ * With `write: false` (dry-run) nothing is written; the result still reports
20
+ * what would change.
21
+ */
22
+ export declare function applyFixes(violations: readonly ArchViolation[], opts: {
23
+ write: boolean;
24
+ }): ApplyResult;
25
+ //# sourceMappingURL=apply-fixes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-fixes.d.ts","sourceRoot":"","sources":["../src/apply-fixes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAW,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE5D,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CACzC;AAOD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,SAAS,aAAa,EAAE,EACpC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GACvB,WAAW,CAmCb"}
@@ -0,0 +1,52 @@
1
+ import fs from 'node:fs';
2
+ /** Do two spans on the same file overlap? Touching endpoints do not overlap. */
3
+ function overlaps(a, b) {
4
+ return a.start < b.end && b.start < a.end;
5
+ }
6
+ /**
7
+ * Apply the deterministic fixes carried by `violations` (plan 0066).
8
+ *
9
+ * Fixes are grouped by file and applied end-to-start so earlier offsets stay
10
+ * valid. Overlapping fixes on a file are **all skipped** — a fix is only ever
11
+ * applied when it is unambiguous, so a collision is reported, never guessed.
12
+ * With `write: false` (dry-run) nothing is written; the result still reports
13
+ * what would change.
14
+ */
15
+ export function applyFixes(violations, opts) {
16
+ const byFile = new Map();
17
+ for (const v of violations) {
18
+ if (v.fix === undefined)
19
+ continue;
20
+ const list = byFile.get(v.fix.file);
21
+ if (list)
22
+ list.push(v.fix);
23
+ else
24
+ byFile.set(v.fix.file, [v.fix]);
25
+ }
26
+ let applied = 0;
27
+ let skipped = 0;
28
+ const files = [];
29
+ const descriptions = [];
30
+ for (const [file, fixes] of byFile) {
31
+ // Drop any fix that overlaps another (skip both) — never write a guess.
32
+ const safe = fixes.filter((f) => !fixes.some((o) => o !== f && overlaps(f, o)));
33
+ skipped += fixes.length - safe.length;
34
+ if (safe.length === 0)
35
+ continue;
36
+ // Apply last-first so each edit's offsets remain valid.
37
+ const ordered = [...safe].sort((a, b) => b.start - a.start);
38
+ let content = fs.readFileSync(file, 'utf8');
39
+ for (const f of ordered) {
40
+ content = content.slice(0, f.start) + f.replacement + content.slice(f.end);
41
+ }
42
+ if (opts.write)
43
+ fs.writeFileSync(file, content);
44
+ files.push(file);
45
+ applied += safe.length;
46
+ // Report in forward (offset-ascending) order for readability.
47
+ for (const f of [...safe].sort((a, b) => a.start - b.start))
48
+ descriptions.push(f.describe);
49
+ }
50
+ return { applied, skipped, files, descriptions };
51
+ }
52
+ //# sourceMappingURL=apply-fixes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-fixes.js","sourceRoot":"","sources":["../src/apply-fixes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AAexB,gFAAgF;AAChF,SAAS,QAAQ,CAAC,CAAU,EAAE,CAAU;IACtC,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAA;AAC3C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CACxB,UAAoC,EACpC,IAAwB;IAExB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAA;IAC3C,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS;YAAE,SAAQ;QACjC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACnC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;;YACrB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACnC,wEAAwE;QACxE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/E,OAAO,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACrC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,SAAQ;QAE/B,wDAAwD;QACxD,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QAC3D,IAAI,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC3C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC5E,CAAC;QACD,IAAI,IAAI,CAAC,KAAK;YAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAE/C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAChB,OAAO,IAAI,IAAI,CAAC,MAAM,CAAA;QACtB,8DAA8D;QAC9D,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;YAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;IAC5F,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA;AAClD,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ArchViolation } from './violation.js';
2
+ /**
3
+ * Collect violations from rules WITHOUT throwing.
4
+ *
5
+ * Used to generate a baseline: run all rules, collect violations,
6
+ * write them to a baseline file.
7
+ *
8
+ * @example
9
+ * const violations = collectViolations(
10
+ * classes(p).that().extend('Base').should().notContain(call('parseInt')),
11
+ * classes(p).that().extend('Base').should().notContain(newExpr('Error')),
12
+ * )
13
+ * generateBaseline(violations, 'arch-baseline.json')
14
+ */
15
+ export declare function collectViolations(...builders: Array<{
16
+ check: () => void;
17
+ }>): ArchViolation[];
18
+ //# sourceMappingURL=baseline-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-generator.d.ts","sourceRoot":"","sources":["../src/baseline-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC,GAAG,aAAa,EAAE,CAc5F"}
@@ -0,0 +1,29 @@
1
+ import { ArchRuleError } from './errors.js';
2
+ /**
3
+ * Collect violations from rules WITHOUT throwing.
4
+ *
5
+ * Used to generate a baseline: run all rules, collect violations,
6
+ * write them to a baseline file.
7
+ *
8
+ * @example
9
+ * const violations = collectViolations(
10
+ * classes(p).that().extend('Base').should().notContain(call('parseInt')),
11
+ * classes(p).that().extend('Base').should().notContain(newExpr('Error')),
12
+ * )
13
+ * generateBaseline(violations, 'arch-baseline.json')
14
+ */
15
+ export function collectViolations(...builders) {
16
+ const allViolations = [];
17
+ for (const builder of builders) {
18
+ try {
19
+ builder.check();
20
+ }
21
+ catch (error) {
22
+ if (error instanceof ArchRuleError) {
23
+ allViolations.push(...error.violations);
24
+ }
25
+ }
26
+ }
27
+ return allViolations;
28
+ }
29
+ //# sourceMappingURL=baseline-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-generator.js","sourceRoot":"","sources":["../src/baseline-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,QAAsC;IACzE,MAAM,aAAa,GAAoB,EAAE,CAAA;IAEzC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,CAAC,KAAK,EAAE,CAAA;QACjB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;gBACnC,aAAa,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAA;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC"}
@@ -0,0 +1,83 @@
1
+ import type { ArchViolation } from './violation.js';
2
+ /**
3
+ * A single entry in the baseline file.
4
+ *
5
+ * Violations are identified by rule + file + content hash.
6
+ * Line numbers are stored for human readability but NOT used for matching —
7
+ * they drift as code moves. The content hash (of the violation message +
8
+ * element name) provides stable identity.
9
+ */
10
+ export interface BaselineEntry {
11
+ /** Rule description (from the fluent chain) */
12
+ rule: string;
13
+ /** Relative file path (relative to baseline file location) */
14
+ file: string;
15
+ /** Line number at time of baseline (informational, not used for matching) */
16
+ line: number;
17
+ /** Stable identity hash: sha256(rule + element + message) */
18
+ hash: string;
19
+ }
20
+ /**
21
+ * The baseline file structure.
22
+ */
23
+ export interface BaselineFile {
24
+ /** ISO timestamp when the baseline was generated */
25
+ generatedAt: string;
26
+ /** Number of violations recorded */
27
+ count: number;
28
+ /** The violations */
29
+ violations: BaselineEntry[];
30
+ }
31
+ /**
32
+ * Compute a stable hash for a violation.
33
+ *
34
+ * Uses rule + element + message as identity. This survives:
35
+ * - Line number changes (code moved)
36
+ * - Unrelated code changes in the same file
37
+ *
38
+ * Does NOT survive:
39
+ * - Rule description changes (rewording .because())
40
+ * - Element renames (class renamed)
41
+ * - Message text changes (condition wording updated)
42
+ *
43
+ * This is intentional — if the rule or element changes,
44
+ * the violation should be re-evaluated.
45
+ */
46
+ export declare function hashViolation(violation: ArchViolation): string;
47
+ /**
48
+ * Load a baseline from a JSON file.
49
+ *
50
+ * @param baselinePath - Path to the baseline JSON file
51
+ * @returns A Baseline object for use with check(\{ baseline \})
52
+ */
53
+ export declare function withBaseline(baselinePath: string): Baseline;
54
+ /**
55
+ * Generate a baseline file from a list of violations.
56
+ *
57
+ * Call this to create/update the baseline:
58
+ * ```typescript
59
+ * const violations = collectAllViolations(rules)
60
+ * generateBaseline(violations, 'arch-baseline.json')
61
+ * ```
62
+ */
63
+ export declare function generateBaseline(violations: ArchViolation[], outputPath: string): void;
64
+ /**
65
+ * A loaded baseline. Passed to check(\{ baseline \}) to filter known violations.
66
+ */
67
+ export declare class Baseline {
68
+ private readonly knownHashes;
69
+ private readonly baselineDir;
70
+ constructor(knownHashes: Set<string>, baselineDir: string);
71
+ /**
72
+ * Check if a violation is known (exists in the baseline).
73
+ * Known violations are filtered out — they don't cause failures.
74
+ */
75
+ isKnown(violation: ArchViolation): boolean;
76
+ /**
77
+ * Filter out known violations, returning only new ones.
78
+ */
79
+ filterNew(violations: ArchViolation[]): ArchViolation[];
80
+ /** Number of known violations in the baseline */
81
+ get size(): number;
82
+ }
83
+ //# sourceMappingURL=baseline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../src/baseline.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,qBAAqB;IACrB,UAAU,EAAE,aAAa,EAAE,CAAA;CAC5B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAG9D;AAUD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ,CA6B3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAmBtF;AAED;;GAEG;AACH,qBAAa,QAAQ;IAEjB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,WAAW;gBADX,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,WAAW,EAAE,MAAM;IAGtC;;;OAGG;IACH,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO;IAI1C;;OAEG;IACH,SAAS,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE;IAIvD,iDAAiD;IACjD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,115 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ /**
5
+ * Compute a stable hash for a violation.
6
+ *
7
+ * Uses rule + element + message as identity. This survives:
8
+ * - Line number changes (code moved)
9
+ * - Unrelated code changes in the same file
10
+ *
11
+ * Does NOT survive:
12
+ * - Rule description changes (rewording .because())
13
+ * - Element renames (class renamed)
14
+ * - Message text changes (condition wording updated)
15
+ *
16
+ * This is intentional — if the rule or element changes,
17
+ * the violation should be re-evaluated.
18
+ */
19
+ export function hashViolation(violation) {
20
+ const content = `${violation.rule}::${violation.element}::${violation.message}`;
21
+ return createHash('sha256').update(content).digest('hex').slice(0, 16);
22
+ }
23
+ /**
24
+ * Convert an absolute file path to a path relative to the baseline file.
25
+ * Baseline files store relative paths so they're portable across machines.
26
+ */
27
+ function toRelativePath(absolutePath, baselineDir) {
28
+ return path.relative(baselineDir, absolutePath);
29
+ }
30
+ /**
31
+ * Load a baseline from a JSON file.
32
+ *
33
+ * @param baselinePath - Path to the baseline JSON file
34
+ * @returns A Baseline object for use with check(\{ baseline \})
35
+ */
36
+ export function withBaseline(baselinePath) {
37
+ const resolved = path.resolve(baselinePath);
38
+ const baselineDir = path.dirname(resolved);
39
+ if (!fs.existsSync(resolved)) {
40
+ // No baseline file = no known violations = all violations are new
41
+ return new Baseline(new Set(), baselineDir);
42
+ }
43
+ const raw = fs.readFileSync(resolved, 'utf-8');
44
+ const parsed = JSON.parse(raw);
45
+ if (!parsed ||
46
+ typeof parsed !== 'object' ||
47
+ !('violations' in parsed) ||
48
+ !Array.isArray(parsed.violations)) {
49
+ console.warn(`[eess] Invalid baseline file format at ${resolved} — treating as empty`);
50
+ return new Baseline(new Set(), baselineDir);
51
+ }
52
+ const violations = parsed.violations;
53
+ const hashes = new Set();
54
+ for (const entry of violations) {
55
+ if (entry && typeof entry === 'object' && 'hash' in entry && typeof entry.hash === 'string') {
56
+ hashes.add(entry.hash);
57
+ }
58
+ }
59
+ return new Baseline(hashes, baselineDir);
60
+ }
61
+ /**
62
+ * Generate a baseline file from a list of violations.
63
+ *
64
+ * Call this to create/update the baseline:
65
+ * ```typescript
66
+ * const violations = collectAllViolations(rules)
67
+ * generateBaseline(violations, 'arch-baseline.json')
68
+ * ```
69
+ */
70
+ export function generateBaseline(violations, outputPath) {
71
+ const resolved = path.resolve(outputPath);
72
+ const baselineDir = path.dirname(resolved);
73
+ const entries = violations.map((v) => ({
74
+ rule: v.rule,
75
+ file: toRelativePath(v.file, baselineDir),
76
+ line: v.line,
77
+ hash: hashViolation(v),
78
+ }));
79
+ const baseline = {
80
+ generatedAt: new Date().toISOString(),
81
+ count: entries.length,
82
+ violations: entries,
83
+ };
84
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
85
+ fs.writeFileSync(resolved, JSON.stringify(baseline, null, 2) + '\n');
86
+ }
87
+ /**
88
+ * A loaded baseline. Passed to check(\{ baseline \}) to filter known violations.
89
+ */
90
+ export class Baseline {
91
+ knownHashes;
92
+ baselineDir;
93
+ constructor(knownHashes, baselineDir) {
94
+ this.knownHashes = knownHashes;
95
+ this.baselineDir = baselineDir;
96
+ }
97
+ /**
98
+ * Check if a violation is known (exists in the baseline).
99
+ * Known violations are filtered out — they don't cause failures.
100
+ */
101
+ isKnown(violation) {
102
+ return this.knownHashes.has(hashViolation(violation));
103
+ }
104
+ /**
105
+ * Filter out known violations, returning only new ones.
106
+ */
107
+ filterNew(violations) {
108
+ return violations.filter((v) => !this.isKnown(v));
109
+ }
110
+ /** Number of known violations in the baseline */
111
+ get size() {
112
+ return this.knownHashes.size;
113
+ }
114
+ }
115
+ //# sourceMappingURL=baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.js","sourceRoot":"","sources":["../src/baseline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { ArchViolation } from './violation.js';
2
+ /**
3
+ * Output format for violations.
4
+ *
5
+ * - 'terminal' (default): ANSI-colored output with code frames
6
+ * - 'json': Machine-readable JSON
7
+ * - 'github': GitHub Actions annotation commands
8
+ */
9
+ export type OutputFormat = 'terminal' | 'json' | 'github';
10
+ /**
11
+ * A filter that removes known violations (e.g. from a baseline file).
12
+ * Implemented by `Baseline` in `../helpers/baseline.js`.
13
+ */
14
+ export interface BaselineFilter {
15
+ /** Filter out known violations, returning only new ones. */
16
+ filterNew(violations: ArchViolation[]): ArchViolation[];
17
+ }
18
+ /**
19
+ * A filter that restricts violations to changed files (e.g. from git diff).
20
+ * Implemented by `DiffFilter` in `../helpers/diff-aware.js`.
21
+ */
22
+ export interface DiffFilterLike {
23
+ /** Filter violations to only those in changed files. */
24
+ filterToChanged(violations: ArchViolation[]): ArchViolation[];
25
+ }
26
+ /**
27
+ * Options passed to .check() and .warn() to filter violations.
28
+ *
29
+ * @example
30
+ * // Baseline only
31
+ * .check(\{ baseline \})
32
+ *
33
+ * // Diff-aware only
34
+ * .check(\{ diff: diffAware('main') \})
35
+ *
36
+ * // Both
37
+ * .check(\{ baseline, diff: diffAware('main') \})
38
+ */
39
+ export interface CheckOptions {
40
+ /** Filter out known violations from a baseline file */
41
+ baseline?: BaselineFilter;
42
+ /** Filter to only violations in changed files */
43
+ diff?: DiffFilterLike;
44
+ /** Output format for violations. Default: 'terminal' */
45
+ format?: OutputFormat;
46
+ }
47
+ //# sourceMappingURL=check-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-options.d.ts","sourceRoot":"","sources":["../src/check-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEzD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,SAAS,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAAA;CACxD;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,eAAe,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAAA;CAC9D;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,iDAAiD;IACjD,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,wDAAwD;IACxD,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=check-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-options.js","sourceRoot":"","sources":["../src/check-options.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Options for code frame generation.
3
+ */
4
+ export interface CodeFrameOptions {
5
+ /** Number of context lines before and after the target line. Default: 3 */
6
+ contextLines?: number;
7
+ }
8
+ /**
9
+ * Generate a code frame showing source context around a target line.
10
+ *
11
+ * @param sourceText - Full source file text
12
+ * @param targetLine - 1-based line number to highlight
13
+ * @param options - Context line count
14
+ * @returns Formatted code frame string, or empty string if targetLine is out of range
15
+ */
16
+ export declare function generateCodeFrame(sourceText: string, targetLine: number, options?: CodeFrameOptions): string;
17
+ //# sourceMappingURL=code-frame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-frame.d.ts","sourceRoot":"","sources":["../src/code-frame.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CA4BR"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Generate a code frame showing source context around a target line.
3
+ *
4
+ * @param sourceText - Full source file text
5
+ * @param targetLine - 1-based line number to highlight
6
+ * @param options - Context line count
7
+ * @returns Formatted code frame string, or empty string if targetLine is out of range
8
+ */
9
+ export function generateCodeFrame(sourceText, targetLine, options) {
10
+ const contextLines = options?.contextLines ?? 3;
11
+ if (sourceText === '') {
12
+ return '';
13
+ }
14
+ const lines = sourceText.split('\n');
15
+ if (targetLine < 1 || targetLine > lines.length) {
16
+ return '';
17
+ }
18
+ const start = Math.max(0, targetLine - 1 - contextLines);
19
+ const end = Math.min(lines.length, targetLine + contextLines);
20
+ // Determine gutter width from the largest line number in the range
21
+ const gutterWidth = String(end).length;
22
+ const frameLines = [];
23
+ for (let i = start; i < end; i++) {
24
+ const lineNum = i + 1;
25
+ const isTarget = lineNum === targetLine;
26
+ const marker = isTarget ? '>' : ' ';
27
+ const paddedNum = String(lineNum).padStart(gutterWidth);
28
+ frameLines.push(` ${marker} ${paddedNum} | ${lines[i]}`);
29
+ }
30
+ return frameLines.join('\n');
31
+ }
32
+ //# sourceMappingURL=code-frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-frame.js","sourceRoot":"","sources":["../src/code-frame.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,UAAkB,EAClB,OAA0B;IAE1B,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,CAAC,CAAA;IAC/C,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAEpC,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAChD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC,CAAA;IACxD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,YAAY,CAAC,CAAA;IAE7D,mEAAmE;IACnE,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAA;IAEtC,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAA;QACrB,MAAM,QAAQ,GAAG,OAAO,KAAK,UAAU,CAAA;QACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;QACnC,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;QACvD,UAAU,CAAC,IAAI,CAAC,KAAK,MAAM,IAAI,SAAS,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC3D,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { Predicate } from './predicate.js';
2
+ /**
3
+ * A function that tests a value against a condition.
4
+ *
5
+ * Dialect-independent generalization of a matcher. The TS dialect's
6
+ * `TypeMatcher = (type: Type) => boolean` is structurally a `Matcher<Type>`, so
7
+ * it composes with `not`/`and`/`or` without the kernel knowing about ts-morph.
8
+ */
9
+ export type Matcher<V> = (value: V) => boolean;
10
+ /**
11
+ * Negates a predicate or matcher.
12
+ *
13
+ * Accepts both `Predicate<T>` objects (used in `.that()` chains) and
14
+ * `Matcher<V>` functions (e.g. type matchers used in `.should()` arguments).
15
+ *
16
+ * @example
17
+ * // Negate a predicate:
18
+ * functions(p).that(not(areAsync())).should()...
19
+ *
20
+ * // Negate a type matcher:
21
+ * .should().haveReturnTypeMatching(not(matching(/void/)))
22
+ */
23
+ export declare function not<T>(input: Predicate<T>): Predicate<T>;
24
+ export declare function not<V>(input: Matcher<V>): Matcher<V>;
25
+ /**
26
+ * Combines predicates or matchers with AND logic.
27
+ *
28
+ * All inputs must be the same kind: either all `Predicate<T>` or all
29
+ * `Matcher<V>`. Requires at least one argument.
30
+ *
31
+ * @example
32
+ * // Combine predicates:
33
+ * functions(p).that(and(areAsync(), areExported())).should()...
34
+ *
35
+ * // Combine type matchers:
36
+ * .should().haveReturnTypeMatching(and(matching(/Promise/), not(matching(/void/))))
37
+ */
38
+ export declare function and<T>(...predicates: Predicate<T>[]): Predicate<T>;
39
+ export declare function and<V>(...matchers: Matcher<V>[]): Matcher<V>;
40
+ /**
41
+ * Combines predicates or matchers with OR logic.
42
+ *
43
+ * All inputs must be the same kind: either all `Predicate<T>` or all
44
+ * `Matcher<V>`. Requires at least one argument.
45
+ *
46
+ * @example
47
+ * // Combine predicates:
48
+ * functions(p).that(or(areAsync(), areExported())).should()...
49
+ *
50
+ * // Combine type matchers:
51
+ * .should().haveReturnTypeMatching(or(matching(/Promise/), matching(/Collection/)))
52
+ */
53
+ export declare function or<T>(...predicates: Predicate<T>[]): Predicate<T>;
54
+ export declare function or<V>(...matchers: Matcher<V>[]): Matcher<V>;
55
+ //# sourceMappingURL=combinators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combinators.d.ts","sourceRoot":"","sources":["../src/combinators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAA;AAE9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;AACzD,wBAAgB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAmBrD;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;AACnE,wBAAgB,GAAG,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAe7D;;;;;;;;;;;;GAYG;AACH,wBAAgB,EAAE,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;AAClE,wBAAgB,EAAE,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA"}