@nielspeter/eess 0.4.0 → 0.5.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 (125) hide show
  1. package/README.md +94 -1
  2. package/dist/baseline-generator.d.ts +9 -0
  3. package/dist/baseline-generator.d.ts.map +1 -1
  4. package/dist/baseline-generator.js +9 -0
  5. package/dist/baseline-generator.js.map +1 -1
  6. package/dist/baseline.d.ts +1 -1
  7. package/dist/cardinality.d.ts.map +1 -1
  8. package/dist/cardinality.js +20 -5
  9. package/dist/cardinality.js.map +1 -1
  10. package/dist/cli-config.d.ts +59 -0
  11. package/dist/cli-config.d.ts.map +1 -0
  12. package/dist/cli-config.js +84 -0
  13. package/dist/cli-config.js.map +1 -0
  14. package/dist/collect-result.d.ts +94 -0
  15. package/dist/collect-result.d.ts.map +1 -0
  16. package/dist/collect-result.js +142 -0
  17. package/dist/collect-result.js.map +1 -0
  18. package/dist/combinators.d.ts +14 -0
  19. package/dist/combinators.d.ts.map +1 -1
  20. package/dist/combinators.js +53 -16
  21. package/dist/combinators.js.map +1 -1
  22. package/dist/condition.d.ts +37 -0
  23. package/dist/condition.d.ts.map +1 -1
  24. package/dist/condition.js +48 -1
  25. package/dist/condition.js.map +1 -1
  26. package/dist/correspondence.d.ts +30 -0
  27. package/dist/correspondence.d.ts.map +1 -1
  28. package/dist/correspondence.js +36 -1
  29. package/dist/correspondence.js.map +1 -1
  30. package/dist/dedupe-config-findings.d.ts.map +1 -1
  31. package/dist/dedupe-config-findings.js +27 -0
  32. package/dist/dedupe-config-findings.js.map +1 -1
  33. package/dist/diff-aware.d.ts +8 -9
  34. package/dist/diff-aware.d.ts.map +1 -1
  35. package/dist/diff-aware.js +38 -17
  36. package/dist/diff-aware.js.map +1 -1
  37. package/dist/emitter-findings.d.ts +167 -0
  38. package/dist/emitter-findings.d.ts.map +1 -0
  39. package/dist/emitter-findings.js +237 -0
  40. package/dist/emitter-findings.js.map +1 -0
  41. package/dist/errors.d.ts +48 -0
  42. package/dist/errors.d.ts.map +1 -1
  43. package/dist/errors.js +61 -0
  44. package/dist/errors.js.map +1 -1
  45. package/dist/exclusion-comments.d.ts +36 -1
  46. package/dist/exclusion-comments.d.ts.map +1 -1
  47. package/dist/exclusion-comments.js +185 -37
  48. package/dist/exclusion-comments.js.map +1 -1
  49. package/dist/execute-rule.d.ts +12 -3
  50. package/dist/execute-rule.d.ts.map +1 -1
  51. package/dist/execute-rule.js +184 -7
  52. package/dist/execute-rule.js.map +1 -1
  53. package/dist/file-walk.d.ts +22 -0
  54. package/dist/file-walk.d.ts.map +1 -0
  55. package/dist/file-walk.js +51 -0
  56. package/dist/file-walk.js.map +1 -0
  57. package/dist/format-json.d.ts +13 -0
  58. package/dist/format-json.d.ts.map +1 -1
  59. package/dist/format-json.js +24 -0
  60. package/dist/format-json.js.map +1 -1
  61. package/dist/index.d.ts +14 -46
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +13 -41
  64. package/dist/index.js.map +1 -1
  65. package/dist/internal.d.ts +55 -0
  66. package/dist/internal.d.ts.map +1 -0
  67. package/dist/internal.js +92 -0
  68. package/dist/internal.js.map +1 -0
  69. package/dist/mask-non-comment.d.ts +49 -0
  70. package/dist/mask-non-comment.d.ts.map +1 -0
  71. package/dist/mask-non-comment.js +261 -0
  72. package/dist/mask-non-comment.js.map +1 -0
  73. package/dist/owns-empty-discovery.d.ts.map +1 -1
  74. package/dist/owns-empty-discovery.js +12 -4
  75. package/dist/owns-empty-discovery.js.map +1 -1
  76. package/dist/path-suffix.d.ts +57 -0
  77. package/dist/path-suffix.d.ts.map +1 -0
  78. package/dist/path-suffix.js +73 -0
  79. package/dist/path-suffix.js.map +1 -0
  80. package/dist/predicate.d.ts +12 -0
  81. package/dist/predicate.d.ts.map +1 -1
  82. package/dist/predicate.js +20 -1
  83. package/dist/predicate.js.map +1 -1
  84. package/dist/preset-dispatch.d.ts +6 -34
  85. package/dist/preset-dispatch.d.ts.map +1 -1
  86. package/dist/preset-dispatch.js +30 -52
  87. package/dist/preset-dispatch.js.map +1 -1
  88. package/dist/report.d.ts +31 -7
  89. package/dist/report.d.ts.map +1 -1
  90. package/dist/report.js +174 -15
  91. package/dist/report.js.map +1 -1
  92. package/dist/rule-builder-like.d.ts +8 -2
  93. package/dist/rule-builder-like.d.ts.map +1 -1
  94. package/dist/rule-builder.d.ts +15 -0
  95. package/dist/rule-builder.d.ts.map +1 -1
  96. package/dist/rule-builder.js +41 -36
  97. package/dist/rule-builder.js.map +1 -1
  98. package/dist/rule-description.d.ts +50 -0
  99. package/dist/rule-description.d.ts.map +1 -1
  100. package/dist/rule-description.js +58 -0
  101. package/dist/rule-description.js.map +1 -1
  102. package/dist/selection-memo.d.ts +1 -3
  103. package/dist/selection-memo.d.ts.map +1 -1
  104. package/dist/selection-memo.js +1 -3
  105. package/dist/selection-memo.js.map +1 -1
  106. package/dist/silent-exclusion.d.ts +12 -0
  107. package/dist/silent-exclusion.d.ts.map +1 -1
  108. package/dist/silent-exclusion.js +22 -0
  109. package/dist/silent-exclusion.js.map +1 -1
  110. package/dist/terminal-builder.d.ts +29 -15
  111. package/dist/terminal-builder.d.ts.map +1 -1
  112. package/dist/terminal-builder.js +97 -51
  113. package/dist/terminal-builder.js.map +1 -1
  114. package/dist/vacuity-findings.d.ts +0 -6
  115. package/dist/vacuity-findings.d.ts.map +1 -1
  116. package/dist/vacuity-findings.js +27 -57
  117. package/dist/vacuity-findings.js.map +1 -1
  118. package/dist/violation.d.ts +22 -1
  119. package/dist/violation.d.ts.map +1 -1
  120. package/dist/violation.js.map +1 -1
  121. package/dist/watch.d.ts +71 -0
  122. package/dist/watch.d.ts.map +1 -0
  123. package/dist/watch.js +129 -0
  124. package/dist/watch.js.map +1 -0
  125. package/package.json +6 -1
