@webpieces/code-rules 0.3.236 → 0.3.238

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/code-rules",
3
- "version": "0.3.236",
3
+ "version": "0.3.238",
4
4
  "description": "Standalone code validation rules extracted from architecture-validators, no Nx dependency required",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -20,7 +20,7 @@
20
20
  "directory": "packages/tooling/code-rules"
21
21
  },
22
22
  "dependencies": {
23
- "@webpieces/rules-config": "0.3.236"
23
+ "@webpieces/rules-config": "0.3.238"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"
package/src/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptio
11
11
  export { NoDestructureValidator } from './validate-no-destructure';
12
12
  export { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';
13
13
  export { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';
14
+ export { EnforceControllerNamingValidator } from './validate-enforce-controller-naming';
14
15
  export { PrismaValidateDtosValidator } from './validate-dtos';
15
16
  export { PrismaConverterValidator } from './validate-prisma-converters';
16
17
  export { default as validateCode } from './validate-code';
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateCode = exports.PrismaConverterValidator = exports.PrismaValidateDtosValidator = exports.NoSymbolDiTokensValidator = exports.NoDirectApiResolverValidator = exports.NoDestructureValidator = exports.NoUnmanagedExceptionsValidator = exports.CatchErrorPatternValidator = exports.NoInlineTypeLiteralsValidator = exports.RequireReturnTypeValidator = exports.MaxFileLinesValidator = exports.runNewMethods = exports.runModifiedMethods = exports.MaxMethodLinesValidator = exports.NoImplicitAnyValidator = exports.NoAnyUnknownValidator = exports.CodeValidator = void 0;
3
+ exports.validateCode = exports.PrismaConverterValidator = exports.PrismaValidateDtosValidator = exports.EnforceControllerNamingValidator = exports.NoSymbolDiTokensValidator = exports.NoDirectApiResolverValidator = exports.NoDestructureValidator = exports.NoUnmanagedExceptionsValidator = exports.CatchErrorPatternValidator = exports.NoInlineTypeLiteralsValidator = exports.RequireReturnTypeValidator = exports.MaxFileLinesValidator = exports.runNewMethods = exports.runModifiedMethods = exports.MaxMethodLinesValidator = exports.NoImplicitAnyValidator = exports.NoAnyUnknownValidator = exports.CodeValidator = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  var code_validator_1 = require("./code-validator");
6
6
  Object.defineProperty(exports, "CodeValidator", { enumerable: true, get: function () { return code_validator_1.CodeValidator; } });
@@ -29,6 +29,8 @@ var validate_no_direct_api_resolver_1 = require("./validate-no-direct-api-resolv
29
29
  Object.defineProperty(exports, "NoDirectApiResolverValidator", { enumerable: true, get: function () { return validate_no_direct_api_resolver_1.NoDirectApiResolverValidator; } });
30
30
  var validate_no_symbol_di_tokens_1 = require("./validate-no-symbol-di-tokens");
31
31
  Object.defineProperty(exports, "NoSymbolDiTokensValidator", { enumerable: true, get: function () { return validate_no_symbol_di_tokens_1.NoSymbolDiTokensValidator; } });
32
+ var validate_enforce_controller_naming_1 = require("./validate-enforce-controller-naming");
33
+ Object.defineProperty(exports, "EnforceControllerNamingValidator", { enumerable: true, get: function () { return validate_enforce_controller_naming_1.EnforceControllerNamingValidator; } });
32
34
  var validate_dtos_1 = require("./validate-dtos");
33
35
  Object.defineProperty(exports, "PrismaValidateDtosValidator", { enumerable: true, get: function () { return validate_dtos_1.PrismaValidateDtosValidator; } });
34
36
  var validate_prisma_converters_1 = require("./validate-prisma-converters");
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/index.ts"],"names":[],"mappings":";;;;AAAA,mDAAiE;AAAxD,+GAAA,aAAa,OAAA;AAEtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,uEAAoE;AAA3D,kIAAA,sBAAsB,OAAA;AAC/B,yEAA0F;AAAjF,oIAAA,uBAAuB,OAAA;AAAE,+HAAA,kBAAkB,OAAA;AACpD,+DAAuD;AAA9C,qHAAA,aAAa,OAAA;AACtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,iEAAqE;AAA5D,mIAAA,0BAA0B,OAAA;AACnC,uEAA2E;AAAlE,yIAAA,6BAA6B,OAAA;AACtC,+EAA4E;AAAnE,0IAAA,0BAA0B,OAAA;AACnC,uFAAoF;AAA3E,kJAAA,8BAA8B,OAAA;AACvC,qEAAmE;AAA1D,iIAAA,sBAAsB,OAAA;AAC/B,qFAAiF;AAAxE,+IAAA,4BAA4B,OAAA;AACrC,+EAA2E;AAAlE,yIAAA,yBAAyB,OAAA;AAClC,iDAA8D;AAArD,4HAAA,2BAA2B,OAAA;AACpC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA;AACjC,iDAA0D;AAAjD,sIAAA,OAAO,OAAgB","sourcesContent":["export { CodeValidator, ExecutorResult } from './code-validator';\n\nexport { NoAnyUnknownValidator } from './validate-no-any-unknown';\nexport { NoImplicitAnyValidator } from './validate-no-implicit-any';\nexport { MaxMethodLinesValidator, runModifiedMethods } from './validate-modified-methods';\nexport { runNewMethods } from './validate-new-methods';\nexport { MaxFileLinesValidator } from './validate-modified-files';\nexport { RequireReturnTypeValidator } from './validate-return-types';\nexport { NoInlineTypeLiteralsValidator } from './validate-no-inline-types';\nexport { CatchErrorPatternValidator } from './validate-catch-error-pattern';\nexport { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptions';\nexport { NoDestructureValidator } from './validate-no-destructure';\nexport { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';\nexport { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';\nexport { PrismaValidateDtosValidator } from './validate-dtos';\nexport { PrismaConverterValidator } from './validate-prisma-converters';\nexport { default as validateCode } from './validate-code';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/index.ts"],"names":[],"mappings":";;;;AAAA,mDAAiE;AAAxD,+GAAA,aAAa,OAAA;AAEtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,uEAAoE;AAA3D,kIAAA,sBAAsB,OAAA;AAC/B,yEAA0F;AAAjF,oIAAA,uBAAuB,OAAA;AAAE,+HAAA,kBAAkB,OAAA;AACpD,+DAAuD;AAA9C,qHAAA,aAAa,OAAA;AACtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,iEAAqE;AAA5D,mIAAA,0BAA0B,OAAA;AACnC,uEAA2E;AAAlE,yIAAA,6BAA6B,OAAA;AACtC,+EAA4E;AAAnE,0IAAA,0BAA0B,OAAA;AACnC,uFAAoF;AAA3E,kJAAA,8BAA8B,OAAA;AACvC,qEAAmE;AAA1D,iIAAA,sBAAsB,OAAA;AAC/B,qFAAiF;AAAxE,+IAAA,4BAA4B,OAAA;AACrC,+EAA2E;AAAlE,yIAAA,yBAAyB,OAAA;AAClC,2FAAwF;AAA/E,sJAAA,gCAAgC,OAAA;AACzC,iDAA8D;AAArD,4HAAA,2BAA2B,OAAA;AACpC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA;AACjC,iDAA0D;AAAjD,sIAAA,OAAO,OAAgB","sourcesContent":["export { CodeValidator, ExecutorResult } from './code-validator';\n\nexport { NoAnyUnknownValidator } from './validate-no-any-unknown';\nexport { NoImplicitAnyValidator } from './validate-no-implicit-any';\nexport { MaxMethodLinesValidator, runModifiedMethods } from './validate-modified-methods';\nexport { runNewMethods } from './validate-new-methods';\nexport { MaxFileLinesValidator } from './validate-modified-files';\nexport { RequireReturnTypeValidator } from './validate-return-types';\nexport { NoInlineTypeLiteralsValidator } from './validate-no-inline-types';\nexport { CatchErrorPatternValidator } from './validate-catch-error-pattern';\nexport { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptions';\nexport { NoDestructureValidator } from './validate-no-destructure';\nexport { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';\nexport { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';\nexport { EnforceControllerNamingValidator } from './validate-enforce-controller-naming';\nexport { PrismaValidateDtosValidator } from './validate-dtos';\nexport { PrismaConverterValidator } from './validate-prisma-converters';\nexport { default as validateCode } from './validate-code';\n"]}
@@ -16,6 +16,7 @@ const validate_catch_error_pattern_1 = require("./validate-catch-error-pattern")
16
16
  const validate_no_unmanaged_exceptions_1 = require("./validate-no-unmanaged-exceptions");
17
17
  const validate_no_direct_api_resolver_1 = require("./validate-no-direct-api-resolver");
18
18
  const validate_no_symbol_di_tokens_1 = require("./validate-no-symbol-di-tokens");
19
+ const validate_enforce_controller_naming_1 = require("./validate-enforce-controller-naming");
19
20
  const validate_match_rules_1 = require("./validate-match-rules");
20
21
  /**
21
22
  * Build every code validator from the typed WebpiecesRulesConfig. Each validator is
@@ -39,6 +40,7 @@ function buildValidators(config, matchRules) {
39
40
  new validate_no_unmanaged_exceptions_1.NoUnmanagedExceptionsValidator(config['no-unmanaged-exceptions'] ?? new rules_config_1.NoUnmanagedExceptionsConfig()),
40
41
  new validate_no_direct_api_resolver_1.NoDirectApiResolverValidator(config['angular-no-direct-api-in-resolver'] ?? new rules_config_1.AngularNoDirectApiInResolverConfig()),
41
42
  new validate_no_symbol_di_tokens_1.NoSymbolDiTokensValidator(config['no-symbol-di-tokens'] ?? new rules_config_1.NoSymbolDiTokensConfig()),
43
+ new validate_enforce_controller_naming_1.EnforceControllerNamingValidator(config['enforce-controller-naming'] ?? new rules_config_1.EnforceControllerNamingConfig()),
42
44
  // One validator per client-authored match-rules entry (each with its own name/mode/epoch).
43
45
  ...matchRules.map((mr) => new validate_match_rules_1.MatchRulesValidator(mr)),
44
46
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"validate-code.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-code.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n loadAndValidate,\n WebpiecesRulesConfig,\n BaseRuleConfig,\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n CatchErrorPatternConfig,\n NoUnmanagedExceptionsConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { runValidators } from './rule-reporter';\nimport { MaxMethodLinesValidator } from './validate-modified-methods';\nimport { MaxFileLinesValidator } from './validate-modified-files';\nimport { RequireReturnTypeValidator } from './validate-return-types';\nimport { NoInlineTypeLiteralsValidator } from './validate-no-inline-types';\nimport { NoAnyUnknownValidator } from './validate-no-any-unknown';\nimport { NoImplicitAnyValidator } from './validate-no-implicit-any';\nimport { PrismaValidateDtosValidator } from './validate-dtos';\nimport { PrismaConverterValidator } from './validate-prisma-converters';\nimport { NoDestructureValidator } from './validate-no-destructure';\nimport { CatchErrorPatternValidator } from './validate-catch-error-pattern';\nimport { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptions';\nimport { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';\nimport { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';\nimport { MatchRulesValidator } from './validate-match-rules';\nimport { MatchRuleConfig } from '@webpieces/rules-config';\n\nexport { ExecutorResult } from './code-validator';\n\n/**\n * Build every code validator from the typed WebpiecesRulesConfig. Each validator is\n * constructed with its own `*Config` (the genuinely-consumed config class), so the\n * config types are exercised at compile time. Missing rule keys fall back to an empty\n * config instance — `loadAndValidate` already validates that configured rules\n * carry an explicit `mode`, so in practice every key is present.\n */\nfunction buildValidators(\n config: WebpiecesRulesConfig,\n matchRules: readonly MatchRuleConfig[],\n): CodeValidator<BaseRuleConfig>[] {\n return [\n new MaxMethodLinesValidator(config['max-method-lines'] ?? new MaxMethodLinesConfig()),\n new MaxFileLinesValidator(config['max-file-lines'] ?? new MaxFileLinesConfig()),\n new RequireReturnTypeValidator(config['require-return-type'] ?? new RequireReturnTypeConfig()),\n new NoInlineTypeLiteralsValidator(config['no-inline-type-literals'] ?? new NoInlineTypeLiteralsConfig()),\n new NoAnyUnknownValidator(config['no-any-unknown'] ?? new NoAnyUnknownConfig()),\n new NoImplicitAnyValidator(config['no-implicit-any'] ?? new NoImplicitAnyConfig()),\n new PrismaValidateDtosValidator(config['prisma-validate-dtos'] ?? new PrismaValidateDtosConfig()),\n new PrismaConverterValidator(config['prisma-converter'] ?? new PrismaConverterConfig()),\n new NoDestructureValidator(config['no-destructure'] ?? new NoDestructureConfig()),\n new CatchErrorPatternValidator(config['catch-error-pattern'] ?? new CatchErrorPatternConfig()),\n new NoUnmanagedExceptionsValidator(config['no-unmanaged-exceptions'] ?? new NoUnmanagedExceptionsConfig()),\n new NoDirectApiResolverValidator(config['angular-no-direct-api-in-resolver'] ?? new AngularNoDirectApiInResolverConfig()),\n new NoSymbolDiTokensValidator(config['no-symbol-di-tokens'] ?? new NoSymbolDiTokensConfig()),\n // One validator per client-authored match-rules entry (each with its own name/mode/epoch).\n ...matchRules.map((mr: MatchRuleConfig) => new MatchRulesValidator(mr)),\n ];\n}\n\n/**\n * Run all configured code validators against the workspace.\n *\n * Owns config loading: callers just pass the workspace root. Config comes from\n * webpieces.config.json (loaded via @webpieces/rules-config so ai-hooks and this\n * executor agree on every rule's enabled/mode/options). A validator runs only when\n * `shouldRun()` is true (i.e. its mode is not OFF and no branch/epoch escape hatch matches).\n */\nexport default async function runValidator(workspaceRoot: string): Promise<ExecutorResult> {\n const loaded = loadAndValidate(workspaceRoot);\n if (loaded.configPath === null) {\n console.error('\\n❌ No webpieces.config.json found at workspace root (or any ancestor).\\n');\n return { success: false };\n }\n\n console.log(`\\n📄 Loaded config: ${loaded.configPath}`);\n\n const validators = buildValidators(loaded.rulesConfig, loaded.matchRules);\n const active = validators.filter((v: CodeValidator<BaseRuleConfig>) => v.shouldRun());\n\n if (active.length === 0) {\n console.log('\\n⏭️ Skipping all code validations (all modes: OFF)\\n');\n return { success: true };\n }\n\n console.log('\\n📏 Running Code Validations\\n');\n console.log(` Active rules: ${active.map((v: CodeValidator<BaseRuleConfig>) => v.name).join(', ')}`);\n console.log('');\n\n // Per-validator isolation lives in runValidators: a bug in one validator no longer aborts the\n // rest, and a thrown RuleFailError is reported like any other failure.\n const result = await runValidators(active, workspaceRoot);\n const allSuccess = result.success;\n\n console.log(allSuccess ? '\\n✅ All code validations passed\\n' : '\\n❌ Some code validations failed\\n');\n return { success: allSuccess };\n}\n"]}
1
+ {"version":3,"file":"validate-code.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-code.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n loadAndValidate,\n WebpiecesRulesConfig,\n BaseRuleConfig,\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n CatchErrorPatternConfig,\n NoUnmanagedExceptionsConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n EnforceControllerNamingConfig,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { runValidators } from './rule-reporter';\nimport { MaxMethodLinesValidator } from './validate-modified-methods';\nimport { MaxFileLinesValidator } from './validate-modified-files';\nimport { RequireReturnTypeValidator } from './validate-return-types';\nimport { NoInlineTypeLiteralsValidator } from './validate-no-inline-types';\nimport { NoAnyUnknownValidator } from './validate-no-any-unknown';\nimport { NoImplicitAnyValidator } from './validate-no-implicit-any';\nimport { PrismaValidateDtosValidator } from './validate-dtos';\nimport { PrismaConverterValidator } from './validate-prisma-converters';\nimport { NoDestructureValidator } from './validate-no-destructure';\nimport { CatchErrorPatternValidator } from './validate-catch-error-pattern';\nimport { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptions';\nimport { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';\nimport { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';\nimport { EnforceControllerNamingValidator } from './validate-enforce-controller-naming';\nimport { MatchRulesValidator } from './validate-match-rules';\nimport { MatchRuleConfig } from '@webpieces/rules-config';\n\nexport { ExecutorResult } from './code-validator';\n\n/**\n * Build every code validator from the typed WebpiecesRulesConfig. Each validator is\n * constructed with its own `*Config` (the genuinely-consumed config class), so the\n * config types are exercised at compile time. Missing rule keys fall back to an empty\n * config instance — `loadAndValidate` already validates that configured rules\n * carry an explicit `mode`, so in practice every key is present.\n */\nfunction buildValidators(\n config: WebpiecesRulesConfig,\n matchRules: readonly MatchRuleConfig[],\n): CodeValidator<BaseRuleConfig>[] {\n return [\n new MaxMethodLinesValidator(config['max-method-lines'] ?? new MaxMethodLinesConfig()),\n new MaxFileLinesValidator(config['max-file-lines'] ?? new MaxFileLinesConfig()),\n new RequireReturnTypeValidator(config['require-return-type'] ?? new RequireReturnTypeConfig()),\n new NoInlineTypeLiteralsValidator(config['no-inline-type-literals'] ?? new NoInlineTypeLiteralsConfig()),\n new NoAnyUnknownValidator(config['no-any-unknown'] ?? new NoAnyUnknownConfig()),\n new NoImplicitAnyValidator(config['no-implicit-any'] ?? new NoImplicitAnyConfig()),\n new PrismaValidateDtosValidator(config['prisma-validate-dtos'] ?? new PrismaValidateDtosConfig()),\n new PrismaConverterValidator(config['prisma-converter'] ?? new PrismaConverterConfig()),\n new NoDestructureValidator(config['no-destructure'] ?? new NoDestructureConfig()),\n new CatchErrorPatternValidator(config['catch-error-pattern'] ?? new CatchErrorPatternConfig()),\n new NoUnmanagedExceptionsValidator(config['no-unmanaged-exceptions'] ?? new NoUnmanagedExceptionsConfig()),\n new NoDirectApiResolverValidator(config['angular-no-direct-api-in-resolver'] ?? new AngularNoDirectApiInResolverConfig()),\n new NoSymbolDiTokensValidator(config['no-symbol-di-tokens'] ?? new NoSymbolDiTokensConfig()),\n new EnforceControllerNamingValidator(config['enforce-controller-naming'] ?? new EnforceControllerNamingConfig()),\n // One validator per client-authored match-rules entry (each with its own name/mode/epoch).\n ...matchRules.map((mr: MatchRuleConfig) => new MatchRulesValidator(mr)),\n ];\n}\n\n/**\n * Run all configured code validators against the workspace.\n *\n * Owns config loading: callers just pass the workspace root. Config comes from\n * webpieces.config.json (loaded via @webpieces/rules-config so ai-hooks and this\n * executor agree on every rule's enabled/mode/options). A validator runs only when\n * `shouldRun()` is true (i.e. its mode is not OFF and no branch/epoch escape hatch matches).\n */\nexport default async function runValidator(workspaceRoot: string): Promise<ExecutorResult> {\n const loaded = loadAndValidate(workspaceRoot);\n if (loaded.configPath === null) {\n console.error('\\n❌ No webpieces.config.json found at workspace root (or any ancestor).\\n');\n return { success: false };\n }\n\n console.log(`\\n📄 Loaded config: ${loaded.configPath}`);\n\n const validators = buildValidators(loaded.rulesConfig, loaded.matchRules);\n const active = validators.filter((v: CodeValidator<BaseRuleConfig>) => v.shouldRun());\n\n if (active.length === 0) {\n console.log('\\n⏭️ Skipping all code validations (all modes: OFF)\\n');\n return { success: true };\n }\n\n console.log('\\n📏 Running Code Validations\\n');\n console.log(` Active rules: ${active.map((v: CodeValidator<BaseRuleConfig>) => v.name).join(', ')}`);\n console.log('');\n\n // Per-validator isolation lives in runValidators: a bug in one validator no longer aborts the\n // rest, and a thrown RuleFailError is reported like any other failure.\n const result = await runValidators(active, workspaceRoot);\n const allSuccess = result.success;\n\n console.log(allSuccess ? '\\n✅ All code validations passed\\n' : '\\n❌ Some code validations failed\\n');\n return { success: allSuccess };\n}\n"]}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Validate enforce-controller-naming at BUILD time.
3
+ *
4
+ * A controller class (decorated @Controller() OR whose heritage ends in `*Api`) must be named
5
+ * `{Something}Controller` and live in a lower-case kebab file `{something}-controller.ts`. The
6
+ * detection (class scan, controller signal, kebab file-name check) + allowedPaths/test-file
7
+ * exemption is shared with the ai-hook engine via findControllerNamingViolations; this validator
8
+ * adds diff-scoping (mode), the `// webpieces-disable enforce-controller-naming` filter, and the
9
+ * console report. Same skeleton as validate-no-symbol-di-tokens / validate-match-rules.
10
+ *
11
+ * MODES: OFF | NEW_AND_MODIFIED_CODE (violations on changed lines) | NEW_AND_MODIFIED_FILES (any
12
+ * violation in a changed file). Because a controller file's very name is what's checked, the file
13
+ * tier (NEW_AND_MODIFIED_FILES) is the intended setting.
14
+ */
15
+ import { EnforceControllerNamingConfig } from '@webpieces/rules-config';
16
+ import { CodeValidator, ExecutorResult } from './code-validator';
17
+ declare class NamingViolationInfo {
18
+ readonly line: number;
19
+ readonly context: string;
20
+ readonly message: string;
21
+ readonly hasDisableComment: boolean;
22
+ constructor(line: number, context: string, message: string, hasDisableComment: boolean);
23
+ }
24
+ export declare function findNamingViolationsInFile(filePath: string, workspaceRoot: string, config: EnforceControllerNamingConfig): NamingViolationInfo[];
25
+ export declare class EnforceControllerNamingValidator extends CodeValidator<EnforceControllerNamingConfig> {
26
+ constructor(config: EnforceControllerNamingConfig);
27
+ run(workspaceRoot: string): Promise<ExecutorResult>;
28
+ }
29
+ export {};
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ /**
3
+ * Validate enforce-controller-naming at BUILD time.
4
+ *
5
+ * A controller class (decorated @Controller() OR whose heritage ends in `*Api`) must be named
6
+ * `{Something}Controller` and live in a lower-case kebab file `{something}-controller.ts`. The
7
+ * detection (class scan, controller signal, kebab file-name check) + allowedPaths/test-file
8
+ * exemption is shared with the ai-hook engine via findControllerNamingViolations; this validator
9
+ * adds diff-scoping (mode), the `// webpieces-disable enforce-controller-naming` filter, and the
10
+ * console report. Same skeleton as validate-no-symbol-di-tokens / validate-match-rules.
11
+ *
12
+ * MODES: OFF | NEW_AND_MODIFIED_CODE (violations on changed lines) | NEW_AND_MODIFIED_FILES (any
13
+ * violation in a changed file). Because a controller file's very name is what's checked, the file
14
+ * tier (NEW_AND_MODIFIED_FILES) is the intended setting.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.EnforceControllerNamingValidator = void 0;
18
+ exports.findNamingViolationsInFile = findNamingViolationsInFile;
19
+ const tslib_1 = require("tslib");
20
+ const fs = tslib_1.__importStar(require("fs"));
21
+ const path = tslib_1.__importStar(require("path"));
22
+ const rules_config_1 = require("@webpieces/rules-config");
23
+ const code_validator_1 = require("./code-validator");
24
+ const resolve_mode_1 = require("./resolve-mode");
25
+ class NamingViolation {
26
+ file;
27
+ line;
28
+ context;
29
+ message;
30
+ constructor(file, line, context, message) {
31
+ this.file = file;
32
+ this.line = line;
33
+ this.context = context;
34
+ this.message = message;
35
+ }
36
+ }
37
+ class NamingViolationInfo {
38
+ line;
39
+ context;
40
+ message;
41
+ hasDisableComment;
42
+ constructor(line, context, message, hasDisableComment) {
43
+ this.line = line;
44
+ this.context = context;
45
+ this.message = message;
46
+ this.hasDisableComment = hasDisableComment;
47
+ }
48
+ }
49
+ function stripLineComment(line) {
50
+ const idx = line.indexOf('//');
51
+ if (idx === -1)
52
+ return line;
53
+ return line.substring(0, idx);
54
+ }
55
+ function findNamingViolationsInFile(filePath, workspaceRoot, config) {
56
+ // Only .ts/.tsx carry controller classes; skip everything else cheaply.
57
+ if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx'))
58
+ return [];
59
+ const fullPath = path.join(workspaceRoot, filePath);
60
+ if (!fs.existsSync(fullPath))
61
+ return [];
62
+ const content = fs.readFileSync(fullPath, 'utf-8');
63
+ const rawLines = content.split('\n');
64
+ // Strip line comments so a commented-out `class Foo extends BarApi` can't false-match (parity
65
+ // with match-rules build-time; the ai-hook engine strips via stripTsNoise upstream).
66
+ const strippedLines = rawLines.map(stripLineComment);
67
+ const hits = (0, rules_config_1.findControllerNamingViolations)(strippedLines, filePath, config);
68
+ const disableAllowed = config.disableAllowed ?? true;
69
+ return hits.map((hit) => {
70
+ const line = rawLines[hit.line - 1] ?? '';
71
+ const prevLine = hit.line > 1 ? (rawLines[hit.line - 2] ?? '') : '';
72
+ const disabled = (0, rules_config_1.hasDisable)(line, rules_config_1.RULE_NAMES.ENFORCE_CONTROLLER_NAMING) || (0, rules_config_1.hasDisable)(prevLine, rules_config_1.RULE_NAMES.ENFORCE_CONTROLLER_NAMING);
73
+ return new NamingViolationInfo(hit.line, hit.context, hit.message, disableAllowed && disabled);
74
+ });
75
+ }
76
+ function findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config) {
77
+ const violations = [];
78
+ for (const file of changedFiles) {
79
+ const diff = (0, rules_config_1.getFileDiff)(workspaceRoot, file, base, head);
80
+ const changedLines = (0, rules_config_1.getChangedLineNumbers)(diff);
81
+ if (changedLines.size === 0)
82
+ continue;
83
+ for (const v of findNamingViolationsInFile(file, workspaceRoot, config)) {
84
+ if (v.hasDisableComment)
85
+ continue;
86
+ if (!changedLines.has(v.line))
87
+ continue;
88
+ violations.push(new NamingViolation(file, v.line, v.context, v.message));
89
+ }
90
+ }
91
+ return violations;
92
+ }
93
+ function findViolationsForModifiedFiles(workspaceRoot, changedFiles, config) {
94
+ const violations = [];
95
+ for (const file of changedFiles) {
96
+ for (const v of findNamingViolationsInFile(file, workspaceRoot, config)) {
97
+ if (v.hasDisableComment)
98
+ continue;
99
+ violations.push(new NamingViolation(file, v.line, v.context, v.message));
100
+ }
101
+ }
102
+ return violations;
103
+ }
104
+ // webpieces-disable max-lines-new-methods -- Console output with guidance message and violation list
105
+ function reportViolations(violations, mode, disableAllowed) {
106
+ console.error('');
107
+ console.error('❌ Controller naming violations (enforce-controller-naming)!');
108
+ console.error('');
109
+ console.error(' Any class implementing/extending an *Api must declare intent: @Controller (then named');
110
+ console.error(' "{Something}Controller" in a "{something}-controller.ts" file) OR @NotController.');
111
+ console.error('');
112
+ for (const v of violations) {
113
+ console.error(` ❌ ${v.file}:${v.line}`);
114
+ console.error(` ${v.context}`);
115
+ console.error(` → ${v.message}`);
116
+ }
117
+ console.error('');
118
+ if (disableAllowed) {
119
+ console.error(' Escape hatch (use sparingly):');
120
+ console.error(' // webpieces-disable enforce-controller-naming -- <reason>');
121
+ }
122
+ else {
123
+ console.error(' Escape hatch: DISABLED (disableAllowed: false)');
124
+ }
125
+ console.error('');
126
+ console.error(` Current mode: ${mode}`);
127
+ console.error('');
128
+ }
129
+ function resolveMode(config) {
130
+ const normalMode = config.mode ?? 'OFF';
131
+ if (normalMode === 'OFF')
132
+ return normalMode;
133
+ const skip = (0, resolve_mode_1.shouldSkipRule)(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch);
134
+ if (skip.skip) {
135
+ console.log(`\n⏭️ Skipping enforce-controller-naming validation (${skip.reason})`);
136
+ console.log('');
137
+ return 'OFF';
138
+ }
139
+ return normalMode;
140
+ }
141
+ async function runValidatorImpl(config, workspaceRoot) {
142
+ const mode = resolveMode(config);
143
+ const disableAllowed = config.disableAllowed ?? true;
144
+ if (mode === 'OFF') {
145
+ console.log('\n⏭️ Skipping enforce-controller-naming validation (mode: OFF)');
146
+ console.log('');
147
+ return { success: true };
148
+ }
149
+ console.log('\n📏 Validating Controller Naming\n');
150
+ console.log(` Mode: ${mode}`);
151
+ let base = process.env['NX_BASE'];
152
+ const head = process.env['NX_HEAD'];
153
+ if (!base) {
154
+ base = (0, rules_config_1.detectBase)(workspaceRoot) ?? undefined;
155
+ if (!base) {
156
+ console.log('\n⏭️ Skipping enforce-controller-naming validation (could not detect base branch)');
157
+ console.log('');
158
+ return { success: true };
159
+ }
160
+ }
161
+ console.log(` Base: ${base}`);
162
+ console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
163
+ console.log('');
164
+ const changedFiles = (0, rules_config_1.getChangedFiles)(workspaceRoot, base, head);
165
+ if (changedFiles.length === 0) {
166
+ console.log('✅ No TypeScript files changed');
167
+ return { success: true };
168
+ }
169
+ console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
170
+ let violations = [];
171
+ if (mode === 'NEW_AND_MODIFIED_CODE') {
172
+ violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config);
173
+ }
174
+ else if (mode === 'NEW_AND_MODIFIED_FILES') {
175
+ violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);
176
+ }
177
+ if (violations.length === 0) {
178
+ console.log('✅ No controller naming violations found');
179
+ return { success: true };
180
+ }
181
+ reportViolations(violations, mode, disableAllowed);
182
+ return { success: false };
183
+ }
184
+ class EnforceControllerNamingValidator extends code_validator_1.CodeValidator {
185
+ constructor(config) {
186
+ super(config, 'enforce-controller-naming');
187
+ }
188
+ async run(workspaceRoot) {
189
+ return runValidatorImpl(this.config, workspaceRoot);
190
+ }
191
+ }
192
+ exports.EnforceControllerNamingValidator = EnforceControllerNamingValidator;
193
+ //# sourceMappingURL=validate-enforce-controller-naming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-enforce-controller-naming.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-enforce-controller-naming.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate enforce-controller-naming at BUILD time.\n *\n * A controller class (decorated @Controller() OR whose heritage ends in `*Api`) must be named\n * `{Something}Controller` and live in a lower-case kebab file `{something}-controller.ts`. The\n * detection (class scan, controller signal, kebab file-name check) + allowedPaths/test-file\n * exemption is shared with the ai-hook engine via findControllerNamingViolations; this validator\n * adds diff-scoping (mode), the `// webpieces-disable enforce-controller-naming` filter, and the\n * console report. Same skeleton as validate-no-symbol-di-tokens / validate-match-rules.\n *\n * MODES: OFF | NEW_AND_MODIFIED_CODE (violations on changed lines) | NEW_AND_MODIFIED_FILES (any\n * violation in a changed file). Because a controller file's very name is what's checked, the file\n * tier (NEW_AND_MODIFIED_FILES) is the intended setting.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n RULE_NAMES,\n EnforceControllerNamingConfig,\n ControllerNamingViolation,\n findControllerNamingViolations,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { shouldSkipRule } from './resolve-mode';\n\nclass NamingViolation {\n readonly file: string;\n readonly line: number;\n readonly context: string;\n readonly message: string;\n\n constructor(file: string, line: number, context: string, message: string) {\n this.file = file;\n this.line = line;\n this.context = context;\n this.message = message;\n }\n}\n\nclass NamingViolationInfo {\n readonly line: number;\n readonly context: string;\n readonly message: string;\n readonly hasDisableComment: boolean;\n\n constructor(line: number, context: string, message: string, hasDisableComment: boolean) {\n this.line = line;\n this.context = context;\n this.message = message;\n this.hasDisableComment = hasDisableComment;\n }\n}\n\nfunction stripLineComment(line: string): string {\n const idx = line.indexOf('//');\n if (idx === -1) return line;\n return line.substring(0, idx);\n}\n\nexport function findNamingViolationsInFile(\n filePath: string,\n workspaceRoot: string,\n config: EnforceControllerNamingConfig,\n): NamingViolationInfo[] {\n // Only .ts/.tsx carry controller classes; skip everything else cheaply.\n if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx')) return [];\n\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const rawLines = content.split('\\n');\n // Strip line comments so a commented-out `class Foo extends BarApi` can't false-match (parity\n // with match-rules build-time; the ai-hook engine strips via stripTsNoise upstream).\n const strippedLines = rawLines.map(stripLineComment);\n\n const hits = findControllerNamingViolations(strippedLines, filePath, config);\n const disableAllowed = config.disableAllowed ?? true;\n\n return hits.map((hit: ControllerNamingViolation) => {\n const line = rawLines[hit.line - 1] ?? '';\n const prevLine = hit.line > 1 ? (rawLines[hit.line - 2] ?? '') : '';\n const disabled = hasDisable(line, RULE_NAMES.ENFORCE_CONTROLLER_NAMING) || hasDisable(prevLine, RULE_NAMES.ENFORCE_CONTROLLER_NAMING);\n return new NamingViolationInfo(hit.line, hit.context, hit.message, disableAllowed && disabled);\n });\n}\n\nfunction findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n config: EnforceControllerNamingConfig,\n): NamingViolation[] {\n const violations: NamingViolation[] = [];\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n if (changedLines.size === 0) continue;\n\n for (const v of findNamingViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n violations.push(new NamingViolation(file, v.line, v.context, v.message));\n }\n }\n return violations;\n}\n\nfunction findViolationsForModifiedFiles(\n workspaceRoot: string,\n changedFiles: string[],\n config: EnforceControllerNamingConfig,\n): NamingViolation[] {\n const violations: NamingViolation[] = [];\n for (const file of changedFiles) {\n for (const v of findNamingViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n violations.push(new NamingViolation(file, v.line, v.context, v.message));\n }\n }\n return violations;\n}\n\n// webpieces-disable max-lines-new-methods -- Console output with guidance message and violation list\nfunction reportViolations(violations: NamingViolation[], mode: ModifiedCodeMode, disableAllowed: boolean): void {\n console.error('');\n console.error('❌ Controller naming violations (enforce-controller-naming)!');\n console.error('');\n console.error(' Any class implementing/extending an *Api must declare intent: @Controller (then named');\n console.error(' \"{Something}Controller\" in a \"{something}-controller.ts\" file) OR @NotController.');\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}`);\n console.error(` ${v.context}`);\n console.error(` → ${v.message}`);\n }\n console.error('');\n if (disableAllowed) {\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable enforce-controller-naming -- <reason>');\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\nfunction resolveMode(config: EnforceControllerNamingConfig): ModifiedCodeMode {\n const normalMode: ModifiedCodeMode = config.mode ?? 'OFF';\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping enforce-controller-naming validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\nasync function runValidatorImpl(config: EnforceControllerNamingConfig, workspaceRoot: string): Promise<ExecutorResult> {\n const mode = resolveMode(config);\n const disableAllowed = config.disableAllowed ?? true;\n\n if (mode === 'OFF') {\n console.log('\\n⏭️ Skipping enforce-controller-naming validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n📏 Validating Controller Naming\\n');\n console.log(` Mode: ${mode}`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n if (!base) {\n console.log('\\n⏭️ Skipping enforce-controller-naming validation (could not detect base branch)');\n console.log('');\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 changedFiles = getChangedFiles(workspaceRoot, base, head);\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n let violations: NamingViolation[] = [];\n if (mode === 'NEW_AND_MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config);\n } else if (mode === 'NEW_AND_MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);\n }\n\n if (violations.length === 0) {\n console.log('✅ No controller naming violations found');\n return { success: true };\n }\n\n reportViolations(violations, mode, disableAllowed);\n return { success: false };\n}\n\nexport class EnforceControllerNamingValidator extends CodeValidator<EnforceControllerNamingConfig> {\n constructor(config: EnforceControllerNamingConfig) {\n super(config, 'enforce-controller-naming');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}