@nielspeter/eess-ts 0.1.1 → 0.2.1

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 (41) hide show
  1. package/README.md +62 -11
  2. package/dist/cli/commands/explain.d.ts +2 -0
  3. package/dist/cli/commands/explain.d.ts.map +1 -1
  4. package/dist/cli/commands/explain.js +52 -1
  5. package/dist/cli/commands/explain.js.map +1 -1
  6. package/dist/cli/commands/init.d.ts +23 -0
  7. package/dist/cli/commands/init.d.ts.map +1 -0
  8. package/dist/cli/commands/init.js +387 -0
  9. package/dist/cli/commands/init.js.map +1 -0
  10. package/dist/cli/index.d.ts +5 -0
  11. package/dist/cli/index.d.ts.map +1 -1
  12. package/dist/cli/index.js +29 -5
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/cli/resolve-config.d.ts.map +1 -1
  15. package/dist/cli/resolve-config.js +11 -1
  16. package/dist/cli/resolve-config.js.map +1 -1
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/presets/agent-guardrails.d.ts +32 -0
  22. package/dist/presets/agent-guardrails.d.ts.map +1 -0
  23. package/dist/presets/agent-guardrails.js +87 -0
  24. package/dist/presets/agent-guardrails.js.map +1 -0
  25. package/dist/presets/index.d.ts +4 -0
  26. package/dist/presets/index.d.ts.map +1 -1
  27. package/dist/presets/index.js +2 -0
  28. package/dist/presets/index.js.map +1 -1
  29. package/dist/presets/recommended.d.ts +33 -0
  30. package/dist/presets/recommended.d.ts.map +1 -0
  31. package/dist/presets/recommended.js +81 -0
  32. package/dist/presets/recommended.js.map +1 -0
  33. package/dist/tsconfig/strict-family.d.ts +30 -0
  34. package/dist/tsconfig/strict-family.d.ts.map +1 -0
  35. package/dist/tsconfig/strict-family.js +45 -0
  36. package/dist/tsconfig/strict-family.js.map +1 -0
  37. package/dist/tsconfig/tsconfig-builder.d.ts +32 -0
  38. package/dist/tsconfig/tsconfig-builder.d.ts.map +1 -0
  39. package/dist/tsconfig/tsconfig-builder.js +149 -0
  40. package/dist/tsconfig/tsconfig-builder.js.map +1 -0
  41. package/package.json +2 -2
