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.
Files changed (152) hide show
  1. package/LICENSE +21 -0
  2. package/build/dts/adapters/cli/main.d.ts +3 -0
  3. package/build/dts/adapters/cli/main.d.ts.map +1 -0
  4. package/build/dts/adapters/cli/run.d.ts +19 -0
  5. package/build/dts/adapters/cli/run.d.ts.map +1 -0
  6. package/build/dts/adapters/cli/source-facts.d.ts +9 -0
  7. package/build/dts/adapters/cli/source-facts.d.ts.map +1 -0
  8. package/build/dts/adapters/cli/source-files.d.ts +2 -0
  9. package/build/dts/adapters/cli/source-files.d.ts.map +1 -0
  10. package/build/dts/adapters/oxlint/config-loader.d.ts +23 -0
  11. package/build/dts/adapters/oxlint/config-loader.d.ts.map +1 -0
  12. package/build/dts/adapters/oxlint/exports-rule.d.ts +4 -0
  13. package/build/dts/adapters/oxlint/exports-rule.d.ts.map +1 -0
  14. package/build/dts/adapters/oxlint/imports-rule.d.ts +4 -0
  15. package/build/dts/adapters/oxlint/imports-rule.d.ts.map +1 -0
  16. package/build/dts/adapters/oxlint/members-rule.d.ts +4 -0
  17. package/build/dts/adapters/oxlint/members-rule.d.ts.map +1 -0
  18. package/build/dts/adapters/oxlint/oxlint-api.d.ts +19 -0
  19. package/build/dts/adapters/oxlint/oxlint-api.d.ts.map +1 -0
  20. package/build/dts/adapters/oxlint/plugin.d.ts +15 -0
  21. package/build/dts/adapters/oxlint/plugin.d.ts.map +1 -0
  22. package/build/dts/adapters/oxlint/structure-rule.d.ts +4 -0
  23. package/build/dts/adapters/oxlint/structure-rule.d.ts.map +1 -0
  24. package/build/dts/core/baseline.d.ts +16 -0
  25. package/build/dts/core/baseline.d.ts.map +1 -0
  26. package/build/dts/core/exports.d.ts +39 -0
  27. package/build/dts/core/exports.d.ts.map +1 -0
  28. package/build/dts/core/imports.d.ts +27 -0
  29. package/build/dts/core/imports.d.ts.map +1 -0
  30. package/build/dts/core/members.d.ts +28 -0
  31. package/build/dts/core/members.d.ts.map +1 -0
  32. package/build/dts/core/patterns.d.ts +19 -0
  33. package/build/dts/core/patterns.d.ts.map +1 -0
  34. package/build/dts/core/structure.d.ts +48 -0
  35. package/build/dts/core/structure.d.ts.map +1 -0
  36. package/build/dts/domain/architecture-config.d.ts +177 -0
  37. package/build/dts/domain/architecture-config.d.ts.map +1 -0
  38. package/build/dts/domain/architecture-error.d.ts +27 -0
  39. package/build/dts/domain/architecture-error.d.ts.map +1 -0
  40. package/build/dts/domain/violation.d.ts +11 -0
  41. package/build/dts/domain/violation.d.ts.map +1 -0
  42. package/build/dts/index.d.ts +10 -0
  43. package/build/dts/index.d.ts.map +1 -0
  44. package/build/dts/infrastructure/file-system-fake.d.ts +3 -0
  45. package/build/dts/infrastructure/file-system-fake.d.ts.map +1 -0
  46. package/build/dts/infrastructure/file-system-live.d.ts +3 -0
  47. package/build/dts/infrastructure/file-system-live.d.ts.map +1 -0
  48. package/build/dts/infrastructure/module-resolver-fake.d.ts +3 -0
  49. package/build/dts/infrastructure/module-resolver-fake.d.ts.map +1 -0
  50. package/build/dts/infrastructure/module-resolver-live.d.ts +4 -0
  51. package/build/dts/infrastructure/module-resolver-live.d.ts.map +1 -0
  52. package/build/dts/manifest/compile.d.ts +16 -0
  53. package/build/dts/manifest/compile.d.ts.map +1 -0
  54. package/build/dts/manifest/glob.d.ts +14 -0
  55. package/build/dts/manifest/glob.d.ts.map +1 -0
  56. package/build/dts/manifest/manifest.d.ts +96 -0
  57. package/build/dts/manifest/manifest.d.ts.map +1 -0
  58. package/build/dts/ports/file-system.d.ts +4 -0
  59. package/build/dts/ports/file-system.d.ts.map +1 -0
  60. package/build/dts/ports/module-resolver.d.ts +11 -0
  61. package/build/dts/ports/module-resolver.d.ts.map +1 -0
  62. package/build/esm/adapters/cli/main.js +17 -0
  63. package/build/esm/adapters/cli/main.js.map +1 -0
  64. package/build/esm/adapters/cli/run.js +188 -0
  65. package/build/esm/adapters/cli/run.js.map +1 -0
  66. package/build/esm/adapters/cli/source-facts.js +117 -0
  67. package/build/esm/adapters/cli/source-facts.js.map +1 -0
  68. package/build/esm/adapters/cli/source-files.js +40 -0
  69. package/build/esm/adapters/cli/source-files.js.map +1 -0
  70. package/build/esm/adapters/oxlint/config-loader.js +81 -0
  71. package/build/esm/adapters/oxlint/config-loader.js.map +1 -0
  72. package/build/esm/adapters/oxlint/exports-rule.js +104 -0
  73. package/build/esm/adapters/oxlint/exports-rule.js.map +1 -0
  74. package/build/esm/adapters/oxlint/imports-rule.js +55 -0
  75. package/build/esm/adapters/oxlint/imports-rule.js.map +1 -0
  76. package/build/esm/adapters/oxlint/members-rule.js +75 -0
  77. package/build/esm/adapters/oxlint/members-rule.js.map +1 -0
  78. package/build/esm/adapters/oxlint/oxlint-api.js +7 -0
  79. package/build/esm/adapters/oxlint/oxlint-api.js.map +1 -0
  80. package/build/esm/adapters/oxlint/plugin.js +23 -0
  81. package/build/esm/adapters/oxlint/plugin.js.map +1 -0
  82. package/build/esm/adapters/oxlint/structure-rule.js +37 -0
  83. package/build/esm/adapters/oxlint/structure-rule.js.map +1 -0
  84. package/build/esm/core/baseline.js +30 -0
  85. package/build/esm/core/baseline.js.map +1 -0
  86. package/build/esm/core/exports.js +96 -0
  87. package/build/esm/core/exports.js.map +1 -0
  88. package/build/esm/core/imports.js +85 -0
  89. package/build/esm/core/imports.js.map +1 -0
  90. package/build/esm/core/members.js +84 -0
  91. package/build/esm/core/members.js.map +1 -0
  92. package/build/esm/core/patterns.js +78 -0
  93. package/build/esm/core/patterns.js.map +1 -0
  94. package/build/esm/core/structure.js +256 -0
  95. package/build/esm/core/structure.js.map +1 -0
  96. package/build/esm/domain/architecture-config.js +172 -0
  97. package/build/esm/domain/architecture-config.js.map +1 -0
  98. package/build/esm/domain/architecture-error.js +29 -0
  99. package/build/esm/domain/architecture-error.js.map +1 -0
  100. package/build/esm/domain/violation.js +8 -0
  101. package/build/esm/domain/violation.js.map +1 -0
  102. package/build/esm/index.js +8 -0
  103. package/build/esm/index.js.map +1 -0
  104. package/build/esm/infrastructure/file-system-fake.js +5 -0
  105. package/build/esm/infrastructure/file-system-fake.js.map +1 -0
  106. package/build/esm/infrastructure/file-system-live.js +19 -0
  107. package/build/esm/infrastructure/file-system-live.js.map +1 -0
  108. package/build/esm/infrastructure/module-resolver-fake.js +23 -0
  109. package/build/esm/infrastructure/module-resolver-fake.js.map +1 -0
  110. package/build/esm/infrastructure/module-resolver-live.js +71 -0
  111. package/build/esm/infrastructure/module-resolver-live.js.map +1 -0
  112. package/build/esm/manifest/compile.js +503 -0
  113. package/build/esm/manifest/compile.js.map +1 -0
  114. package/build/esm/manifest/glob.js +77 -0
  115. package/build/esm/manifest/glob.js.map +1 -0
  116. package/build/esm/manifest/manifest.js +120 -0
  117. package/build/esm/manifest/manifest.js.map +1 -0
  118. package/build/esm/ports/file-system.js +2 -0
  119. package/build/esm/ports/file-system.js.map +1 -0
  120. package/build/esm/ports/module-resolver.js +2 -0
  121. package/build/esm/ports/module-resolver.js.map +1 -0
  122. package/package.json +73 -0
  123. package/src/adapters/cli/main.ts +20 -0
  124. package/src/adapters/cli/run.ts +270 -0
  125. package/src/adapters/cli/source-facts.ts +137 -0
  126. package/src/adapters/cli/source-files.ts +42 -0
  127. package/src/adapters/oxlint/config-loader.ts +136 -0
  128. package/src/adapters/oxlint/exports-rule.ts +144 -0
  129. package/src/adapters/oxlint/imports-rule.ts +67 -0
  130. package/src/adapters/oxlint/members-rule.ts +114 -0
  131. package/src/adapters/oxlint/oxlint-api.ts +25 -0
  132. package/src/adapters/oxlint/plugin.ts +35 -0
  133. package/src/adapters/oxlint/structure-rule.ts +39 -0
  134. package/src/core/baseline.ts +62 -0
  135. package/src/core/exports.ts +164 -0
  136. package/src/core/imports.ts +138 -0
  137. package/src/core/members.ts +131 -0
  138. package/src/core/patterns.ts +122 -0
  139. package/src/core/structure.ts +348 -0
  140. package/src/domain/architecture-config.ts +206 -0
  141. package/src/domain/architecture-error.ts +43 -0
  142. package/src/domain/violation.ts +24 -0
  143. package/src/index.ts +28 -0
  144. package/src/infrastructure/file-system-fake.ts +6 -0
  145. package/src/infrastructure/file-system-live.ts +20 -0
  146. package/src/infrastructure/module-resolver-fake.ts +29 -0
  147. package/src/infrastructure/module-resolver-live.ts +100 -0
  148. package/src/manifest/compile.ts +736 -0
  149. package/src/manifest/glob.ts +108 -0
  150. package/src/manifest/manifest.ts +178 -0
  151. package/src/ports/file-system.ts +5 -0
  152. package/src/ports/module-resolver.ts +23 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-facts.js","sourceRoot":"","sources":["../../../../src/adapters/cli/source-facts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import * as path from "node:path";