package/dist/watch.js ADDED
@@ -0,0 +1,129 @@
1
+ import { watch } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { isArchRuleError } from './errors.js';
4
+ import { isNullaryCallable } from './type-guards.js';
5
+ const DEFAULT_DEBOUNCE_MS = 250;
6
+ /** `fs.watch` reports this when a watcher is closed; it is not a fault. */
7
+ const ABORTED = 'The operation was aborted';
8
+ /**
9
+ * Scheduling logic for watch mode — separate from the loop so it is testable
10
+ * without a filesystem.
11
+ *
12
+ * Debounces rapid triggers. A trigger arriving mid-run is remembered and
13
+ * replayed once the run finishes, so a save during a run is never dropped and
14
+ * never starts a second concurrent run.
15
+ */
16
+ export class RunScheduler {
17
+ debounceTimer;
18
+ running = false;
19
+ _pendingRerun = false;
20
+ debounceMs;
21
+ onRun;
22
+ #runCount = 0;
23
+ constructor(onRun, debounceMs = DEFAULT_DEBOUNCE_MS) {
24
+ this.onRun = onRun;
25
+ this.debounceMs = debounceMs;
26
+ }
27
+ /**
28
+ * Completed runs.
29
+ *
30
+ * Hard-private with a getter: the counter is this class's own bookkeeping, and
31
+ * a caller that could reassign it would make the number mean nothing.
32
+ */
33
+ get runCount() {
34
+ return this.#runCount;
35
+ }
36
+ get pendingRerun() {
37
+ return this._pendingRerun;
38
+ }
39
+ get isRunning() {
40
+ return this.running;
41
+ }
42
+ /** Debounce a change on `trigger`, coalescing bursts into a single re-run. */
43
+ schedule(trigger) {
44
+ if (this.debounceTimer)
45
+ clearTimeout(this.debounceTimer);
46
+ this.debounceTimer = setTimeout(() => {
47
+ if (this.running) {
48
+ this._pendingRerun = true;
49
+ return;
50
+ }
51
+ this.executeRun(trigger);
52
+ }, this.debounceMs);
53
+ }
54
+ executeRun(trigger) {
55
+ this.running = true;
56
+ this._pendingRerun = false;
57
+ this.#runCount++;
58
+ process.stdout.write('\x1B[2J\x1B[H'); // clear screen, preserve scrollback
59
+ process.stdout.write(`Change detected: ${trigger}\n\n`);
60
+ this.onRun(trigger)
61
+ .catch((err) => {
62
+ // A rule failure is the expected outcome of a watch run — swallow it and
63
+ // let the reporter's own output stand. Anything else is a real fault.
64
+ if (!isArchRuleError(err) && err instanceof Error) {
65
+ console.error(err.message);
66
+ }
67
+ })
68
+ .finally(() => {
69
+ this.running = false;
70
+ if (this._pendingRerun) {
71
+ this.executeRun('(queued change)');
72
+ }
73
+ else {
74
+ process.stdout.write('\nWatching for changes...\n');
75
+ }
76
+ });
77
+ }
78
+ }
79
+ /** Consume one watcher, scheduling on each qualifying event. */
80
+ function consume(watcher, label, onEvent) {
81
+ void (async () => {
82
+ try {
83
+ for await (const event of watcher)
84
+ onEvent(event);
85
+ }
86
+ catch (err) {
87
+ if (err instanceof Error && err.message !== ABORTED) {
88
+ console.error(`Watcher error on ${label}: ${err.message}`);
89
+ }
90
+ }
91
+ })();
92
+ }
93
+ /**
94
+ * Watch for file changes and re-run the callback.
95
+ *
96
+ * Uses `fs.watch` with `recursive: true` (Node 24+). Debounces rapid events; a
97
+ * change during a run is queued and executed after it completes.
98
+ */
99
+ export function watchAndRerun(options) {
100
+ const { watchDirs, watchFiles, watchedFileRe, onChangeDetected, debounceMs = DEFAULT_DEBOUNCE_MS, } = options;
101
+ const scheduler = new RunScheduler(onChangeDetected, debounceMs);
102
+ const watchers = [];
103
+ for (const dir of watchDirs) {
104
+ const watcher = watch(path.resolve(dir), { recursive: true });
105
+ watchers.push(watcher);
106
+ consume(watcher, dir, (event) => {
107
+ if (event.filename && watchedFileRe.test(event.filename)) {
108
+ scheduler.schedule(event.filename);
109
+ }
110
+ });
111
+ }
112
+ for (const file of watchFiles) {
113
+ const watcher = watch(path.resolve(file));
114
+ watchers.push(watcher);
115
+ consume(watcher, file, () => {
116
+ scheduler.schedule(path.basename(file));
117
+ });
118
+ }
119
+ // Graceful shutdown — close all watchers on SIGINT.
120
+ process.on('SIGINT', () => {
121
+ for (const w of watchers) {
122
+ if ('return' in w && isNullaryCallable(w.return)) {
123
+ void w.return();
124
+ }
125
+ }
126
+ process.exit(0);
127
+ });
128
+ }
129
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@nielspeter/eess",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "eess kernel — the dialect-independent rule engine (RuleBuilder, Predicate, Condition, baseline, formatters). Specifications you can run.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
8
8
  "types": "./dist/index.d.ts",
9
9
  "import": "./dist/index.js"
10
+ },
11
+ "./internal": {
12
+ "types": "./dist/internal.d.ts",
13
+ "import": "./dist/internal.js"
10
14
  }
11
15
  },
12
16
  "files": [
@@ -26,6 +30,7 @@
26
30
  "license": "MIT",
27
31
  "scripts": {
28
32
  "prepublishOnly": "npm run build",
33
+ "prebuild": "rm -rf dist",
29
34
  "build": "tsc -p tsconfig.build.json",
30
35
  "typecheck": "tsc --noEmit",
31
36
  "test": "vitest run",