@webpieces/nx-webpieces-rules 0.4.819 → 0.4.820

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.4.819",
3
+ "version": "0.4.820",
4
4
  "description": "Nx-specific webpieces validation rules and graph tooling. Bundles all @webpieces rule packages with Nx graph validators and an inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -18,13 +18,13 @@
18
18
  "README.md"
19
19
  ],
20
20
  "dependencies": {
21
- "@webpieces/ai-hook-rules": "0.4.819",
22
- "@webpieces/api-doc-model": "0.4.819",
23
- "@webpieces/code-rules": "0.4.819",
24
- "@webpieces/core-util": "0.4.819",
25
- "@webpieces/eslint-rules": "0.4.819",
26
- "@webpieces/pr-gate": "0.4.819",
27
- "@webpieces/rules-config": "0.4.819",
21
+ "@webpieces/ai-hook-rules": "0.4.820",
22
+ "@webpieces/api-doc-model": "0.4.820",
23
+ "@webpieces/code-rules": "0.4.820",
24
+ "@webpieces/core-util": "0.4.820",
25
+ "@webpieces/eslint-rules": "0.4.820",
26
+ "@webpieces/pr-gate": "0.4.820",
27
+ "@webpieces/rules-config": "0.4.820",
28
28
  "madge": "8.0.0"
29
29
  },
30
30
  "peerDependencies": {
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = runExecutor;
4
4
  const code_rules_1 = require("@webpieces/code-rules");
5
5
  async function runExecutor(options, context) {
6
- return new code_rules_1.CatchErrorPatternValidator(options).run(context.root);
6
+ return new code_rules_1.CatchErrorPatternValidator(options, new code_rules_1.GateScanScope()).run(context.root);
7
7
  }
8
8
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-catch-error-pattern/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAAmE;AAGpD,KAAK,UAAU,WAAW,CACrC,OAAgC,EAChC,OAAwB;IAExB,OAAO,IAAI,uCAA0B,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACrE,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { CatchErrorPatternValidator } from '@webpieces/code-rules';\nimport { CatchErrorPatternConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: CatchErrorPatternConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new CatchErrorPatternValidator(options).run(context.root);\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-catch-error-pattern/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAAkF;AAGnE,KAAK,UAAU,WAAW,CACrC,OAAgC,EAChC,OAAwB;IAExB,OAAO,IAAI,uCAA0B,CAAC,OAAO,EAAE,IAAI,0BAAa,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1F,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { CatchErrorPatternValidator, GateScanScope } from '@webpieces/code-rules';\nimport { CatchErrorPatternConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: CatchErrorPatternConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new CatchErrorPatternValidator(options, new GateScanScope()).run(context.root);\n}\n"]}
@@ -1,11 +1,14 @@
1
1
  import type { ExecutorContext } from '@nx/devkit';
2
2
  import { ExecutorResult } from '../../executor-result';
3
3
  /**
4
- * The build's code-rules pass. With no options it is the gate: every rule at its committed mode. The
5
- * three debug options (#1027) judge ONE rule without a config edit, e.g.
6
- *
7
- * nx run architecture:validate-code --rule=one-enum-spelling-in-api-lib --mode=RUN_EVERY_TIME --projects=lang-apis
8
- *
9
- * Every other option in schema.json is accepted and ignored — the rules read webpieces.config.json.
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.
10
8
  */
11
- export default function runExecutor(options: Record<string, unknown>, context: ExecutorContext): Promise<ExecutorResult>;
9
+ export interface ValidateCodeOptions {
10
+ rule?: string;
11
+ mode?: string;
12
+ projects?: string | string[];
13
+ }
14
+ export default function runExecutor(options: ValidateCodeOptions, context: ExecutorContext): Promise<ExecutorResult>;
@@ -2,17 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = runExecutor;
4
4
  const code_rules_1 = require("@webpieces/code-rules");
5
- /**
6
- * The build's code-rules pass. With no options it is the gate: every rule at its committed mode. The
7
- * three debug options (#1027) judge ONE rule without a config edit, e.g.
8
- *
9
- * nx run architecture:validate-code --rule=one-enum-spelling-in-api-lib --mode=RUN_EVERY_TIME --projects=lang-apis
10
- *
11
- * Every other option in schema.json is accepted and ignored — the rules read webpieces.config.json.
12
- */
13
- async function runExecutor(
14
- // webpieces-disable no-any-unknown -- nx executor options arrive as an untyped record
15
- options, context) {
16
- return (0, code_rules_1.validateCode)(context.root, new code_rules_1.CodeRulesRunRequestParser().fromExecutorOptions(options));
5
+ 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));
17
7
  }
