@webpieces/nx-webpieces-rules 0.4.847 → 0.4.849

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 (96) hide show
  1. package/README.md +28 -15
  2. package/executors.json +1 -66
  3. package/package.json +9 -9
  4. package/src/executors/validate-architecture-unchanged/executor.d.ts +8 -0
  5. package/src/executors/validate-architecture-unchanged/executor.js +20 -18
  6. package/src/executors/validate-architecture-unchanged/executor.js.map +1 -1
  7. package/src/executors/validate-code/executor.d.ts +2 -7
  8. package/src/executors/validate-code/executor.js +31 -2
  9. package/src/executors/validate-code/executor.js.map +1 -1
  10. package/src/executors/validate-code/schema.json +6 -281
  11. package/src/executors/validate-runtime-architecture/schema.json +1 -1
  12. package/src/lib/api-usage/wire-closure.d.ts +3 -3
  13. package/src/lib/api-usage/wire-closure.js +5 -5
  14. package/src/lib/api-usage/wire-closure.js.map +1 -1
  15. package/src/lib/api-usage/wire-suffix-entry.d.ts +5 -0
  16. package/src/lib/api-usage/wire-suffix-entry.js +10 -0
  17. package/src/lib/api-usage/wire-suffix-entry.js.map +1 -0
  18. package/src/lib/rule-gate.d.ts +1 -2
  19. package/src/lib/rule-gate.js +3 -4
  20. package/src/lib/rule-gate.js.map +1 -1
  21. package/src/lib/runtime-visualizer.d.ts +4 -4
  22. package/src/lib/runtime-visualizer.js +2 -2
  23. package/src/lib/runtime-visualizer.js.map +1 -1
  24. package/src/native-actions.d.ts +23 -0
  25. package/src/native-actions.js +69 -0
  26. package/src/native-actions.js.map +1 -0
  27. package/src/nx-policy-registry.d.ts +8 -0
  28. package/src/nx-policy-registry.js +40 -0
  29. package/src/nx-policy-registry.js.map +1 -0
  30. package/src/pack-build-runner.d.ts +6 -0
  31. package/src/pack-build-runner.js +46 -0
  32. package/src/pack-build-runner.js.map +1 -0
  33. package/src/plugin.js +6 -40
  34. package/src/plugin.js.map +1 -1
  35. package/src/rule-help.d.ts +3 -0
  36. package/src/rule-help.js +24 -0
  37. package/src/rule-help.js.map +1 -0
  38. package/src/rule-pack.js +5 -28
  39. package/src/rule-pack.js.map +1 -1
  40. package/src/rule-runtime.d.ts +5 -0
  41. package/src/rule-runtime.js +94 -0
  42. package/src/rule-runtime.js.map +1 -0
  43. package/src/validation-targets.js +21 -5
  44. package/src/validation-targets.js.map +1 -1
  45. package/src/executors/validate-catch-error-pattern/executor.d.ts +0 -4
  46. package/src/executors/validate-catch-error-pattern/executor.js +0 -8
  47. package/src/executors/validate-catch-error-pattern/executor.js.map +0 -1
  48. package/src/executors/validate-catch-error-pattern/schema.json +0 -24
  49. package/src/executors/validate-dtos/executor.d.ts +0 -4
  50. package/src/executors/validate-dtos/executor.js +0 -8
  51. package/src/executors/validate-dtos/executor.js.map +0 -1
  52. package/src/executors/validate-dtos/schema.json +0 -33
  53. package/src/executors/validate-modified-files/executor.d.ts +0 -4
  54. package/src/executors/validate-modified-files/executor.js +0 -8
  55. package/src/executors/validate-modified-files/executor.js.map +0 -1
  56. package/src/executors/validate-modified-files/schema.json +0 -25
  57. package/src/executors/validate-modified-methods/executor.d.ts +0 -4
  58. package/src/executors/validate-modified-methods/executor.js +0 -8
  59. package/src/executors/validate-modified-methods/executor.js.map +0 -1
  60. package/src/executors/validate-modified-methods/schema.json +0 -25
  61. package/src/executors/validate-new-methods/executor.d.ts +0 -4
  62. package/src/executors/validate-new-methods/executor.js +0 -8
  63. package/src/executors/validate-new-methods/executor.js.map +0 -1
  64. package/src/executors/validate-new-methods/schema.json +0 -25
  65. package/src/executors/validate-no-any-unknown/executor.d.ts +0 -4
  66. package/src/executors/validate-no-any-unknown/executor.js +0 -8
  67. package/src/executors/validate-no-any-unknown/executor.js.map +0 -1
  68. package/src/executors/validate-no-any-unknown/schema.json +0 -24
  69. package/src/executors/validate-no-destructure/executor.d.ts +0 -4
  70. package/src/executors/validate-no-destructure/executor.js +0 -8
  71. package/src/executors/validate-no-destructure/executor.js.map +0 -1
  72. package/src/executors/validate-no-destructure/schema.json +0 -24
  73. package/src/executors/validate-no-direct-api-resolver/executor.d.ts +0 -4
  74. package/src/executors/validate-no-direct-api-resolver/executor.js +0 -8
  75. package/src/executors/validate-no-direct-api-resolver/executor.js.map +0 -1
  76. package/src/executors/validate-no-direct-api-resolver/schema.json +0 -29
  77. package/src/executors/validate-no-implicit-any/executor.d.ts +0 -4
  78. package/src/executors/validate-no-implicit-any/executor.js +0 -8
  79. package/src/executors/validate-no-implicit-any/executor.js.map +0 -1
  80. package/src/executors/validate-no-implicit-any/schema.json +0 -24
  81. package/src/executors/validate-no-inline-types/executor.d.ts +0 -4
  82. package/src/executors/validate-no-inline-types/executor.js +0 -8
  83. package/src/executors/validate-no-inline-types/executor.js.map +0 -1
  84. package/src/executors/validate-no-inline-types/schema.json +0 -24
  85. package/src/executors/validate-no-unmanaged-exceptions/executor.d.ts +0 -4
  86. package/src/executors/validate-no-unmanaged-exceptions/executor.js +0 -8
  87. package/src/executors/validate-no-unmanaged-exceptions/executor.js.map +0 -1
  88. package/src/executors/validate-no-unmanaged-exceptions/schema.json +0 -24
  89. package/src/executors/validate-prisma-converters/executor.d.ts +0 -4
  90. package/src/executors/validate-prisma-converters/executor.js +0 -8
  91. package/src/executors/validate-prisma-converters/executor.js.map +0 -1
  92. package/src/executors/validate-prisma-converters/schema.json +0 -38
  93. package/src/executors/validate-return-types/executor.d.ts +0 -4
  94. package/src/executors/validate-return-types/executor.js +0 -8
  95. package/src/executors/validate-return-types/executor.js.map +0 -1
  96. package/src/executors/validate-return-types/schema.json +0 -24
package/README.md CHANGED
@@ -27,32 +27,45 @@ It is wired into the build: the `@nx/js:tsc` target default lists it in
27
27
 
