@intentset/architecture 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.
Files changed (91) hide show
  1. package/dist/baseline.d.ts +39 -0
  2. package/dist/baseline.d.ts.map +1 -0
  3. package/dist/baseline.js +104 -0
  4. package/dist/baseline.js.map +1 -0
  5. package/dist/boundaries.d.ts +63 -0
  6. package/dist/boundaries.d.ts.map +1 -0
  7. package/dist/boundaries.js +436 -0
  8. package/dist/boundaries.js.map +1 -0
  9. package/dist/check.d.ts +73 -0
  10. package/dist/check.d.ts.map +1 -0
  11. package/dist/check.js +130 -0
  12. package/dist/check.js.map +1 -0
  13. package/dist/claims.d.ts +24 -0
  14. package/dist/claims.d.ts.map +1 -0
  15. package/dist/claims.js +201 -0
  16. package/dist/claims.js.map +1 -0
  17. package/dist/config.d.ts +53 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/config.js +159 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/dependencies.d.ts +30 -0
  22. package/dist/dependencies.d.ts.map +1 -0
  23. package/dist/dependencies.js +179 -0
  24. package/dist/dependencies.js.map +1 -0
  25. package/dist/exceptions.d.ts +43 -0
  26. package/dist/exceptions.d.ts.map +1 -0
  27. package/dist/exceptions.js +233 -0
  28. package/dist/exceptions.js.map +1 -0
  29. package/dist/extract.d.ts +24 -0
  30. package/dist/extract.d.ts.map +1 -0
  31. package/dist/extract.js +316 -0
  32. package/dist/extract.js.map +1 -0
  33. package/dist/finding.d.ts +39 -0
  34. package/dist/finding.d.ts.map +1 -0
  35. package/dist/finding.js +29 -0
  36. package/dist/finding.js.map +1 -0
  37. package/dist/imports.d.ts +30 -0
  38. package/dist/imports.d.ts.map +1 -0
  39. package/dist/imports.js +48 -0
  40. package/dist/imports.js.map +1 -0
  41. package/dist/index.d.ts +23 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +22 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/layers.d.ts +38 -0
  46. package/dist/layers.d.ts.map +1 -0
  47. package/dist/layers.js +41 -0
  48. package/dist/layers.js.map +1 -0
  49. package/dist/ownership.d.ts +25 -0
  50. package/dist/ownership.d.ts.map +1 -0
  51. package/dist/ownership.js +97 -0
  52. package/dist/ownership.js.map +1 -0
  53. package/dist/paths.d.ts +18 -0
  54. package/dist/paths.d.ts.map +1 -0
  55. package/dist/paths.js +54 -0
  56. package/dist/paths.js.map +1 -0
  57. package/dist/patterns.d.ts +25 -0
  58. package/dist/patterns.d.ts.map +1 -0
  59. package/dist/patterns.js +101 -0
  60. package/dist/patterns.js.map +1 -0
  61. package/dist/regions.d.ts +85 -0
  62. package/dist/regions.d.ts.map +1 -0
  63. package/dist/regions.js +144 -0
  64. package/dist/regions.js.map +1 -0
  65. package/dist/resolve.d.ts +53 -0
  66. package/dist/resolve.d.ts.map +1 -0
  67. package/dist/resolve.js +268 -0
  68. package/dist/resolve.js.map +1 -0
  69. package/dist/tsconfig.d.ts +42 -0
  70. package/dist/tsconfig.d.ts.map +1 -0
  71. package/dist/tsconfig.js +186 -0
  72. package/dist/tsconfig.js.map +1 -0
  73. package/package.json +36 -0
  74. package/src/baseline.ts +126 -0
  75. package/src/boundaries.ts +499 -0
  76. package/src/check.ts +197 -0
  77. package/src/claims.ts +229 -0
  78. package/src/config.ts +212 -0
  79. package/src/dependencies.ts +211 -0
  80. package/src/exceptions.ts +269 -0
  81. package/src/extract.ts +344 -0
  82. package/src/finding.ts +64 -0
  83. package/src/imports.ts +77 -0
  84. package/src/index.ts +58 -0
  85. package/src/layers.ts +67 -0
  86. package/src/ownership.ts +135 -0
  87. package/src/paths.ts +53 -0
  88. package/src/patterns.ts +95 -0
  89. package/src/regions.ts +243 -0
  90. package/src/resolve.ts +283 -0
  91. package/src/tsconfig.ts +198 -0