18
8
  //# 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":";;AAYA,8BAMC;AAhBD,sDAAgF;AAEhF;;;;;;;GAOG;AACY,KAAK,UAAU,WAAW;AACrC,sFAAsF;AACtF,OAAgC,EAChC,OAAwB;IAExB,OAAO,IAAA,yBAAY,EAAC,OAAO,CAAC,IAAI,EAAE,IAAI,sCAAyB,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AACpG,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { CodeRulesRunRequestParser, validateCode } from '@webpieces/code-rules';\n\n/**\n * The build's code-rules pass. With no options it is the gate: every rule at its committed mode. The\n * three debug options (#1027) judge ONE rule without a config edit, e.g.\n *\n * nx run architecture:validate-code --rule=one-enum-spelling-in-api-lib --mode=RUN_EVERY_TIME --projects=lang-apis\n *\n * Every other option in schema.json is accepted and ignored — the rules read webpieces.config.json.\n */\nexport default async function runExecutor(\n // webpieces-disable no-any-unknown -- nx executor options arrive as an untyped record\n options: Record<string, unknown>,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return validateCode(context.root, new CodeRulesRunRequestParser().fromExecutorOptions(options));\n}\n"]}
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"]}
@@ -6,15 +6,16 @@
6
6
  "properties": {
7
7
  "rule": {
8
8
  "type": "string",
9
- "description": "DEBUG RUN (#1027): judge only this rule (a code-rules key or a match-rules name). Not the gate: it labels itself, changes nothing on disk, prints the rule's own failure text plus a site count per project, and exits non-zero when sites exist."
9
+ "description": "DEBUG run (#1027): run ONLY this code rule, e.g. one-enum-spelling-in-api-lib. Nothing is written and webpieces.config.json is unchanged, so the normal gate keeps its committed mode. Exits non-zero when any site exists."
10
10
  },
11
11
  "mode": {
12
12
  "type": "string",
13
- "description": "DEBUG RUN: judge --rule at this mode instead of its committed one, without editing webpieces.config.json, e.g. RUN_EVERY_TIME (every file in the repo) or MODIFIED_PROJECTS (every file of every project the diff touches). Omit to use the committed mode. Requires --rule."
13
+ "description": "DEBUG run: run --rule at this mode instead of its committed one, e.g. RUN_EVERY_TIME (every file in the repo) or MODIFIED_PROJECTS (every file of every project the diff touches). Omit to use the committed mode."
14
14
  },
15
15
  "projects": {
16
- "type": "string",
17
- "description": "DEBUG RUN: comma-separated nx project names to restrict --rule to, e.g. lang-apis,lang-fsdb-api. Requires --rule."
16
+ "type": ["string", "array"],
17
+ "items": { "type": "string" },
18
+ "description": "DEBUG run: judge only files owned by these nx projects, comma-separated, e.g. lang-apis,lang-fsdb-api. Prints a site count per project."
18
19
  },
19
20
  "methodMaxLimit": {
20
21
  "type": "object",
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = runExecutor;
4
4
  const code_rules_1 = require("@webpieces/code-rules");
5
5
  async function runExecutor(options, context) {
6
- return new code_rules_1.NoAnyUnknownValidator(options).run(context.root);
6
+ return new code_rules_1.NoAnyUnknownValidator(options, new code_rules_1.GateScanScope()).run(context.root);
7
7
  }
8
8
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-any-unknown/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAA8D;AAG/C,KAAK,UAAU,WAAW,CACrC,OAA2B,EAC3B,OAAwB;IAExB,OAAO,IAAI,kCAAqB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAChE,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoAnyUnknownValidator } from '@webpieces/code-rules';\nimport { NoAnyUnknownConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoAnyUnknownConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoAnyUnknownValidator(options).run(context.root);\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-any-unknown/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAA6E;AAG9D,KAAK,UAAU,WAAW,CACrC,OAA2B,EAC3B,OAAwB;IAExB,OAAO,IAAI,kCAAqB,CAAC,OAAO,EAAE,IAAI,0BAAa,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACrF,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoAnyUnknownValidator, GateScanScope } from '@webpieces/code-rules';\nimport { NoAnyUnknownConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoAnyUnknownConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoAnyUnknownValidator(options, new GateScanScope()).run(context.root);\n}\n"]}
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = runExecutor;
4
4
  const code_rules_1 = require("@webpieces/code-rules");
5
5
  async function runExecutor(options, context) {
6
- return new code_rules_1.NoDestructureValidator(options).run(context.root);
6
+ return new code_rules_1.NoDestructureValidator(options, new code_rules_1.GateScanScope()).run(context.root);
7
7
  }
8
8
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-destructure/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAA+D;AAGhD,KAAK,UAAU,WAAW,CACrC,OAA4B,EAC5B,OAAwB;IAExB,OAAO,IAAI,mCAAsB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACjE,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoDestructureValidator } from '@webpieces/code-rules';\nimport { NoDestructureConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoDestructureConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoDestructureValidator(options).run(context.root);\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-destructure/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAA8E;AAG/D,KAAK,UAAU,WAAW,CACrC,OAA4B,EAC5B,OAAwB;IAExB,OAAO,IAAI,mCAAsB,CAAC,OAAO,EAAE,IAAI,0BAAa,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoDestructureValidator, GateScanScope } from '@webpieces/code-rules';\nimport { NoDestructureConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoDestructureConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoDestructureValidator(options, new GateScanScope()).run(context.root);\n}\n"]}
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = runExecutor;
4
4
  const code_rules_1 = require("@webpieces/code-rules");