@@ -0,0 +1,32 @@
1
+ import type { CompilerOptions } from 'ts-morph';
2
+ import { TerminalBuilder } from '@nielspeter/eess';
3
+ import type { ArchProject } from '../core/project.js';
4
+ import type { ArchViolation } from '../core/violation.js';
5
+ /**
6
+ * Asserts that a project's resolved TypeScript compiler options match a
7
+ * user-supplied spec. A non-iterating rule (one project → one options object),
8
+ * so it extends {@link TerminalBuilder} like the smell detectors rather than the
9
+ * element-builder DSL. One violation is emitted per mismatched flag; the flag
10
+ * name is the violation `element`, so `.excluding('strictNullChecks')` filters
11
+ * by flag.
12
+ */
13
+ export declare class TsconfigBuilder extends TerminalBuilder {
14
+ private readonly project;
15
+ private _requirements;
16
+ constructor(project: ArchProject);
17
+ /**
18
+ * Merge a partial compiler-options spec into the requirements for this rule.
19
+ * Each present key must equal the project's resolved value (strict-family
20
+ * flags are resolved through `strict: true` the way tsc resolves them).
21
+ * Multiple `.requires()` calls merge additively; later keys win on conflict.
22
+ */
23
+ requires(spec: Partial<CompilerOptions>): this;
24
+ protected collectViolations(): ArchViolation[];
25
+ }
26
+ /**
27
+ * Entry point for a tsconfig config-assertion rule. Mirrors `project()` /
28
+ * `smells` — a flat top-level entry returning a builder that composes with
29
+ * `.because()` / `.excluding()` / `.check()` / `.warn()`.
30
+ */
31
+ export declare function tsconfig(p: ArchProject): TsconfigBuilder;
32
+ //# sourceMappingURL=tsconfig-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsconfig-builder.d.ts","sourceRoot":"","sources":["../../src/tsconfig/tsconfig-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAKzD;;;;;;;GAOG;AACH,qBAAa,eAAgB,SAAQ,eAAe;IAGtC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,aAAa,CAA+B;gBAEvB,OAAO,EAAE,WAAW;IAIjD;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAK9C,SAAS,CAAC,iBAAiB,IAAI,aAAa,EAAE;CAyB/C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,eAAe,CAExD"}
@@ -0,0 +1,149 @@
1
+ import { ScriptTarget, ModuleKind, ModuleResolutionKind } from 'ts-morph';
2
+ import { TerminalBuilder } from '@nielspeter/eess';
3
+ import { isStrictFamily, resolveFlag } from './strict-family.js';
4
+ const RULE_DESCRIPTION = 'tsconfig compiler options must satisfy requirements';
5
+ /**
6
+ * Asserts that a project's resolved TypeScript compiler options match a
7
+ * user-supplied spec. A non-iterating rule (one project → one options object),
8
+ * so it extends {@link TerminalBuilder} like the smell detectors rather than the
9
+ * element-builder DSL. One violation is emitted per mismatched flag; the flag
10
+ * name is the violation `element`, so `.excluding('strictNullChecks')` filters
11
+ * by flag.
12
+ */
13
+ export class TsconfigBuilder extends TerminalBuilder {
14
+ project;
15
+ _requirements = {};
16
+ constructor(project) {
17
+ super();
18
+ this.project = project;
19
+ }
20
+ /**
21
+ * Merge a partial compiler-options spec into the requirements for this rule.
22
+ * Each present key must equal the project's resolved value (strict-family
23
+ * flags are resolved through `strict: true` the way tsc resolves them).
24
+ * Multiple `.requires()` calls merge additively; later keys win on conflict.
25
+ */
26
+ requires(spec) {
27
+ this._requirements = { ...this._requirements, ...spec };
28
+ return this;
29
+ }
30
+ collectViolations() {
31
+ const opts = this.project._project.getCompilerOptions();
32
+ const file = this.project.tsConfigPath;
33
+ const violations = [];
34
+ for (const key of Object.keys(this._requirements)) {
35
+ const expected = this._requirements[key];
36
+ const strictFamily = isStrictFamily(key);
37
+ const actual = strictFamily ? resolveFlag(opts, key) : opts[key];
38
+ if (valuesEqual(key, expected, actual))
39
+ continue;
40
+ const expectedText = displayValue(key, expected);
41
+ const actualText = displayValue(key, actual);
42
+ violations.push({
43
+ rule: RULE_DESCRIPTION,
44
+ element: key,
45
+ file,
46
+ line: 1,
47
+ message: `compiler option "${key}": required ${expectedText}, actual ${actualText}`,
48
+ suggestion: fixSuggestion(key, expected, strictFamily, opts),
49
+ });
50
+ }
51
+ return violations;
52
+ }
53
+ }
54
+ /**
55
+ * Entry point for a tsconfig config-assertion rule. Mirrors `project()` /
56
+ * `smells` — a flat top-level entry returning a builder that composes with
57
+ * `.because()` / `.excluding()` / `.check()` / `.warn()`.
58
+ */
59
+ export function tsconfig(p) {
60
+ return new TsconfigBuilder(p);
61
+ }
62
+ /**
63
+ * Human-readable fix hint for a mismatched flag. Enum-backed values are rendered
64
+ * by name (`"ES2022"`, never the raw number `9`, which isn't valid tsconfig JSON).
65
+ */
66
+ function fixSuggestion(key, expected, strictFamily, opts) {
67
+ const base = `Set "${key}": ${suggestionLiteral(key, expected)} in compilerOptions.`;
68
+ if (strictFamily && expected === true) {
69
+ // strict is on but the sub-flag is explicitly disabled → drop the override,
70
+ // not "enable strict" (it already is).
71
+ if (Boolean(opts.strict) && opts[key] === false) {
72
+ return `Remove the explicit "${key}": false override — it disables a flag "strict" turns on.`;
73
+ }
74
+ return `${base} Or enable "strict".`;
75
+ }
76
+ return base;
77
+ }
78
+ /** A tsconfig-writable literal for a suggestion — enum names quoted, else JSON. */
79
+ function suggestionLiteral(key, value) {
80
+ if (typeof value === 'number') {
81
+ const name = enumName(key, value);
82
+ if (name !== undefined)
83
+ return `"${name}"`;
84
+ }
85
+ return JSON.stringify(value);
86
+ }
87
+ /**
88
+ * Render a compiler-option value for a message. Numeric enum fields
89
+ * (`target`, `module`, `moduleResolution`) are shown by name, not their raw
90
+ * numeric value; unset shows `(unset)`.
91
+ */
92
+ function displayValue(key, value) {
93
+ if (value === undefined)
94
+ return '(unset)';
95
+ if (typeof value === 'number')
96
+ return enumName(key, value) ?? String(value);
97
+ if (typeof value === 'boolean' || typeof value === 'bigint')
98
+ return String(value);
99
+ if (typeof value === 'string')
100
+ return value;
101
+ return JSON.stringify(value); // arrays, objects, null
102
+ }
103
+ function enumName(key, value) {
104
+ if (key === 'target')
105
+ return ScriptTarget[value];
106
+ if (key === 'module')
107
+ return ModuleKind[value];
108
+ if (key === 'moduleResolution')
109
+ return ModuleResolutionKind[value];
110
+ return undefined;
111
+ }
112
+ /** Options tsc treats as a set (order-insensitive), not an ordered list. */
113
+ const SET_VALUED_KEYS = new Set(['lib', 'types']);
114
+ /**
115
+ * Equality for a required-vs-actual option value. `lib` / `types` are compared
116
+ * order-insensitively (tsc treats them as sets); everything else is deep-compared
117
+ * structurally (primitives, ordered arrays like `paths` entries, plain objects).
118
+ */
119
+ function valuesEqual(key, a, b) {
120
+ if (SET_VALUED_KEYS.has(key) && Array.isArray(a) && Array.isArray(b)) {
121
+ return setEqual(a, b);
122
+ }
123
+ return deepEqual(a, b);
124
+ }
125
+ function setEqual(a, b) {
126
+ if (a.length !== b.length)
127
+ return false;
128
+ const norm = (arr) => arr.map((x) => JSON.stringify(x)).sort();
129
+ const na = norm(a);
130
+ const nb = norm(b);
131
+ return na.every((x, i) => x === nb[i]);
132
+ }
133
+ function deepEqual(a, b) {
134
+ if (a === b)
135
+ return true;
136
+ if (Array.isArray(a) && Array.isArray(b)) {
137
+ return a.length === b.length && a.every((x, i) => deepEqual(x, b[i]));
138
+ }
139
+ if (isRecord(a) && isRecord(b)) {
140
+ const ak = Object.keys(a);
141
+ const bk = Object.keys(b);
142
+ return ak.length === bk.length && ak.every((k) => deepEqual(a[k], b[k]));
143
+ }
144
+ return false;
145
+ }
146
+ function isRecord(value) {
147
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
148
+ }
149
+ //# sourceMappingURL=tsconfig-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsconfig-builder.js","sourceRoot":"","sources":["../../src/tsconfig/tsconfig-builder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nielspeter/eess-ts",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Architecture testing for TypeScript — the TS dialect of the eess family (formerly ts-archunit)",
5
5
  "type": "module",
6
6
  "exports": {
@@ -113,7 +113,7 @@
113
113
  }
114
114
  },
115
115
  "dependencies": {
116
- "@nielspeter/eess": "^0.1.1",
116
+ "@nielspeter/eess": "^0.2.1",
117
117
  "jiti": "^2.6.1",
118
118
  "picomatch": "^4.0.4",
119
119
  "ts-morph": "^27.0.2"