3
+ // Folders no policy is written about and no linter visits.
4
+ const SKIPPED = new Set([
5
+ "node_modules",
6
+ "build",
7
+ "dist",
8
+ ".next",
9
+ ".git",
10
+ "storybook-static",
11
+ "coverage",
12
+ ]);
13
+ const SOURCE = /\.(ts|tsx|mts|cts)$/;
14
+ // A declaration file states types, not code; no linter visits one and no policy
15
+ // is written about one.
16
+ const DECLARATION = /\.d\.[cm]?ts$/;
17
+ export const listSourceFiles = (repoRoot, roots) => {
18
+ const found = [];
19
+ const walk = (absolute) => {
20
+ for (const entry of readdirSync(absolute)) {
21
+ if (SKIPPED.has(entry))
22
+ continue;
23
+ const child = path.join(absolute, entry);
24
+ if (statSync(child).isDirectory())
25
+ walk(child);
26
+ else if (SOURCE.test(entry) && !DECLARATION.test(entry)) {
27
+ found.push(path.relative(repoRoot, child).replaceAll(path.sep, "/"));
28
+ }
29
+ }
30
+ };
31
+ for (const root of roots) {
32
+ const absolute = path.resolve(repoRoot, root);
33
+ if (statSync(absolute).isDirectory())
34
+ walk(absolute);
35
+ else
36
+ found.push(path.relative(repoRoot, absolute).replaceAll(path.sep, "/"));
37
+ }
38
+ return found.sort();
39
+ };
40
+ //# sourceMappingURL=source-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-files.js","sourceRoot":"","sources":["../../../../src/adapters/cli/source-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,2DAA2D;AAC3D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC;IACtB,cAAc;IACd,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,kBAAkB;IAClB,UAAU;CACX,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,qBAAqB,CAAC;AAErC,gFAAgF;AAChF,wBAAwB;AACxB,MAAM,WAAW,GAAG,eAAe,CAAC;AAEpC,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,QAAgB,EAChB,KAA4B,EACL,EAAE;IACzB,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,CAAC,QAAgB,EAAQ,EAAE;QACtC,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1C,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,SAAS;YACjC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;gBAAE,IAAI,CAAC,KAAK,CAAC,CAAC;iBAC1C,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9C,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;YAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;;YAChD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { readFileSync } from "node:fs";
2
+ import * as path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import * as Result from "effect/Result";
5
+ import { decodeBaseline, EMPTY_BASELINE, makeBaselineFilter, } from "../../core/baseline.js";
6
+ import { compileExportRules, exportRulesFailingTheirProbe, } from "../../core/exports.js";
7
+ import { compileImportRules, rulesFailingTheirProbe, } from "../../core/imports.js";
8
+ import { compileMemberRules, memberRulesFailingTheirProbe, } from "../../core/members.js";
9
+ import { compileStructure, structureRulesFailingTheirProbe, } from "../../core/structure.js";
10
+ import { ConfigInvalid } from "../../domain/architecture-error.js";
11
+ import { makeFileSystemLive } from "../../infrastructure/file-system-live.js";
12
+ import { makeModuleResolverLive } from "../../infrastructure/module-resolver-live.js";
13
+ import { lowerManifest } from "../../manifest/compile.js";
14
+ import { decodeManifest } from "../../manifest/manifest.js";
15
+ const readBaselineAt = (repoRoot, at) => {
16
+ try {
17
+ return decodeBaseline(JSON.parse(readFileSync(path.resolve(repoRoot, at), "utf8")));
18
+ }
19
+ catch {
20
+ // An absent or unreadable baseline carries nothing, which is the safe
21
+ // direction: every violation reports.
22
+ return EMPTY_BASELINE;
23
+ }
24
+ };
25
+ export const DEFAULT_CONFIG_FILENAME = "architecture.config.mjs";
26
+ // Anything wrong with the policy — a missing file, a bad shape, an uncompilable
27
+ // pattern — must stop the lint run. A plugin that loads with an empty policy
28
+ // reports nothing and looks exactly like a clean codebase.
29
+ export const loadPolicy = async (repoRoot, configFilename = DEFAULT_CONFIG_FILENAME) => {
30
+ const configPath = path.resolve(repoRoot, configFilename);
31
+ const module = await import(pathToFileURL(configPath).href).catch((cause) => {
32
+ throw new ConfigInvalid({ configPath, detail: String(cause) });
33
+ });
34
+ const exported = typeof module === "object" && module !== null && "default" in module ? module.default : module;
35
+ const decoded = decodeManifest(configPath, exported);
36
+ if (Result.isFailure(decoded))
37
+ throw decoded.failure;
38
+ const config = decoded.success;
39
+ // The manifest is the authoring surface; these flat rules are the machine's.
40
+ const rules = lowerManifest(config);
41
+ const importRules = compileImportRules(rules.imports);
42
+ if (Result.isFailure(importRules))
43
+ throw importRules.failure;
44
+ const exportRules = compileExportRules(rules.exports);
45
+ if (Result.isFailure(exportRules))
46
+ throw exportRules.failure;
47
+ const memberRules = compileMemberRules(rules.members);
48
+ if (Result.isFailure(memberRules))
49
+ throw memberRules.failure;
50
+ const structure = compileStructure(rules.structure);
51
+ if (Result.isFailure(structure))
52
+ throw structure.failure;
53
+ const vacuous = [
54
+ ...rulesFailingTheirProbe(importRules.success),
55
+ ...exportRulesFailingTheirProbe(exportRules.success),
56
+ ...memberRulesFailingTheirProbe(memberRules.success),
57
+ ]
58
+ .map((rule) => rule.name)
59
+ .concat(structureRulesFailingTheirProbe(structure.success));
60
+ if (vacuous.length > 0) {
61
+ throw new ConfigInvalid({
62
+ configPath,
63
+ detail: `these import rules do not report their own probe, so they enforce nothing: ` +
64
+ `${vacuous.join(", ")}. Fix the rule or its probe — ` +
65
+ `a rule that cannot flag a violation it was written for is worse than no rule.`,
66
+ });
67
+ }
68
+ return {
69
+ repoRoot,
70
+ config,
71
+ importRules: importRules.success,
72
+ exportRules: exportRules.success,
73
+ memberRules: memberRules.success,
74
+ structure: structure.success,
75
+ fileSystem: makeFileSystemLive(repoRoot),
76
+ baseline: makeBaselineFilter(config.baseline === undefined ? EMPTY_BASELINE : readBaselineAt(repoRoot, config.baseline)),
77
+ resolver: makeModuleResolverLive(repoRoot, config.resolve),
78
+ ignoreUnresolved: (config.resolve.ignoreUnresolved ?? []).map((pattern) => new RegExp(pattern)),
79
+ };
80
+ };
81
+ //# sourceMappingURL=config-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../../../src/adapters/oxlint/config-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ import * as Result from "effect/Result";
2
+ import { evaluateSelectedBindings, exportRulesSelecting, } from "../../core/exports.js";
3
+ import { formatMessage } from "../../domain/violation.js";
4
+ import { toRepoRelative, } from "./oxlint-api.js";
5
+ const nameOf = (node) => {
6
+ if (node === null || node === undefined)
7
+ return null;
8
+ if (typeof node.name === "string")
9
+ return node.name;
10
+ // `import { "a-b" as ab }` — a string-literal export name.
11
+ return typeof node.value === "string" ? node.value : null;
12
+ };
13
+ const boundOf = (specifier) => {
14
+ const local = nameOf(specifier.local) ?? "";
15
+ switch (specifier.type) {
16
+ case "ImportSpecifier": {
17
+ const symbol = nameOf(specifier.imported);
18
+ return symbol === null ? null : { symbol, kind: "named", node: specifier, local };
19
+ }
20
+ case "ImportDefaultSpecifier":
21
+ return { symbol: "default", kind: "default", node: specifier, local };
22
+ case "ImportNamespaceSpecifier":
23
+ return { symbol: "*", kind: "namespace", node: specifier, local };
24
+ // `export { a } from "…"` — `local` is the name in the source module.
25
+ case "ExportSpecifier": {
26
+ const symbol = nameOf(specifier.local);
27
+ return symbol === null ? null : { symbol, kind: "named", node: specifier, local: symbol };
28
+ }
29
+ default:
30
+ return null;
31
+ }
32
+ };
33
+ // `import { A, B as C } from "pkg"` becomes `import * as A from "pkg/A"` and
34
+ // `import * as C from "pkg/B"`. Only whole-declaration rewrites are offered: a
35
+ // declaration mixing restricted named imports with a default or namespace one
36
+ // would need comma surgery inside the braces, and a fix that is subtly wrong is
37
+ // worse than a diagnostic the author resolves by hand.
38
+ const subpathNamespaceImport = (specifier, bound) => bound
39
+ .map((binding) => `import * as ${binding.local} from "${specifier}/${binding.symbol}";`)
40
+ .join("\n");
41
+ export const makeExportsRule = (policy) => ({
42
+ meta: {
43
+ type: "problem",
44
+ fixable: "code",
45
+ docs: {
46
+ description: "which exported symbols a file may import, for rules a path alone cannot express",
47
+ },
48
+ schema: [],
49
+ },
50
+ createOnce(context) {
51
+ let importer = "";
52
+ let selected = [];
53
+ const check = (node) => {
54
+ const specifierValue = node.source?.value;
55
+ if (typeof specifierValue !== "string")
56
+ return;
57
+ const bound = (node.specifiers ?? [])
58
+ .map(boundOf)
59
+ .filter((one) => one !== null);
60
+ if (bound.length === 0)
61
+ return;
62
+ const outcome = evaluateSelectedBindings(selected, policy.resolver, {
63
+ importer,
64
+ specifier: specifierValue,
65
+ bindings: bound,
66
+ });
67
+ if (Result.isFailure(outcome)) {
68
+ // `architecture/imports` reports the same unresolved edge, so staying
69
+ // quiet here avoids two diagnostics for one broken specifier.
70
+ return;
71
+ }
72
+ for (const { bindings, rule, violation } of outcome.success) {
73
+ if (policy.baseline.isBaselined(violation))
74
+ continue;
75
+ const offending = bound.filter((one) => bindings.some((binding) => binding.symbol === one.symbol && binding.kind === one.kind));
76
+ const rewritable = rule.fix === "subpath-namespace-import" && offending.length === bound.length;
77
+ if (rewritable) {
78
+ context.report({
79
+ node,
80
+ message: formatMessage(violation),
81
+ fix: (fixer) => fixer.replaceText(node, subpathNamespaceImport(specifierValue, offending)),
82
+ });
83
+ continue;
84
+ }
85
+ context.report({
86
+ node: offending[0]?.node ?? node,
87
+ message: formatMessage(violation),
88
+ });
89
+ }
90
+ };
91
+ return {
92
+ before() {
93
+ importer = toRepoRelative(policy.repoRoot, context.filename);
94
+ if (importer.startsWith(".."))
95
+ return false;
96
+ selected = exportRulesSelecting(policy.exportRules, importer);
97
+ return selected.length > 0;
98
+ },
99
+ ImportDeclaration: check,
100
+ ExportNamedDeclaration: check,
101
+ };
102
+ },
103
+ });
104
+ //# sourceMappingURL=exports-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exports-rule.js","sourceRoot":"","sources":["../../../../src/adapters/oxlint/exports-rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import * as Result from "effect/Result";
2
+ import { evaluateSelectedEdge, rulesSelecting } from "../../core/imports.js";
3
+ import { formatMessage } from "../../domain/violation.js";
4
+ import { specifierOf, toRepoRelative, } from "./oxlint-api.js";
5
+ const unresolvedMessage = (specifier, detail) => `[unresolved-import] "${specifier}" could not be resolved, so every import rule about it ` +
6
+ `enforces nothing. Fix the resolve scope in the architecture config, or list the specifier ` +
7
+ `in resolve.ignoreUnresolved. (${detail})`;
8
+ export const makeImportsRule = (policy) => ({
9
+ meta: {
10
+ type: "problem",
11
+ docs: {
12
+ description: "import boundaries between folders and packages, matched against fully resolved module paths",
13
+ },
14
+ schema: [],
15
+ },
16
+ // `createOnce` is what makes resolution affordable: the resolver and the
17
+ // compiled rules are built once per lint run, and `before` decides per file
18
+ // whether any rule selects it at all — a file none select is skipped whole.
19
+ createOnce(context) {
20
+ let importer = "";
21
+ let selected = [];
22
+ const check = (node) => {
23
+ const specifier = specifierOf(node);
24
+ if (specifier === null)
25
+ return;
26
+ const outcome = evaluateSelectedEdge(selected, policy.resolver, { importer, specifier });
27
+ if (Result.isFailure(outcome)) {
28
+ if (policy.config.resolve.unresolved === "off")
29
+ return;
30
+ if (policy.ignoreUnresolved.some((pattern) => pattern.test(specifier)))
31
+ return;
32
+ context.report({ node, message: unresolvedMessage(specifier, outcome.failure.detail) });
33
+ return;
34
+ }
35
+ for (const violation of outcome.success) {
36
+ if (policy.baseline.isBaselined(violation))
37
+ continue;
38
+ context.report({ node, message: formatMessage(violation) });
39
+ }
40
+ };
41
+ return {
42
+ before() {
43
+ importer = toRepoRelative(policy.repoRoot, context.filename);
44
+ if (importer.startsWith(".."))
45
+ return false;
46
+ selected = rulesSelecting(policy.importRules, importer);
47
+ return selected.length > 0;
48
+ },
49
+ ImportDeclaration: check,
50
+ ExportNamedDeclaration: check,
51
+ ExportAllDeclaration: check,
52
+ };
53
+ },
54
+ });
55
+ //# sourceMappingURL=imports-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports-rule.js","sourceRoot":"","sources":["../../../../src/adapters/oxlint/imports-rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAqB,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,EAIL,WAAW,EACX,cAAc,GACf,MAAM,iBAAiB,CAAC;AAEzB,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAE,MAAc,EAAU,EAAE,CACtE,wBAAwB,SAAS,yDAAyD;IAC1F,4FAA4F;IAC5F,iCAAiC,MAAM,GAAG,CAAC;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAoB,EAAc,EAAE,CAAC,CAAC;IACpE,IAAI,EAAE;QACJ,IAAI,EAAE,SAAkB;QACxB,IAAI,EAAE;YACJ,WAAW,EACT,6FAA6F;SAChG;QACD,MAAM,EAAE,EAAE;KACX;IAED,yEAAyE;IACzE,4EAA4E;IAC5E,4EAA4E;IAC5E,UAAU,CAAC,OAAoB;QAC7B,IAAI,QAAQ,GAAG,EAAE,CAAC;QAClB,IAAI,QAAQ,GAAgC,EAAE,CAAC;QAE/C,MAAM,KAAK,GAAG,CAAC,IAAgB,EAAQ,EAAE;YACvC,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,SAAS,KAAK,IAAI;gBAAE,OAAO;YAE/B,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAEzF,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC9B,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,KAAK,KAAK;oBAAE,OAAO;gBACvD,IAAI,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAAE,OAAO;gBAC/E,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACxF,OAAO;YACT,CAAC;YAED,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC;oBAAE,SAAS;gBACrD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC;QAEF,OAAO;YACL,MAAM;gBACJ,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC7D,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;oBAAE,OAAO,KAAK,CAAC;gBAC5C,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;gBACxD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7B,CAAC;YACD,iBAAiB,EAAE,KAAK;YACxB,sBAAsB,EAAE,KAAK;YAC7B,oBAAoB,EAAE,KAAK;SAC5B,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { evaluateMemberSite, memberRulesSelecting, } from "../../core/members.js";
2
+ import { formatMessage } from "../../domain/violation.js";
3
+ import { toRepoRelative, } from "./oxlint-api.js";
4
+ const DECLARED_MEMBER_TYPES = new Set(["TSPropertySignature", "TSMethodSignature"]);
5
+ const nameOf = (node) => {
6
+ if (node === null || node === undefined)
7
+ return null;
8
+ if (typeof node.name === "string")
9
+ return node.name;
10
+ return typeof node.value === "string" ? node.value : null;
11
+ };
12
+ const calleeName = (node) => {
13
+ const callee = node.callee;
14
+ if (callee === null || callee === undefined)
15
+ return null;
16
+ if (typeof callee.name === "string")
17
+ return callee.name;
18
+ return nameOf(callee.property);
19
+ };
20
+ export const makeMembersRule = (policy) => ({
21
+ meta: {
22
+ type: "problem",
23
+ docs: {
24
+ description: "which names a file may declare or call — a port's method vocabulary, a tier's allowed hooks",
25
+ },
26
+ schema: [],
27
+ },
28
+ createOnce(context) {
29
+ let file = "";
30
+ let selected = [];
31
+ const report = (node, name, declaration) => {
32
+ const violations = evaluateMemberSite(selected, {
33
+ file,
34
+ subject: declaration === undefined ? "calls" : "type-members",
35
+ name,
36
+ ...(declaration === undefined ? {} : { in: declaration }),
37
+ });
38
+ for (const violation of violations) {
39
+ if (policy.baseline.isBaselined(violation))
40
+ continue;
41
+ context.report({ node, message: formatMessage(violation) });
42
+ }
43
+ };
44
+ return {
45
+ before() {
46
+ file = toRepoRelative(policy.repoRoot, context.filename);
47
+ if (file.startsWith(".."))
48
+ return false;
49
+ selected = memberRulesSelecting(policy.memberRules, file);
50
+ return selected.length > 0;
51
+ },
52
+ TSTypeAliasDeclaration(node) {
53
+ const declaration = nameOf(node.id);
54
+ const annotation = node.typeAnnotation;
55
+ if (declaration === null || annotation?.type !== "TSTypeLiteral")
56
+ return;
57
+ for (const member of annotation.members ?? []) {
58
+ // A computed key is not a name a vocabulary rule can speak about, and
59
+ // no port in this codebase declares one.
60
+ if (member.computed === true || !DECLARED_MEMBER_TYPES.has(member.type))
61
+ continue;
62
+ const name = nameOf(member.key);
63
+ if (name !== null)
64
+ report(member.key ?? member, name, declaration);
65
+ }
66
+ },
67
+ CallExpression(node) {
68
+ const name = calleeName(node);
69
+ if (name !== null)
70
+ report(node, name);
71
+ },
72
+ };
73
+ },
74
+ });
75
+ //# sourceMappingURL=members-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members-rule.js","sourceRoot":"","sources":["../../../../src/adapters/oxlint/members-rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import * as path from "node:path";
2
+ export const toRepoRelative = (repoRoot, filename) => path.relative(repoRoot, filename).replaceAll(path.sep, "/");
3
+ export const specifierOf = (node) => {
4
+ const value = node.source?.value;
5
+ return typeof value === "string" ? value : null;
6
+ };
7
+ //# sourceMappingURL=oxlint-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oxlint-api.js","sourceRoot":"","sources":["../../../../src/adapters/oxlint/oxlint-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAkBlC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAU,EAAE,CAC3E,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAgB,EAAiB,EAAE;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { DEFAULT_CONFIG_FILENAME, loadPolicy } from "./config-loader.js";
2
+ import { makeExportsRule } from "./exports-rule.js";
3
+ import { makeImportsRule } from "./imports-rule.js";
4
+ import { makeMembersRule } from "./members-rule.js";
5
+ import { makeStructureRule } from "./structure-rule.js";
6
+ // oxlint imports this module once per lint run and reads `rules` synchronously,
7
+ // so the policy is loaded here rather than inside a rule. A load failure throws
8
+ // out of the import and fails the run — which is the point: a plugin that came
9
+ // up with no policy would report nothing and be indistinguishable from a clean
10
+ // codebase.
11
+ const policy = await loadPolicy(process.env.ARCHITECTURE_ROOT ?? process.cwd(), process.env.ARCHITECTURE_CONFIG ?? DEFAULT_CONFIG_FILENAME);
12
+ export const rules = {
13
+ imports: makeImportsRule(policy),
14
+ exports: makeExportsRule(policy),
15
+ members: makeMembersRule(policy),
16
+ structure: makeStructureRule(policy),
17
+ };
18
+ const plugin = {
19
+ meta: { name: "architecture" },
20
+ rules,
21
+ };
22
+ export default plugin;
23
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../src/adapters/oxlint/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,gFAAgF;AAChF,gFAAgF;AAChF,+EAA+E;AAC/E,+EAA+E;AAC/E,YAAY;AACZ,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,EAAE,EAC9C,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,uBAAuB,CAC3D,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAKd;IACF,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC;IAChC,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC;IAChC,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC;IAChC,SAAS,EAAE,iBAAiB,CAAC,MAAM,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,GAA+E;IACzF,IAAI,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;IAC9B,KAAK;CACN,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { evaluateStructure } from "../../core/structure.js";
2
+ import { formatMessage } from "../../domain/violation.js";
3
+ import { toRepoRelative } from "./oxlint-api.js";
4
+ export const makeStructureRule = (policy) => ({
5
+ meta: {
6
+ type: "problem",
7
+ docs: {
8
+ description: "the file taxonomy: which file kinds a folder admits, and which siblings a file owes",
9
+ },
10
+ schema: [],
11
+ },
12
+ createOnce(context) {
13
+ // The taxonomy is a property of the path, not of the syntax, so the whole
14
+ // check runs once in `before` and the visitor exists only because oxlint
15
+ // does not run hooks for a rule with no visitor keys.
16
+ return {
17
+ before() {
18
+ const file = toRepoRelative(policy.repoRoot, context.filename);
19
+ if (file.startsWith(".."))
20
+ return false;
21
+ for (const violation of evaluateStructure(policy.structure, policy.fileSystem, file)) {
22
+ if (policy.baseline.isBaselined(violation))
23
+ continue;
24
+ context.report({
25
+ message: formatMessage(violation),
26
+ loc: { line: 1, column: 0 },
27
+ });
28
+ }
29
+ return false;
30
+ },
31
+ Program() {
32
+ return undefined;
33
+ },
34
+ };
35
+ },
36
+ });
37
+ //# sourceMappingURL=structure-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure-rule.js","sourceRoot":"","sources":["../../../../src/adapters/oxlint/structure-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,EAAqC,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAoB,EAAc,EAAE,CAAC,CAAC;IACtE,IAAI,EAAE;QACJ,IAAI,EAAE,SAAkB;QACxB,IAAI,EAAE;YACJ,WAAW,EACT,qFAAqF;SACxF;QACD,MAAM,EAAE,EAAE;KACX;IAED,UAAU,CAAC,OAAoB;QAC7B,0EAA0E;QAC1E,yEAAyE;QACzE,sDAAsD;QACtD,OAAO;YACL,MAAM;gBACJ,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC/D,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;oBAAE,OAAO,KAAK,CAAC;gBAExC,KAAK,MAAM,SAAS,IAAI,iBAAiB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;oBACrF,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC;wBAAE,SAAS;oBACrD,OAAO,CAAC,MAAM,CAAC;wBACb,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC;wBACjC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;qBAC5B,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO;gBACL,OAAO,SAAS,CAAC;YACnB,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { fingerprintOf } from "../domain/violation.js";
2
+ export const EMPTY_BASELINE = { version: 1, entries: [] };
3
+ export const baselineOf = (violations) => ({
4
+ version: 1,
5
+ entries: [...new Set([...violations].map(fingerprintOf))].sort(),
6
+ });
7
+ export const decodeBaseline = (raw) => {
8
+ if (typeof raw !== "object" || raw === null)
9
+ return EMPTY_BASELINE;
10
+ const entries = raw.entries;
11
+ if (!Array.isArray(entries))
12
+ return EMPTY_BASELINE;
13
+ return { version: 1, entries: entries.filter((one) => typeof one === "string") };
14
+ };
15
+ export const serializeBaseline = (baseline) => `${JSON.stringify(baseline, null, 2)}\n`;
16
+ export const makeBaselineFilter = (baseline) => {
17
+ const entries = new Set(baseline.entries);
18
+ return { isBaselined: (violation) => entries.has(fingerprintOf(violation)) };
19
+ };
20
+ // The ratchet's teeth: entries the code no longer produces. A baseline that is
21
+ // allowed to keep them stops being a record of debt and becomes a place to hide.
22
+ export const staleEntriesOf = (baseline, violations) => {
23
+ const current = new Set([...violations].map(fingerprintOf));
24
+ return baseline.entries.filter((entry) => !current.has(entry));
25
+ };
26
+ export const unbaselined = (baseline, violations) => {
27
+ const { isBaselined } = makeBaselineFilter(baseline);
28
+ return [...violations].filter((violation) => !isBaselined(violation));
29
+ };
30
+ //# sourceMappingURL=baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../../src/core/baseline.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAkBvD,MAAM,CAAC,MAAM,cAAc,GAAa,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAEpE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,UAA+B,EAAY,EAAE,CAAC,CAAC;IACxE,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;CACjE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAY,EAAY,EAAE;IACvD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,cAAc,CAAC;IACnE,MAAM,OAAO,GAAI,GAA6B,CAAC,OAAO,CAAC;IACvD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,cAAc,CAAC;IACnD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,EAAE,CAAC;AAClG,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,QAAkB,EAAU,EAAE,CAC9D,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAM3C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAkB,EAAkB,EAAE;IACvE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO,EAAE,WAAW,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;AAC/E,CAAC,CAAC;AAEF,+EAA+E;AAC/E,iFAAiF;AACjF,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,QAAkB,EAClB,UAA+B,EACR,EAAE;IACzB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5D,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AACjE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,QAAkB,EAClB,UAA+B,EACL,EAAE;IAC5B,MAAM,EAAE,WAAW,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;AACxE,CAAC,CAAC"}
@@ -0,0 +1,96 @@
1
+ import * as Result from "effect/Result";
2
+ import { compilePatterns, firstFromMatch, sourcesOf, targetAllowed, validateTargetPatterns, } from "./patterns.js";
3
+ const DEFAULT_KINDS = ["named"];
4
+ export const compileExportRule = (rule) => {
5
+ const from = compilePatterns(rule.name, "from", rule.from);
6
+ if (Result.isFailure(from))
7
+ return Result.fail(from.failure);
8
+ const fromNot = compilePatterns(rule.name, "fromNot", rule.fromNot);
9
+ if (Result.isFailure(fromNot))
10
+ return Result.fail(fromNot.failure);
11
+ const targets = validateTargetPatterns(rule.name, [
12
+ ["to", rule.to],
13
+ ["toNot", rule.toNot],
14
+ ]);
15
+ if (Result.isFailure(targets))
16
+ return Result.fail(targets.failure);
17
+ return Result.succeed({
18
+ name: rule.name,
19
+ message: rule.message,
20
+ probe: rule.probe,
21
+ from: from.success,
22
+ fromNot: fromNot.success,
23
+ to: sourcesOf(rule.to),
24
+ toNot: sourcesOf(rule.toNot),
25
+ symbols: rule.symbols === undefined ? null : new Set(rule.symbols),
26
+ kinds: rule.kinds ?? DEFAULT_KINDS,
27
+ fix: rule.fix ?? null,
28
+ });
29
+ };
30
+ export const compileExportRules = (rules) => {
31
+ const compiled = [];
32
+ for (const rule of rules) {
33
+ const one = compileExportRule(rule);
34
+ if (Result.isFailure(one))
35
+ return Result.fail(one.failure);
36
+ compiled.push(one.success);
37
+ }
38
+ return Result.succeed(compiled);
39
+ };
40
+ export const exportRulesSelecting = (rules, importer) => {
41
+ const selected = [];
42
+ for (const rule of rules) {
43
+ const captures = firstFromMatch(rule, importer);
44
+ if (captures !== null)
45
+ selected.push([rule, captures]);
46
+ }
47
+ return selected;
48
+ };
49
+ const covers = (rule, binding) => rule.kinds.includes(binding.kind) && (rule.symbols === null || rule.symbols.has(binding.symbol));
50
+ export const evaluateSelectedBindings = (selected, resolver, edge) => {
51
+ if (selected.length === 0 || edge.bindings.length === 0)
52
+ return Result.succeed([]);
53
+ const resolved = resolver.resolve(edge.importer, edge.specifier);
54
+ if (Result.isFailure(resolved))
55
+ return Result.fail(resolved.failure);
56
+ const target = resolved.success;
57
+ const violations = [];
58
+ for (const [rule, captures] of selected) {
59
+ if (!targetAllowed(rule, captures, target.path))
60
+ continue;
61
+ const offending = edge.bindings.filter((binding) => covers(rule, binding));
62
+ if (offending.length === 0)
63
+ continue;
64
+ // A rule carrying a fix reports once for the whole declaration, because the
65
+ // fix rewrites the declaration as a unit; one without reports per symbol, so
66
+ // the diagnostic sits on the name that is actually restricted.
67
+ const groups = rule.fix === null ? offending.map((binding) => [binding]) : [offending];
68
+ for (const bindings of groups) {
69
+ violations.push({
70
+ rule,
71
+ bindings,
72
+ violation: {
73
+ kind: "export",
74
+ ruleName: rule.name,
75
+ message: rule.message,
76
+ file: edge.importer,
77
+ subject: `${target.path}#${bindings.map((binding) => binding.symbol).join(",")}`,
78
+ },
79
+ });
80
+ }
81
+ }
82
+ return Result.succeed(violations);
83
+ };
84
+ export const evaluateBindingEdge = (rules, resolver, edge) => evaluateSelectedBindings(exportRulesSelecting(rules, edge.importer), resolver, edge);
85
+ export const exportRulesFailingTheirProbe = (rules) => rules.filter((rule) => {
86
+ const captures = firstFromMatch(rule, rule.probe.from);
87
+ if (captures === null)
88
+ return true;
89
+ if (!targetAllowed(rule, captures, rule.probe.to))
90
+ return true;
91
+ return !covers(rule, {
92
+ symbol: rule.probe.symbol,
93
+ kind: rule.probe.kind ?? "named",
94
+ });
95
+ });
96
+ //# sourceMappingURL=exports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exports.js","sourceRoot":"","sources":["../../../src/core/exports.ts"],"names":[],"mappings":"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"}