5
5
  async function runExecutor(options, context) {
6
- return new code_rules_1.NoImplicitAnyValidator(options).run(context.root);
6
+ return new code_rules_1.NoImplicitAnyValidator(options, new code_rules_1.GateScanScope()).run(context.root);
7
7
  }
8
8
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-implicit-any/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAA+D;AAGhD,KAAK,UAAU,WAAW,CACrC,OAA4B,EAC5B,OAAwB;IAExB,OAAO,IAAI,mCAAsB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACjE,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoImplicitAnyValidator } from '@webpieces/code-rules';\nimport { NoImplicitAnyConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoImplicitAnyConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoImplicitAnyValidator(options).run(context.root);\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-implicit-any/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAA8E;AAG/D,KAAK,UAAU,WAAW,CACrC,OAA4B,EAC5B,OAAwB;IAExB,OAAO,IAAI,mCAAsB,CAAC,OAAO,EAAE,IAAI,0BAAa,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoImplicitAnyValidator, GateScanScope } from '@webpieces/code-rules';\nimport { NoImplicitAnyConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoImplicitAnyConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoImplicitAnyValidator(options, new GateScanScope()).run(context.root);\n}\n"]}
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = runExecutor;
4
4
  const code_rules_1 = require("@webpieces/code-rules");
5
5
  async function runExecutor(options, context) {
6
- return new code_rules_1.NoUnmanagedExceptionsValidator(options).run(context.root);
6
+ return new code_rules_1.NoUnmanagedExceptionsValidator(options, new code_rules_1.GateScanScope()).run(context.root);
7
7
  }