28
28
  ### Configuration
29
29
 
30
- On/off and a time-boxed grace window come from `webpieces.config.json` at the
31
- workspace root — the same source of truth as every other webpieces rule — under
32
- the rule key `no-file-import-cycles`:
30
+ `webpieces.config.json` declares each owning pack and its config path in the root
31
+ `rulePacks` array. For example, the Nx entry is:
33
32
 
34
- ```jsonc
33
+ ```json
35
34
  {
36
- "rules": {
37
- "no-file-import-cycles": {
38
- "mode": "ON", // "OFF" disables the gate everywhere
39
- "turnOffRuleUntilEpoch": 1771931925, // epoch SECONDS — while now < epoch,
40
- // cycles are REPORTED but the build
41
- // PASSES; after it, the gate fails again
42
- "ignoreTypeOnly": false // when true, ignore `import type`
43
- // re-export cycles (erased at compile
44
- // time, harmless at runtime)
45
- }
35
+ "package": "@webpieces/nx-webpieces-rules",
36
+ "config": ".webpieces/rules/nx.json"
37
+ }
38
+ ```
39
+
40
+ Keep the other selected owners and required root settings. Policy settings come
41
+ from the declared owner file's direct policy-ID map. This entry belongs directly
42
+ in `.webpieces/rules/nx.json` (an excerpt; the other owned policies also require
43
+ explicit settings):
44
+
45
+ ```json
46
+ {
47
+ "no-file-import-cycles": {
48
+ "mode": "RUN_EVERY_TIME",
49
+ "turnOffRuleUntilEpoch": 0,
50
+ "turnOffRuleWhileOnBranch": null,
51
+ "ignoreTypeOnly": false
46
52
  }
47
53
  }
48
54
  ```
49
55
 
56
+ Use complete `OFF` settings for an intentional opt-out. `ignoreTypeOnly: true`
57
+ ignores type-only import/re-export cycles. A future `turnOffRuleUntilEpoch` value
58
+ uses epoch seconds; `0` and a `null` branch hatch keep enforcement active.
59
+ After reviewing the declarations, `pnpm wp-rules-sync` explicitly seeds missing
60
+ owner settings and refreshes the lock/catalog artifacts. Review and commit its
61
+ changes; normal loading never supplies missing required settings.
62
+
50
63
  Semantics, mirroring the method/file-size dated-disable model:
51
64
 
52
65
  | Situation | Result |
53
66
  | ------------------------------------------- | ------------------------------- |
54
67
  | `mode: "OFF"` | Skipped (passes), no madge run |
55
- | Cycle found, no `turnOffRuleUntilEpoch` | **Fails** |
68
+ | Cycle found, `turnOffRuleUntilEpoch: 0` | **Fails** |
56
69
  | Cycle found, `now < turnOffRuleUntilEpoch` | Reported but **passes** (warn) |
57
70
  | Cycle found, `now >= turnOffRuleUntilEpoch` | **Fails** again |
58
71
  | No cycle | Passes |
package/executors.json CHANGED
@@ -65,75 +65,10 @@
65
65
  "schema": "./src/executors/validate-rules-config/schema.json",
66
66
  "description": "Validate webpieces.config.json once at the scoped rules:check boundary"
67
67
  },
68
- "validate-no-any-unknown": {
69
- "implementation": "./src/executors/validate-no-any-unknown/executor",
70
- "schema": "./src/executors/validate-no-any-unknown/schema.json",
71
- "description": "Validate no any/unknown keywords are used - use specific types instead"
72
- },
73
- "validate-new-methods": {
74
- "implementation": "./src/executors/validate-new-methods/executor",
75
- "schema": "./src/executors/validate-new-methods/schema.json",
76
- "description": "Validate newly added methods don't exceed maximum line count"
77
- },
78
- "validate-modified-methods": {
79
- "implementation": "./src/executors/validate-modified-methods/executor",
80
- "schema": "./src/executors/validate-modified-methods/schema.json",
81
- "description": "Validate modified methods don't exceed maximum line count"
82
- },
83
- "validate-modified-files": {
84
- "implementation": "./src/executors/validate-modified-files/executor",
85
- "schema": "./src/executors/validate-modified-files/schema.json",
86
- "description": "Validate modified files don't exceed maximum line count"
87
- },
88
- "validate-return-types": {
89
- "implementation": "./src/executors/validate-return-types/executor",
90
- "schema": "./src/executors/validate-return-types/schema.json",
91
- "description": "Validate methods have explicit return type annotations"
92
- },
93
- "validate-no-inline-types": {
94
- "implementation": "./src/executors/validate-no-inline-types/executor",
95
- "schema": "./src/executors/validate-no-inline-types/schema.json",
96
- "description": "Validate no inline type literals are used - prefer named types"
97
- },
98
- "validate-no-implicit-any": {
99
- "implementation": "./src/executors/validate-no-implicit-any/executor",
100
- "schema": "./src/executors/validate-no-implicit-any/schema.json",
101
- "description": "Validate no implicit-any inferences on parameters, variables, or properties"
102
- },
103
- "validate-catch-error-pattern": {
104
- "implementation": "./src/executors/validate-catch-error-pattern/executor",
105
- "schema": "./src/executors/validate-catch-error-pattern/schema.json",
106
- "description": "Validate catch blocks follow standardized pattern: catch (err: unknown) { const error = toError(err); }"
107
- },
108
- "validate-no-unmanaged-exceptions": {
109
- "implementation": "./src/executors/validate-no-unmanaged-exceptions/executor",
110
- "schema": "./src/executors/validate-no-unmanaged-exceptions/schema.json",
111
- "description": "Validate try/catch blocks are not used outside chokepoints"
112
- },
113
- "validate-no-destructure": {
114
- "implementation": "./src/executors/validate-no-destructure/executor",
115
- "schema": "./src/executors/validate-no-destructure/schema.json",
116
- "description": "Validate no destructuring patterns are used - use explicit property access instead"
117
- },
118
- "validate-no-direct-api-resolver": {
119
- "implementation": "./src/executors/validate-no-direct-api-resolver/executor",
120
- "schema": "./src/executors/validate-no-direct-api-resolver/schema.json",
121
- "description": "Validate resolvers use services (not APIs) and components subscribe to observables (not route.snapshot.data)"
122
- },
123
- "validate-dtos": {
124
- "implementation": "./src/executors/validate-dtos/executor",
125
- "schema": "./src/executors/validate-dtos/schema.json",
126
- "description": "Validate DTO fields match Prisma Dbo model fields"
127
- },
128
- "validate-prisma-converters": {
129
- "implementation": "./src/executors/validate-prisma-converters/executor",
130
- "schema": "./src/executors/validate-prisma-converters/schema.json",
131
- "description": "Validate Prisma converter method patterns and Dto creation locations"
132
- },
133
68
  "validate-code": {
134
69
  "implementation": "./src/executors/validate-code/executor",
135
70
  "schema": "./src/executors/validate-code/schema.json",
136
- "description": "Combined validation for new methods, modified methods, and file sizes"
71
+ "description": "Execute declared build contributions through their public owner runtimes, with optional single-rule debug execution"
137
72
  },
138
73
  "help": {
139
74
  "implementation": "./src/executors/help/executor",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.4.847",
3
+ "version": "0.4.849",
4
4
  "description": "Nx-specific webpieces validation rules, graph tooling, executors, and inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -10,7 +10,8 @@
10
10
  "./package.json": "./package.json",
11
11
  "./plugin": "./src/plugin.js",
12
12
  "./executors.json": "./executors.json",
13
- "./rule-pack": "./src/rule-pack.js"
13
+ "./rule-pack": "./src/rule-pack.js",
14
+ "./rule-runtime": "./src/rule-runtime.js"
14
15
  },
15
16
  "files": [
16
17
  "src/**/*",
@@ -19,13 +20,12 @@
19
20
  "README.md"
20
21
  ],
21
22
  "dependencies": {
22
- "@webpieces/api-doc-model": "0.4.847",
23
- "@webpieces/code-rules": "0.4.847",
24
- "@webpieces/core-util": "0.4.847",
25
- "@webpieces/eslint-rules": "0.4.847",
26
- "@webpieces/rules-config": "0.4.847",
23
+ "@webpieces/api-doc-model": "0.4.849",
24
+ "@webpieces/core-util": "0.4.849",
25
+ "@webpieces/eslint-rules": "0.4.849",
26
+ "@webpieces/rules-config": "0.4.849",
27
27
  "madge": "8.0.0",
28
- "@webpieces/rules-sdk": "0.4.847"
28
+ "@webpieces/rules-sdk": "0.4.849"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@nx/devkit": ">=18.0.0"
@@ -41,7 +41,7 @@
41
41
  "access": "public"
42
42
  },
43
43
  "devDependencies": {
44
- "@webpieces/tooling-testkit": "0.4.847"
44
+ "@webpieces/tooling-testkit": "0.4.849"
45
45
  },
46
46
  "types": "./src/index.d.ts",
47
47
  "bin": {
@@ -24,6 +24,14 @@ export interface ExecutorResult {
24
24
  * fixing it is the same single command either way, so listing both adds noise rather than information.
25
25
  */
26
26
  export declare function describeTableDrift(current: CurrentArchitecture, saved: DependenciesFile): string | null;
27
+ /**
28
+ * Build the current dependency graph exactly as the generator does: reduce the nx
29
+ * graph, sort into levels, enrich with metadata, and attach the derived
30
+ * apiRelations — so this validator compares like-for-like against the committed file.
31
+ */
32
+ export declare class CurrentGraphBuilder {
33
+ build(workspaceRoot: string): Promise<CurrentArchitecture>;
34
+ }
27
35
  /** The regenerated graph plus the two tables beside it — everything dependencies.json holds. */
28
36
  export declare class CurrentArchitecture {
29
37
  readonly graph: EnhancedGraph;
@@ -9,7 +9,7 @@
9
9
  * nx run architecture:validate-architecture-unchanged
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.CurrentArchitecture = void 0;
12
+ exports.CurrentArchitecture = exports.CurrentGraphBuilder = void 0;
13
13
  exports.describeTableDrift = describeTableDrift;
14
14
  exports.default = runExecutor;
15
15
  const rules_config_1 = require("@webpieces/rules-config");
@@ -112,23 +112,25 @@ function describeExternalSystemDrift(current, saved) {
112
112
  * graph, sort into levels, enrich with metadata, and attach the derived
113
113
  * apiRelations — so this validator compares like-for-like against the committed file.
114
114
  */
115
- // webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch/writeTmpInstructionsFile in this file
116
- async function buildCurrentGraph(workspaceRoot) {
117
- console.log('📊 Generating current dependency graph...');
118
- const reducedGraph = await (0, graph_generator_1.generateReducedGraph)();
119
- console.log('🔄 Computing topological layers...');
120
- const currentGraph = (0, graph_sorter_1.sortGraphTopologically)(reducedGraph);
121
- console.log('🏷️ Enriching graph with framework + responsibilities metadata...');
122
- const projectInfos = await (0, graph_metadata_1.collectProjectInfo)();
123
- (0, graph_metadata_1.enrichGraph)(currentGraph, projectInfos, workspaceRoot);
124
- new tag_truth_1.TagTruthCheck().assertTrue(currentGraph, projectInfos, workspaceRoot);
125
- console.log('🔎 Scanning source for implements/uses API relations...');
126
- // The SAME externalApiPaths the generator uses: scanning without them would drop every vendor
127
- // relation from the regenerated graph and report drift against a perfectly fresh file.
128
- const externalApiPaths = (0, runtime_config_1.loadRuntimeConfig)(workspaceRoot).externalApiPaths;
129
- const scan = (0, api_scanner_1.scanAndAttachApiRelations)(workspaceRoot, currentGraph, projectInfos, externalApiPaths);
130
- return new CurrentArchitecture(currentGraph, new api_contract_files_1.ApiContractFiles().refsFor((0, api_scanner_1.buildApiContracts)(scan)), (0, external_systems_1.buildExternalSystems)(scan.apiIndex, projectInfos));
115
+ class CurrentGraphBuilder {
116
+ async build(workspaceRoot) {
117
+ console.log('📊 Generating current dependency graph...');
118
+ const reducedGraph = await (0, graph_generator_1.generateReducedGraph)();
119
+ console.log('🔄 Computing topological layers...');
120
+ const currentGraph = (0, graph_sorter_1.sortGraphTopologically)(reducedGraph);
121
+ console.log('🏷️ Enriching graph with framework + responsibilities metadata...');
122
+ const projectInfos = await (0, graph_metadata_1.collectProjectInfo)();
123
+ (0, graph_metadata_1.enrichGraph)(currentGraph, projectInfos, workspaceRoot);
124
+ new tag_truth_1.TagTruthCheck().assertTrue(currentGraph, projectInfos, workspaceRoot);
125
+ console.log('🔎 Scanning source for implements/uses API relations...');
126
+ // The SAME externalApiPaths the generator uses: scanning without them would drop every vendor
127
+ // relation from the regenerated graph and report drift against a perfectly fresh file.
128
+ const externalApiPaths = (0, runtime_config_1.loadRuntimeConfig)(workspaceRoot).externalApiPaths;
129
+ const scan = (0, api_scanner_1.scanAndAttachApiRelations)(workspaceRoot, currentGraph, projectInfos, externalApiPaths);
130
+ return new CurrentArchitecture(currentGraph, new api_contract_files_1.ApiContractFiles().refsFor((0, api_scanner_1.buildApiContracts)(scan)), (0, external_systems_1.buildExternalSystems)(scan.apiIndex, projectInfos));
131
+ }
131
132
  }
133
+ exports.CurrentGraphBuilder = CurrentGraphBuilder;
132
134
  /** The regenerated graph plus the two tables beside it — everything dependencies.json holds. */
133
135
  class CurrentArchitecture {
134
136
  graph;
@@ -170,7 +172,7 @@ async function runExecutor(options, context) {
170
172
  }
171
173
  // Steps 1-3: build + enrich + scan the current graph (same pipeline the
172
174
  // generator runs, so any drift is caught).
173
- const currentGraph = await buildCurrentGraph(workspaceRoot);
175
+ const currentGraph = await new CurrentGraphBuilder().build(workspaceRoot);
174
176
  // Step 4: Load saved graph
175
177
  console.log('📂 Loading saved graph...');
176
178
  const savedGraph = (0, graph_loader_1.loadBlessedGraph)(workspaceRoot, graphPath);
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-architecture-unchanged/executor.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAqFH,gDAIC;AAqED,8BAqEC;AAhOD,0DAA+F;AAC/F,+DAAiE;AACjE,yDAAgE;AAChE,iEAA2D;AAC3D,yDAA2E;AAE3E,6DAAoG;AACpG,mDAAoD;AACpD,iEAA+F;AAC/F,2EAA4E;AAE5E,qEAAgE;AAEhE,6DAA6D;AAC7D,mDAA+C;AAE/C,2CAAwC;AAUxC,MAAM,WAAW,GAAG,2BAA2B,CAAC;AAEhD;;;GAGG;AACH,SAAS,wBAAwB,CAAC,aAAqB;IACnD,MAAM,MAAM,GAAG,IAAA,4BAAa,EAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAEzD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,OAAe,EAAE,aAAqB;IAC1D,MAAM,MAAM,GAAG,wBAAwB,CAAC,aAAa,CAAC,CAAC;IAEvD,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAC/D,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,mBAAmB,GAAG,MAAM,GAAG,wCAAwC,CAAC,CAAC;IACvF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACzB,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/C,OAAO,CAAC,KAAK,CAAC,oGAAoG,CAAC,CAAC;IACpH,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;AAC5E,CAAC;AAED;;;;GAIG;AACH,2GAA2G;AAC3G,SAAS,yBAAyB,CAAC,OAA4B,EAAE,KAA0B;IACvF,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,uDAAuD,CAAC,CAAC;aACjG,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,mDAAmD,CAAC,CAAC;aAClG,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,iCAAiC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO,2BAA2B,OAAO,CAAC,MAAM,cAAc,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACvF,CAAC;AAED;;;;GAIG;AACH,+GAA+G;AAC/G,SAAgB,kBAAkB,CAAC,OAA4B,EAAE,KAAuB;IACpF,MAAM,SAAS,GAAG,yBAAyB,CAAC,OAAO,CAAC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC9F,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACzC,OAAO,2BAA2B,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;AACvF,CAAC;AAED;;;GAGG;AACH,+GAA+G;AAC/G,SAAS,2BAA2B,CAAC,OAA4B,EAAE,KAA0B;IACzF,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,yDAAyD,CAAC,CAAC;aACnG,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,yDAAyD,CAAC,CAAC;aACxG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,gCAAgC,CAAC,CAAC;IAChH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO,0BAA0B,OAAO,CAAC,MAAM,iBAAiB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACzF,CAAC;AAED;;;;GAIG;AACH,oIAAoI;AACpI,KAAK,UAAU,iBAAiB,CAAC,aAAqB;IAClD,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IACzD,MAAM,YAAY,GAAG,MAAM,IAAA,sCAAoB,GAAE,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,IAAA,qCAAsB,EAAC,YAAY,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAClF,MAAM,YAAY,GAAG,MAAM,IAAA,mCAAkB,GAAE,CAAC;IAChD,IAAA,4BAAW,EAAC,YAAY,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;IACvD,IAAI,yBAAa,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;IAC1E,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,8FAA8F;IAC9F,uFAAuF;IACvF,MAAM,gBAAgB,GAAG,IAAA,kCAAiB,EAAC,aAAa,CAAC,CAAC,gBAAgB,CAAC;IAC3E,MAAM,IAAI,GAAG,IAAA,uCAAyB,EAAC,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC;IACpG,OAAO,IAAI,mBAAmB,CAC1B,YAAY,EACZ,IAAI,qCAAgB,EAAE,CAAC,OAAO,CAAC,IAAA,+BAAiB,EAAC,IAAI,CAAC,CAAC,EACvD,IAAA,uCAAoB,EAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CACpD,CAAC;AACN,CAAC;AAED,gGAAgG;AAChG,MAAa,mBAAmB;IAER;IACA;IACA;IAHpB,YACoB,KAAoB,EACpB,gBAAqC,EACrC,eAAoC;QAFpC,UAAK,GAAL,KAAK,CAAe;QACpB,qBAAgB,GAAhB,gBAAgB,CAAqB;QACrC,oBAAe,GAAf,eAAe,CAAqB;IACrD,CAAC;CACP;AAND,kDAMC;AAED,yFAAyF;AACzF,2GAA2G;AAC3G,SAAS,kBAAkB;IACvB,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC1E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACxD,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,CAAC,qFAAqF,CAAC,CAAC;IACrG,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;AAChE,CAAC;AAEc,KAAK,UAAU,WAAW,CACrC,OAA6C,EAC7C,OAAwB;IAExB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACpC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnC,yFAAyF;IACzF,yFAAyF;IACzF,IAAI,IAAI,oBAAQ,EAAE,CAAC,UAAU,CAAC,aAAa,EAAE,iCAAiC,EAAE,IAAI,CAAC,EAAE,CAAC;QACpF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IAExD,8DAA8D;IAC9D,IAAI,CAAC;QACD,8BAA8B;QAC9B,IAAI,CAAC,IAAA,8BAAe,EAAC,aAAa,EAAE,SAAS,CAAC,EAAE,CAAC;YAC7C,kBAAkB,EAAE,CAAC;YACrB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;QAED,wEAAwE;QACxE,2CAA2C;QAC3C,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC;QAE5D,2BAA2B;QAC3B,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,IAAA,+BAAgB,EAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QAE9D,IAAI,CAAC,UAAU,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAC9C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;QAED,yBAAyB;QACzB,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAA,gCAAa,EAAC,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;QAE1E,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;YACxB,cAAc,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YAClD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;QAED,6FAA6F;QAC7F,0FAA0F;QAC1F,sEAAsE;QACtE,MAAM,UAAU,GAAG,kBAAkB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAChE,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACtB,cAAc,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;YAC1C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;QAC5E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAA,iBAAO,EAAC,GAAG,CAAC,CAAC;QAC3B,yFAAyF;QACzF,wFAAwF;QACxF,MAAM,QAAQ,GAAG,KAAK,YAAY,4BAAa,CAAC,CAAC,CAAC,IAAA,qCAAsB,EAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAChG,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,QAAQ,CAAC,CAAC;QAC7D,IAAI,KAAK,YAAY,wCAAuB,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAA,4BAAa,EAAC,aAAa,EAAE,+BAA+B,CAAC,CAAC;YAC7E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,mBAAmB,GAAG,MAAM,GAAG,qDAAqD,CAAC,CAAC;QACxG,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;AACL,CAAC","sourcesContent":["/**\n * Validate Architecture Unchanged Executor\n *\n * Validates that the current architecture graph matches the saved blessed graph.\n * This ensures no unapproved architecture changes have been made.\n *\n * Usage:\n * nx run architecture:validate-architecture-unchanged\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { writeTemplate, RuleFailError, renderRuleFailForHuman } from '@webpieces/rules-config';\nimport { generateReducedGraph } from '../../lib/graph-generator';\nimport { sortGraphTopologically } from '../../lib/graph-sorter';\nimport { compareGraphs } from '../../lib/graph-comparator';\nimport { loadBlessedGraph, graphFileExists } from '../../lib/graph-loader';\nimport type { DependenciesFile } from '../../lib/graph-loader';\nimport { collectProjectInfo, enrichGraph, MetadataValidationError } from '../../lib/graph-metadata';\nimport { TagTruthCheck } from '../../lib/tag-truth';\nimport { scanAndAttachApiRelations, buildApiContracts } from '../../lib/api-usage/api-scanner';\nimport { buildExternalSystems } from '../../lib/api-usage/external-systems';\nimport type { ExternalSystemDecls } from '../../lib/api-usage/api-relations';\nimport { ApiContractFiles } from '../../lib/api-contract-files';\nimport type { ApiContractFileRefs } from '../../lib/api-contract-files';\nimport { loadRuntimeConfig } from '../../lib/runtime-config';\nimport { RuleGate } from '../../lib/rule-gate';\nimport type { EnhancedGraph } from '../../lib/graph-sorter';\nimport { toError } from '../../toError';\n\nexport interface ValidateArchitectureUnchangedOptions {\n graphPath?: string;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst TMP_MD_FILE = 'webpieces.dependencies.md';\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructionsFile(workspaceRoot: string): string {\n const mdPath = writeTemplate(workspaceRoot, TMP_MD_FILE);\n\n return mdPath;\n}\n\n/**\n * Report a current-vs-saved graph mismatch and write the AI instructions file.\n */\nfunction reportMismatch(summary: string, workspaceRoot: string): void {\n const mdPath = writeTmpInstructionsFile(workspaceRoot);\n\n console.error('❌ Architecture has changed since last update!');\n console.error('\\nDifferences:');\n console.error(summary);\n console.error('');\n console.error('⚠️ *** Refer to ' + mdPath + ' for instructions on how to fix *** ⚠️');\n console.error('');\n console.error('To fix:');\n console.error(' 1. Review the changes above');\n console.error(' 2. If intentional, ASK USER to run: nx run architecture:generate since this is a critical change');\n console.error(' 3. Commit the updated architecture/dependencies.json');\n}\n\n/**\n * Which APIs dependencies.json links to a contract file, compared by LINK only — an added or removed\n * API. The endpoints inside `architecture/apis/<Api>.json` are deliberately NOT compared (#949): an\n * endpoint change must not fail this rule. Null when the links match.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction describeContractLinkDrift(current: ApiContractFileRefs, saved: ApiContractFileRefs): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined) changes.push(` - ${name}: linked in dependencies.json but no longer in source`);\n else if (b === undefined) changes.push(` + ${name}: in source but not linked from dependencies.json`);\n else if (a !== b) changes.push(` ~ ${name}: contract file link changed (${b} -> ${a})`);\n }\n if (changes.length === 0) return null;\n return `apiContractFiles drift (${changes.length} api(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Drift in EITHER side table of dependencies.json — the api contract-file links or the\n * external-system declarations — or null when both match. The first difference found is reported;\n * fixing it is the same single command either way, so listing both adds noise rather than information.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nexport function describeTableDrift(current: CurrentArchitecture, saved: DependenciesFile): string | null {\n const linkDrift = describeContractLinkDrift(current.apiContractFiles, saved.apiContractFiles);\n if (linkDrift !== null) return linkDrift;\n return describeExternalSystemDrift(current.externalSystems, saved.externalSystems);\n}\n\n/**\n * The same drift report for the declared external systems, or null when they match. Named per\n * system so the message points at the database that changed rather than dumping two JSON blobs.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nfunction describeExternalSystemDrift(current: ExternalSystemDecls, saved: ExternalSystemDecls): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined) changes.push(` - ${name}: in dependencies.json but no longer declared in source`);\n else if (b === undefined) changes.push(` + ${name}: declared in source but missing from dependencies.json`);\n else if (JSON.stringify(a) !== JSON.stringify(b)) changes.push(` ~ ${name}: kind/label/declarers changed`);\n }\n if (changes.length === 0) return null;\n return `externalSystems drift (${changes.length} system(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Build the current dependency graph exactly as the generator does: reduce the nx\n * graph, sort into levels, enrich with metadata, and attach the derived\n * apiRelations — so this validator compares like-for-like against the committed file.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch/writeTmpInstructionsFile in this file\nasync function buildCurrentGraph(workspaceRoot: string): Promise<CurrentArchitecture> {\n console.log('📊 Generating current dependency graph...');\n const reducedGraph = await generateReducedGraph();\n console.log('🔄 Computing topological layers...');\n const currentGraph = sortGraphTopologically(reducedGraph);\n console.log('🏷️ Enriching graph with framework + responsibilities metadata...');\n const projectInfos = await collectProjectInfo();\n enrichGraph(currentGraph, projectInfos, workspaceRoot);\n new TagTruthCheck().assertTrue(currentGraph, projectInfos, workspaceRoot);\n console.log('🔎 Scanning source for implements/uses API relations...');\n // The SAME externalApiPaths the generator uses: scanning without them would drop every vendor\n // relation from the regenerated graph and report drift against a perfectly fresh file.\n const externalApiPaths = loadRuntimeConfig(workspaceRoot).externalApiPaths;\n const scan = scanAndAttachApiRelations(workspaceRoot, currentGraph, projectInfos, externalApiPaths);\n return new CurrentArchitecture(\n currentGraph,\n new ApiContractFiles().refsFor(buildApiContracts(scan)),\n buildExternalSystems(scan.apiIndex, projectInfos),\n );\n}\n\n/** The regenerated graph plus the two tables beside it — everything dependencies.json holds. */\nexport class CurrentArchitecture {\n constructor(\n public readonly graph: EnhancedGraph,\n public readonly apiContractFiles: ApiContractFileRefs,\n public readonly externalSystems: ExternalSystemDecls,\n ) {}\n}\n\n/** The bootstrap path: there is nothing to diff against yet, so say how to create it. */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction reportMissingGraph(): void {\n console.error('❌ No saved graph found at architecture/dependencies.json');\n console.error('');\n console.error('To initialize:');\n console.error(' 1. Run: nx run architecture:generate');\n console.error(' 2. Run: nx run architecture:visualize');\n console.error(' 3. Manually inspect the generated graph to confirm it is the desired architecture');\n console.error(' 4. Commit architecture/dependencies.json');\n}\n\nexport default async function runExecutor(\n options: ValidateArchitectureUnchangedOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const graphPath = options.graphPath;\n const workspaceRoot = context.root;\n\n // Epoch-gateable: this rule diffs against the blessed architecture/dependencies.json, so\n // \"grandfather the current drift until <epoch>\" is meaningful — hence honorEpoch = true.\n if (new RuleGate().isDisabled(workspaceRoot, 'validate-architecture-unchanged', true)) {\n return { success: true };\n }\n\n console.log('\\n🔍 Validating Architecture Unchanged\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Check if saved graph exists\n if (!graphFileExists(workspaceRoot, graphPath)) {\n reportMissingGraph();\n return { success: false };\n }\n\n // Steps 1-3: build + enrich + scan the current graph (same pipeline the\n // generator runs, so any drift is caught).\n const currentGraph = await buildCurrentGraph(workspaceRoot);\n\n // Step 4: Load saved graph\n console.log('📂 Loading saved graph...');\n const savedGraph = loadBlessedGraph(workspaceRoot, graphPath);\n\n if (!savedGraph) {\n console.error('❌ Could not load saved graph');\n return { success: false };\n }\n\n // Step 5: Compare graphs\n console.log('🔍 Comparing current graph to saved graph...');\n const comparison = compareGraphs(currentGraph.graph, savedGraph.projects);\n\n if (!comparison.identical) {\n reportMismatch(comparison.summary, workspaceRoot);\n return { success: false };\n }\n\n // Step 6: Compare the two side tables as well: which APIs are linked to a contract file, and\n // the external-system declarations. The endpoints inside architecture/apis/<Api>.json are\n // NOT compared — an endpoint change must never fail this rule (#949).\n const tableDrift = describeTableDrift(currentGraph, savedGraph);\n if (tableDrift !== null) {\n reportMismatch(tableDrift, workspaceRoot);\n return { success: false };\n }\n\n console.log('✅ Architecture unchanged - current graph matches saved graph');\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n // A RuleFailError (e.g. a dependencies.json still carrying the moved `apiContracts` key)\n // carries its cures in Option[]; render them rather than dropping them with `.message`.\n const rendered = error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message;\n console.error('❌ Architecture validation failed:', rendered);\n if (error instanceof MetadataValidationError) {\n const mdPath = writeTemplate(workspaceRoot, 'webpieces.responsibilities.md');\n console.error('');\n console.error('⚠️ *** Refer to ' + mdPath + ' for how to author responsibilities.md files *** ⚠️');\n }\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-architecture-unchanged/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Architecture Unchanged Executor\n *\n * Validates that the current architecture graph matches the saved blessed graph.\n * This ensures no unapproved architecture changes have been made.\n *\n * Usage:\n * nx run architecture:validate-architecture-unchanged\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { writeTemplate, RuleFailError, renderRuleFailForHuman } from '@webpieces/rules-config';\nimport { generateReducedGraph } from '../../lib/graph-generator';\nimport { sortGraphTopologically } from '../../lib/graph-sorter';\nimport { compareGraphs } from '../../lib/graph-comparator';\nimport { loadBlessedGraph, graphFileExists } from '../../lib/graph-loader';\nimport type { DependenciesFile } from '../../lib/graph-loader';\nimport { collectProjectInfo, enrichGraph, MetadataValidationError } from '../../lib/graph-metadata';\nimport { TagTruthCheck } from '../../lib/tag-truth';\nimport { scanAndAttachApiRelations, buildApiContracts } from '../../lib/api-usage/api-scanner';\nimport { buildExternalSystems } from '../../lib/api-usage/external-systems';\nimport type { ExternalSystemDecls } from '../../lib/api-usage/api-relations';\nimport { ApiContractFiles } from '../../lib/api-contract-files';\nimport type { ApiContractFileRefs } from '../../lib/api-contract-files';\nimport { loadRuntimeConfig } from '../../lib/runtime-config';\nimport { RuleGate } from '../../lib/rule-gate';\nimport type { EnhancedGraph } from '../../lib/graph-sorter';\nimport { toError } from '../../toError';\n\nexport interface ValidateArchitectureUnchangedOptions {\n graphPath?: string;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst TMP_MD_FILE = 'webpieces.dependencies.md';\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructionsFile(workspaceRoot: string): string {\n const mdPath = writeTemplate(workspaceRoot, TMP_MD_FILE);\n\n return mdPath;\n}\n\n/**\n * Report a current-vs-saved graph mismatch and write the AI instructions file.\n */\nfunction reportMismatch(summary: string, workspaceRoot: string): void {\n const mdPath = writeTmpInstructionsFile(workspaceRoot);\n\n console.error('❌ Architecture has changed since last update!');\n console.error('\\nDifferences:');\n console.error(summary);\n console.error('');\n console.error('⚠️ *** Refer to ' + mdPath + ' for instructions on how to fix *** ⚠️');\n console.error('');\n console.error('To fix:');\n console.error(' 1. Review the changes above');\n console.error(' 2. If intentional, ASK USER to run: nx run architecture:generate since this is a critical change');\n console.error(' 3. Commit the updated architecture/dependencies.json');\n}\n\n/**\n * Which APIs dependencies.json links to a contract file, compared by LINK only — an added or removed\n * API. The endpoints inside `architecture/apis/<Api>.json` are deliberately NOT compared (#949): an\n * endpoint change must not fail this rule. Null when the links match.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction describeContractLinkDrift(\n current: ApiContractFileRefs,\n saved: ApiContractFileRefs,\n): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined)\n changes.push(` - ${name}: linked in dependencies.json but no longer in source`);\n else if (b === undefined)\n changes.push(` + ${name}: in source but not linked from dependencies.json`);\n else if (a !== b) changes.push(` ~ ${name}: contract file link changed (${b} -> ${a})`);\n }\n if (changes.length === 0) return null;\n return `apiContractFiles drift (${changes.length} api(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Drift in EITHER side table of dependencies.json — the api contract-file links or the\n * external-system declarations — or null when both match. The first difference found is reported;\n * fixing it is the same single command either way, so listing both adds noise rather than information.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nexport function describeTableDrift(current: CurrentArchitecture, saved: DependenciesFile): string | null {\n const linkDrift = describeContractLinkDrift(current.apiContractFiles, saved.apiContractFiles);\n if (linkDrift !== null) return linkDrift;\n return describeExternalSystemDrift(current.externalSystems, saved.externalSystems);\n}\n\n/**\n * The same drift report for the declared external systems, or null when they match. Named per\n * system so the message points at the database that changed rather than dumping two JSON blobs.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nfunction describeExternalSystemDrift(\n current: ExternalSystemDecls,\n saved: ExternalSystemDecls,\n): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined)\n changes.push(` - ${name}: in dependencies.json but no longer declared in source`);\n else if (b === undefined)\n changes.push(` + ${name}: declared in source but missing from dependencies.json`);\n else if (JSON.stringify(a) !== JSON.stringify(b))\n changes.push(` ~ ${name}: kind/label/declarers changed`);\n }\n if (changes.length === 0) return null;\n return `externalSystems drift (${changes.length} system(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Build the current dependency graph exactly as the generator does: reduce the nx\n * graph, sort into levels, enrich with metadata, and attach the derived\n * apiRelations — so this validator compares like-for-like against the committed file.\n */\nexport class CurrentGraphBuilder {\n async build(workspaceRoot: string): Promise<CurrentArchitecture> {\n console.log('📊 Generating current dependency graph...');\n const reducedGraph = await generateReducedGraph();\n console.log('🔄 Computing topological layers...');\n const currentGraph = sortGraphTopologically(reducedGraph);\n console.log('🏷️ Enriching graph with framework + responsibilities metadata...');\n const projectInfos = await collectProjectInfo();\n enrichGraph(currentGraph, projectInfos, workspaceRoot);\n new TagTruthCheck().assertTrue(currentGraph, projectInfos, workspaceRoot);\n console.log('🔎 Scanning source for implements/uses API relations...');\n // The SAME externalApiPaths the generator uses: scanning without them would drop every vendor\n // relation from the regenerated graph and report drift against a perfectly fresh file.\n const externalApiPaths = loadRuntimeConfig(workspaceRoot).externalApiPaths;\n const scan = scanAndAttachApiRelations(workspaceRoot, currentGraph, projectInfos, externalApiPaths);\n return new CurrentArchitecture(\n currentGraph,\n new ApiContractFiles().refsFor(buildApiContracts(scan)),\n buildExternalSystems(scan.apiIndex, projectInfos),\n );\n }\n}\n\n/** The regenerated graph plus the two tables beside it — everything dependencies.json holds. */\nexport class CurrentArchitecture {\n constructor(\n public readonly graph: EnhancedGraph,\n public readonly apiContractFiles: ApiContractFileRefs,\n public readonly externalSystems: ExternalSystemDecls,\n ) {}\n}\n\n/** The bootstrap path: there is nothing to diff against yet, so say how to create it. */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction reportMissingGraph(): void {\n console.error('❌ No saved graph found at architecture/dependencies.json');\n console.error('');\n console.error('To initialize:');\n console.error(' 1. Run: nx run architecture:generate');\n console.error(' 2. Run: nx run architecture:visualize');\n console.error(' 3. Manually inspect the generated graph to confirm it is the desired architecture');\n console.error(' 4. Commit architecture/dependencies.json');\n}\n\nexport default async function runExecutor(\n options: ValidateArchitectureUnchangedOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const graphPath = options.graphPath;\n const workspaceRoot = context.root;\n\n // Epoch-gateable: this rule diffs against the blessed architecture/dependencies.json, so\n // \"grandfather the current drift until <epoch>\" is meaningful — hence honorEpoch = true.\n if (new RuleGate().isDisabled(workspaceRoot, 'validate-architecture-unchanged', true)) {\n return { success: true };\n }\n\n console.log('\\n🔍 Validating Architecture Unchanged\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Check if saved graph exists\n if (!graphFileExists(workspaceRoot, graphPath)) {\n reportMissingGraph();\n return { success: false };\n }\n\n // Steps 1-3: build + enrich + scan the current graph (same pipeline the\n // generator runs, so any drift is caught).\n const currentGraph = await new CurrentGraphBuilder().build(workspaceRoot);\n\n // Step 4: Load saved graph\n console.log('📂 Loading saved graph...');\n const savedGraph = loadBlessedGraph(workspaceRoot, graphPath);\n\n if (!savedGraph) {\n console.error('❌ Could not load saved graph');\n return { success: false };\n }\n\n // Step 5: Compare graphs\n console.log('🔍 Comparing current graph to saved graph...');\n const comparison = compareGraphs(currentGraph.graph, savedGraph.projects);\n\n if (!comparison.identical) {\n reportMismatch(comparison.summary, workspaceRoot);\n return { success: false };\n }\n\n // Step 6: Compare the two side tables as well: which APIs are linked to a contract file, and\n // the external-system declarations. The endpoints inside architecture/apis/<Api>.json are\n // NOT compared — an endpoint change must never fail this rule (#949).\n const tableDrift = describeTableDrift(currentGraph, savedGraph);\n if (tableDrift !== null) {\n reportMismatch(tableDrift, workspaceRoot);\n return { success: false };\n }\n\n console.log('✅ Architecture unchanged - current graph matches saved graph');\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n // A RuleFailError (e.g. a dependencies.json still carrying the moved `apiContracts` key)\n // carries its cures in Option[]; render them rather than dropping them with `.message`.\n const rendered = error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message;\n console.error('❌ Architecture validation failed:', rendered);\n if (error instanceof MetadataValidationError) {\n const mdPath = writeTemplate(workspaceRoot, 'webpieces.responsibilities.md');\n console.error('');\n console.error('⚠️ *** Refer to ' + mdPath + ' for how to author responsibilities.md files *** ⚠️');\n }\n return { success: false };\n }\n}\n"]}
@@ -1,12 +1,7 @@
1
1
  import type { ExecutorContext } from '@nx/devkit';
2
2
  import { ExecutorResult } from '../../executor-result';
3
- /**
4
- * The three DEBUG options (#1027). Every rule's mode and settings come from webpieces.config.json, never
5
- * from here; these only turn ONE run into a debug run of one rule:
6
- * nx run architecture:validate-code --rule=<name> [--mode=RUN_EVERY_TIME] [--projects=a,b]
7
- * All absent → the gate, at every committed mode.
8
- */
9
- export interface ValidateCodeOptions {
3
+ /** Runtime policy options come only from validated owner files. These flags request one ephemeral debug run. */
4
+ export declare class ValidateCodeOptions {
10
5
  rule?: string;
11
6
  mode?: string;
12
7
  projects?: string | string[];
@@ -1,8 +1,37 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidateCodeOptions = void 0;
3
4
  exports.default = runExecutor;
4
- const code_rules_1 = require("@webpieces/code-rules");
5
+ const rules_sdk_1 = require("@webpieces/rules-sdk");
6
+ const rules_config_1 = require("@webpieces/rules-config");
7
+ const rules_config_2 = require("@webpieces/rules-config");
8
+ const pack_build_runner_1 = require("../../pack-build-runner");
9
+ /** Runtime policy options come only from validated owner files. These flags request one ephemeral debug run. */
10
+ class ValidateCodeOptions {
11
+ rule;
12
+ mode;
13
+ projects;
14
+ }
15
+ exports.ValidateCodeOptions = ValidateCodeOptions;
16
+ // webpieces-disable no-function-outside-class -- Nx's required public executor entry point
5
17
  async function runExecutor(options, context) {
6
- return (0, code_rules_1.validateCode)(context.root, new code_rules_1.RunRequestParser().parse(options.rule, options.mode, options.projects));
18
+ const loaded = (0, rules_config_1.loadAndValidate)(context.root);
19
+ if (loaded.configPath === null)
20
+ throw new rules_config_2.RuleFailError('policy-configuration', 'Missing webpieces.config.json. Configure explicit rulePacks before running build policies.');
21
+ if (options.rule === undefined &&
22
+ options.mode === undefined &&
23
+ options.projects === undefined) {
24
+ return new pack_build_runner_1.PackBuildRunner().run(context.root, loaded);
25
+ }
26
+ if (options.rule === undefined)
27
+ throw new rules_config_2.RuleFailError('policy-configuration', '--mode and --projects require --rule=<name>: a debug run judges exactly one rule.');
28
+ const modules = new rules_config_1.RuleRuntimeModules();
29
+ const group = modules
30
+ .groups(loaded.ruleRegistry, 'build')
31
+ .find((entry) => entry.ruleIds.includes(options.rule));
32
+ if (!group)
33
+ throw new rules_config_2.RuleFailError('policy-configuration', `No declared build contribution for ${options.rule}. Use a rule from the generated policy catalog.`);
34
+ const exports = modules.load(group, loaded.ruleRegistry.manifestModules, new rules_config_1.NodeRuleRuntimeModuleLoader(context.root));
35
+ return modules.runBuildDebug(exports, new rules_sdk_1.BuildDebugRequest(context.root, new rules_sdk_1.PolicyDebugSelection(options.rule, options.mode, options.projects)));
7
36
  }
8
37
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-code/executor.ts"],"names":[],"mappings":";;AAgBA,8BAKC;AAnBD,sDAAuE;AAcxD,KAAK,UAAU,WAAW,CACrC,OAA4B,EAC5B,OAAwB;IAExB,OAAO,IAAA,yBAAY,EAAC,OAAO,CAAC,IAAI,EAAE,IAAI,6BAAgB,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClH,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { validateCode, RunRequestParser } from '@webpieces/code-rules';\n\n/**\n * The three DEBUG options (#1027). Every rule's mode and settings come from webpieces.config.json, never\n * from here; these only turn ONE run into a debug run of one rule:\n * nx run architecture:validate-code --rule=<name> [--mode=RUN_EVERY_TIME] [--projects=a,b]\n * All absent → the gate, at every committed mode.\n */\nexport interface ValidateCodeOptions {\n rule?: string;\n mode?: string;\n projects?: string | string[];\n}\n\nexport default async function runExecutor(\n options: ValidateCodeOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return validateCode(context.root, new RunRequestParser().parse(options.rule, options.mode, options.projects));\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-code/executor.ts"],"names":[],"mappings":";;;AAoBA,8BA2CC;AA9DD,oDAA+E;AAC/E,0DAKiC;AACjC,0DAAwD;AACxD,+DAA0D;AAG1D,gHAAgH;AAChH,MAAa,mBAAmB;IAC5B,IAAI,CAAU;IACd,IAAI,CAAU;IACd,QAAQ,CAAqB;CAChC;AAJD,kDAIC;AAED,2FAA2F;AAC5E,KAAK,UAAU,WAAW,CACrC,OAA4B,EAC5B,OAAwB;IAExB,MAAM,MAAM,GAAG,IAAA,8BAAe,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI;QAC1B,MAAM,IAAI,4BAAa,CACnB,sBAAsB,EACtB,4FAA4F,CAC/F,CAAC;IACN,IACI,OAAO,CAAC,IAAI,KAAK,SAAS;QAC1B,OAAO,CAAC,IAAI,KAAK,SAAS;QAC1B,OAAO,CAAC,QAAQ,KAAK,SAAS,EAChC,CAAC;QACC,OAAO,IAAI,mCAAe,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAC1B,MAAM,IAAI,4BAAa,CACnB,sBAAsB,EACtB,mFAAmF,CACtF,CAAC;IACN,MAAM,OAAO,GAAG,IAAI,iCAAkB,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO;SAChB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC;SACpC,IAAI,CAAC,CAAC,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAK,CAAC,CAAC,CAAC;IACtF,IAAI,CAAC,KAAK;QACN,MAAM,IAAI,4BAAa,CACnB,sBAAsB,EACtB,sCAAsC,OAAO,CAAC,IAAI,iDAAiD,CACtG,CAAC;IACN,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CACxB,KAAK,EACL,MAAM,CAAC,YAAY,CAAC,eAAe,EACnC,IAAI,0CAA2B,CAAC,OAAO,CAAC,IAAI,CAAC,CAChD,CAAC;IACF,OAAO,OAAO,CAAC,aAAa,CACxB,OAAO,EACP,IAAI,6BAAiB,CACjB,OAAO,CAAC,IAAI,EACZ,IAAI,gCAAoB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CACzE,CACJ,CAAC;AACN,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { BuildDebugRequest, PolicyDebugSelection } from '@webpieces/rules-sdk';\nimport {\n loadAndValidate,\n NodeRuleRuntimeModuleLoader,\n RuleRuntimeModules,\n RuntimeContributionGroup,\n} from '@webpieces/rules-config';\nimport { RuleFailError } from '@webpieces/rules-config';\nimport { PackBuildRunner } from '../../pack-build-runner';\nimport { ExecutorResult } from '../../executor-result';\n\n/** Runtime policy options come only from validated owner files. These flags request one ephemeral debug run. */\nexport class ValidateCodeOptions {\n rule?: string;\n mode?: string;\n projects?: string | string[];\n}\n\n// webpieces-disable no-function-outside-class -- Nx's required public executor entry point\nexport default async function runExecutor(\n options: ValidateCodeOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n const loaded = loadAndValidate(context.root);\n if (loaded.configPath === null)\n throw new RuleFailError(\n 'policy-configuration',\n 'Missing webpieces.config.json. Configure explicit rulePacks before running build policies.',\n );\n if (\n options.rule === undefined &&\n options.mode === undefined &&\n options.projects === undefined\n ) {\n return new PackBuildRunner().run(context.root, loaded);\n }\n if (options.rule === undefined)\n throw new RuleFailError(\n 'policy-configuration',\n '--mode and --projects require --rule=<name>: a debug run judges exactly one rule.',\n );\n const modules = new RuleRuntimeModules();\n const group = modules\n .groups(loaded.ruleRegistry, 'build')\n .find((entry: RuntimeContributionGroup) => entry.ruleIds.includes(options.rule!));\n if (!group)\n throw new RuleFailError(\n 'policy-configuration',\n `No declared build contribution for ${options.rule}. Use a rule from the generated policy catalog.`,\n );\n const exports = modules.load(\n group,\n loaded.ruleRegistry.manifestModules,\n new NodeRuleRuntimeModuleLoader(context.root),\n );\n return modules.runBuildDebug(\n exports,\n new BuildDebugRequest(\n context.root,\n new PolicyDebugSelection(options.rule, options.mode, options.projects),\n ),\n );\n}\n"]}