oxlint-architecture-rules 0.1.0-beta.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/build/dts/adapters/cli/main.d.ts +3 -0
- package/build/dts/adapters/cli/main.d.ts.map +1 -0
- package/build/dts/adapters/cli/run.d.ts +19 -0
- package/build/dts/adapters/cli/run.d.ts.map +1 -0
- package/build/dts/adapters/cli/source-facts.d.ts +9 -0
- package/build/dts/adapters/cli/source-facts.d.ts.map +1 -0
- package/build/dts/adapters/cli/source-files.d.ts +2 -0
- package/build/dts/adapters/cli/source-files.d.ts.map +1 -0
- package/build/dts/adapters/oxlint/config-loader.d.ts +23 -0
- package/build/dts/adapters/oxlint/config-loader.d.ts.map +1 -0
- package/build/dts/adapters/oxlint/exports-rule.d.ts +4 -0
- package/build/dts/adapters/oxlint/exports-rule.d.ts.map +1 -0
- package/build/dts/adapters/oxlint/imports-rule.d.ts +4 -0
- package/build/dts/adapters/oxlint/imports-rule.d.ts.map +1 -0
- package/build/dts/adapters/oxlint/members-rule.d.ts +4 -0
- package/build/dts/adapters/oxlint/members-rule.d.ts.map +1 -0
- package/build/dts/adapters/oxlint/oxlint-api.d.ts +19 -0
- package/build/dts/adapters/oxlint/oxlint-api.d.ts.map +1 -0
- package/build/dts/adapters/oxlint/plugin.d.ts +15 -0
- package/build/dts/adapters/oxlint/plugin.d.ts.map +1 -0
- package/build/dts/adapters/oxlint/structure-rule.d.ts +4 -0
- package/build/dts/adapters/oxlint/structure-rule.d.ts.map +1 -0
- package/build/dts/core/baseline.d.ts +16 -0
- package/build/dts/core/baseline.d.ts.map +1 -0
- package/build/dts/core/exports.d.ts +39 -0
- package/build/dts/core/exports.d.ts.map +1 -0
- package/build/dts/core/imports.d.ts +27 -0
- package/build/dts/core/imports.d.ts.map +1 -0
- package/build/dts/core/members.d.ts +28 -0
- package/build/dts/core/members.d.ts.map +1 -0
- package/build/dts/core/patterns.d.ts +19 -0
- package/build/dts/core/patterns.d.ts.map +1 -0
- package/build/dts/core/structure.d.ts +48 -0
- package/build/dts/core/structure.d.ts.map +1 -0
- package/build/dts/domain/architecture-config.d.ts +177 -0
- package/build/dts/domain/architecture-config.d.ts.map +1 -0
- package/build/dts/domain/architecture-error.d.ts +27 -0
- package/build/dts/domain/architecture-error.d.ts.map +1 -0
- package/build/dts/domain/violation.d.ts +11 -0
- package/build/dts/domain/violation.d.ts.map +1 -0
- package/build/dts/index.d.ts +10 -0
- package/build/dts/index.d.ts.map +1 -0
- package/build/dts/infrastructure/file-system-fake.d.ts +3 -0
- package/build/dts/infrastructure/file-system-fake.d.ts.map +1 -0
- package/build/dts/infrastructure/file-system-live.d.ts +3 -0
- package/build/dts/infrastructure/file-system-live.d.ts.map +1 -0
- package/build/dts/infrastructure/module-resolver-fake.d.ts +3 -0
- package/build/dts/infrastructure/module-resolver-fake.d.ts.map +1 -0
- package/build/dts/infrastructure/module-resolver-live.d.ts +4 -0
- package/build/dts/infrastructure/module-resolver-live.d.ts.map +1 -0
- package/build/dts/manifest/compile.d.ts +16 -0
- package/build/dts/manifest/compile.d.ts.map +1 -0
- package/build/dts/manifest/glob.d.ts +14 -0
- package/build/dts/manifest/glob.d.ts.map +1 -0
- package/build/dts/manifest/manifest.d.ts +96 -0
- package/build/dts/manifest/manifest.d.ts.map +1 -0
- package/build/dts/ports/file-system.d.ts +4 -0
- package/build/dts/ports/file-system.d.ts.map +1 -0
- package/build/dts/ports/module-resolver.d.ts +11 -0
- package/build/dts/ports/module-resolver.d.ts.map +1 -0
- package/build/esm/adapters/cli/main.js +17 -0
- package/build/esm/adapters/cli/main.js.map +1 -0
- package/build/esm/adapters/cli/run.js +188 -0
- package/build/esm/adapters/cli/run.js.map +1 -0
- package/build/esm/adapters/cli/source-facts.js +117 -0
- package/build/esm/adapters/cli/source-facts.js.map +1 -0
- package/build/esm/adapters/cli/source-files.js +40 -0
- package/build/esm/adapters/cli/source-files.js.map +1 -0
- package/build/esm/adapters/oxlint/config-loader.js +81 -0
- package/build/esm/adapters/oxlint/config-loader.js.map +1 -0
- package/build/esm/adapters/oxlint/exports-rule.js +104 -0
- package/build/esm/adapters/oxlint/exports-rule.js.map +1 -0
- package/build/esm/adapters/oxlint/imports-rule.js +55 -0
- package/build/esm/adapters/oxlint/imports-rule.js.map +1 -0
- package/build/esm/adapters/oxlint/members-rule.js +75 -0
- package/build/esm/adapters/oxlint/members-rule.js.map +1 -0
- package/build/esm/adapters/oxlint/oxlint-api.js +7 -0
- package/build/esm/adapters/oxlint/oxlint-api.js.map +1 -0
- package/build/esm/adapters/oxlint/plugin.js +23 -0
- package/build/esm/adapters/oxlint/plugin.js.map +1 -0
- package/build/esm/adapters/oxlint/structure-rule.js +37 -0
- package/build/esm/adapters/oxlint/structure-rule.js.map +1 -0
- package/build/esm/core/baseline.js +30 -0
- package/build/esm/core/baseline.js.map +1 -0
- package/build/esm/core/exports.js +96 -0
- package/build/esm/core/exports.js.map +1 -0
- package/build/esm/core/imports.js +85 -0
- package/build/esm/core/imports.js.map +1 -0
- package/build/esm/core/members.js +84 -0
- package/build/esm/core/members.js.map +1 -0
- package/build/esm/core/patterns.js +78 -0
- package/build/esm/core/patterns.js.map +1 -0
- package/build/esm/core/structure.js +256 -0
- package/build/esm/core/structure.js.map +1 -0
- package/build/esm/domain/architecture-config.js +172 -0
- package/build/esm/domain/architecture-config.js.map +1 -0
- package/build/esm/domain/architecture-error.js +29 -0
- package/build/esm/domain/architecture-error.js.map +1 -0
- package/build/esm/domain/violation.js +8 -0
- package/build/esm/domain/violation.js.map +1 -0
- package/build/esm/index.js +8 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/infrastructure/file-system-fake.js +5 -0
- package/build/esm/infrastructure/file-system-fake.js.map +1 -0
- package/build/esm/infrastructure/file-system-live.js +19 -0
- package/build/esm/infrastructure/file-system-live.js.map +1 -0
- package/build/esm/infrastructure/module-resolver-fake.js +23 -0
- package/build/esm/infrastructure/module-resolver-fake.js.map +1 -0
- package/build/esm/infrastructure/module-resolver-live.js +71 -0
- package/build/esm/infrastructure/module-resolver-live.js.map +1 -0
- package/build/esm/manifest/compile.js +503 -0
- package/build/esm/manifest/compile.js.map +1 -0
- package/build/esm/manifest/glob.js +77 -0
- package/build/esm/manifest/glob.js.map +1 -0
- package/build/esm/manifest/manifest.js +120 -0
- package/build/esm/manifest/manifest.js.map +1 -0
- package/build/esm/ports/file-system.js +2 -0
- package/build/esm/ports/file-system.js.map +1 -0
- package/build/esm/ports/module-resolver.js +2 -0
- package/build/esm/ports/module-resolver.js.map +1 -0
- package/package.json +73 -0
- package/src/adapters/cli/main.ts +20 -0
- package/src/adapters/cli/run.ts +270 -0
- package/src/adapters/cli/source-facts.ts +137 -0
- package/src/adapters/cli/source-files.ts +42 -0
- package/src/adapters/oxlint/config-loader.ts +136 -0
- package/src/adapters/oxlint/exports-rule.ts +144 -0
- package/src/adapters/oxlint/imports-rule.ts +67 -0
- package/src/adapters/oxlint/members-rule.ts +114 -0
- package/src/adapters/oxlint/oxlint-api.ts +25 -0
- package/src/adapters/oxlint/plugin.ts +35 -0
- package/src/adapters/oxlint/structure-rule.ts +39 -0
- package/src/core/baseline.ts +62 -0
- package/src/core/exports.ts +164 -0
- package/src/core/imports.ts +138 -0
- package/src/core/members.ts +131 -0
- package/src/core/patterns.ts +122 -0
- package/src/core/structure.ts +348 -0
- package/src/domain/architecture-config.ts +206 -0
- package/src/domain/architecture-error.ts +43 -0
- package/src/domain/violation.ts +24 -0
- package/src/index.ts +28 -0
- package/src/infrastructure/file-system-fake.ts +6 -0
- package/src/infrastructure/file-system-live.ts +20 -0
- package/src/infrastructure/module-resolver-fake.ts +29 -0
- package/src/infrastructure/module-resolver-live.ts +100 -0
- package/src/manifest/compile.ts +736 -0
- package/src/manifest/glob.ts +108 -0
- package/src/manifest/manifest.ts +178 -0
- package/src/ports/file-system.ts +5 -0
- package/src/ports/module-resolver.ts +23 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
declare const ConfigInvalid_base: Schema.Class<ConfigInvalid, Schema.TaggedStruct<"ConfigInvalid", {
|
|
3
|
+
readonly configPath: Schema.String;
|
|
4
|
+
readonly detail: Schema.String;
|
|
5
|
+
}>, import("effect/Cause").YieldableError>;
|
|
6
|
+
export declare class ConfigInvalid extends ConfigInvalid_base {
|
|
7
|
+
get message(): string;
|
|
8
|
+
}
|
|
9
|
+
declare const PatternInvalid_base: Schema.Class<PatternInvalid, Schema.TaggedStruct<"PatternInvalid", {
|
|
10
|
+
readonly ruleName: Schema.String;
|
|
11
|
+
readonly field: Schema.String;
|
|
12
|
+
readonly pattern: Schema.String;
|
|
13
|
+
readonly detail: Schema.String;
|
|
14
|
+
}>, import("effect/Cause").YieldableError>;
|
|
15
|
+
export declare class PatternInvalid extends PatternInvalid_base {
|
|
16
|
+
get message(): string;
|
|
17
|
+
}
|
|
18
|
+
declare const ImportUnresolved_base: Schema.Class<ImportUnresolved, Schema.TaggedStruct<"ImportUnresolved", {
|
|
19
|
+
readonly fromFile: Schema.String;
|
|
20
|
+
readonly specifier: Schema.String;
|
|
21
|
+
readonly detail: Schema.String;
|
|
22
|
+
}>, import("effect/Cause").YieldableError>;
|
|
23
|
+
export declare class ImportUnresolved extends ImportUnresolved_base {
|
|
24
|
+
get message(): string;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=architecture-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture-error.d.ts","sourceRoot":"","sources":["../../../src/domain/architecture-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;;;;;AAMxC,qBAAa,aAAc,SAAQ,kBAGlC;IACC,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF;;;;;;;AAED,qBAAa,cAAe,SAAQ,mBAQnC;IACC,IAAa,OAAO,IAAI,MAAM,CAI7B;CACF;;;;;;AAED,qBAAa,gBAAiB,SAAQ,qBAOrC;IACC,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ViolationKind = "import" | "export" | "structure" | "member";
|
|
2
|
+
export type Violation = {
|
|
3
|
+
readonly kind: ViolationKind;
|
|
4
|
+
readonly ruleName: string;
|
|
5
|
+
readonly message: string;
|
|
6
|
+
readonly file: string;
|
|
7
|
+
readonly subject: string | null;
|
|
8
|
+
};
|
|
9
|
+
export declare const fingerprintOf: (violation: Violation) => string;
|
|
10
|
+
export declare const formatMessage: (violation: Violation) => string;
|
|
11
|
+
//# sourceMappingURL=violation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"violation.d.ts","sourceRoot":"","sources":["../../../src/domain/violation.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEzE,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAItB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,CAAC;AAKF,eAAO,MAAM,aAAa,GAAI,WAAW,SAAS,KAAG,MACoC,CAAC;AAI1F,eAAO,MAAM,aAAa,GAAI,WAAW,SAAS,KAAG,MACyC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { type CompiledImportRule, compileImportRule, compileImportRules, evaluateImportEdge, type ImportEdge, } from "./core/imports.js";
|
|
2
|
+
export { type ImportRule, type ResolveConfig, type ResolveScope, } from "./domain/architecture-config.js";
|
|
3
|
+
export { ConfigInvalid, ImportUnresolved, PatternInvalid } from "./domain/architecture-error.js";
|
|
4
|
+
export { fingerprintOf, formatMessage, type Violation, type ViolationKind, } from "./domain/violation.js";
|
|
5
|
+
export { makeModuleResolverFake } from "./infrastructure/module-resolver-fake.js";
|
|
6
|
+
export { makeModuleResolverLive } from "./infrastructure/module-resolver-live.js";
|
|
7
|
+
export { type LoweredRules, lowerManifest } from "./manifest/compile.js";
|
|
8
|
+
export { type Manifest, type ManifestNode, Manifest as ManifestSchema, } from "./manifest/manifest.js";
|
|
9
|
+
export { type ModuleResolver, type ResolvedTarget } from "./ports/module-resolver.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,UAAU,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,SAAS,EACd,KAAK,aAAa,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,KAAK,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,QAAQ,IAAI,cAAc,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-system-fake.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/file-system-fake.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,eAAO,MAAM,kBAAkB,GAAI,SAAS,QAAQ,CAAC,MAAM,CAAC,KAAG,UAG9D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-system-live.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/file-system-live.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAK1D,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,KAAG,UAWrD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-resolver-fake.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/module-resolver-fake.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,6BAA6B,CAAC;AAKlF,eAAO,MAAM,sBAAsB,GACjC,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KACxC,cAkBD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ResolveConfig } from "../domain/architecture-config.js";
|
|
2
|
+
import type { ModuleResolver } from "../ports/module-resolver.js";
|
|
3
|
+
export declare const makeModuleResolverLive: (repoRoot: string, config: ResolveConfig) => ModuleResolver;
|
|
4
|
+
//# sourceMappingURL=module-resolver-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-resolver-live.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/module-resolver-live.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,6BAA6B,CAAC;AA2BlF,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,EAAE,QAAQ,aAAa,KAAG,cAiEhF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ExportRule, ImportRule, MemberRule, StructureFolder, StructureNaming, StructureParity, StructureRoot } from "../domain/architecture-config.js";
|
|
2
|
+
import { type Manifest } from "./manifest.js";
|
|
3
|
+
export type LoweredRules = {
|
|
4
|
+
readonly imports: ReadonlyArray<ImportRule>;
|
|
5
|
+
readonly exports: ReadonlyArray<ExportRule>;
|
|
6
|
+
readonly members: ReadonlyArray<MemberRule>;
|
|
7
|
+
readonly structure: {
|
|
8
|
+
readonly roots: ReadonlyArray<StructureRoot>;
|
|
9
|
+
readonly folders: ReadonlyArray<StructureFolder>;
|
|
10
|
+
readonly parity: ReadonlyArray<StructureParity>;
|
|
11
|
+
readonly naming: ReadonlyArray<StructureNaming>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export declare const ANY_FILE = "^.*$";
|
|
15
|
+
export declare const lowerManifest: (manifest: Manifest) => LoweredRules;
|
|
16
|
+
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/manifest/compile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,eAAe,EACf,eAAe,EACf,eAAe,EACf,aAAa,EACd,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAGL,KAAK,QAAQ,EAGd,MAAM,eAAe,CAAC;AAKvB,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;QAC7C,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;QACjD,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;QAChD,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;KACjD,CAAC;CACH,CAAC;AAMF,eAAO,MAAM,QAAQ,SAAS,CAAC;AAkN/B,eAAO,MAAM,aAAa,GAAI,UAAU,QAAQ,KAAG,YAwelD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type CaptureIndex = Readonly<Record<string, number>>;
|
|
2
|
+
export type GlobCompilation = {
|
|
3
|
+
readonly source: string;
|
|
4
|
+
readonly captures: CaptureIndex;
|
|
5
|
+
readonly wildcards: ReadonlyArray<number>;
|
|
6
|
+
};
|
|
7
|
+
export declare const globToRegexSource: (glob: string, captures: CaptureIndex, options: {
|
|
8
|
+
readonly declaring: boolean;
|
|
9
|
+
readonly nextGroup: number;
|
|
10
|
+
readonly capturing?: boolean;
|
|
11
|
+
}) => GlobCompilation;
|
|
12
|
+
export declare const anchored: (source: string) => string;
|
|
13
|
+
export declare const prefixed: (source: string) => string;
|
|
14
|
+
//# sourceMappingURL=glob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../../src/manifest/glob.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAM5D,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAGhC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC3C,CAAC;AAKF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,UAAU,YAAY,EACtB,SAAS;IACP,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAI3B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B,KACA,eAwDF,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,KAAG,MAAuB,CAAC;AAElE,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,KAAG,MAAsB,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as Result from "effect/Result";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import { ConfigInvalid } from "../domain/architecture-error.js";
|
|
4
|
+
declare const Imports: Schema.Struct<{
|
|
5
|
+
readonly message: Schema.optionalKey<Schema.String>;
|
|
6
|
+
readonly allow: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
7
|
+
readonly external: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
8
|
+
readonly deny: Schema.optionalKey<Schema.$Array<Schema.Struct<{
|
|
9
|
+
readonly match: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>;
|
|
10
|
+
readonly matchNot: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
11
|
+
readonly except: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
12
|
+
readonly message: Schema.String;
|
|
13
|
+
}>>>;
|
|
14
|
+
readonly reset: Schema.optionalKey<Schema.Boolean>;
|
|
15
|
+
readonly unrestricted: Schema.optionalKey<Schema.Boolean>;
|
|
16
|
+
}>;
|
|
17
|
+
declare const ImportedBy: Schema.Struct<{
|
|
18
|
+
readonly message: Schema.String;
|
|
19
|
+
readonly allow: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>;
|
|
20
|
+
readonly matchNot: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
21
|
+
}>;
|
|
22
|
+
declare const Naming: Schema.Union<readonly [Schema.Literals<readonly ["kebab-case", "camelCase", "PascalCase", "snake_case"]>, Schema.Struct<{
|
|
23
|
+
readonly regex: Schema.String;
|
|
24
|
+
readonly message: Schema.optionalKey<Schema.String>;
|
|
25
|
+
}>, Schema.Struct<{
|
|
26
|
+
readonly like: Schema.String;
|
|
27
|
+
readonly message: Schema.optionalKey<Schema.String>;
|
|
28
|
+
}>]>;
|
|
29
|
+
declare const Members: Schema.Struct<{
|
|
30
|
+
readonly message: Schema.String;
|
|
31
|
+
readonly subject: Schema.Literals<readonly ["type-members", "calls"]>;
|
|
32
|
+
readonly in: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
33
|
+
readonly match: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
34
|
+
readonly matchNot: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
35
|
+
readonly allow: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
36
|
+
}>;
|
|
37
|
+
declare const ExportRestriction: Schema.Struct<{
|
|
38
|
+
readonly name: Schema.String;
|
|
39
|
+
readonly message: Schema.String;
|
|
40
|
+
readonly module: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>;
|
|
41
|
+
readonly symbols: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
42
|
+
readonly except: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
43
|
+
readonly fix: Schema.optionalKey<Schema.Literal<"subpath-namespace-import">>;
|
|
44
|
+
}>;
|
|
45
|
+
export type ManifestNode = {
|
|
46
|
+
readonly message?: string;
|
|
47
|
+
readonly partial?: boolean;
|
|
48
|
+
readonly layout?: "open";
|
|
49
|
+
readonly name?: typeof Naming.Type;
|
|
50
|
+
readonly imports?: typeof Imports.Type;
|
|
51
|
+
readonly importedBy?: typeof ImportedBy.Type;
|
|
52
|
+
readonly members?: ReadonlyArray<typeof Members.Type>;
|
|
53
|
+
readonly requires?: ReadonlyArray<string>;
|
|
54
|
+
readonly requiresNot?: ReadonlyArray<string>;
|
|
55
|
+
readonly children?: Readonly<Record<string, ManifestNode>>;
|
|
56
|
+
};
|
|
57
|
+
export declare const Manifest: Schema.Struct<{
|
|
58
|
+
readonly resolve: Schema.Struct<{
|
|
59
|
+
readonly scopes: Schema.$Array<Schema.Struct<{
|
|
60
|
+
readonly files: Schema.String;
|
|
61
|
+
readonly tsconfig: Schema.String;
|
|
62
|
+
}>>;
|
|
63
|
+
readonly extensions: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
64
|
+
readonly conditionNames: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
65
|
+
readonly mainFields: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
66
|
+
readonly unresolved: Schema.optionalKey<Schema.Literals<readonly ["error", "off"]>>;
|
|
67
|
+
readonly ignoreUnresolved: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
68
|
+
}>;
|
|
69
|
+
readonly baseline: Schema.optionalKey<Schema.String>;
|
|
70
|
+
readonly deny: Schema.optionalKey<Schema.$Array<Schema.Struct<{
|
|
71
|
+
readonly match: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>;
|
|
72
|
+
readonly matchNot: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
73
|
+
readonly except: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
74
|
+
readonly message: Schema.String;
|
|
75
|
+
}>>>;
|
|
76
|
+
readonly exports: Schema.optionalKey<Schema.$Array<Schema.Struct<{
|
|
77
|
+
readonly name: Schema.String;
|
|
78
|
+
readonly message: Schema.String;
|
|
79
|
+
readonly module: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>;
|
|
80
|
+
readonly symbols: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
81
|
+
readonly except: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>>;
|
|
82
|
+
readonly fix: Schema.optionalKey<Schema.Literal<"subpath-namespace-import">>;
|
|
83
|
+
}>>>;
|
|
84
|
+
readonly aliases: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
|
|
85
|
+
readonly tree: Schema.$Record<Schema.String, Schema.Codec<ManifestNode, ManifestNode, never, never>>;
|
|
86
|
+
}>;
|
|
87
|
+
export type Manifest = typeof Manifest.Type;
|
|
88
|
+
export type ImportsSpec = typeof Imports.Type;
|
|
89
|
+
export type ImportedBySpec = typeof ImportedBy.Type;
|
|
90
|
+
export type MembersSpec = typeof Members.Type;
|
|
91
|
+
export type NamingSpec = typeof Naming.Type;
|
|
92
|
+
export type ExportRestriction = typeof ExportRestriction.Type;
|
|
93
|
+
export declare const globsOf: (globs: string | ReadonlyArray<string>) => ReadonlyArray<string>;
|
|
94
|
+
export declare const decodeManifest: (configPath: string, input: unknown) => Result.Result<Manifest, ConfigInvalid>;
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/manifest/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAwBhE,QAAA,MAAM,OAAO;;;;;;;;;;;;EAkBX,CAAC;AAMH,QAAA,MAAM,UAAU;;;;EAMd,CAAC;AASH,QAAA,MAAM,MAAM;;;;;;IAIV,CAAC;AAEH,QAAA,MAAM,OAAO;;;;;;;EAOX,CAAC;AAKH,QAAA,MAAM,iBAAiB;;;;;;;EAUrB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAI1B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAK3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAGzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,MAAM,CAAC,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,IAAI,CAAC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,UAAU,CAAC,IAAI,CAAC;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IAGtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAI1C,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAE7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;CAC5D,CAAC;AAiBF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBnB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAC9C,MAAM,MAAM,cAAc,GAAG,OAAO,UAAU,CAAC,IAAI,CAAC;AACpD,MAAM,MAAM,WAAW,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAC9C,MAAM,MAAM,UAAU,GAAG,OAAO,MAAM,CAAC,IAAI,CAAC;AAC5C,MAAM,MAAM,iBAAiB,GAAG,OAAO,iBAAiB,CAAC,IAAI,CAAC;AAE9D,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,KAAG,aAAa,CAAC,MAAM,CACvC,CAAC;AAI9C,eAAO,MAAM,cAAc,GACzB,YAAY,MAAM,EAClB,OAAO,OAAO,KACb,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAIrC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-system.d.ts","sourceRoot":"","sources":["../../../src/ports/file-system.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,OAAO,CAAC;CACxD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type * as Result from "effect/Result";
|
|
2
|
+
import type { ImportUnresolved } from "../domain/architecture-error.js";
|
|
3
|
+
export type DependencyKind = "local" | "external" | "builtin";
|
|
4
|
+
export type ResolvedTarget = {
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly kind: DependencyKind;
|
|
7
|
+
};
|
|
8
|
+
export type ModuleResolver = {
|
|
9
|
+
readonly resolve: (fromFile: string, specifier: string) => Result.Result<ResolvedTarget, ImportUnresolved>;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=module-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-resolver.d.ts","sourceRoot":"","sources":["../../../src/ports/module-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAE9D,MAAM,MAAM,cAAc,GAAG;IAK3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAGtB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;CACtD,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as Cause from "effect/Cause";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Exit from "effect/Exit";
|
|
5
|
+
import { run } from "./run.js";
|
|
6
|
+
const exit = await Effect.runPromiseExit(run(process.cwd(), process.argv.slice(2)));
|
|
7
|
+
if (Exit.isFailure(exit)) {
|
|
8
|
+
// The expected failures carry their own sentence; anything else is a defect
|
|
9
|
+
// and deserves the full cause.
|
|
10
|
+
const squashed = Cause.squash(exit.cause);
|
|
11
|
+
const message = typeof squashed === "object" && squashed !== null && "message" in squashed
|
|
12
|
+
? String(squashed.message)
|
|
13
|
+
: Cause.pretty(exit.cause);
|
|
14
|
+
process.stderr.write(`\n${message}\n`);
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../src/adapters/cli/main.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpF,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;IACzB,4EAA4E;IAC5E,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,OAAO,GACX,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,SAAS,IAAI,QAAQ;QACxE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC1B,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,OAAO,IAAI,CAAC,CAAC;IACvC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Result from "effect/Result";
|
|
5
|
+
import { baselineOf, decodeBaseline, EMPTY_BASELINE, serializeBaseline, staleEntriesOf, unbaselined, } from "../../core/baseline.js";
|
|
6
|
+
import { evaluateSelectedBindings, exportRulesSelecting } from "../../core/exports.js";
|
|
7
|
+
import { evaluateSelectedEdge, rulesSelecting } from "../../core/imports.js";
|
|
8
|
+
import { evaluateMemberSite, memberRulesSelecting } from "../../core/members.js";
|
|
9
|
+
import { evaluateStructure, requiredSiblingsOf } from "../../core/structure.js";
|
|
10
|
+
import { fingerprintOf, formatMessage } from "../../domain/violation.js";
|
|
11
|
+
import { loadPolicy } from "../oxlint/config-loader.js";
|
|
12
|
+
import { sourceFactsOf } from "./source-facts.js";
|
|
13
|
+
import { listSourceFiles } from "./source-files.js";
|
|
14
|
+
const fail = (message) => ({ _tag: "CliFailure", message });
|
|
15
|
+
export const collectFindings = (policy, roots) => {
|
|
16
|
+
const files = listSourceFiles(policy.repoRoot, roots);
|
|
17
|
+
const violations = [];
|
|
18
|
+
const unresolved = [];
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
for (const violation of evaluateStructure(policy.structure, policy.fileSystem, file)) {
|
|
21
|
+
violations.push(violation);
|
|
22
|
+
}
|
|
23
|
+
const selectedImports = rulesSelecting(policy.importRules, file);
|
|
24
|
+
const selectedExports = exportRulesSelecting(policy.exportRules, file);
|
|
25
|
+
const selectedMembers = memberRulesSelecting(policy.memberRules, file);
|
|
26
|
+
if (selectedImports.length + selectedExports.length + selectedMembers.length === 0)
|
|
27
|
+
continue;
|
|
28
|
+
const facts = sourceFactsOf(policy.repoRoot, file);
|
|
29
|
+
for (const site of facts.memberSites) {
|
|
30
|
+
for (const violation of evaluateMemberSite(selectedMembers, site))
|
|
31
|
+
violations.push(violation);
|
|
32
|
+
}
|
|
33
|
+
for (const specifier of facts.specifiers) {
|
|
34
|
+
const edge = { importer: file, specifier };
|
|
35
|
+
const imported = evaluateSelectedEdge(selectedImports, policy.resolver, edge);
|
|
36
|
+
if (Result.isFailure(imported)) {
|
|
37
|
+
if (policy.config.resolve.unresolved === "off")
|
|
38
|
+
continue;
|
|
39
|
+
if (policy.ignoreUnresolved.some((pattern) => pattern.test(specifier)))
|
|
40
|
+
continue;
|
|
41
|
+
unresolved.push(`${file} → ${specifier} (${imported.failure.detail})`);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
for (const violation of imported.success)
|
|
45
|
+
violations.push(violation);
|
|
46
|
+
const bound = facts.bindings.get(specifier) ?? [];
|
|
47
|
+
const exported = evaluateSelectedBindings(selectedExports, policy.resolver, {
|
|
48
|
+
...edge,
|
|
49
|
+
bindings: bound,
|
|
50
|
+
});
|
|
51
|
+
if (!Result.isFailure(exported)) {
|
|
52
|
+
for (const { violation } of exported.success)
|
|
53
|
+
violations.push(violation);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { violations, unresolved, files: files.length };
|
|
58
|
+
};
|
|
59
|
+
const baselinePathOf = (policy) => policy.config.baseline === undefined
|
|
60
|
+
? null
|
|
61
|
+
: path.resolve(policy.repoRoot, policy.config.baseline);
|
|
62
|
+
const readBaseline = (policy) => {
|
|
63
|
+
const at = baselinePathOf(policy);
|
|
64
|
+
if (at === null)
|
|
65
|
+
return EMPTY_BASELINE;
|
|
66
|
+
try {
|
|
67
|
+
return decodeBaseline(JSON.parse(readFileSync(at, "utf8")));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return EMPTY_BASELINE;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const report = (lines) => Effect.sync(() => {
|
|
74
|
+
for (const line of lines)
|
|
75
|
+
process.stdout.write(`${line}\n`);
|
|
76
|
+
});
|
|
77
|
+
const describe = (violation) => ` ${violation.file}\n ${formatMessage(violation)}`;
|
|
78
|
+
export const check = (policy, roots) => Effect.gen(function* () {
|
|
79
|
+
const findings = collectFindings(policy, roots);
|
|
80
|
+
const baseline = readBaseline(policy);
|
|
81
|
+
const reportable = unbaselined(baseline, findings.violations);
|
|
82
|
+
const stale = staleEntriesOf(baseline, findings.violations);
|
|
83
|
+
yield* report(reportable.map(describe));
|
|
84
|
+
yield* report(findings.unresolved.map((one) => ` unresolved: ${one}`));
|
|
85
|
+
const carried = findings.violations.length - reportable.length;
|
|
86
|
+
yield* report([
|
|
87
|
+
"",
|
|
88
|
+
`${String(findings.files)} files, ${String(reportable.length)} violations` +
|
|
89
|
+
(carried > 0 ? `, ${String(carried)} carried by the baseline` : ""),
|
|
90
|
+
]);
|
|
91
|
+
if (stale.length > 0) {
|
|
92
|
+
// The ratchet: a fixed violation must leave the baseline, or the floor
|
|
93
|
+
// never rises and the file stops describing anything real.
|
|
94
|
+
yield* report([
|
|
95
|
+
"",
|
|
96
|
+
`${String(stale.length)} baseline entries no longer fire. The code was fixed; prune them:`,
|
|
97
|
+
...stale.map((entry) => ` ${entry}`),
|
|
98
|
+
"",
|
|
99
|
+
" architecture baseline # rewrites the file from what still fires",
|
|
100
|
+
]);
|
|
101
|
+
return yield* Effect.fail(fail("stale baseline entries"));
|
|
102
|
+
}
|
|
103
|
+
if (reportable.length > 0 || findings.unresolved.length > 0) {
|
|
104
|
+
return yield* Effect.fail(fail("architecture violations"));
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
export const writeBaseline = (policy, roots) => Effect.gen(function* () {
|
|
108
|
+
const at = baselinePathOf(policy);
|
|
109
|
+
if (at === null) {
|
|
110
|
+
return yield* Effect.fail(fail("this policy declares no `baseline` path, so there is nowhere to write one"));
|
|
111
|
+
}
|
|
112
|
+
const findings = collectFindings(policy, roots);
|
|
113
|
+
const baseline = baselineOf(findings.violations);
|
|
114
|
+
yield* Effect.sync(() => {
|
|
115
|
+
writeFileSync(at, serializeBaseline(baseline));
|
|
116
|
+
});
|
|
117
|
+
yield* report([
|
|
118
|
+
`${String(baseline.entries.length)} violations recorded in ${path.relative(policy.repoRoot, at)}.`,
|
|
119
|
+
"Each one is debt the policy is carrying. Fixing one means deleting its line.",
|
|
120
|
+
]);
|
|
121
|
+
});
|
|
122
|
+
// The question a tree config makes harder to answer than a flat one: given a
|
|
123
|
+
// file, what governs it? A flat config you grep; a tree you have to walk.
|
|
124
|
+
export const explain = (policy, file) => Effect.gen(function* () {
|
|
125
|
+
const relative = path.relative(policy.repoRoot, path.resolve(policy.repoRoot, file));
|
|
126
|
+
const selected = rulesSelecting(policy.importRules, relative);
|
|
127
|
+
// An allowlist rule names no `to` — it fires when the target matches none of
|
|
128
|
+
// its patterns. A prohibition names one.
|
|
129
|
+
const allowlists = selected.filter(([rule]) => rule.to.length === 0 && rule.toNot.length > 0);
|
|
130
|
+
const prohibitions = selected.filter(([rule]) => rule.to.length > 0);
|
|
131
|
+
const owed = policy.structure.parity
|
|
132
|
+
.filter((rule) => rule.file.some((pattern) => pattern.test(relative)) &&
|
|
133
|
+
!rule.fileNot.some((pattern) => pattern.test(relative)))
|
|
134
|
+
.flatMap((rule) => requiredSiblingsOf(rule, relative));
|
|
135
|
+
const governing = policy.structure.folders.filter((rule) => rule.folder.some((pattern) => pattern.test(path.dirname(relative))));
|
|
136
|
+
const naming = policy.structure.naming.filter((rule) => rule.file.some((pattern) => pattern.test(relative)) &&
|
|
137
|
+
!rule.fileNot.some((pattern) => pattern.test(relative)));
|
|
138
|
+
const firstSentence = (message) => `${message.split(". ")[0] ?? message}.`;
|
|
139
|
+
yield* report([
|
|
140
|
+
relative,
|
|
141
|
+
"",
|
|
142
|
+
allowlists.length === 0
|
|
143
|
+
? " may import: anything (no tier above this file states an allowlist)"
|
|
144
|
+
: " may import:",
|
|
145
|
+
...allowlists.flatMap(([rule]) => [
|
|
146
|
+
` — ${rule.name}`,
|
|
147
|
+
...rule.toNot.map((pattern) => ` ${pattern}`),
|
|
148
|
+
]),
|
|
149
|
+
"",
|
|
150
|
+
" may not import:",
|
|
151
|
+
...(prohibitions.length === 0
|
|
152
|
+
? [" (nothing beyond the allowlist above)"]
|
|
153
|
+
: prohibitions.map(([rule]) => ` ${rule.name} — ${firstSentence(rule.message)}`)),
|
|
154
|
+
"",
|
|
155
|
+
` lives in: ${governing.length === 0 ? "a folder no rule governs" : governing.map((rule) => rule.name).join(", ")}`,
|
|
156
|
+
...(naming.length === 0
|
|
157
|
+
? []
|
|
158
|
+
: [
|
|
159
|
+
" is named by:",
|
|
160
|
+
...naming.map((rule) => ` ${rule.name} — ${rule.sameAs !== null ? "its folder's own name" : (rule.convention?.source ?? "")}`),
|
|
161
|
+
]),
|
|
162
|
+
...(owed.length === 0 ? [] : [" owes:", ...owed.map((one) => ` ${one}`)]),
|
|
163
|
+
]);
|
|
164
|
+
});
|
|
165
|
+
export const run = (repoRoot, argv) => Effect.gen(function* () {
|
|
166
|
+
const [command = "check", ...rest] = argv;
|
|
167
|
+
const policy = yield* Effect.tryPromise({
|
|
168
|
+
try: () => loadPolicy(repoRoot),
|
|
169
|
+
catch: (cause) => fail(String(cause)),
|
|
170
|
+
});
|
|
171
|
+
const roots = rest.length > 0 ? rest : ["packages"];
|
|
172
|
+
switch (command) {
|
|
173
|
+
case "check":
|
|
174
|
+
return yield* check(policy, roots);
|
|
175
|
+
case "baseline":
|
|
176
|
+
return yield* writeBaseline(policy, roots);
|
|
177
|
+
case "explain": {
|
|
178
|
+
const [file] = rest;
|
|
179
|
+
if (file === undefined)
|
|
180
|
+
return yield* Effect.fail(fail("explain needs a file path"));
|
|
181
|
+
return yield* explain(policy, file);
|
|
182
|
+
}
|
|
183
|
+
default:
|
|
184
|
+
return yield* Effect.fail(fail(`unknown command "${command}". Try: check | baseline | explain <file>`));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
export const fingerprint = fingerprintOf;
|
|
188
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../src/adapters/cli/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
const scriptKindOf = (file) => file.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
5
|
+
const nameOf = (node) => {
|
|
6
|
+
if (node === undefined)
|
|
7
|
+
return null;
|
|
8
|
+
if (ts.isIdentifier(node))
|
|
9
|
+
return node.text;
|
|
10
|
+
if (ts.isStringLiteral(node))
|
|
11
|
+
return node.text;
|
|
12
|
+
return null;
|
|
13
|
+
};
|
|
14
|
+
const bindingsOfImportClause = (clause) => {
|
|
15
|
+
if (clause === undefined)
|
|
16
|
+
return [];
|
|
17
|
+
const found = [];
|
|
18
|
+
if (clause.name !== undefined)
|
|
19
|
+
found.push({ symbol: "default", kind: "default" });
|
|
20
|
+
const bindings = clause.namedBindings;
|
|
21
|
+
if (bindings !== undefined) {
|
|
22
|
+
if (ts.isNamespaceImport(bindings))
|
|
23
|
+
found.push({ symbol: "*", kind: "namespace" });
|
|
24
|
+
else {
|
|
25
|
+
for (const element of bindings.elements) {
|
|
26
|
+
const symbol = nameOf(element.propertyName ?? element.name);
|
|
27
|
+
if (symbol !== null)
|
|
28
|
+
found.push({ symbol, kind: "named" });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return found;
|
|
33
|
+
};
|
|
34
|
+
// `export { a } from "m"` — `propertyName` is the name in the source module when
|
|
35
|
+
// the export is renamed, so it is the one the policy is about.
|
|
36
|
+
const bindingsOfExportClause = (clause) => {
|
|
37
|
+
if (clause === undefined || ts.isNamespaceExport(clause))
|
|
38
|
+
return [];
|
|
39
|
+
const found = [];
|
|
40
|
+
for (const element of clause.elements) {
|
|
41
|
+
const symbol = nameOf(element.propertyName ?? element.name);
|
|
42
|
+
if (symbol !== null)
|
|
43
|
+
found.push({ symbol, kind: "named" });
|
|
44
|
+
}
|
|
45
|
+
return found;
|
|
46
|
+
};
|
|
47
|
+
const calleeNameOf = (expression) => {
|
|
48
|
+
if (ts.isIdentifier(expression))
|
|
49
|
+
return expression.text;
|
|
50
|
+
if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.name)) {
|
|
51
|
+
return expression.name.text;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
export const sourceFactsOf = (repoRoot, file) => {
|
|
56
|
+
const text = readFileSync(path.join(repoRoot, file), "utf8");
|
|
57
|
+
const parsed = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, scriptKindOf(file));
|
|
58
|
+
const specifiers = [];
|
|
59
|
+
const bindings = new Map();
|
|
60
|
+
const memberSites = [];
|
|
61
|
+
const record = (specifier, found) => {
|
|
62
|
+
if (!bindings.has(specifier)) {
|
|
63
|
+
specifiers.push(specifier);
|
|
64
|
+
bindings.set(specifier, []);
|
|
65
|
+
}
|
|
66
|
+
const existing = bindings.get(specifier);
|
|
67
|
+
if (existing !== undefined)
|
|
68
|
+
for (const binding of found)
|
|
69
|
+
existing.push(binding);
|
|
70
|
+
};
|
|
71
|
+
const visit = (node) => {
|
|
72
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
73
|
+
// A side-effect import carries no bindings but is still an edge — the
|
|
74
|
+
// `import "server-only"` form a regex cannot see.
|
|
75
|
+
record(node.moduleSpecifier.text, bindingsOfImportClause(node.importClause));
|
|
76
|
+
}
|
|
77
|
+
else if (ts.isExportDeclaration(node) &&
|
|
78
|
+
node.moduleSpecifier !== undefined &&
|
|
79
|
+
ts.isStringLiteral(node.moduleSpecifier)) {
|
|
80
|
+
record(node.moduleSpecifier.text, bindingsOfExportClause(node.exportClause));
|
|
81
|
+
}
|
|
82
|
+
else if (ts.isImportEqualsDeclaration(node) &&
|
|
83
|
+
ts.isExternalModuleReference(node.moduleReference) &&
|
|
84
|
+
ts.isStringLiteral(node.moduleReference.expression)) {
|
|
85
|
+
record(node.moduleReference.expression.text, []);
|
|
86
|
+
}
|
|
87
|
+
else if (ts.isCallExpression(node)) {
|
|
88
|
+
const [first] = node.arguments;
|
|
89
|
+
const isModuleCall = node.expression.kind === ts.SyntaxKind.ImportKeyword ||
|
|
90
|
+
(ts.isIdentifier(node.expression) && node.expression.text === "require");
|
|
91
|
+
if (isModuleCall && first !== undefined && ts.isStringLiteral(first)) {
|
|
92
|
+
record(first.text, []);
|
|
93
|
+
}
|
|
94
|
+
const callee = calleeNameOf(node.expression);
|
|
95
|
+
if (callee !== null)
|
|
96
|
+
memberSites.push({ file, subject: "calls", name: callee });
|
|
97
|
+
}
|
|
98
|
+
else if (ts.isTypeAliasDeclaration(node) && ts.isTypeLiteralNode(node.type)) {
|
|
99
|
+
const declaration = node.name.text;
|
|
100
|
+
for (const member of node.type.members) {
|
|
101
|
+
// A computed key is not a name a vocabulary rule can speak about.
|
|
102
|
+
if (!ts.isPropertySignature(member) && !ts.isMethodSignature(member))
|
|
103
|
+
continue;
|
|
104
|
+
if (ts.isComputedPropertyName(member.name))
|
|
105
|
+
continue;
|
|
106
|
+
const name = nameOf(member.name);
|
|
107
|
+
if (name !== null) {
|
|
108
|
+
memberSites.push({ file, subject: "type-members", name, in: declaration });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
ts.forEachChild(node, visit);
|
|
113
|
+
};
|
|
114
|
+
visit(parsed);
|
|
115
|
+
return { specifiers, bindings, memberSites };
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=source-facts.js.map
|