8
8
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-unmanaged-exceptions/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAAuE;AAGxD,KAAK,UAAU,WAAW,CACrC,OAAoC,EACpC,OAAwB;IAExB,OAAO,IAAI,2CAA8B,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzE,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoUnmanagedExceptionsValidator } from '@webpieces/code-rules';\nimport { NoUnmanagedExceptionsConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoUnmanagedExceptionsConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoUnmanagedExceptionsValidator(options).run(context.root);\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-unmanaged-exceptions/executor.ts"],"names":[],"mappings":";;AAKA,8BAKC;AARD,sDAAsF;AAGvE,KAAK,UAAU,WAAW,CACrC,OAAoC,EACpC,OAAwB;IAExB,OAAO,IAAI,2CAA8B,CAAC,OAAO,EAAE,IAAI,0BAAa,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9F,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { NoUnmanagedExceptionsValidator, GateScanScope } from '@webpieces/code-rules';\nimport { NoUnmanagedExceptionsConfig } from '@webpieces/rules-config';\n\nexport default async function runExecutor(\n options: NoUnmanagedExceptionsConfig,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return new NoUnmanagedExceptionsValidator(options, new GateScanScope()).run(context.root);\n}\n"]}
@@ -10,15 +10,13 @@
10
10
  * `excludePaths` is holistic — its bare dir names and globs exempt files
11
11
  * from BOTH layers. Defaults exempt **\/*.d.ts and **\/jest.config.ts.
12
12
  *
13
- * NEW_AND_MODIFIED_FILES validates only the files changed vs the base branch, so
14
- * the rule applies cleanly to legacy projects — pre-existing orphan files are
15
- * grandfathered and only newly-touched files are checked. The whole-scope modes
16
- * (#1027) widen that file set centrally (DiffScope / FileScope): MODIFIED_PROJECTS
17
- * adds every file of every project the diff touches, RUN_EVERY_TIME every file.
13
+ * Only the files changed vs the base branch are validated (NEW_AND_MODIFIED_FILES),
14
+ * so the rule applies cleanly to legacy projects — pre-existing orphan files
15
+ * are grandfathered and only newly-touched files are checked.
18
16
  *
19
17
  * Configurable via webpieces.config.json:
20
18
  * "validate-ts-in-src": {
21
- * "mode": "NEW_AND_MODIFIED_FILES", // | MODIFIED_PROJECTS | RUN_EVERY_TIME; "OFF" disables the rule
19
+ * "mode": "NEW_AND_MODIFIED_FILES", // "OFF" disables the rule
22
20
  * "excludePaths": [...], // dir names + globs, e.g. "**\/codegen.ts"
23
21
  * "allowedRootFiles": [...],
24
22
  * "turnOffRuleUntilEpoch": 0, // epoch SECONDS; skip the rule until it passes
@@ -28,9 +26,9 @@
28
26
  * Usage: nx run architecture:validate-ts-in-src
29
27
  */
30
28
  import type { ExecutorContext } from '@nx/devkit';
31
- import { ValidateTsMode } from '@webpieces/rules-config';
29
+ export type ValidateTsInSrcMode = 'OFF' | 'NEW_AND_MODIFIED_FILES';
32
30
  export interface ValidateTsInSrcOptions {
33
- mode?: ValidateTsMode;
31
+ mode?: ValidateTsInSrcMode;
34
32
  excludePaths?: string[];
35
33
  allowedRootFiles?: string[];
36
34
  turnOffRuleUntilEpoch?: number;
@@ -11,15 +11,13 @@
11
11
  * `excludePaths` is holistic — its bare dir names and globs exempt files
12
12
  * from BOTH layers. Defaults exempt **\/*.d.ts and **\/jest.config.ts.
13
13
  *
14
- * NEW_AND_MODIFIED_FILES validates only the files changed vs the base branch, so
15
- * the rule applies cleanly to legacy projects — pre-existing orphan files are
16
- * grandfathered and only newly-touched files are checked. The whole-scope modes
17
- * (#1027) widen that file set centrally (DiffScope / FileScope): MODIFIED_PROJECTS
18
- * adds every file of every project the diff touches, RUN_EVERY_TIME every file.
14
+ * Only the files changed vs the base branch are validated (NEW_AND_MODIFIED_FILES),
15
+ * so the rule applies cleanly to legacy projects — pre-existing orphan files
16
+ * are grandfathered and only newly-touched files are checked.
19
17
  *
20
18
  * Configurable via webpieces.config.json:
21
19
  * "validate-ts-in-src": {
22
- * "mode": "NEW_AND_MODIFIED_FILES", // | MODIFIED_PROJECTS | RUN_EVERY_TIME; "OFF" disables the rule
20
+ * "mode": "NEW_AND_MODIFIED_FILES", // "OFF" disables the rule
23
21
  * "excludePaths": [...], // dir names + globs, e.g. "**\/codegen.ts"
24
22
  * "allowedRootFiles": [...],
25
23
  * "turnOffRuleUntilEpoch": 0, // epoch SECONDS; skip the rule until it passes
@@ -142,8 +140,8 @@ function reportLayerTwoFailure(violations) {
142
140
  console.error(' in nx.json targetDefaults, or add the filename to allowedRootFiles');
143
141
  console.error(' if it is a legitimate workspace-root file (e.g., jest.setup.ts)\n');
144
142
  }
145
- async function runModifiedFilesMode(mode, workspaceRoot, excludePaths, allowedRootFiles) {
146
- console.log(`\n📁 Validating TypeScript files are in src/ and owned by a project (${mode} mode)\n`);
143
+ async function runModifiedFilesMode(workspaceRoot, excludePaths, allowedRootFiles) {
144
+ console.log('\n📁 Validating TypeScript files are in src/ and owned by a project (NEW_AND_MODIFIED_FILES mode)\n');
147
145
  let base = process.env['NX_BASE'];
148
146
  const head = process.env['NX_HEAD'];
149
147
  if (!base) {
@@ -208,9 +206,8 @@ async function runExecutor(_nxOptions, context) {
208
206
  const workspaceRoot = context.root;
209
207
  const excludePaths = rule?.options['excludePaths'] ?? DEFAULT_EXCLUDE_PATHS;
210
208
  const allowedRootFiles = rule?.options['allowedRootFiles'] ?? DEFAULT_ALLOWED_ROOT_FILES;
211
- // OFF is handled above. NEW_AND_MODIFIED_FILES validates just the files changed vs the base branch
212
- // (legacy-friendly); a whole-scope mode widens that file set inside DiffScope.within.
213
- const scope = new rules_config_1.FileScope(new rules_config_1.WholeScopeModes().isWholeScopeMode(effectiveMode) ? effectiveMode : 'DIFF', null);
214
- return new rules_config_1.DiffScope().within(scope, () => runModifiedFilesMode(effectiveMode, workspaceRoot, excludePaths, allowedRootFiles));
209
+ // Only NEW_AND_MODIFIED_FILES remains once OFF is handled above — validate just the
210
+ // files changed vs the base branch (legacy-friendly; no whole-workspace scan).
211
+ return runModifiedFilesMode(workspaceRoot, excludePaths, allowedRootFiles);
215
212
  }
216
213
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-ts-in-src/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate TypeScript Files in src/ Executor\n *\n * Two-layer rule:\n * Layer 1: every .ts file inside an Nx project must live under src/\n * Layer 2: every .ts file anywhere in the workspace must belong to some\n * Nx project. Orphan files (at workspace root or in a non-project\n * directory) fail the rule unless explicitly allowlisted.\n *\n * `excludePaths` is holistic — its bare dir names and globs exempt files\n * from BOTH layers. Defaults exempt **\\/*.d.ts and **\\/jest.config.ts.\n *\n * NEW_AND_MODIFIED_FILES validates only the files changed vs the base branch, so\n * the rule applies cleanly to legacy projects — pre-existing orphan files are\n * grandfathered and only newly-touched files are checked. The whole-scope modes\n * (#1027) widen that file set centrally (DiffScope / FileScope): MODIFIED_PROJECTS\n * adds every file of every project the diff touches, RUN_EVERY_TIME every file.\n *\n * Configurable via webpieces.config.json:\n * \"validate-ts-in-src\": {\n * \"mode\": \"NEW_AND_MODIFIED_FILES\", // | MODIFIED_PROJECTS | RUN_EVERY_TIME; \"OFF\" disables the rule\n * \"excludePaths\": [...], // dir names + globs, e.g. \"**\\/codegen.ts\"\n * \"allowedRootFiles\": [...],\n * \"turnOffRuleUntilEpoch\": 0, // epoch SECONDS; skip the rule until it passes\n * \"turnOffRuleWhileOnBranch\": null // branch name; skip the rule while it is checked out\n * }\n *\n * Usage: nx run architecture:validate-ts-in-src\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { createProjectGraphAsync, readProjectsConfigurationFromProjectGraph } from '@nx/devkit';\nimport { loadAndValidate, isPathExcluded, shouldSkipRule, detectBase, getChangedFiles, DiffScope, FileScope, ValidateTsMode, WholeScopeModes } from '@webpieces/rules-config';\nimport * as path from 'path';\nimport * as fs from 'fs';\n\nexport interface ValidateTsInSrcOptions {\n mode?: ValidateTsMode;\n excludePaths?: string[];\n allowedRootFiles?: string[];\n turnOffRuleUntilEpoch?: number;\n turnOffRuleWhileOnBranch?: string | null;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst DEFAULT_EXCLUDE_PATHS: string[] = [\n 'node_modules', 'dist', '.nx', '.git',\n 'architecture', 'tmp', 'scripts',\n '**/*.d.ts', '**/jest.config.ts',\n];\n\nconst DEFAULT_ALLOWED_ROOT_FILES: string[] = ['jest.setup.ts'];\n\nclass LayerOneViolation {\n filePath: string;\n projectName: string;\n\n constructor(filePath: string, projectName: string) {\n this.filePath = filePath;\n this.projectName = projectName;\n }\n}\n\nclass LayerTwoViolation {\n filePath: string;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n }\n}\n\nasync function getProjectRoots(workspaceRoot: string): Promise<string[]> {\n const projectGraph = await createProjectGraphAsync();\n const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);\n const roots: string[] = [];\n for (const cfg of Object.values(projectsConfig.projects)) {\n if (cfg.root === '' || cfg.root === '.') continue;\n if (cfg.root === 'architecture') continue;\n roots.push(path.join(workspaceRoot, cfg.root));\n }\n return roots;\n}\n\nfunction checkSingleFileLayerOne(\n relPath: string,\n projectRoots: string[],\n workspaceRoot: string,\n excludePaths: string[],\n): LayerOneViolation | null {\n if (isPathExcluded(relPath, excludePaths)) return null;\n const fullPath = path.join(workspaceRoot, relPath);\n for (const projectRoot of projectRoots) {\n if (fullPath.startsWith(projectRoot + path.sep) || fullPath === projectRoot) {\n const relToProject = path.relative(projectRoot, fullPath);\n if (relToProject.startsWith('src' + path.sep) || relToProject === 'src') return null;\n const projectName = path.relative(workspaceRoot, projectRoot);\n return new LayerOneViolation(relPath, projectName);\n }\n }\n return null; // not in any project — that's layer 2's concern\n}\n\nfunction checkSingleFileLayerTwo(\n relPath: string,\n projectRoots: string[],\n workspaceRoot: string,\n allowedRootFiles: string[],\n excludePaths: string[],\n): LayerTwoViolation | null {\n if (isPathExcluded(relPath, excludePaths)) return null;\n const parts = relPath.split(path.sep);\n if (parts.length === 1 && allowedRootFiles.includes(parts[0] ?? '')) return null;\n const fullPath = path.join(workspaceRoot, relPath);\n for (const projectRoot of projectRoots) {\n if (fullPath.startsWith(projectRoot + path.sep)) return null; // owned by a project\n }\n return new LayerTwoViolation(relPath);\n}\n\nfunction resolveMode(\n normalMode: ValidateTsMode,\n epoch: number | undefined,\n branch: string | undefined,\n): ValidateTsMode {\n if (normalMode === 'OFF') {\n return normalMode;\n }\n // Honor the universal escape hatches: skip while on a named branch or until epoch.\n const skip = shouldSkipRule(epoch, branch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping validate-ts-in-src validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\nfunction reportLayerOneFailure(violations: LayerOneViolation[]): void {\n console.error('❌ TypeScript files found outside src/ directory!\\n');\n console.error('All .ts source files must be inside the project\\'s src/ directory.');\n console.error('This enforces the standard project structure:\\n');\n console.error(' packages/{category}/{name}/');\n console.error(' ├── src/ ← ALL .ts files here');\n console.error(' ├── package.json');\n console.error(' ├── project.json');\n console.error(' └── tsconfig.json\\n');\n\n for (const v of violations) {\n console.error(` ❌ ${v.filePath}`);\n }\n\n console.error('\\nTo fix, pick one:');\n console.error(' (a) Move the .ts file(s) into the src/ directory');\n console.error(' (b) Add a glob/dir to validate-ts-in-src.excludePaths in');\n console.error(' webpieces.config.json (e.g. \"**/codegen.ts\"). Defaults already');\n console.error(' exempt **/*.d.ts and **/jest.config.ts.\\n');\n}\n\nfunction reportLayerTwoFailure(violations: LayerTwoViolation[]): void {\n console.error('❌ TypeScript files found outside any Nx project!\\n');\n console.error('Every .ts file must belong to an Nx project so it is compiled,');\n console.error('linted, and tested under a known project config. Orphan files are');\n console.error('invisible to the build graph and will rot.\\n');\n\n for (const v of violations) {\n console.error(` ❌ ${v.filePath}`);\n }\n\n console.error('\\nTo fix, pick one:');\n console.error(' (a) Move the file into an existing project\\'s src/ directory');\n console.error(' (b) Create a new project (add project.json) that owns the directory');\n console.error(' (c) Add the containing top-level directory to validate-ts-in-src.excludePaths');\n console.error(' in nx.json targetDefaults, or add the filename to allowedRootFiles');\n console.error(' if it is a legitimate workspace-root file (e.g., jest.setup.ts)\\n');\n}\n\nasync function runModifiedFilesMode(\n mode: ValidateTsMode,\n workspaceRoot: string,\n excludePaths: string[],\n allowedRootFiles: string[],\n): Promise<ExecutorResult> {\n console.log(`\\n📁 Validating TypeScript files are in src/ and owned by a project (${mode} mode)\\n`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n if (!base) {\n console.log('\\n⏭️ Skipping validate-ts-in-src validation (could not detect base branch)\\n');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const projectRoots = await getProjectRoots(workspaceRoot);\n // git diff --name-only lists DELETED paths too (renames = delete+add);\n // a file that no longer exists cannot be an orphan - skip it\n const changedFiles = getChangedFiles(workspaceRoot, base, head)\n .filter((relPath: string) => fs.existsSync(path.join(workspaceRoot, relPath)));\n\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed\\n');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n const layerOneViolations: LayerOneViolation[] = [];\n const layerTwoViolations: LayerTwoViolation[] = [];\n\n for (const relPath of changedFiles) {\n const l1 = checkSingleFileLayerOne(relPath, projectRoots, workspaceRoot, excludePaths);\n if (l1) layerOneViolations.push(l1);\n const l2 = checkSingleFileLayerTwo(relPath, projectRoots, workspaceRoot, allowedRootFiles, excludePaths);\n if (l2) layerTwoViolations.push(l2);\n }\n\n if (layerOneViolations.length === 0 && layerTwoViolations.length === 0) {\n console.log('✅ All changed .ts files are inside a project\\'s src/ directory\\n');\n return { success: true };\n }\n\n if (layerOneViolations.length > 0) {\n reportLayerOneFailure(layerOneViolations);\n }\n if (layerTwoViolations.length > 0) {\n reportLayerTwoFailure(layerTwoViolations);\n }\n\n console.error('To disable: set rules[\"validate-ts-in-src\"].mode to \"OFF\" in webpieces.config.json\\n');\n return { success: false };\n}\n\nexport default async function runExecutor(\n _nxOptions: ValidateTsInSrcOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n // Config comes from webpieces.config.json — same source as ai-hooks\n // and validate-code — via @webpieces/rules-config.\n const shared = loadAndValidate(context.root).resolved;\n const rule = shared.rules.get('validate-ts-in-src');\n\n const rawMode = (rule?.options['mode'] as ValidateTsMode | undefined) ?? 'NEW_AND_MODIFIED_FILES';\n const epoch = rule?.options['turnOffRuleUntilEpoch'] as number | undefined;\n // turnOffRuleWhileOnBranch is required-but-NULLABLE in the config (null = \"always on\"), so narrow\n // to a branch NAME here; anything else means no branch scoping.\n const rawBranch = rule?.options['turnOffRuleWhileOnBranch'];\n const branch = typeof rawBranch === 'string' ? rawBranch : undefined;\n const effectiveMode = resolveMode(rawMode, epoch, branch);\n\n if (effectiveMode === 'OFF' || (rule && rule.isOff)) {\n console.log('\\n⏭️ Skipping validate-ts-in-src (mode: OFF)\\n');\n return { success: true };\n }\n\n const workspaceRoot = context.root;\n const excludePaths =\n (rule?.options['excludePaths'] as string[] | undefined) ?? DEFAULT_EXCLUDE_PATHS;\n const allowedRootFiles =\n (rule?.options['allowedRootFiles'] as string[] | undefined) ?? DEFAULT_ALLOWED_ROOT_FILES;\n\n // OFF is handled above. NEW_AND_MODIFIED_FILES validates just the files changed vs the base branch\n // (legacy-friendly); a whole-scope mode widens that file set inside DiffScope.within.\n const scope = new FileScope(new WholeScopeModes().isWholeScopeMode(effectiveMode) ? effectiveMode : 'DIFF', null);\n return new DiffScope().within(scope, () => runModifiedFilesMode(effectiveMode, workspaceRoot, excludePaths, allowedRootFiles));\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-ts-in-src/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate TypeScript Files in src/ Executor\n *\n * Two-layer rule:\n * Layer 1: every .ts file inside an Nx project must live under src/\n * Layer 2: every .ts file anywhere in the workspace must belong to some\n * Nx project. Orphan files (at workspace root or in a non-project\n * directory) fail the rule unless explicitly allowlisted.\n *\n * `excludePaths` is holistic — its bare dir names and globs exempt files\n * from BOTH layers. Defaults exempt **\\/*.d.ts and **\\/jest.config.ts.\n *\n * Only the files changed vs the base branch are validated (NEW_AND_MODIFIED_FILES),\n * so the rule applies cleanly to legacy projects — pre-existing orphan files\n * are grandfathered and only newly-touched files are checked.\n *\n * Configurable via webpieces.config.json:\n * \"validate-ts-in-src\": {\n * \"mode\": \"NEW_AND_MODIFIED_FILES\", // \"OFF\" disables the rule\n * \"excludePaths\": [...], // dir names + globs, e.g. \"**\\/codegen.ts\"\n * \"allowedRootFiles\": [...],\n * \"turnOffRuleUntilEpoch\": 0, // epoch SECONDS; skip the rule until it passes\n * \"turnOffRuleWhileOnBranch\": null // branch name; skip the rule while it is checked out\n * }\n *\n * Usage: nx run architecture:validate-ts-in-src\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { createProjectGraphAsync, readProjectsConfigurationFromProjectGraph } from '@nx/devkit';\nimport { loadAndValidate, isPathExcluded, shouldSkipRule, detectBase, getChangedFiles } from '@webpieces/rules-config';\nimport * as path from 'path';\nimport * as fs from 'fs';\n\nexport type ValidateTsInSrcMode = 'OFF' | 'NEW_AND_MODIFIED_FILES';\n\nexport interface ValidateTsInSrcOptions {\n mode?: ValidateTsInSrcMode;\n excludePaths?: string[];\n allowedRootFiles?: string[];\n turnOffRuleUntilEpoch?: number;\n turnOffRuleWhileOnBranch?: string | null;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst DEFAULT_EXCLUDE_PATHS: string[] = [\n 'node_modules', 'dist', '.nx', '.git',\n 'architecture', 'tmp', 'scripts',\n '**/*.d.ts', '**/jest.config.ts',\n];\n\nconst DEFAULT_ALLOWED_ROOT_FILES: string[] = ['jest.setup.ts'];\n\nclass LayerOneViolation {\n filePath: string;\n projectName: string;\n\n constructor(filePath: string, projectName: string) {\n this.filePath = filePath;\n this.projectName = projectName;\n }\n}\n\nclass LayerTwoViolation {\n filePath: string;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n }\n}\n\nasync function getProjectRoots(workspaceRoot: string): Promise<string[]> {\n const projectGraph = await createProjectGraphAsync();\n const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);\n const roots: string[] = [];\n for (const cfg of Object.values(projectsConfig.projects)) {\n if (cfg.root === '' || cfg.root === '.') continue;\n if (cfg.root === 'architecture') continue;\n roots.push(path.join(workspaceRoot, cfg.root));\n }\n return roots;\n}\n\nfunction checkSingleFileLayerOne(\n relPath: string,\n projectRoots: string[],\n workspaceRoot: string,\n excludePaths: string[],\n): LayerOneViolation | null {\n if (isPathExcluded(relPath, excludePaths)) return null;\n const fullPath = path.join(workspaceRoot, relPath);\n for (const projectRoot of projectRoots) {\n if (fullPath.startsWith(projectRoot + path.sep) || fullPath === projectRoot) {\n const relToProject = path.relative(projectRoot, fullPath);\n if (relToProject.startsWith('src' + path.sep) || relToProject === 'src') return null;\n const projectName = path.relative(workspaceRoot, projectRoot);\n return new LayerOneViolation(relPath, projectName);\n }\n }\n return null; // not in any project — that's layer 2's concern\n}\n\nfunction checkSingleFileLayerTwo(\n relPath: string,\n projectRoots: string[],\n workspaceRoot: string,\n allowedRootFiles: string[],\n excludePaths: string[],\n): LayerTwoViolation | null {\n if (isPathExcluded(relPath, excludePaths)) return null;\n const parts = relPath.split(path.sep);\n if (parts.length === 1 && allowedRootFiles.includes(parts[0] ?? '')) return null;\n const fullPath = path.join(workspaceRoot, relPath);\n for (const projectRoot of projectRoots) {\n if (fullPath.startsWith(projectRoot + path.sep)) return null; // owned by a project\n }\n return new LayerTwoViolation(relPath);\n}\n\nfunction resolveMode(\n normalMode: ValidateTsInSrcMode,\n epoch: number | undefined,\n branch: string | undefined,\n): ValidateTsInSrcMode {\n if (normalMode === 'OFF') {\n return normalMode;\n }\n // Honor the universal escape hatches: skip while on a named branch or until epoch.\n const skip = shouldSkipRule(epoch, branch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping validate-ts-in-src validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\nfunction reportLayerOneFailure(violations: LayerOneViolation[]): void {\n console.error('❌ TypeScript files found outside src/ directory!\\n');\n console.error('All .ts source files must be inside the project\\'s src/ directory.');\n console.error('This enforces the standard project structure:\\n');\n console.error(' packages/{category}/{name}/');\n console.error(' ├── src/ ← ALL .ts files here');\n console.error(' ├── package.json');\n console.error(' ├── project.json');\n console.error(' └── tsconfig.json\\n');\n\n for (const v of violations) {\n console.error(` ❌ ${v.filePath}`);\n }\n\n console.error('\\nTo fix, pick one:');\n console.error(' (a) Move the .ts file(s) into the src/ directory');\n console.error(' (b) Add a glob/dir to validate-ts-in-src.excludePaths in');\n console.error(' webpieces.config.json (e.g. \"**/codegen.ts\"). Defaults already');\n console.error(' exempt **/*.d.ts and **/jest.config.ts.\\n');\n}\n\nfunction reportLayerTwoFailure(violations: LayerTwoViolation[]): void {\n console.error('❌ TypeScript files found outside any Nx project!\\n');\n console.error('Every .ts file must belong to an Nx project so it is compiled,');\n console.error('linted, and tested under a known project config. Orphan files are');\n console.error('invisible to the build graph and will rot.\\n');\n\n for (const v of violations) {\n console.error(` ❌ ${v.filePath}`);\n }\n\n console.error('\\nTo fix, pick one:');\n console.error(' (a) Move the file into an existing project\\'s src/ directory');\n console.error(' (b) Create a new project (add project.json) that owns the directory');\n console.error(' (c) Add the containing top-level directory to validate-ts-in-src.excludePaths');\n console.error(' in nx.json targetDefaults, or add the filename to allowedRootFiles');\n console.error(' if it is a legitimate workspace-root file (e.g., jest.setup.ts)\\n');\n}\n\nasync function runModifiedFilesMode(\n workspaceRoot: string,\n excludePaths: string[],\n allowedRootFiles: string[],\n): Promise<ExecutorResult> {\n console.log('\\n📁 Validating TypeScript files are in src/ and owned by a project (NEW_AND_MODIFIED_FILES mode)\\n');\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n if (!base) {\n console.log('\\n⏭️ Skipping validate-ts-in-src validation (could not detect base branch)\\n');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const projectRoots = await getProjectRoots(workspaceRoot);\n // git diff --name-only lists DELETED paths too (renames = delete+add);\n // a file that no longer exists cannot be an orphan - skip it\n const changedFiles = getChangedFiles(workspaceRoot, base, head)\n .filter((relPath: string) => fs.existsSync(path.join(workspaceRoot, relPath)));\n\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed\\n');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n const layerOneViolations: LayerOneViolation[] = [];\n const layerTwoViolations: LayerTwoViolation[] = [];\n\n for (const relPath of changedFiles) {\n const l1 = checkSingleFileLayerOne(relPath, projectRoots, workspaceRoot, excludePaths);\n if (l1) layerOneViolations.push(l1);\n const l2 = checkSingleFileLayerTwo(relPath, projectRoots, workspaceRoot, allowedRootFiles, excludePaths);\n if (l2) layerTwoViolations.push(l2);\n }\n\n if (layerOneViolations.length === 0 && layerTwoViolations.length === 0) {\n console.log('✅ All changed .ts files are inside a project\\'s src/ directory\\n');\n return { success: true };\n }\n\n if (layerOneViolations.length > 0) {\n reportLayerOneFailure(layerOneViolations);\n }\n if (layerTwoViolations.length > 0) {\n reportLayerTwoFailure(layerTwoViolations);\n }\n\n console.error('To disable: set rules[\"validate-ts-in-src\"].mode to \"OFF\" in webpieces.config.json\\n');\n return { success: false };\n}\n\nexport default async function runExecutor(\n _nxOptions: ValidateTsInSrcOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n // Config comes from webpieces.config.json — same source as ai-hooks\n // and validate-code — via @webpieces/rules-config.\n const shared = loadAndValidate(context.root).resolved;\n const rule = shared.rules.get('validate-ts-in-src');\n\n const rawMode = (rule?.options['mode'] as ValidateTsInSrcMode | undefined) ?? 'NEW_AND_MODIFIED_FILES';\n const epoch = rule?.options['turnOffRuleUntilEpoch'] as number | undefined;\n // turnOffRuleWhileOnBranch is required-but-NULLABLE in the config (null = \"always on\"), so narrow\n // to a branch NAME here; anything else means no branch scoping.\n const rawBranch = rule?.options['turnOffRuleWhileOnBranch'];\n const branch = typeof rawBranch === 'string' ? rawBranch : undefined;\n const effectiveMode = resolveMode(rawMode, epoch, branch);\n\n if (effectiveMode === 'OFF' || (rule && rule.isOff)) {\n console.log('\\n⏭️ Skipping validate-ts-in-src (mode: OFF)\\n');\n return { success: true };\n }\n\n const workspaceRoot = context.root;\n const excludePaths =\n (rule?.options['excludePaths'] as string[] | undefined) ?? DEFAULT_EXCLUDE_PATHS;\n const allowedRootFiles =\n (rule?.options['allowedRootFiles'] as string[] | undefined) ?? DEFAULT_ALLOWED_ROOT_FILES;\n\n // Only NEW_AND_MODIFIED_FILES remains once OFF is handled above — validate just the\n // files changed vs the base branch (legacy-friendly; no whole-workspace scan).\n return runModifiedFilesMode(workspaceRoot, excludePaths, allowedRootFiles);\n}\n"]}