@nielspeter/eess-ts 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.
- package/LICENSE +21 -0
- package/README.md +364 -0
- package/dist/builders/call-rule-builder.d.ts +199 -0
- package/dist/builders/call-rule-builder.d.ts.map +1 -0
- package/dist/builders/call-rule-builder.js +254 -0
- package/dist/builders/call-rule-builder.js.map +1 -0
- package/dist/builders/class-rule-builder.d.ts +136 -0
- package/dist/builders/class-rule-builder.d.ts.map +1 -0
- package/dist/builders/class-rule-builder.js +253 -0
- package/dist/builders/class-rule-builder.js.map +1 -0
- package/dist/builders/cross-layer-builder.d.ts +96 -0
- package/dist/builders/cross-layer-builder.d.ts.map +1 -0
- package/dist/builders/cross-layer-builder.js +172 -0
- package/dist/builders/cross-layer-builder.js.map +1 -0
- package/dist/builders/function-rule-builder.d.ts +198 -0
- package/dist/builders/function-rule-builder.d.ts.map +1 -0
- package/dist/builders/function-rule-builder.js +287 -0
- package/dist/builders/function-rule-builder.js.map +1 -0
- package/dist/builders/jsx-rule-builder.d.ts +113 -0
- package/dist/builders/jsx-rule-builder.d.ts.map +1 -0
- package/dist/builders/jsx-rule-builder.js +150 -0
- package/dist/builders/jsx-rule-builder.js.map +1 -0
- package/dist/builders/module-rule-builder.d.ts +159 -0
- package/dist/builders/module-rule-builder.d.ts.map +1 -0
- package/dist/builders/module-rule-builder.js +237 -0
- package/dist/builders/module-rule-builder.js.map +1 -0
- package/dist/builders/scoped-function-rule-builder.d.ts +21 -0
- package/dist/builders/scoped-function-rule-builder.d.ts.map +1 -0
- package/dist/builders/scoped-function-rule-builder.js +26 -0
- package/dist/builders/scoped-function-rule-builder.js.map +1 -0
- package/dist/builders/slice-rule-builder.d.ts +85 -0
- package/dist/builders/slice-rule-builder.d.ts.map +1 -0
- package/dist/builders/slice-rule-builder.js +134 -0
- package/dist/builders/slice-rule-builder.js.map +1 -0
- package/dist/builders/type-rule-builder.d.ts +103 -0
- package/dist/builders/type-rule-builder.d.ts.map +1 -0
- package/dist/builders/type-rule-builder.js +170 -0
- package/dist/builders/type-rule-builder.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +4 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/baseline.d.ts +11 -0
- package/dist/cli/commands/baseline.d.ts.map +1 -0
- package/dist/cli/commands/baseline.js +16 -0
- package/dist/cli/commands/baseline.js.map +1 -0
- package/dist/cli/commands/check.d.ts +21 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +94 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +9 -0
- package/dist/cli/commands/explain.d.ts.map +1 -0
- package/dist/cli/commands/explain.js +49 -0
- package/dist/cli/commands/explain.js.map +1 -0
- package/dist/cli/config.d.ts +31 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +20 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +21 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +168 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/load-rules.d.ts +20 -0
- package/dist/cli/load-rules.d.ts.map +1 -0
- package/dist/cli/load-rules.js +97 -0
- package/dist/cli/load-rules.js.map +1 -0
- package/dist/cli/resolve-config.d.ts +11 -0
- package/dist/cli/resolve-config.d.ts.map +1 -0
- package/dist/cli/resolve-config.js +61 -0
- package/dist/cli/resolve-config.js.map +1 -0
- package/dist/cli/watch.d.ts +49 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +138 -0
- package/dist/cli/watch.js.map +1 -0
- package/dist/conditions/body-analysis-function.d.ts +23 -0
- package/dist/conditions/body-analysis-function.d.ts.map +1 -0
- package/dist/conditions/body-analysis-function.js +103 -0
- package/dist/conditions/body-analysis-function.js.map +1 -0
- package/dist/conditions/body-analysis-module.d.ts +27 -0
- package/dist/conditions/body-analysis-module.d.ts.map +1 -0
- package/dist/conditions/body-analysis-module.js +99 -0
- package/dist/conditions/body-analysis-module.js.map +1 -0
- package/dist/conditions/body-analysis.d.ts +34 -0
- package/dist/conditions/body-analysis.d.ts.map +1 -0
- package/dist/conditions/body-analysis.js +95 -0
- package/dist/conditions/body-analysis.js.map +1 -0
- package/dist/conditions/call.d.ts +62 -0
- package/dist/conditions/call.d.ts.map +1 -0
- package/dist/conditions/call.js +267 -0
- package/dist/conditions/call.js.map +1 -0
- package/dist/conditions/catch-analysis.d.ts +31 -0
- package/dist/conditions/catch-analysis.d.ts.map +1 -0
- package/dist/conditions/catch-analysis.js +78 -0
- package/dist/conditions/catch-analysis.js.map +1 -0
- package/dist/conditions/class.d.ts +33 -0
- package/dist/conditions/class.d.ts.map +1 -0
- package/dist/conditions/class.js +110 -0
- package/dist/conditions/class.js.map +1 -0
- package/dist/conditions/cross-layer.d.ts +28 -0
- package/dist/conditions/cross-layer.d.ts.map +1 -0
- package/dist/conditions/cross-layer.js +105 -0
- package/dist/conditions/cross-layer.js.map +1 -0
- package/dist/conditions/dependency.d.ts +73 -0
- package/dist/conditions/dependency.d.ts.map +1 -0
- package/dist/conditions/dependency.js +177 -0
- package/dist/conditions/dependency.js.map +1 -0
- package/dist/conditions/exports.d.ts +33 -0
- package/dist/conditions/exports.d.ts.map +1 -0
- package/dist/conditions/exports.js +101 -0
- package/dist/conditions/exports.js.map +1 -0
- package/dist/conditions/function.d.ts +79 -0
- package/dist/conditions/function.d.ts.map +1 -0
- package/dist/conditions/function.js +167 -0
- package/dist/conditions/function.js.map +1 -0
- package/dist/conditions/helpers.d.ts +14 -0
- package/dist/conditions/helpers.d.ts.map +1 -0
- package/dist/conditions/helpers.js +26 -0
- package/dist/conditions/helpers.js.map +1 -0
- package/dist/conditions/jsx.d.ts +40 -0
- package/dist/conditions/jsx.d.ts.map +1 -0
- package/dist/conditions/jsx.js +133 -0
- package/dist/conditions/jsx.js.map +1 -0
- package/dist/conditions/members.d.ts +74 -0
- package/dist/conditions/members.d.ts.map +1 -0
- package/dist/conditions/members.js +224 -0
- package/dist/conditions/members.js.map +1 -0
- package/dist/conditions/pattern.d.ts +20 -0
- package/dist/conditions/pattern.d.ts.map +1 -0
- package/dist/conditions/pattern.js +108 -0
- package/dist/conditions/pattern.js.map +1 -0
- package/dist/conditions/reverse-dependency.d.ts +28 -0
- package/dist/conditions/reverse-dependency.d.ts.map +1 -0
- package/dist/conditions/reverse-dependency.js +275 -0
- package/dist/conditions/reverse-dependency.js.map +1 -0
- package/dist/conditions/slice.d.ts +49 -0
- package/dist/conditions/slice.d.ts.map +1 -0
- package/dist/conditions/slice.js +153 -0
- package/dist/conditions/slice.js.map +1 -0
- package/dist/conditions/structural.d.ts +58 -0
- package/dist/conditions/structural.d.ts.map +1 -0
- package/dist/conditions/structural.js +102 -0
- package/dist/conditions/structural.js.map +1 -0
- package/dist/conditions/type-level.d.ts +29 -0
- package/dist/conditions/type-level.d.ts.map +1 -0
- package/dist/conditions/type-level.js +48 -0
- package/dist/conditions/type-level.js.map +1 -0
- package/dist/core/import-options.d.ts +32 -0
- package/dist/core/import-options.d.ts.map +1 -0
- package/dist/core/import-options.js +29 -0
- package/dist/core/import-options.js.map +1 -0
- package/dist/core/module-dependencies.d.ts +28 -0
- package/dist/core/module-dependencies.d.ts.map +1 -0
- package/dist/core/module-dependencies.js +35 -0
- package/dist/core/module-dependencies.js.map +1 -0
- package/dist/core/pair-condition.d.ts +10 -0
- package/dist/core/pair-condition.d.ts.map +1 -0
- package/dist/core/pair-condition.js +2 -0
- package/dist/core/pair-condition.js.map +1 -0
- package/dist/core/project.d.ts +68 -0
- package/dist/core/project.d.ts.map +1 -0
- package/dist/core/project.js +127 -0
- package/dist/core/project.js.map +1 -0
- package/dist/core/type-matcher.d.ts +10 -0
- package/dist/core/type-matcher.d.ts.map +1 -0
- package/dist/core/type-matcher.js +2 -0
- package/dist/core/type-matcher.js.map +1 -0
- package/dist/core/violation.d.ts +38 -0
- package/dist/core/violation.d.ts.map +1 -0
- package/dist/core/violation.js +130 -0
- package/dist/core/violation.js.map +1 -0
- package/dist/graphql/index.d.ts +76 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +108 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/resolver-rule-builder.d.ts +75 -0
- package/dist/graphql/resolver-rule-builder.d.ts.map +1 -0
- package/dist/graphql/resolver-rule-builder.js +146 -0
- package/dist/graphql/resolver-rule-builder.js.map +1 -0
- package/dist/graphql/schema-conditions.d.ts +31 -0
- package/dist/graphql/schema-conditions.d.ts.map +1 -0
- package/dist/graphql/schema-conditions.js +119 -0
- package/dist/graphql/schema-conditions.js.map +1 -0
- package/dist/graphql/schema-loader.d.ts +75 -0
- package/dist/graphql/schema-loader.d.ts.map +1 -0
- package/dist/graphql/schema-loader.js +113 -0
- package/dist/graphql/schema-loader.js.map +1 -0
- package/dist/graphql/schema-predicates.d.ts +42 -0
- package/dist/graphql/schema-predicates.d.ts.map +1 -0
- package/dist/graphql/schema-predicates.js +74 -0
- package/dist/graphql/schema-predicates.js.map +1 -0
- package/dist/graphql/schema-rule-builder.d.ts +74 -0
- package/dist/graphql/schema-rule-builder.d.ts.map +1 -0
- package/dist/graphql/schema-rule-builder.js +188 -0
- package/dist/graphql/schema-rule-builder.js.map +1 -0
- package/dist/helpers/body-traversal.d.ts +58 -0
- package/dist/helpers/body-traversal.d.ts.map +1 -0
- package/dist/helpers/body-traversal.js +180 -0
- package/dist/helpers/body-traversal.js.map +1 -0
- package/dist/helpers/callback-extractor.d.ts +28 -0
- package/dist/helpers/callback-extractor.d.ts.map +1 -0
- package/dist/helpers/callback-extractor.js +159 -0
- package/dist/helpers/callback-extractor.js.map +1 -0
- package/dist/helpers/complexity.d.ts +26 -0
- package/dist/helpers/complexity.d.ts.map +1 -0
- package/dist/helpers/complexity.js +64 -0
- package/dist/helpers/complexity.js.map +1 -0
- package/dist/helpers/matchers.d.ts +206 -0
- package/dist/helpers/matchers.d.ts.map +1 -0
- package/dist/helpers/matchers.js +470 -0
- package/dist/helpers/matchers.js.map +1 -0
- package/dist/helpers/pattern.d.ts +37 -0
- package/dist/helpers/pattern.d.ts.map +1 -0
- package/dist/helpers/pattern.js +22 -0
- package/dist/helpers/pattern.js.map +1 -0
- package/dist/helpers/slice-graph.d.ts +32 -0
- package/dist/helpers/slice-graph.d.ts.map +1 -0
- package/dist/helpers/slice-graph.js +89 -0
- package/dist/helpers/slice-graph.js.map +1 -0
- package/dist/helpers/tarjan.d.ts +21 -0
- package/dist/helpers/tarjan.d.ts.map +1 -0
- package/dist/helpers/tarjan.js +71 -0
- package/dist/helpers/tarjan.js.map +1 -0
- package/dist/helpers/type-matchers.d.ts +67 -0
- package/dist/helpers/type-matchers.d.ts.map +1 -0
- package/dist/helpers/type-matchers.js +108 -0
- package/dist/helpers/type-matchers.js.map +1 -0
- package/dist/helpers/within.d.ts +41 -0
- package/dist/helpers/within.d.ts.map +1 -0
- package/dist/helpers/within.js +32 -0
- package/dist/helpers/within.js.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/models/arch-call.d.ts +83 -0
- package/dist/models/arch-call.d.ts.map +1 -0
- package/dist/models/arch-call.js +90 -0
- package/dist/models/arch-call.js.map +1 -0
- package/dist/models/arch-function.d.ts +76 -0
- package/dist/models/arch-function.d.ts.map +1 -0
- package/dist/models/arch-function.js +122 -0
- package/dist/models/arch-function.js.map +1 -0
- package/dist/models/arch-jsx-element.d.ts +75 -0
- package/dist/models/arch-jsx-element.d.ts.map +1 -0
- package/dist/models/arch-jsx-element.js +231 -0
- package/dist/models/arch-jsx-element.js.map +1 -0
- package/dist/models/cross-layer.d.ts +15 -0
- package/dist/models/cross-layer.d.ts.map +1 -0
- package/dist/models/cross-layer.js +2 -0
- package/dist/models/cross-layer.js.map +1 -0
- package/dist/models/slice.d.ts +60 -0
- package/dist/models/slice.d.ts.map +1 -0
- package/dist/models/slice.js +89 -0
- package/dist/models/slice.js.map +1 -0
- package/dist/predicates/call.d.ts +49 -0
- package/dist/predicates/call.d.ts.map +1 -0
- package/dist/predicates/call.js +115 -0
- package/dist/predicates/call.js.map +1 -0
- package/dist/predicates/class.d.ts +42 -0
- package/dist/predicates/class.d.ts.map +1 -0
- package/dist/predicates/class.js +83 -0
- package/dist/predicates/class.js.map +1 -0
- package/dist/predicates/function.d.ts +81 -0
- package/dist/predicates/function.d.ts.map +1 -0
- package/dist/predicates/function.js +157 -0
- package/dist/predicates/function.js.map +1 -0
- package/dist/predicates/identity.d.ts +55 -0
- package/dist/predicates/identity.d.ts.map +1 -0
- package/dist/predicates/identity.js +96 -0
- package/dist/predicates/identity.js.map +1 -0
- package/dist/predicates/index.d.ts +4 -0
- package/dist/predicates/index.d.ts.map +1 -0
- package/dist/predicates/index.js +3 -0
- package/dist/predicates/index.js.map +1 -0
- package/dist/predicates/jsx.d.ts +41 -0
- package/dist/predicates/jsx.d.ts.map +1 -0
- package/dist/predicates/jsx.js +84 -0
- package/dist/predicates/jsx.js.map +1 -0
- package/dist/predicates/metrics.d.ts +30 -0
- package/dist/predicates/metrics.d.ts.map +1 -0
- package/dist/predicates/metrics.js +65 -0
- package/dist/predicates/metrics.js.map +1 -0
- package/dist/predicates/module.d.ts +44 -0
- package/dist/predicates/module.d.ts.map +1 -0
- package/dist/predicates/module.js +70 -0
- package/dist/predicates/module.js.map +1 -0
- package/dist/predicates/type.d.ts +48 -0
- package/dist/predicates/type.d.ts.map +1 -0
- package/dist/predicates/type.js +107 -0
- package/dist/predicates/type.js.map +1 -0
- package/dist/presets/boundaries.d.ts +19 -0
- package/dist/presets/boundaries.d.ts.map +1 -0
- package/dist/presets/boundaries.js +93 -0
- package/dist/presets/boundaries.js.map +1 -0
- package/dist/presets/data-layer.d.ts +20 -0
- package/dist/presets/data-layer.d.ts.map +1 -0
- package/dist/presets/data-layer.js +30 -0
- package/dist/presets/data-layer.js.map +1 -0
- package/dist/presets/index.d.ts +9 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +5 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/layered.d.ts +21 -0
- package/dist/presets/layered.d.ts.map +1 -0
- package/dist/presets/layered.js +103 -0
- package/dist/presets/layered.js.map +1 -0
- package/dist/presets/shared.d.ts +3 -0
- package/dist/presets/shared.d.ts.map +1 -0
- package/dist/presets/shared.js +5 -0
- package/dist/presets/shared.js.map +1 -0
- package/dist/rules/architecture.d.ts +10 -0
- package/dist/rules/architecture.d.ts.map +1 -0
- package/dist/rules/architecture.js +14 -0
- package/dist/rules/architecture.js.map +1 -0
- package/dist/rules/code-quality.d.ts +55 -0
- package/dist/rules/code-quality.d.ts.map +1 -0
- package/dist/rules/code-quality.js +116 -0
- package/dist/rules/code-quality.js.map +1 -0
- package/dist/rules/dependencies.d.ts +32 -0
- package/dist/rules/dependencies.d.ts.map +1 -0
- package/dist/rules/dependencies.js +37 -0
- package/dist/rules/dependencies.js.map +1 -0
- package/dist/rules/errors.d.ts +31 -0
- package/dist/rules/errors.d.ts.map +1 -0
- package/dist/rules/errors.js +97 -0
- package/dist/rules/errors.js.map +1 -0
- package/dist/rules/hygiene.d.ts +54 -0
- package/dist/rules/hygiene.d.ts.map +1 -0
- package/dist/rules/hygiene.js +62 -0
- package/dist/rules/hygiene.js.map +1 -0
- package/dist/rules/metrics-function.d.ts +45 -0
- package/dist/rules/metrics-function.d.ts.map +1 -0
- package/dist/rules/metrics-function.js +87 -0
- package/dist/rules/metrics-function.js.map +1 -0
- package/dist/rules/metrics.d.ts +64 -0
- package/dist/rules/metrics.d.ts.map +1 -0
- package/dist/rules/metrics.js +157 -0
- package/dist/rules/metrics.js.map +1 -0
- package/dist/rules/naming.d.ts +24 -0
- package/dist/rules/naming.d.ts.map +1 -0
- package/dist/rules/naming.js +51 -0
- package/dist/rules/naming.js.map +1 -0
- package/dist/rules/security.d.ts +59 -0
- package/dist/rules/security.d.ts.map +1 -0
- package/dist/rules/security.js +92 -0
- package/dist/rules/security.js.map +1 -0
- package/dist/rules/typescript.d.ts +73 -0
- package/dist/rules/typescript.d.ts.map +1 -0
- package/dist/rules/typescript.js +105 -0
- package/dist/rules/typescript.js.map +1 -0
- package/dist/smells/duplicate-bodies.d.ts +24 -0
- package/dist/smells/duplicate-bodies.d.ts.map +1 -0
- package/dist/smells/duplicate-bodies.js +131 -0
- package/dist/smells/duplicate-bodies.js.map +1 -0
- package/dist/smells/fingerprint.d.ts +27 -0
- package/dist/smells/fingerprint.d.ts.map +1 -0
- package/dist/smells/fingerprint.js +50 -0
- package/dist/smells/fingerprint.js.map +1 -0
- package/dist/smells/inconsistent-siblings.d.ts +21 -0
- package/dist/smells/inconsistent-siblings.d.ts.map +1 -0
- package/dist/smells/inconsistent-siblings.js +135 -0
- package/dist/smells/inconsistent-siblings.js.map +1 -0
- package/dist/smells/index.d.ts +12 -0
- package/dist/smells/index.d.ts.map +1 -0
- package/dist/smells/index.js +15 -0
- package/dist/smells/index.js.map +1 -0
- package/dist/smells/smell-builder.d.ts +37 -0
- package/dist/smells/smell-builder.d.ts.map +1 -0
- package/dist/smells/smell-builder.js +51 -0
- package/dist/smells/smell-builder.js.map +1 -0
- package/package.json +121 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structural.js","sourceRoot":"","sources":["../../src/conditions/structural.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Condition } from '@nielspeter/eess';
|
|
2
|
+
import type { InterfaceDeclaration, TypeAliasDeclaration } from 'ts-morph';
|
|
3
|
+
import type { TypeMatcher } from '../helpers/type-matchers.js';
|
|
4
|
+
type TypeDeclaration = InterfaceDeclaration | TypeAliasDeclaration;
|
|
5
|
+
/**
|
|
6
|
+
* Assert that a named property's type satisfies the given matcher.
|
|
7
|
+
*
|
|
8
|
+
* This is the key condition for type-level architecture rules.
|
|
9
|
+
* Resolves through type aliases, Partial<>, Pick<>, etc.
|
|
10
|
+
*
|
|
11
|
+
* Elements without the named property are skipped (no violation).
|
|
12
|
+
* Use the `haveProperty()` predicate to filter to types that have the property.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // sortBy must not be bare string
|
|
16
|
+
* types(project)
|
|
17
|
+
* .that().haveProperty('sortBy')
|
|
18
|
+
* .should().havePropertyType('sortBy', not(isString()))
|
|
19
|
+
* .check()
|
|
20
|
+
*
|
|
21
|
+
* // sortBy must be a union of string literals
|
|
22
|
+
* types(project)
|
|
23
|
+
* .that().haveProperty('sortBy')
|
|
24
|
+
* .should().havePropertyType('sortBy', isUnionOfLiterals())
|
|
25
|
+
* .check()
|
|
26
|
+
*/
|
|
27
|
+
export declare function havePropertyType(propertyName: string, matcher: TypeMatcher): Condition<TypeDeclaration>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=type-level.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-level.d.ts","sourceRoot":"","sources":["../../src/conditions/type-level.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAGnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAG9D,KAAK,eAAe,GAAG,oBAAoB,GAAG,oBAAoB,CAAA;AAElE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,WAAW,GACnB,SAAS,CAAC,eAAe,CAAC,CAiC5B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createViolation } from '../core/violation.js';
|
|
2
|
+
/**
|
|
3
|
+
* Assert that a named property's type satisfies the given matcher.
|
|
4
|
+
*
|
|
5
|
+
* This is the key condition for type-level architecture rules.
|
|
6
|
+
* Resolves through type aliases, Partial<>, Pick<>, etc.
|
|
7
|
+
*
|
|
8
|
+
* Elements without the named property are skipped (no violation).
|
|
9
|
+
* Use the `haveProperty()` predicate to filter to types that have the property.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // sortBy must not be bare string
|
|
13
|
+
* types(project)
|
|
14
|
+
* .that().haveProperty('sortBy')
|
|
15
|
+
* .should().havePropertyType('sortBy', not(isString()))
|
|
16
|
+
* .check()
|
|
17
|
+
*
|
|
18
|
+
* // sortBy must be a union of string literals
|
|
19
|
+
* types(project)
|
|
20
|
+
* .that().haveProperty('sortBy')
|
|
21
|
+
* .should().havePropertyType('sortBy', isUnionOfLiterals())
|
|
22
|
+
* .check()
|
|
23
|
+
*/
|
|
24
|
+
export function havePropertyType(propertyName, matcher) {
|
|
25
|
+
return {
|
|
26
|
+
description: `have property "${propertyName}" with matching type`,
|
|
27
|
+
evaluate(elements, context) {
|
|
28
|
+
const violations = [];
|
|
29
|
+
for (const element of elements) {
|
|
30
|
+
const type = element.getType();
|
|
31
|
+
const prop = type.getProperty(propertyName);
|
|
32
|
+
// Skip elements without the property — not a violation.
|
|
33
|
+
// The predicate haveProperty() should be used to filter these out.
|
|
34
|
+
if (prop === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
// Resolve property type in context (critical for Partial<>, Pick<>)
|
|
37
|
+
const propType = prop.getTypeAtLocation(element);
|
|
38
|
+
const stripped = propType.getNonNullableType();
|
|
39
|
+
const typeText = stripped.getText();
|
|
40
|
+
if (!matcher(propType)) {
|
|
41
|
+
violations.push(createViolation(element, `property "${propertyName}" has type '${typeText}' which does not match the expected type constraint`, context));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return violations;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=type-level.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-level.js","sourceRoot":"","sources":["../../src/conditions/type-level.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAOtD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAAoB,EACpB,OAAoB;IAEpB,OAAO;QACL,WAAW,EAAE,kBAAkB,YAAY,sBAAsB;QACjE,QAAQ,CAAC,QAA2B,EAAE,OAAyB;YAC7D,MAAM,UAAU,GAAoB,EAAE,CAAA;YAEtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAA;gBAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAA;gBAE3C,wDAAwD;gBACxD,mEAAmE;gBACnE,IAAI,IAAI,KAAK,SAAS;oBAAE,SAAQ;gBAEhC,oEAAoE;gBACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAA;gBAChD,MAAM,QAAQ,GAAG,QAAQ,CAAC,kBAAkB,EAAE,CAAA;gBAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAA;gBAEnC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACvB,UAAU,CAAC,IAAI,CACb,eAAe,CACb,OAAO,EACP,aAAa,YAAY,eAAe,QAAQ,qDAAqD,EACrG,OAAO,CACR,CACF,CAAA;gBACH,CAAC;YACH,CAAC;YAED,OAAO,UAAU,CAAA;QACnB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ImportDeclaration } from 'ts-morph';
|
|
2
|
+
/**
|
|
3
|
+
* Options for import-related conditions and predicates.
|
|
4
|
+
*/
|
|
5
|
+
export interface ImportOptions {
|
|
6
|
+
/**
|
|
7
|
+
* When true, type-only imports (`import type { X }` and imports where
|
|
8
|
+
* ALL specifiers are type-only) are excluded from violation checks.
|
|
9
|
+
*
|
|
10
|
+
* Type-only imports are erased at compile time and create no runtime dependency.
|
|
11
|
+
* Useful for layer isolation rules where type-sharing is acceptable.
|
|
12
|
+
*
|
|
13
|
+
* Default: false (all imports checked, for backward compatibility).
|
|
14
|
+
*/
|
|
15
|
+
ignoreTypeImports?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check whether an import declaration is purely type-only (no runtime dependency).
|
|
19
|
+
*
|
|
20
|
+
* Returns true for:
|
|
21
|
+
* - `import type { X } from '...'` (declaration-level type-only)
|
|
22
|
+
* - `import type Foo from '...'` (default type-only import)
|
|
23
|
+
* - `import { type X, type Y } from '...'` (all specifiers are type-only, no default/namespace)
|
|
24
|
+
*
|
|
25
|
+
* Returns false for:
|
|
26
|
+
* - `import { X } from '...'` (runtime import)
|
|
27
|
+
* - `import { type X, Y } from '...'` (mixed: Y is runtime)
|
|
28
|
+
* - `import defaultExport, { type X } from '...'` (default import is runtime)
|
|
29
|
+
* - `import * as Foo from '...'` (namespace import is runtime)
|
|
30
|
+
*/
|
|
31
|
+
export declare function isTypeOnlyImport(decl: ImportDeclaration): boolean;
|
|
32
|
+
//# sourceMappingURL=import-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-options.d.ts","sourceRoot":"","sources":["../../src/core/import-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAEjD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAUjE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check whether an import declaration is purely type-only (no runtime dependency).
|
|
3
|
+
*
|
|
4
|
+
* Returns true for:
|
|
5
|
+
* - `import type { X } from '...'` (declaration-level type-only)
|
|
6
|
+
* - `import type Foo from '...'` (default type-only import)
|
|
7
|
+
* - `import { type X, type Y } from '...'` (all specifiers are type-only, no default/namespace)
|
|
8
|
+
*
|
|
9
|
+
* Returns false for:
|
|
10
|
+
* - `import { X } from '...'` (runtime import)
|
|
11
|
+
* - `import { type X, Y } from '...'` (mixed: Y is runtime)
|
|
12
|
+
* - `import defaultExport, { type X } from '...'` (default import is runtime)
|
|
13
|
+
* - `import * as Foo from '...'` (namespace import is runtime)
|
|
14
|
+
*/
|
|
15
|
+
export function isTypeOnlyImport(decl) {
|
|
16
|
+
// Declaration-level: import type { X } or import type Foo
|
|
17
|
+
if (decl.isTypeOnly())
|
|
18
|
+
return true;
|
|
19
|
+
// Default import creates a runtime binding
|
|
20
|
+
if (decl.getDefaultImport())
|
|
21
|
+
return false;
|
|
22
|
+
// Namespace import creates a runtime binding
|
|
23
|
+
if (decl.getNamespaceImport())
|
|
24
|
+
return false;
|
|
25
|
+
// All named specifiers must be individually type-only
|
|
26
|
+
const specifiers = decl.getNamedImports();
|
|
27
|
+
return specifiers.length > 0 && specifiers.every((s) => s.isTypeOnly());
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=import-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-options.js","sourceRoot":"","sources":["../../src/core/import-options.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAuB;IACtD,0DAA0D;IAC1D,IAAI,IAAI,CAAC,UAAU,EAAE;QAAE,OAAO,IAAI,CAAA;IAClC,2CAA2C;IAC3C,IAAI,IAAI,CAAC,gBAAgB,EAAE;QAAE,OAAO,KAAK,CAAA;IACzC,6CAA6C;IAC7C,IAAI,IAAI,CAAC,kBAAkB,EAAE;QAAE,OAAO,KAAK,CAAA;IAC3C,sDAAsD;IACtD,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAE,CAAA;IACzC,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAA;AACzE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ImportDeclaration, ExportDeclaration, SourceFile } from 'ts-morph';
|
|
2
|
+
/**
|
|
3
|
+
* A module dependency edge — an `import … from` or an `export … from` re-export.
|
|
4
|
+
*/
|
|
5
|
+
export type DependencyDecl = ImportDeclaration | ExportDeclaration;
|
|
6
|
+
/**
|
|
7
|
+
* Every module dependency edge of a source file: its import declarations plus
|
|
8
|
+
* its `export … from` re-exports.
|
|
9
|
+
*
|
|
10
|
+
* A re-export is a real dependency — `export { x } from './y'` makes this module
|
|
11
|
+
* depend on `./y` exactly as an `import` would — so dependency-direction rules
|
|
12
|
+
* (`importFrom` / `notImportFrom` / `onlyImportFrom` / `dependOn`) must see it.
|
|
13
|
+
* ts-morph's `getImportDeclarations()` alone misses re-exports, which lets a
|
|
14
|
+
* forbidden edge hide behind `export … from` and pass a rule that should fail.
|
|
15
|
+
* A bare `export { x }` with no `from` has no target module and is skipped.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getDependencyDecls(sf: SourceFile): DependencyDecl[];
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a dependency edge to an absolute path (when the target resolves to a
|
|
20
|
+
* file in the project) or its raw specifier (for external packages).
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveDependencyPath(decl: DependencyDecl): string;
|
|
23
|
+
/**
|
|
24
|
+
* Is this dependency edge type-only? `import type …` / `export type … from …`,
|
|
25
|
+
* or an import whose every named specifier is inline `type`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isTypeOnlyDependency(decl: DependencyDecl): boolean;
|
|
28
|
+
//# sourceMappingURL=module-dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-dependencies.d.ts","sourceRoot":"","sources":["../../src/core/module-dependencies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAGhF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,iBAAiB,CAAA;AAElE;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,UAAU,GAAG,cAAc,EAAE,CAKnE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAGlE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAElE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
import { isTypeOnlyImport } from './import-options.js';
|
|
3
|
+
/**
|
|
4
|
+
* Every module dependency edge of a source file: its import declarations plus
|
|
5
|
+
* its `export … from` re-exports.
|
|
6
|
+
*
|
|
7
|
+
* A re-export is a real dependency — `export { x } from './y'` makes this module
|
|
8
|
+
* depend on `./y` exactly as an `import` would — so dependency-direction rules
|
|
9
|
+
* (`importFrom` / `notImportFrom` / `onlyImportFrom` / `dependOn`) must see it.
|
|
10
|
+
* ts-morph's `getImportDeclarations()` alone misses re-exports, which lets a
|
|
11
|
+
* forbidden edge hide behind `export … from` and pass a rule that should fail.
|
|
12
|
+
* A bare `export { x }` with no `from` has no target module and is skipped.
|
|
13
|
+
*/
|
|
14
|
+
export function getDependencyDecls(sf) {
|
|
15
|
+
const reexports = sf
|
|
16
|
+
.getExportDeclarations()
|
|
17
|
+
.filter((d) => d.getModuleSpecifierValue() !== undefined);
|
|
18
|
+
return [...sf.getImportDeclarations(), ...reexports];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a dependency edge to an absolute path (when the target resolves to a
|
|
22
|
+
* file in the project) or its raw specifier (for external packages).
|
|
23
|
+
*/
|
|
24
|
+
export function resolveDependencyPath(decl) {
|
|
25
|
+
const resolved = decl.getModuleSpecifierSourceFile();
|
|
26
|
+
return resolved ? resolved.getFilePath() : (decl.getModuleSpecifierValue() ?? '');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Is this dependency edge type-only? `import type …` / `export type … from …`,
|
|
30
|
+
* or an import whose every named specifier is inline `type`.
|
|
31
|
+
*/
|
|
32
|
+
export function isTypeOnlyDependency(decl) {
|
|
33
|
+
return Node.isImportDeclaration(decl) ? isTypeOnlyImport(decl) : decl.isTypeOnly();
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=module-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-dependencies.js","sourceRoot":"","sources":["../../src/core/module-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAE/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAOtD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAc;IAC/C,MAAM,SAAS,GAAG,EAAE;SACjB,qBAAqB,EAAE;SACvB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,uBAAuB,EAAE,KAAK,SAAS,CAAC,CAAA;IAC3D,OAAO,CAAC,GAAG,EAAE,CAAC,qBAAqB,EAAE,EAAE,GAAG,SAAS,CAAC,CAAA;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAoB;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,4BAA4B,EAAE,CAAA;IACpD,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,uBAAuB,EAAE,IAAI,EAAE,CAAC,CAAA;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAoB;IACvD,OAAO,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAA;AACpF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SourceFile } from 'ts-morph';
|
|
2
|
+
import type { ArchViolation } from './violation.js';
|
|
3
|
+
import type { ConditionContext } from '@nielspeter/eess';
|
|
4
|
+
import type { LayerPair } from '../models/cross-layer.js';
|
|
5
|
+
/** Condition that evaluates matched pairs from two layers. */
|
|
6
|
+
export interface PairCondition<A = SourceFile, B = SourceFile> {
|
|
7
|
+
readonly description: string;
|
|
8
|
+
evaluate(pairs: LayerPair<A, B>[], context: ConditionContext): ArchViolation[];
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=pair-condition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pair-condition.d.ts","sourceRoot":"","sources":["../../src/core/pair-condition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAEzD,8DAA8D;AAC9D,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,UAAU;IAC3D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAAA;CAC/E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pair-condition.js","sourceRoot":"","sources":["../../src/core/pair-condition.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Project, type SourceFile } from 'ts-morph';
|
|
2
|
+
/**
|
|
3
|
+
* A loaded TypeScript project. Returned by `project()`.
|
|
4
|
+
*
|
|
5
|
+
* Wraps a ts-morph `Project` and provides access to source files.
|
|
6
|
+
* Use this as the first argument to entry points like `classes(p)`, `modules(p)`, etc.
|
|
7
|
+
*/
|
|
8
|
+
export interface ArchProject {
|
|
9
|
+
/** Resolved absolute path to the tsconfig.json used to load this project. */
|
|
10
|
+
readonly tsConfigPath: string;
|
|
11
|
+
/** Returns all source files included by the tsconfig. */
|
|
12
|
+
getSourceFiles(): SourceFile[];
|
|
13
|
+
/**
|
|
14
|
+
* The underlying ts-morph Project.
|
|
15
|
+
* @internal Used by entry points — not part of the public API.
|
|
16
|
+
*/
|
|
17
|
+
readonly _project: Project;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Load a TypeScript project from a tsconfig.json path.
|
|
21
|
+
*
|
|
22
|
+
* Returns a cached instance if the same tsconfig has been loaded before.
|
|
23
|
+
* The tsconfig path is resolved to an absolute path before caching,
|
|
24
|
+
* so relative and absolute paths pointing to the same file share one instance.
|
|
25
|
+
*
|
|
26
|
+
* @param tsConfigPath - Path to tsconfig.json (relative or absolute)
|
|
27
|
+
* @throws {Error} If the tsconfig file does not exist
|
|
28
|
+
*/
|
|
29
|
+
export declare function project(tsConfigPath: string): ArchProject;
|
|
30
|
+
/**
|
|
31
|
+
* Load multiple TypeScript projects into a unified view.
|
|
32
|
+
*
|
|
33
|
+
* Returns a standard `ArchProject` backed by a single ts-morph `Project`
|
|
34
|
+
* that contains source files from all tsconfigs. This makes cross-workspace
|
|
35
|
+
* imports visible to `beImported()`, `haveNoUnusedExports()`, and all other
|
|
36
|
+
* conditions that traverse the import graph.
|
|
37
|
+
*
|
|
38
|
+
* Paths are sorted alphabetically before loading. The alphabetically first
|
|
39
|
+
* tsconfig's compiler options are used for type checking — this makes
|
|
40
|
+
* behavior deterministic regardless of the order paths are passed.
|
|
41
|
+
* Subsequent tsconfigs only contribute their source files.
|
|
42
|
+
*
|
|
43
|
+
* @param tsConfigPaths - Paths to tsconfig.json files (relative or absolute)
|
|
44
|
+
* @throws {Error} If any tsconfig file does not exist or if no paths are provided
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const ws = workspace([
|
|
48
|
+
* 'apps/web/tsconfig.json',
|
|
49
|
+
* 'apps/api/tsconfig.json',
|
|
50
|
+
* 'packages/shared/tsconfig.json',
|
|
51
|
+
* ])
|
|
52
|
+
*
|
|
53
|
+
* modules(ws)
|
|
54
|
+
* .that().resideInFolder('** /packages/shared/src/** ')
|
|
55
|
+
* .should().satisfy(noUnusedExports())
|
|
56
|
+
* .check()
|
|
57
|
+
*/
|
|
58
|
+
export declare function workspace(tsConfigPaths: string[]): ArchProject;
|
|
59
|
+
/**
|
|
60
|
+
* Clear the project singleton cache.
|
|
61
|
+
*
|
|
62
|
+
* Used by watch mode to force fresh ts-morph Project creation on re-runs,
|
|
63
|
+
* and by tests for isolation between test cases.
|
|
64
|
+
*
|
|
65
|
+
* Clears both the `project()` and `workspace()` caches.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resetProjectCache(): void;
|
|
68
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/core/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AAInD;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAE7B,yDAAyD;IACzD,cAAc,IAAI,UAAU,EAAE,CAAA;IAE9B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAC3B;AAID;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,CA6BzD;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,WAAW,CAuD9D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Project } from 'ts-morph';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
const cache = new Map();
|
|
5
|
+
/**
|
|
6
|
+
* Load a TypeScript project from a tsconfig.json path.
|
|
7
|
+
*
|
|
8
|
+
* Returns a cached instance if the same tsconfig has been loaded before.
|
|
9
|
+
* The tsconfig path is resolved to an absolute path before caching,
|
|
10
|
+
* so relative and absolute paths pointing to the same file share one instance.
|
|
11
|
+
*
|
|
12
|
+
* @param tsConfigPath - Path to tsconfig.json (relative or absolute)
|
|
13
|
+
* @throws {Error} If the tsconfig file does not exist
|
|
14
|
+
*/
|
|
15
|
+
export function project(tsConfigPath) {
|
|
16
|
+
const resolved = path.resolve(tsConfigPath);
|
|
17
|
+
const cached = cache.get(resolved);
|
|
18
|
+
if (cached) {
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
if (!fs.existsSync(resolved)) {
|
|
22
|
+
throw new Error(`tsconfig not found: ${resolved}\n` +
|
|
23
|
+
`Provide a valid path to tsconfig.json, e.g. project('tsconfig.json') or project('./packages/app/tsconfig.json')`);
|
|
24
|
+
}
|
|
25
|
+
const tsMorphProject = new Project({
|
|
26
|
+
tsConfigFilePath: resolved,
|
|
27
|
+
});
|
|
28
|
+
const archProject = {
|
|
29
|
+
tsConfigPath: resolved,
|
|
30
|
+
_project: tsMorphProject,
|
|
31
|
+
getSourceFiles() {
|
|
32
|
+
return tsMorphProject.getSourceFiles();
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
cache.set(resolved, archProject);
|
|
36
|
+
return archProject;
|
|
37
|
+
}
|
|
38
|
+
// ─── Workspace (multi-tsconfig) ─────────────────────────────────
|
|
39
|
+
const workspaceCache = new Map();
|
|
40
|
+
/**
|
|
41
|
+
* Load multiple TypeScript projects into a unified view.
|
|
42
|
+
*
|
|
43
|
+
* Returns a standard `ArchProject` backed by a single ts-morph `Project`
|
|
44
|
+
* that contains source files from all tsconfigs. This makes cross-workspace
|
|
45
|
+
* imports visible to `beImported()`, `haveNoUnusedExports()`, and all other
|
|
46
|
+
* conditions that traverse the import graph.
|
|
47
|
+
*
|
|
48
|
+
* Paths are sorted alphabetically before loading. The alphabetically first
|
|
49
|
+
* tsconfig's compiler options are used for type checking — this makes
|
|
50
|
+
* behavior deterministic regardless of the order paths are passed.
|
|
51
|
+
* Subsequent tsconfigs only contribute their source files.
|
|
52
|
+
*
|
|
53
|
+
* @param tsConfigPaths - Paths to tsconfig.json files (relative or absolute)
|
|
54
|
+
* @throws {Error} If any tsconfig file does not exist or if no paths are provided
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const ws = workspace([
|
|
58
|
+
* 'apps/web/tsconfig.json',
|
|
59
|
+
* 'apps/api/tsconfig.json',
|
|
60
|
+
* 'packages/shared/tsconfig.json',
|
|
61
|
+
* ])
|
|
62
|
+
*
|
|
63
|
+
* modules(ws)
|
|
64
|
+
* .that().resideInFolder('** /packages/shared/src/** ')
|
|
65
|
+
* .should().satisfy(noUnusedExports())
|
|
66
|
+
* .check()
|
|
67
|
+
*/
|
|
68
|
+
export function workspace(tsConfigPaths) {
|
|
69
|
+
if (tsConfigPaths.length === 0) {
|
|
70
|
+
throw new Error('workspace() requires at least one tsconfig path.\n' +
|
|
71
|
+
'Example: workspace(["apps/web/tsconfig.json", "packages/shared/tsconfig.json"])');
|
|
72
|
+
}
|
|
73
|
+
// Sort resolved paths so the primary config (first) is deterministic
|
|
74
|
+
// regardless of call order. workspace([A,B]) and workspace([B,A]) produce
|
|
75
|
+
// identical projects with the same compiler options (alphabetically first wins).
|
|
76
|
+
// Unicode codepoint order — deterministic across all OS locales (no localeCompare)
|
|
77
|
+
const resolvedPaths = tsConfigPaths
|
|
78
|
+
.map((p) => path.resolve(p))
|
|
79
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
80
|
+
const cacheKey = resolvedPaths.join('\0');
|
|
81
|
+
const cached = workspaceCache.get(cacheKey);
|
|
82
|
+
if (cached) {
|
|
83
|
+
return cached;
|
|
84
|
+
}
|
|
85
|
+
// Validate all paths exist before creating the project
|
|
86
|
+
for (const resolved of resolvedPaths) {
|
|
87
|
+
if (!fs.existsSync(resolved)) {
|
|
88
|
+
throw new Error(`tsconfig not found: ${resolved}\n` +
|
|
89
|
+
`Provide valid paths to tsconfig.json files in the workspace() call.`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Create project with the alphabetically first tsconfig's compiler options
|
|
93
|
+
const primaryConfig = resolvedPaths[0];
|
|
94
|
+
if (!primaryConfig)
|
|
95
|
+
throw new Error('No resolved paths available');
|
|
96
|
+
const tsMorphProject = new Project({
|
|
97
|
+
tsConfigFilePath: primaryConfig,
|
|
98
|
+
});
|
|
99
|
+
// Add source files from remaining tsconfigs
|
|
100
|
+
for (let i = 1; i < resolvedPaths.length; i++) {
|
|
101
|
+
const configPath = resolvedPaths[i];
|
|
102
|
+
if (configPath)
|
|
103
|
+
tsMorphProject.addSourceFilesFromTsConfig(configPath);
|
|
104
|
+
}
|
|
105
|
+
const archProject = {
|
|
106
|
+
tsConfigPath: primaryConfig,
|
|
107
|
+
_project: tsMorphProject,
|
|
108
|
+
getSourceFiles() {
|
|
109
|
+
return tsMorphProject.getSourceFiles();
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
workspaceCache.set(cacheKey, archProject);
|
|
113
|
+
return archProject;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Clear the project singleton cache.
|
|
117
|
+
*
|
|
118
|
+
* Used by watch mode to force fresh ts-morph Project creation on re-runs,
|
|
119
|
+
* and by tests for isolation between test cases.
|
|
120
|
+
*
|
|
121
|
+
* Clears both the `project()` and `workspace()` caches.
|
|
122
|
+
*/
|
|
123
|
+
export function resetProjectCache() {
|
|
124
|
+
cache.clear();
|
|
125
|
+
workspaceCache.clear();
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/core/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Type } from 'ts-morph';
|
|
2
|
+
/**
|
|
3
|
+
* A function that tests a ts-morph Type against a condition.
|
|
4
|
+
*
|
|
5
|
+
* All matchers MUST call getNonNullableType() internally to handle
|
|
6
|
+
* optional properties (strip `undefined` from `T | undefined`).
|
|
7
|
+
* This was a critical finding from the PoC (plan 0001).
|
|
8
|
+
*/
|
|
9
|
+
export type TypeMatcher = (type: Type) => boolean;
|
|
10
|
+
//# sourceMappingURL=type-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-matcher.d.ts","sourceRoot":"","sources":["../../src/core/type-matcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAEpC;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-matcher.js","sourceRoot":"","sources":["../../src/core/type-matcher.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
import { type ArchViolation } from '@nielspeter/eess';
|
|
3
|
+
export type { ArchViolation };
|
|
4
|
+
/**
|
|
5
|
+
* Extract a human-readable name from a ts-morph Node.
|
|
6
|
+
*
|
|
7
|
+
* If the node itself is a named declaration (class, function, method, etc.),
|
|
8
|
+
* returns its name directly. Otherwise, walks up the AST ancestors to find
|
|
9
|
+
* the nearest named declaration and builds a qualified name like
|
|
10
|
+
* "ClassName.methodName". This ensures that inner nodes (e.g., AsExpression,
|
|
11
|
+
* CallExpression) produce meaningful element names for `.excluding()` matching.
|
|
12
|
+
*
|
|
13
|
+
* Falls back to the node's kind name only if no named ancestor is found
|
|
14
|
+
* (e.g., top-level expressions in a module).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getElementName(node: Node): string;
|
|
17
|
+
/**
|
|
18
|
+
* Get the absolute file path for a ts-morph Node.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getElementFile(node: Node): string;
|
|
21
|
+
/**
|
|
22
|
+
* Get the start line number for a ts-morph Node.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getElementLine(node: Node): number;
|
|
25
|
+
/**
|
|
26
|
+
* Create an ArchViolation from a ts-morph Node and context.
|
|
27
|
+
*
|
|
28
|
+
* Convenience function used by all condition implementations to produce
|
|
29
|
+
* consistent violation objects.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createViolation(node: Node, message: string, context: {
|
|
32
|
+
rule: string;
|
|
33
|
+
because?: string;
|
|
34
|
+
suggestion?: string;
|
|
35
|
+
ruleId?: string;
|
|
36
|
+
docs?: string;
|
|
37
|
+
}): ArchViolation;
|
|
38
|
+
//# sourceMappingURL=violation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"violation.d.ts","sourceRoot":"","sources":["../../src/core/violation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAKxE,YAAY,EAAE,aAAa,EAAE,CAAA;AAgE7B;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAyBjD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEjD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IACP,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GACA,aAAa,CAef"}
|