package/dist/config.js ADDED
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Where the regions are, what counts as a test, which files may import
3
+ * screens or the response parser, and the declared scope (VSA §5, §6, §9;
4
+ * profile §2–§4). Every value has a default for the reference layout of
5
+ * profile §1. A repository states its own in `.intentset/architecture.yaml`,
6
+ * a file of its own because `.intentset/config.yaml` belongs to core and
7
+ * rejects keys it does not know.
8
+ */
9
+ import { parseYamlDetailed } from "@intentset/core";
10
+ import { compareStrings, validatePattern } from "./patterns.js";
11
+ export const ARCHITECTURE_CONFIG_PATH = ".intentset/architecture.yaml";
12
+ export const DEFAULT_ARCHITECTURE_CONFIG = {
13
+ scope: ["**"],
14
+ sourceRoots: ["src/**"],
15
+ shared: ["src/shared/**"],
16
+ infrastructure: ["src/infrastructure/**"],
17
+ composition: ["src/app/**"],
18
+ backendRoots: ["amplify/**"],
19
+ routerFiles: [],
20
+ responseParserModules: [],
21
+ ignore: ["**/node_modules/**", "**/dist/**", ".git/**"],
22
+ tests: ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"],
23
+ screensGlob: "**/ui/screens/**",
24
+ backendSdks: ["aws-amplify/**", "@aws-amplify/**", "@aws-sdk/**"],
25
+ layerMatrix: {
26
+ presentation: ["presentation", "application", "policy", "model"],
27
+ application: ["application", "policy", "model", "external"],
28
+ policy: ["policy", "model"],
29
+ model: ["model"],
30
+ external: ["external", "model"],
31
+ },
32
+ conditions: [],
33
+ };
34
+ const LIST_KEYS = [
35
+ "scope",
36
+ "sourceRoots",
37
+ "shared",
38
+ "infrastructure",
39
+ "composition",
40
+ "backendRoots",
41
+ "routerFiles",
42
+ "responseParserModules",
43
+ "ignore",
44
+ "tests",
45
+ "backendSdks",
46
+ "conditions",
47
+ ];
48
+ /** Keys whose entries are path patterns and must pass validatePattern. */
49
+ const PATTERN_KEYS = new Set([
50
+ "scope",
51
+ "sourceRoots",
52
+ "shared",
53
+ "infrastructure",
54
+ "composition",
55
+ "backendRoots",
56
+ "routerFiles",
57
+ "responseParserModules",
58
+ "ignore",
59
+ "tests",
60
+ "screensGlob",
61
+ ]);
62
+ const KNOWN_KEYS = [...LIST_KEYS, "screensGlob", "layerMatrix"].sort(compareStrings);
63
+ /** The defaults with a partial configuration laid over them; a key given replaces the default whole. */
64
+ export function resolveConfig(...layers) {
65
+ const config = structuredClone(DEFAULT_ARCHITECTURE_CONFIG);
66
+ for (const layer of layers) {
67
+ if (layer === undefined)
68
+ continue;
69
+ for (const [key, value] of Object.entries(layer)) {
70
+ if (value !== undefined)
71
+ config[key] = structuredClone(value);
72
+ }
73
+ }
74
+ return config;
75
+ }
76
+ /**
77
+ * Read `.intentset/architecture.yaml` with core's strict reader. Every key is
78
+ * optional; an unknown key, a wrong shape or an invalid pattern is CFG001
79
+ * with origin "architecture", and that key keeps its default.
80
+ */
81
+ export function readArchitectureConfig(text, path = ARCHITECTURE_CONFIG_PATH) {
82
+ const config = {};
83
+ const diagnostics = [];
84
+ const parsed = parseYamlDetailed(text);
85
+ const report = (field, line, message, remediation) => {
86
+ diagnostics.push({
87
+ code: "CFG001",
88
+ severity: "error",
89
+ origin: "architecture",
90
+ artifact: null,
91
+ path,
92
+ ...(line !== undefined ? { location: { line } } : {}),
93
+ ...(field !== undefined ? { field } : {}),
94
+ message,
95
+ remediation,
96
+ });
97
+ };
98
+ if (parsed.error !== null) {
99
+ report(undefined, parsed.error.line, `The architecture configuration does not parse: ${parsed.error.message}`, "Write it as a block mapping of the keys documented for ArchitectureConfig.");
100
+ return { config, diagnostics };
101
+ }
102
+ const root = parsed.value;
103
+ const at = (field) => parsed.lines.get(field);
104
+ for (const key of Object.keys(root).sort(compareStrings)) {
105
+ const field = `/${key}`;
106
+ const value = root[key];
107
+ if (!KNOWN_KEYS.includes(key)) {
108
+ report(field, at(field), `Unknown architecture configuration key \`${key}\`.`, `Remove it; the keys are ${KNOWN_KEYS.join(", ")}.`);
109
+ continue;
110
+ }
111
+ if (value === null)
112
+ continue;
113
+ if (key === "screensGlob") {
114
+ const why = typeof value === "string" ? validatePattern(value) : "is not a string";
115
+ if (why !== null) {
116
+ report(field, at(field), `screensGlob ${why}.`, "Give one pattern such as **/ui/screens/**.");
117
+ }
118
+ else
119
+ config.screensGlob = value;
120
+ continue;
121
+ }
122
+ if (key === "layerMatrix") {
123
+ const matrix = readMatrix(value);
124
+ if (matrix === null) {
125
+ report(field, at(field), "layerMatrix must map each layer name to a list of layer names.", "Write each layer as `presentation: [presentation, application]`.");
126
+ }
127
+ else
128
+ config.layerMatrix = matrix;
129
+ continue;
130
+ }
131
+ if (!Array.isArray(value) || !value.every((item) => typeof item === "string" && item !== "")) {
132
+ report(field, at(field), `\`${key}\` must be a list of non-empty strings.`, `Write ${key} as a sequence.`);
133
+ continue;
134
+ }
135
+ const list = value;
136
+ if (PATTERN_KEYS.has(key)) {
137
+ const bad = list.findIndex((pattern) => validatePattern(pattern) !== null);
138
+ if (bad !== -1) {
139
+ const pointer = `${field}/${bad}`;
140
+ report(pointer, at(pointer) ?? at(field), `Pattern ${list[bad]} in \`${key}\` ${validatePattern(list[bad])}.`, "Use literal segments, `*` within a segment and `**` across segments only (VSA §3).");
141
+ continue;
142
+ }
143
+ }
144
+ config[key] = [...list];
145
+ }
146
+ return { config, diagnostics };
147
+ }
148
+ function readMatrix(value) {
149
+ if (typeof value !== "object" || value === null || Array.isArray(value))
150
+ return null;
151
+ const matrix = {};
152
+ for (const [layer, targets] of Object.entries(value)) {
153
+ if (!Array.isArray(targets) || !targets.every((item) => typeof item === "string"))
154
+ return null;
155
+ matrix[layer] = [...targets];
156
+ }
157
+ return matrix;
158
+ }
159
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAmB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhE,MAAM,CAAC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAiCvE,MAAM,CAAC,MAAM,2BAA2B,GAAuB;IAC7D,KAAK,EAAE,CAAC,IAAI,CAAC;IACb,WAAW,EAAE,CAAC,QAAQ,CAAC;IACvB,MAAM,EAAE,CAAC,eAAe,CAAC;IACzB,cAAc,EAAE,CAAC,uBAAuB,CAAC;IACzC,WAAW,EAAE,CAAC,YAAY,CAAC;IAC3B,YAAY,EAAE,CAAC,YAAY,CAAC;IAC5B,WAAW,EAAE,EAAE;IACf,qBAAqB,EAAE,EAAE;IACzB,MAAM,EAAE,CAAC,oBAAoB,EAAE,YAAY,EAAE,SAAS,CAAC;IACvD,KAAK,EAAE,CAAC,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,CAAC;IACzE,WAAW,EAAE,kBAAkB;IAC/B,WAAW,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,CAAC;IACjE,WAAW,EAAE;QACX,YAAY,EAAE,CAAC,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,CAAC;QAChE,WAAW,EAAE,CAAC,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC;QAC3D,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC3B,KAAK,EAAE,CAAC,OAAO,CAAC;QAChB,QAAQ,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC;KAChC;IACD,UAAU,EAAE,EAAE;CACf,CAAC;AAEF,MAAM,SAAS,GAAG;IAChB,OAAO;IACP,aAAa;IACb,QAAQ;IACR,gBAAgB;IAChB,aAAa;IACb,cAAc;IACd,aAAa;IACb,uBAAuB;IACvB,QAAQ;IACR,OAAO;IACP,aAAa;IACb,YAAY;CACJ,CAAC;AAEX,0EAA0E;AAC1E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACnC,OAAO;IACP,aAAa;IACb,QAAQ;IACR,gBAAgB;IAChB,aAAa;IACb,cAAc;IACd,aAAa;IACb,uBAAuB;IACvB,QAAQ;IACR,OAAO;IACP,aAAa;CACd,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,CAAC,GAAG,SAAS,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AAErF,wGAAwG;AACxG,MAAM,UAAU,aAAa,CAAC,GAAG,MAAmD;IAClF,MAAM,MAAM,GAAuB,eAAe,CAAC,2BAA2B,CAAC,CAAC;IAChF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,IAAI,KAAK,KAAK,SAAS;gBAAG,MAA6C,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,IAAI,GAAW,wBAAwB;IAEvC,MAAM,MAAM,GAAgC,EAAE,CAAC;IAC/C,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,CAAC,KAAyB,EAAE,IAAwB,EAAE,OAAe,EAAE,WAAmB,EAAE,EAAE;QAC3G,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,cAAc;YACtB,QAAQ,EAAE,IAAI;YACd,IAAI;YACJ,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,OAAO;YACP,WAAW;SACZ,CAAC,CAAC;IACL,CAAC,CAAC;IACF,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1B,MAAM,CACJ,SAAS,EACT,MAAM,CAAC,KAAK,CAAC,IAAI,EACjB,kDAAkD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EACxE,4EAA4E,CAC7E,CAAC;QACF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IACjC,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;IAC1B,MAAM,EAAE,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAEtD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QACzD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,CACJ,KAAK,EACL,EAAE,CAAC,KAAK,CAAC,EACT,4CAA4C,GAAG,KAAK,EACpD,2BAA2B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACpD,CAAC;YACF,SAAS;QACX,CAAC;QACD,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;YACnF,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,GAAG,EAAE,4CAA4C,CAAC,CAAC;YAChG,CAAC;;gBAAM,MAAM,CAAC,WAAW,GAAG,KAAe,CAAC;YAC5C,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,MAAM,CACJ,KAAK,EACL,EAAE,CAAC,KAAK,CAAC,EACT,gEAAgE,EAChE,kEAAkE,CACnE,CAAC;YACJ,CAAC;;gBAAM,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC;YACnC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,CAAC,EAAE,CAAC;YAC7F,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,yCAAyC,EAAE,SAAS,GAAG,iBAAiB,CAAC,CAAC;YAC3G,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,KAAiB,CAAC;QAC/B,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;YAC3E,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC;gBAClC,MAAM,CACJ,OAAO,EACP,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EACxB,WAAW,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EACnE,oFAAoF,CACrF,CAAC;gBACF,SAAS;YACX,CAAC;QACH,CAAC;QACA,MAAkC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrF,MAAM,MAAM,GAA6B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/F,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAI,OAAoB,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Declared against observed dependencies (VSA004) and cycles (VSA005).
3
+ *
4
+ * VSA004: an observed import from one slice into another that the importer
5
+ * does not list in `dependsOn`, one finding per pair of slices at the first
6
+ * import; a consumed contract that no slice exposes, or that more than one
7
+ * exposes; a consumed contract whose one exposing slice is not depended on.
8
+ *
9
+ * VSA005: strongly connected components (Tarjan) over the union of observed
10
+ * slice edges and declared `dependsOn` edges, type-only imports included
11
+ * (profile §3: they still count for cycles). One finding per component of
12
+ * two or more slices, naming them along one concrete cycle.
13
+ */
14
+ import type { Graph } from "@intentset/core";
15
+ import type { SliceEdge } from "./boundaries.ts";
16
+ import { type Finding } from "./finding.ts";
17
+ import type { Model } from "./regions.ts";
18
+ export declare function checkDependencies(model: Model, graph: Graph, sliceEdges: ReadonlyMap<string, SliceEdge>): {
19
+ findings: Finding[];
20
+ cycles: number;
21
+ };
22
+ /**
23
+ * Tarjan's strongly connected components. Nodes and successors are visited in
24
+ * sorted order and each component comes back sorted, components ordered by
25
+ * their first member, so the output is the same for the same graph.
26
+ */
27
+ export declare function stronglyConnected(nodes: readonly string[], successors: ReadonlyMap<string, readonly string[]>): string[][];
28
+ /** The shortest cycle through `start` inside the component, as a closed path: A -> B -> A. */
29
+ export declare function shortestCycle(start: string, successors: ReadonlyMap<string, readonly string[]>, members: ReadonlySet<string>): string[];
30
+ //# sourceMappingURL=dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,KAAK,OAAO,EAAmB,MAAM,cAAc,CAAC;AAE7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,GACzC;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAgHzC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,GACjD,MAAM,EAAE,EAAE,CAoCZ;AAED,8FAA8F;AAC9F,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,EAClD,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3B,MAAM,EAAE,CAsBV"}
@@ -0,0 +1,179 @@
1
+ import { finding, plural } from "./finding.js";
2
+ import { compareStrings } from "./patterns.js";
3
+ export function checkDependencies(model, graph, sliceEdges) {
4
+ const findings = [];
5
+ for (const key of [...sliceEdges.keys()].sort(compareStrings)) {
6
+ const { from, to, imports } = sliceEdges.get(key);
7
+ const importer = model.sliceById.get(from);
8
+ if (importer.dependsOn.includes(to))
9
+ continue;
10
+ const first = imports[0];
11
+ findings.push(finding({
12
+ code: "VSA004",
13
+ artifact: from,
14
+ path: first.from,
15
+ location: { line: first.line },
16
+ message: `${from} imports ${to} (${plural(imports.length, "import")}, the first here) but does not declare ${to} in dependsOn.`,
17
+ remediation: `Add ${to} to links.dependsOn in ${importer.path}, or remove the import (VSA004).`,
18
+ paths: [...new Set(imports.map((edge) => edge.from)), importer.path],
19
+ edges: [{ from, to }, ...imports.map((edge) => ({ from: edge.from, to: edge.to }))],
20
+ }));
21
+ }
22
+ const exposers = new Map();
23
+ for (const slice of model.slices) {
24
+ for (const contract of slice.exposes) {
25
+ const list = exposers.get(contract) ?? [];
26
+ list.push(slice.id);
27
+ exposers.set(contract, list);
28
+ }
29
+ }
30
+ for (const slice of model.slices) {
31
+ const consumes = slice.artifact.meta.links.consumes ?? [];
32
+ consumes.forEach((contract, i) => {
33
+ const field = `/intentset/links/consumes/${i}`;
34
+ const owners = (exposers.get(contract) ?? []).sort(compareStrings);
35
+ const base = { artifact: slice.id, path: slice.path, field, edges: [{ from: slice.id, to: contract }] };
36
+ if (owners.length === 0) {
37
+ if (graph.artifacts.get(contract)?.meta.type !== "contract")
38
+ return; // An unresolved reference is core's CORE003.
39
+ findings.push(finding({
40
+ ...base,
41
+ code: "VSA004",
42
+ message: `${slice.id} consumes ${contract}, which no slice exposes.`,
43
+ remediation: `Add ${contract} to the exposes of the slice that maintains it, or stop consuming it (VSA004).`,
44
+ }));
45
+ }
46
+ else if (owners.length > 1) {
47
+ findings.push(finding({
48
+ ...base,
49
+ code: "VSA004",
50
+ message: `${slice.id} consumes ${contract}, which ${owners.length} slices expose: ${owners.join(", ")}.`,
51
+ remediation: `Keep ${contract} in the exposes of the one slice that maintains it (VSA004).`,
52
+ }));
53
+ }
54
+ else if (owners[0] !== slice.id && !slice.dependsOn.includes(owners[0])) {
55
+ findings.push(finding({
56
+ ...base,
57
+ code: "VSA004",
58
+ message: `${slice.id} consumes ${contract}, exposed by ${owners[0]}, but does not declare ${owners[0]} in dependsOn.`,
59
+ remediation: `Add ${owners[0]} to links.dependsOn of ${slice.id}; a consumer lists both consumes and dependsOn (VSA §4).`,
60
+ }));
61
+ }
62
+ });
63
+ }
64
+ // Cycles over observed and declared slice edges.
65
+ const nodes = model.slices.map((slice) => slice.id);
66
+ const adjacency = new Map(nodes.map((id) => [id, new Set()]));
67
+ const declared = new Set();
68
+ for (const slice of model.slices) {
69
+ for (const target of slice.dependsOn) {
70
+ if (!adjacency.has(target) || target === slice.id)
71
+ continue;
72
+ adjacency.get(slice.id).add(target);
73
+ declared.add(`${slice.id}->${target}`);
74
+ }
75
+ }
76
+ for (const { from, to } of sliceEdges.values())
77
+ adjacency.get(from)?.add(to);
78
+ const successors = new Map([...adjacency].map(([id, set]) => [id, [...set].sort(compareStrings)]));
79
+ const components = stronglyConnected(nodes, successors).filter((component) => component.length > 1);
80
+ for (const component of components) {
81
+ const members = new Set(component);
82
+ const cycle = shortestCycle(component[0], successors, members);
83
+ const internal = [];
84
+ let observed = 0;
85
+ let written = 0;
86
+ for (const from of component) {
87
+ for (const to of successors.get(from) ?? []) {
88
+ if (!members.has(to))
89
+ continue;
90
+ internal.push({ from, to });
91
+ if (sliceEdges.has(`${from}->${to}`))
92
+ observed++;
93
+ if (declared.has(`${from}->${to}`))
94
+ written++;
95
+ }
96
+ }
97
+ const first = model.sliceById.get(component[0]);
98
+ findings.push(finding({
99
+ code: "VSA005",
100
+ artifact: first.id,
101
+ path: first.path,
102
+ message: `Slices ${component.join(", ")} form a compile-time dependency cycle, ${cycle.join(" -> ")}, from ${plural(observed, "observed import edge")} and ${plural(written, "declared dependsOn edge")}.`,
103
+ remediation: "Break the cycle: move the shared rule to one owner's contract, invert one dependency, or decouple it through an event contract (VSA005).",
104
+ paths: component.map((id) => model.sliceById.get(id).path),
105
+ edges: internal,
106
+ }));
107
+ }
108
+ return { findings, cycles: components.length };
109
+ }
110
+ /**
111
+ * Tarjan's strongly connected components. Nodes and successors are visited in
112
+ * sorted order and each component comes back sorted, components ordered by
113
+ * their first member, so the output is the same for the same graph.
114
+ */
115
+ export function stronglyConnected(nodes, successors) {
116
+ let counter = 0;
117
+ const index = new Map();
118
+ const low = new Map();
119
+ const stack = [];
120
+ const onStack = new Set();
121
+ const components = [];
122
+ const visit = (node) => {
123
+ index.set(node, counter);
124
+ low.set(node, counter);
125
+ counter++;
126
+ stack.push(node);
127
+ onStack.add(node);
128
+ for (const next of successors.get(node) ?? []) {
129
+ if (!index.has(next)) {
130
+ visit(next);
131
+ low.set(node, Math.min(low.get(node), low.get(next)));
132
+ }
133
+ else if (onStack.has(next)) {
134
+ low.set(node, Math.min(low.get(node), index.get(next)));
135
+ }
136
+ }
137
+ if (low.get(node) === index.get(node)) {
138
+ const component = [];
139
+ let member;
140
+ do {
141
+ member = stack.pop();
142
+ onStack.delete(member);
143
+ component.push(member);
144
+ } while (member !== node);
145
+ components.push(component.sort(compareStrings));
146
+ }
147
+ };
148
+ for (const node of [...nodes].sort(compareStrings))
149
+ if (!index.has(node))
150
+ visit(node);
151
+ return components.sort((a, b) => compareStrings(a[0], b[0]));
152
+ }
153
+ /** The shortest cycle through `start` inside the component, as a closed path: A -> B -> A. */
154
+ export function shortestCycle(start, successors, members) {
155
+ const previous = new Map();
156
+ const queue = [start];
157
+ const seen = new Set([start]);
158
+ while (queue.length > 0) {
159
+ const node = queue.shift();
160
+ for (const next of successors.get(node) ?? []) {
161
+ if (!members.has(next))
162
+ continue;
163
+ if (next === start) {
164
+ const path = [start];
165
+ for (let at = node; at !== undefined && at !== start; at = previous.get(at))
166
+ path.splice(1, 0, at);
167
+ path.push(start);
168
+ return path;
169
+ }
170
+ if (seen.has(next))
171
+ continue;
172
+ seen.add(next);
173
+ previous.set(next, node);
174
+ queue.push(next);
175
+ }
176
+ }
177
+ return [start];
178
+ }
179
+ //# sourceMappingURL=dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { type Finding, type SubjectEdge } from "./finding.ts";
2
+ export declare const EXCEPTIONS_PATTERNS: string[];
3
+ export interface ExceptionRecord {
4
+ id: string;
5
+ rule: string;
6
+ paths: string[];
7
+ edges: SubjectEdge[];
8
+ rationale: string;
9
+ owner: string;
10
+ approver: string;
11
+ /** YYYY-MM-DD. */
12
+ created: string;
13
+ /** YYYY-MM-DD, the last day the exception holds. */
14
+ expires: string;
15
+ remediation: string;
16
+ /** The file it was read from, or null when it was handed in. */
17
+ source: string | null;
18
+ }
19
+ /** Validate one record. Returns the record, or the problems that keep it from covering anything. */
20
+ export declare function readExceptionRecord(value: unknown, source: string | null, lines?: ReadonlyMap<string, number>): {
21
+ record: ExceptionRecord | null;
22
+ findings: Finding[];
23
+ };
24
+ /** Every exception file in the tree, read with core's strict YAML reader. */
25
+ export declare function readExceptions(files: ReadonlyMap<string, string>): {
26
+ records: ExceptionRecord[];
27
+ findings: Finding[];
28
+ };
29
+ /** Does the record name this finding's rule and one of its exact paths or edges? */
30
+ export declare function covers(record: ExceptionRecord, target: Finding): boolean;
31
+ /** Put a note in parentheses before a message's final period. */
32
+ export declare function annotate(message: string, note: string): string;
33
+ /**
34
+ * Apply exceptions on a given date (YYYY-MM-DD). Returns the findings with
35
+ * covered ones rewritten, the VSA013 findings about the records themselves,
36
+ * and how many diagnostics a current exception covers.
37
+ */
38
+ export declare function applyExceptions(findings: readonly Finding[], records: readonly ExceptionRecord[], today: string): {
39
+ findings: Finding[];
40
+ excepted: number;
41
+ recordFindings: Finding[];
42
+ };
43
+ //# sourceMappingURL=exceptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../src/exceptions.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAGvE,eAAO,MAAM,mBAAmB,UAAsE,CAAC;AAEvG,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAcD,oGAAoG;AACpG,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa,GAC7C;IAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAoFzD;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;IAClE,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB,CAwBA;AAED,oFAAoF;AACpF,wBAAgB,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAIxE;AAED,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,KAAK,EAAE,MAAM,GACZ;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,EAAE,CAAA;CAAE,CA6EtE"}