@webpieces/code-rules 0.4.467 → 0.4.469

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.4.467",
3
+ "version": "0.4.469",
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.4.467",
23
+ "@webpieces/rules-config": "0.4.469",
24
24
  "@inversifyjs/binding-decorators": "1.1.5",
25
25
  "inversify": "7.10.4",
26
26
  "reflect-metadata": "0.2.2"
@@ -22,6 +22,7 @@ exports.CONFIG_BINDINGS = [
22
22
  [rules_config_1.NoUnmanagedExceptionsConfig, 'no-unmanaged-exceptions'],
23
23
  [rules_config_1.AngularNoDirectApiInResolverConfig, 'angular-no-direct-api-in-resolver'],
24
24
  [rules_config_1.NoSymbolDiTokensConfig, 'no-symbol-di-tokens'],
25
+ [rules_config_1.NoClientCreationOutsideServerOrClientConfig, 'no-client-creation-outside-server-or-client'],
25
26
  [rules_config_1.NoCustomCssConfig, 'no-custom-css'],
26
27
  [rules_config_1.NoProcessExitOutsideMainConfig, 'no-process-exit-outside-main'],
27
28
  [rules_config_1.NoFunctionOutsideClassConfig, 'no-function-outside-class'],
@@ -1 +1 @@
1
- {"version":3,"file":"code-rules-config-table.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/code-rules-config-table.ts"],"names":[],"mappings":";;;AAAA,0DAsBiC;AAKjC;;;;;GAKG;AACU,QAAA,eAAe,GAAqE;IAC7F,CAAC,mCAAoB,EAAE,kBAAkB,CAAC;IAC1C,CAAC,iCAAkB,EAAE,gBAAgB,CAAC;IACtC,CAAC,sCAAuB,EAAE,qBAAqB,CAAC;IAChD,CAAC,yCAA0B,EAAE,yBAAyB,CAAC;IACvD,CAAC,iCAAkB,EAAE,gBAAgB,CAAC;IACtC,CAAC,kCAAmB,EAAE,iBAAiB,CAAC;IACxC,CAAC,uCAAwB,EAAE,sBAAsB,CAAC;IAClD,CAAC,oCAAqB,EAAE,kBAAkB,CAAC;IAC3C,CAAC,kCAAmB,EAAE,gBAAgB,CAAC;IACvC,CAAC,sCAAuB,EAAE,qBAAqB,CAAC;IAChD,CAAC,0CAA2B,EAAE,yBAAyB,CAAC;IACxD,CAAC,iDAAkC,EAAE,mCAAmC,CAAC;IACzE,CAAC,qCAAsB,EAAE,qBAAqB,CAAC;IAC/C,CAAC,gCAAiB,EAAE,eAAe,CAAC;IACpC,CAAC,6CAA8B,EAAE,8BAA8B,CAAC;IAChE,CAAC,2CAA4B,EAAE,2BAA2B,CAAC;IAC3D,CAAC,8DAA+C,EAAE,iDAAiD,CAAC;IACpG,CAAC,iCAAkB,EAAE,eAAe,CAAC;IACrC,CAAC,4BAAa,EAAE,UAAU,CAAC;CAC9B,CAAC","sourcesContent":["import {\n BaseRuleConfig,\n WebpiecesRulesConfig,\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 NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n} from '@webpieces/rules-config';\n\n/** A rule config class usable as an inversify inject-by-type token. */\nexport type ConfigCtor = new () => BaseRuleConfig;\n\n/**\n * The 1:1 table of `[config class, webpieces.config.json rule key]`. The composition root iterates it\n * to bind each rule's config into the container (`bind(ConfigClass).toConstantValue(config[key] ??\n * new ConfigClass())`), so every `@provideSingleton` validator injects its config by type. Data only\n * — the binding loop lives inline in the bin (an inline loop, exempt from no-function-outside-class).\n */\nexport const CONFIG_BINDINGS: ReadonlyArray<readonly [ConfigCtor, keyof WebpiecesRulesConfig]> = [\n [MaxMethodLinesConfig, 'max-method-lines'],\n [MaxFileLinesConfig, 'max-file-lines'],\n [RequireReturnTypeConfig, 'require-return-type'],\n [NoInlineTypeLiteralsConfig, 'no-inline-type-literals'],\n [NoAnyUnknownConfig, 'no-any-unknown'],\n [NoImplicitAnyConfig, 'no-implicit-any'],\n [PrismaValidateDtosConfig, 'prisma-validate-dtos'],\n [PrismaConverterConfig, 'prisma-converter'],\n [NoDestructureConfig, 'no-destructure'],\n [CatchErrorPatternConfig, 'catch-error-pattern'],\n [NoUnmanagedExceptionsConfig, 'no-unmanaged-exceptions'],\n [AngularNoDirectApiInResolverConfig, 'angular-no-direct-api-in-resolver'],\n [NoSymbolDiTokensConfig, 'no-symbol-di-tokens'],\n [NoCustomCssConfig, 'no-custom-css'],\n [NoProcessExitOutsideMainConfig, 'no-process-exit-outside-main'],\n [NoFunctionOutsideClassConfig, 'no-function-outside-class'],\n [InjectAnnotationNotNeededForConcreteClassConfig, 'inject-annotation-not-needed-for-concrete-class'],\n [FrameworkTagConfig, 'framework-tag'],\n [RoleTagConfig, 'role-tag'],\n];\n"]}
1
+ {"version":3,"file":"code-rules-config-table.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/code-rules-config-table.ts"],"names":[],"mappings":";;;AAAA,0DAuBiC;AAKjC;;;;;GAKG;AACU,QAAA,eAAe,GAAqE;IAC7F,CAAC,mCAAoB,EAAE,kBAAkB,CAAC;IAC1C,CAAC,iCAAkB,EAAE,gBAAgB,CAAC;IACtC,CAAC,sCAAuB,EAAE,qBAAqB,CAAC;IAChD,CAAC,yCAA0B,EAAE,yBAAyB,CAAC;IACvD,CAAC,iCAAkB,EAAE,gBAAgB,CAAC;IACtC,CAAC,kCAAmB,EAAE,iBAAiB,CAAC;IACxC,CAAC,uCAAwB,EAAE,sBAAsB,CAAC;IAClD,CAAC,oCAAqB,EAAE,kBAAkB,CAAC;IAC3C,CAAC,kCAAmB,EAAE,gBAAgB,CAAC;IACvC,CAAC,sCAAuB,EAAE,qBAAqB,CAAC;IAChD,CAAC,0CAA2B,EAAE,yBAAyB,CAAC;IACxD,CAAC,iDAAkC,EAAE,mCAAmC,CAAC;IACzE,CAAC,qCAAsB,EAAE,qBAAqB,CAAC;IAC/C,CAAC,0DAA2C,EAAE,6CAA6C,CAAC;IAC5F,CAAC,gCAAiB,EAAE,eAAe,CAAC;IACpC,CAAC,6CAA8B,EAAE,8BAA8B,CAAC;IAChE,CAAC,2CAA4B,EAAE,2BAA2B,CAAC;IAC3D,CAAC,8DAA+C,EAAE,iDAAiD,CAAC;IACpG,CAAC,iCAAkB,EAAE,eAAe,CAAC;IACrC,CAAC,4BAAa,EAAE,UAAU,CAAC;CAC9B,CAAC","sourcesContent":["import {\n BaseRuleConfig,\n WebpiecesRulesConfig,\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 NoClientCreationOutsideServerOrClientConfig,\n NoCustomCssConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n} from '@webpieces/rules-config';\n\n/** A rule config class usable as an inversify inject-by-type token. */\nexport type ConfigCtor = new () => BaseRuleConfig;\n\n/**\n * The 1:1 table of `[config class, webpieces.config.json rule key]`. The composition root iterates it\n * to bind each rule's config into the container (`bind(ConfigClass).toConstantValue(config[key] ??\n * new ConfigClass())`), so every `@provideSingleton` validator injects its config by type. Data only\n * — the binding loop lives inline in the bin (an inline loop, exempt from no-function-outside-class).\n */\nexport const CONFIG_BINDINGS: ReadonlyArray<readonly [ConfigCtor, keyof WebpiecesRulesConfig]> = [\n [MaxMethodLinesConfig, 'max-method-lines'],\n [MaxFileLinesConfig, 'max-file-lines'],\n [RequireReturnTypeConfig, 'require-return-type'],\n [NoInlineTypeLiteralsConfig, 'no-inline-type-literals'],\n [NoAnyUnknownConfig, 'no-any-unknown'],\n [NoImplicitAnyConfig, 'no-implicit-any'],\n [PrismaValidateDtosConfig, 'prisma-validate-dtos'],\n [PrismaConverterConfig, 'prisma-converter'],\n [NoDestructureConfig, 'no-destructure'],\n [CatchErrorPatternConfig, 'catch-error-pattern'],\n [NoUnmanagedExceptionsConfig, 'no-unmanaged-exceptions'],\n [AngularNoDirectApiInResolverConfig, 'angular-no-direct-api-in-resolver'],\n [NoSymbolDiTokensConfig, 'no-symbol-di-tokens'],\n [NoClientCreationOutsideServerOrClientConfig, 'no-client-creation-outside-server-or-client'],\n [NoCustomCssConfig, 'no-custom-css'],\n [NoProcessExitOutsideMainConfig, 'no-process-exit-outside-main'],\n [NoFunctionOutsideClassConfig, 'no-function-outside-class'],\n [InjectAnnotationNotNeededForConcreteClassConfig, 'inject-annotation-not-needed-for-concrete-class'],\n [FrameworkTagConfig, 'framework-tag'],\n [RoleTagConfig, 'role-tag'],\n];\n"]}
@@ -15,6 +15,7 @@ import { CatchErrorPatternValidator } from './validate-catch-error-pattern';
15
15
  import { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptions';
16
16
  import { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';
17
17
  import { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';
18
+ import { NoClientCreationOutsideServerOrClientValidator } from './validate-no-client-creation-outside-server-or-client';
18
19
  import { NoCustomCssValidator } from './validate-no-custom-css';
19
20
  import { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';
20
21
  import { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';
@@ -45,14 +46,15 @@ export declare class CodeRulesEngine {
45
46
  private readonly noUnmanagedExceptions;
46
47
  private readonly noDirectApiResolver;
47
48
  private readonly noSymbolDiTokens;
49
+ private readonly noClientCreationOutsideServerOrClient;
48
50
  private readonly noCustomCss;
49
51
  private readonly noProcessExitOutsideMain;
50
52
  private readonly noFunctionOutsideClass;
51
53
  private readonly injectAnnotationNotNeeded;
52
54
  private readonly frameworkTag;
53
55
  private readonly roleTag;
54
- constructor(workspace: WorkspaceRoot, reporter: RuleReporter, matchRules: MatchRulesHolder, matchChecker: MatchRulesChecker, maxMethodLines: MaxMethodLinesValidator, maxFileLines: MaxFileLinesValidator, requireReturnType: RequireReturnTypeValidator, noInlineTypeLiterals: NoInlineTypeLiteralsValidator, noAnyUnknown: NoAnyUnknownValidator, noImplicitAny: NoImplicitAnyValidator, prismaValidateDtos: PrismaValidateDtosValidator, prismaConverter: PrismaConverterValidator, noDestructure: NoDestructureValidator, catchErrorPattern: CatchErrorPatternValidator, noUnmanagedExceptions: NoUnmanagedExceptionsValidator, noDirectApiResolver: NoDirectApiResolverValidator, noSymbolDiTokens: NoSymbolDiTokensValidator, noCustomCss: NoCustomCssValidator, noProcessExitOutsideMain: NoProcessExitOutsideMainValidator, noFunctionOutsideClass: NoFunctionOutsideClassValidator, injectAnnotationNotNeeded: InjectAnnotationNotNeededForConcreteClassValidator, frameworkTag: FrameworkTagValidator, roleTag: RoleTagValidator);
55
- /** The 19 injected built-in validators, in run order. */
56
+ constructor(workspace: WorkspaceRoot, reporter: RuleReporter, matchRules: MatchRulesHolder, matchChecker: MatchRulesChecker, maxMethodLines: MaxMethodLinesValidator, maxFileLines: MaxFileLinesValidator, requireReturnType: RequireReturnTypeValidator, noInlineTypeLiterals: NoInlineTypeLiteralsValidator, noAnyUnknown: NoAnyUnknownValidator, noImplicitAny: NoImplicitAnyValidator, prismaValidateDtos: PrismaValidateDtosValidator, prismaConverter: PrismaConverterValidator, noDestructure: NoDestructureValidator, catchErrorPattern: CatchErrorPatternValidator, noUnmanagedExceptions: NoUnmanagedExceptionsValidator, noDirectApiResolver: NoDirectApiResolverValidator, noSymbolDiTokens: NoSymbolDiTokensValidator, noClientCreationOutsideServerOrClient: NoClientCreationOutsideServerOrClientValidator, noCustomCss: NoCustomCssValidator, noProcessExitOutsideMain: NoProcessExitOutsideMainValidator, noFunctionOutsideClass: NoFunctionOutsideClassValidator, injectAnnotationNotNeeded: InjectAnnotationNotNeededForConcreteClassValidator, frameworkTag: FrameworkTagValidator, roleTag: RoleTagValidator);
57
+ /** The 20 injected built-in validators, in run order. */
56
58
  private builtIns;
57
59
  /**
58
60
  * Every ACTIVE run: an injected built-in validator whose `shouldRun()` is true, or an injected
@@ -20,6 +20,7 @@ const validate_catch_error_pattern_1 = require("./validate-catch-error-pattern")
20
20
  const validate_no_unmanaged_exceptions_1 = require("./validate-no-unmanaged-exceptions");
21
21
  const validate_no_direct_api_resolver_1 = require("./validate-no-direct-api-resolver");
22
22
  const validate_no_symbol_di_tokens_1 = require("./validate-no-symbol-di-tokens");
23
+ const validate_no_client_creation_outside_server_or_client_1 = require("./validate-no-client-creation-outside-server-or-client");
23
24
  const validate_no_custom_css_1 = require("./validate-no-custom-css");
24
25
  const validate_no_process_exit_outside_main_1 = require("./validate-no-process-exit-outside-main");
25
26
  const validate_no_function_outside_class_1 = require("./validate-no-function-outside-class");
@@ -50,6 +51,7 @@ let CodeRulesEngine = class CodeRulesEngine {
50
51
  noUnmanagedExceptions;
51
52
  noDirectApiResolver;
52
53
  noSymbolDiTokens;
54
+ noClientCreationOutsideServerOrClient;
53
55
  noCustomCss;
54
56
  noProcessExitOutsideMain;
55
57
  noFunctionOutsideClass;
@@ -57,7 +59,7 @@ let CodeRulesEngine = class CodeRulesEngine {
57
59
  frameworkTag;
58
60
  roleTag;
59
61
  // webpieces-disable max-lines-new-methods -- the built-in validator set is flat; each is one injected field
60
- constructor(workspace, reporter, matchRules, matchChecker, maxMethodLines, maxFileLines, requireReturnType, noInlineTypeLiterals, noAnyUnknown, noImplicitAny, prismaValidateDtos, prismaConverter, noDestructure, catchErrorPattern, noUnmanagedExceptions, noDirectApiResolver, noSymbolDiTokens, noCustomCss, noProcessExitOutsideMain, noFunctionOutsideClass, injectAnnotationNotNeeded, frameworkTag, roleTag) {
62
+ constructor(workspace, reporter, matchRules, matchChecker, maxMethodLines, maxFileLines, requireReturnType, noInlineTypeLiterals, noAnyUnknown, noImplicitAny, prismaValidateDtos, prismaConverter, noDestructure, catchErrorPattern, noUnmanagedExceptions, noDirectApiResolver, noSymbolDiTokens, noClientCreationOutsideServerOrClient, noCustomCss, noProcessExitOutsideMain, noFunctionOutsideClass, injectAnnotationNotNeeded, frameworkTag, roleTag) {
61
63
  this.workspace = workspace;
62
64
  this.reporter = reporter;
63
65
  this.matchRules = matchRules;
@@ -75,6 +77,7 @@ let CodeRulesEngine = class CodeRulesEngine {
75
77
  this.noUnmanagedExceptions = noUnmanagedExceptions;
76
78
  this.noDirectApiResolver = noDirectApiResolver;
77
79
  this.noSymbolDiTokens = noSymbolDiTokens;
80
+ this.noClientCreationOutsideServerOrClient = noClientCreationOutsideServerOrClient;
78
81
  this.noCustomCss = noCustomCss;
79
82
  this.noProcessExitOutsideMain = noProcessExitOutsideMain;
80
83
  this.noFunctionOutsideClass = noFunctionOutsideClass;
@@ -82,13 +85,14 @@ let CodeRulesEngine = class CodeRulesEngine {
82
85
  this.frameworkTag = frameworkTag;
83
86
  this.roleTag = roleTag;
84
87
  }
85
- /** The 19 injected built-in validators, in run order. */
88
+ /** The 20 injected built-in validators, in run order. */
86
89
  builtIns() {
87
90
  return [
88
91
  this.maxMethodLines, this.maxFileLines, this.requireReturnType, this.noInlineTypeLiterals,
89
92
  this.noAnyUnknown, this.noImplicitAny, this.prismaValidateDtos, this.prismaConverter,
90
93
  this.noDestructure, this.catchErrorPattern, this.noUnmanagedExceptions, this.noDirectApiResolver,
91
- this.noSymbolDiTokens, this.noCustomCss, this.noProcessExitOutsideMain, this.noFunctionOutsideClass,
94
+ this.noSymbolDiTokens, this.noClientCreationOutsideServerOrClient, this.noCustomCss,
95
+ this.noProcessExitOutsideMain, this.noFunctionOutsideClass,
92
96
  this.injectAnnotationNotNeeded, this.frameworkTag, this.roleTag,
93
97
  ];
94
98
  }
@@ -148,6 +152,7 @@ exports.CodeRulesEngine = CodeRulesEngine = tslib_1.__decorate([
148
152
  validate_no_unmanaged_exceptions_1.NoUnmanagedExceptionsValidator,
149
153
  validate_no_direct_api_resolver_1.NoDirectApiResolverValidator,
150
154
  validate_no_symbol_di_tokens_1.NoSymbolDiTokensValidator,
155
+ validate_no_client_creation_outside_server_or_client_1.NoClientCreationOutsideServerOrClientValidator,
151
156
  validate_no_custom_css_1.NoCustomCssValidator,
152
157
  validate_no_process_exit_outside_main_1.NoProcessExitOutsideMainValidator,
153
158
  validate_no_function_outside_class_1.NoFunctionOutsideClassValidator,
@@ -1 +1 @@
1
- {"version":3,"file":"code-rules-engine.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/code-rules-engine.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseRuleConfig } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { CodeValidator, ExecutorResult, RuleRun } from './code-validator';\nimport { RuleReporter } from './rule-reporter';\nimport { WorkspaceRoot, MatchRulesHolder } from './code-rules-context';\nimport { MatchRulesChecker } from './validate-match-rules';\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 { NoCustomCssValidator } from './validate-no-custom-css';\nimport { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';\nimport { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';\nimport { InjectAnnotationNotNeededForConcreteClassValidator } from './validate-inject-annotation-not-needed-for-concrete-class';\nimport { FrameworkTagValidator } from './validate-framework-tag';\nimport { RoleTagValidator } from './validate-role-tag';\n\n/**\n * Owns running the code-rules suite. Every built-in validator is injected as a singleton (its config\n * is bound in the container at bootstrap), so this class IS the code-rules DI DAG the design graph\n * draws. The per-entry match-rules validators are the one exception — they are config-per-instance,\n * so they are built from the injected {@link MatchRulesHolder}.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class CodeRulesEngine {\n // webpieces-disable max-lines-new-methods -- the built-in validator set is flat; each is one injected field\n constructor(\n private readonly workspace: WorkspaceRoot,\n private readonly reporter: RuleReporter,\n private readonly matchRules: MatchRulesHolder,\n private readonly matchChecker: MatchRulesChecker,\n private readonly maxMethodLines: MaxMethodLinesValidator,\n private readonly maxFileLines: MaxFileLinesValidator,\n private readonly requireReturnType: RequireReturnTypeValidator,\n private readonly noInlineTypeLiterals: NoInlineTypeLiteralsValidator,\n private readonly noAnyUnknown: NoAnyUnknownValidator,\n private readonly noImplicitAny: NoImplicitAnyValidator,\n private readonly prismaValidateDtos: PrismaValidateDtosValidator,\n private readonly prismaConverter: PrismaConverterValidator,\n private readonly noDestructure: NoDestructureValidator,\n private readonly catchErrorPattern: CatchErrorPatternValidator,\n private readonly noUnmanagedExceptions: NoUnmanagedExceptionsValidator,\n private readonly noDirectApiResolver: NoDirectApiResolverValidator,\n private readonly noSymbolDiTokens: NoSymbolDiTokensValidator,\n private readonly noCustomCss: NoCustomCssValidator,\n private readonly noProcessExitOutsideMain: NoProcessExitOutsideMainValidator,\n private readonly noFunctionOutsideClass: NoFunctionOutsideClassValidator,\n private readonly injectAnnotationNotNeeded: InjectAnnotationNotNeededForConcreteClassValidator,\n private readonly frameworkTag: FrameworkTagValidator,\n private readonly roleTag: RoleTagValidator,\n ) {}\n\n /** The 19 injected built-in validators, in run order. */\n private builtIns(): CodeValidator<BaseRuleConfig>[] {\n return [\n this.maxMethodLines, this.maxFileLines, this.requireReturnType, this.noInlineTypeLiterals,\n this.noAnyUnknown, this.noImplicitAny, this.prismaValidateDtos, this.prismaConverter,\n this.noDestructure, this.catchErrorPattern, this.noUnmanagedExceptions, this.noDirectApiResolver,\n this.noSymbolDiTokens, this.noCustomCss, this.noProcessExitOutsideMain, this.noFunctionOutsideClass,\n this.injectAnnotationNotNeeded, this.frameworkTag, this.roleTag,\n ];\n }\n\n /**\n * Every ACTIVE run: an injected built-in validator whose `shouldRun()` is true, or an injected\n * match-rule check per configured entry that is active. Built as {@link RuleRun} value objects\n * (name + thunk) so NO DAG member is `new`-ed — the validators and the checker are injected.\n */\n private activeRuns(root: string): RuleRun[] {\n const runs: RuleRun[] = [];\n for (const v of this.builtIns()) {\n if (v.shouldRun()) runs.push(new RuleRun(v.name, () => v.run(root)));\n }\n for (const mr of this.matchRules.rules) {\n if (this.matchChecker.shouldRun(mr)) runs.push(new RuleRun(mr.name, () => this.matchChecker.runForConfig(mr, root)));\n }\n return runs;\n }\n\n /**\n * Run all configured code validators against the workspace. A validator runs only when\n * `shouldRun()` is true (mode not OFF and no branch/epoch escape hatch). Per-run isolation lives\n * in {@link RuleReporter} so one validator can never abort the rest.\n */\n async run(): Promise<ExecutorResult> {\n const runs = this.activeRuns(this.workspace.path);\n if (runs.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: ${runs.map((r: RuleRun) => r.name).join(', ')}`);\n console.log('');\n\n const result = await this.reporter.runValidators(runs);\n console.log(result.success ? '\\n✅ All code validations passed\\n' : '\\n❌ Some code validations failed\\n');\n return result;\n }\n}\n"]}
1
+ {"version":3,"file":"code-rules-engine.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/code-rules-engine.ts"],"names":[],"mappings":";;;;AACA,yCAA2D;AAE3D,qDAA0E;AAC1E,mDAA+C;AAC/C,6DAAuE;AACvE,iEAA2D;AAC3D,2EAAsE;AACtE,uEAAkE;AAClE,mEAAqE;AACrE,yEAA2E;AAC3E,uEAAkE;AAClE,yEAAoE;AACpE,mDAA8D;AAC9D,6EAAwE;AACxE,uEAAmE;AACnE,iFAA4E;AAC5E,yFAAoF;AACpF,uFAAiF;AACjF,iFAA2E;AAC3E,iIAAwH;AACxH,qEAAgE;AAChE,mGAA4F;AAC5F,6FAAuF;AACvF,yIAAgI;AAChI,qEAAiE;AACjE,2DAAuD;AAEvD;;;;;GAKG;AAEI,IAAM,eAAe,GAArB,MAAM,eAAe;IAGH;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IAzBrB,4GAA4G;IAC5G,YACqB,SAAwB,EACxB,QAAsB,EACtB,UAA4B,EAC5B,YAA+B,EAC/B,cAAuC,EACvC,YAAmC,EACnC,iBAA6C,EAC7C,oBAAmD,EACnD,YAAmC,EACnC,aAAqC,EACrC,kBAA+C,EAC/C,eAAyC,EACzC,aAAqC,EACrC,iBAA6C,EAC7C,qBAAqD,EACrD,mBAAiD,EACjD,gBAA2C,EAC3C,qCAAqF,EACrF,WAAiC,EACjC,wBAA2D,EAC3D,sBAAuD,EACvD,yBAA6E,EAC7E,YAAmC,EACnC,OAAyB;QAvBzB,cAAS,GAAT,SAAS,CAAe;QACxB,aAAQ,GAAR,QAAQ,CAAc;QACtB,eAAU,GAAV,UAAU,CAAkB;QAC5B,iBAAY,GAAZ,YAAY,CAAmB;QAC/B,mBAAc,GAAd,cAAc,CAAyB;QACvC,iBAAY,GAAZ,YAAY,CAAuB;QACnC,sBAAiB,GAAjB,iBAAiB,CAA4B;QAC7C,yBAAoB,GAApB,oBAAoB,CAA+B;QACnD,iBAAY,GAAZ,YAAY,CAAuB;QACnC,kBAAa,GAAb,aAAa,CAAwB;QACrC,uBAAkB,GAAlB,kBAAkB,CAA6B;QAC/C,oBAAe,GAAf,eAAe,CAA0B;QACzC,kBAAa,GAAb,aAAa,CAAwB;QACrC,sBAAiB,GAAjB,iBAAiB,CAA4B;QAC7C,0BAAqB,GAArB,qBAAqB,CAAgC;QACrD,wBAAmB,GAAnB,mBAAmB,CAA8B;QACjD,qBAAgB,GAAhB,gBAAgB,CAA2B;QAC3C,0CAAqC,GAArC,qCAAqC,CAAgD;QACrF,gBAAW,GAAX,WAAW,CAAsB;QACjC,6BAAwB,GAAxB,wBAAwB,CAAmC;QAC3D,2BAAsB,GAAtB,sBAAsB,CAAiC;QACvD,8BAAyB,GAAzB,yBAAyB,CAAoD;QAC7E,iBAAY,GAAZ,YAAY,CAAuB;QACnC,YAAO,GAAP,OAAO,CAAkB;IAC3C,CAAC;IAEJ,yDAAyD;IACjD,QAAQ;QACZ,OAAO;YACH,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,oBAAoB;YACzF,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,eAAe;YACpF,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,mBAAmB;YAChG,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,qCAAqC,EAAE,IAAI,CAAC,WAAW;YACnF,IAAI,CAAC,wBAAwB,EAAE,IAAI,CAAC,sBAAsB;YAC1D,IAAI,CAAC,yBAAyB,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO;SAClE,CAAC;IACN,CAAC;IAED;;;;OAIG;IACK,UAAU,CAAC,IAAY;QAC3B,MAAM,IAAI,GAAc,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC9B,IAAI,CAAC,CAAC,SAAS,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAO,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzE,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAO,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACzH,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAG;QACL,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC7B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC;QACzG,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ,CAAA;AA7EY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;6CAIL,kCAAa;QACd,4BAAY;QACV,qCAAgB;QACd,wCAAiB;QACf,mDAAuB;QACzB,+CAAqB;QAChB,kDAA0B;QACvB,wDAA6B;QACrC,+CAAqB;QACpB,iDAAsB;QACjB,2CAA2B;QAC9B,qDAAwB;QAC1B,gDAAsB;QAClB,yDAA0B;QACtB,iEAA8B;QAChC,8DAA4B;QAC/B,wDAAyB;QACJ,qGAA8C;QACxE,6CAAoB;QACP,yEAAiC;QACnC,oEAA+B;QAC5B,6GAAkD;QAC/D,8CAAqB;QAC1B,oCAAgB;GA1BrC,eAAe,CA6E3B","sourcesContent":["import { BaseRuleConfig } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { CodeValidator, ExecutorResult, RuleRun } from './code-validator';\nimport { RuleReporter } from './rule-reporter';\nimport { WorkspaceRoot, MatchRulesHolder } from './code-rules-context';\nimport { MatchRulesChecker } from './validate-match-rules';\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 { NoClientCreationOutsideServerOrClientValidator } from './validate-no-client-creation-outside-server-or-client';\nimport { NoCustomCssValidator } from './validate-no-custom-css';\nimport { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';\nimport { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';\nimport { InjectAnnotationNotNeededForConcreteClassValidator } from './validate-inject-annotation-not-needed-for-concrete-class';\nimport { FrameworkTagValidator } from './validate-framework-tag';\nimport { RoleTagValidator } from './validate-role-tag';\n\n/**\n * Owns running the code-rules suite. Every built-in validator is injected as a singleton (its config\n * is bound in the container at bootstrap), so this class IS the code-rules DI DAG the design graph\n * draws. The per-entry match-rules validators are the one exception — they are config-per-instance,\n * so they are built from the injected {@link MatchRulesHolder}.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class CodeRulesEngine {\n // webpieces-disable max-lines-new-methods -- the built-in validator set is flat; each is one injected field\n constructor(\n private readonly workspace: WorkspaceRoot,\n private readonly reporter: RuleReporter,\n private readonly matchRules: MatchRulesHolder,\n private readonly matchChecker: MatchRulesChecker,\n private readonly maxMethodLines: MaxMethodLinesValidator,\n private readonly maxFileLines: MaxFileLinesValidator,\n private readonly requireReturnType: RequireReturnTypeValidator,\n private readonly noInlineTypeLiterals: NoInlineTypeLiteralsValidator,\n private readonly noAnyUnknown: NoAnyUnknownValidator,\n private readonly noImplicitAny: NoImplicitAnyValidator,\n private readonly prismaValidateDtos: PrismaValidateDtosValidator,\n private readonly prismaConverter: PrismaConverterValidator,\n private readonly noDestructure: NoDestructureValidator,\n private readonly catchErrorPattern: CatchErrorPatternValidator,\n private readonly noUnmanagedExceptions: NoUnmanagedExceptionsValidator,\n private readonly noDirectApiResolver: NoDirectApiResolverValidator,\n private readonly noSymbolDiTokens: NoSymbolDiTokensValidator,\n private readonly noClientCreationOutsideServerOrClient: NoClientCreationOutsideServerOrClientValidator,\n private readonly noCustomCss: NoCustomCssValidator,\n private readonly noProcessExitOutsideMain: NoProcessExitOutsideMainValidator,\n private readonly noFunctionOutsideClass: NoFunctionOutsideClassValidator,\n private readonly injectAnnotationNotNeeded: InjectAnnotationNotNeededForConcreteClassValidator,\n private readonly frameworkTag: FrameworkTagValidator,\n private readonly roleTag: RoleTagValidator,\n ) {}\n\n /** The 20 injected built-in validators, in run order. */\n private builtIns(): CodeValidator<BaseRuleConfig>[] {\n return [\n this.maxMethodLines, this.maxFileLines, this.requireReturnType, this.noInlineTypeLiterals,\n this.noAnyUnknown, this.noImplicitAny, this.prismaValidateDtos, this.prismaConverter,\n this.noDestructure, this.catchErrorPattern, this.noUnmanagedExceptions, this.noDirectApiResolver,\n this.noSymbolDiTokens, this.noClientCreationOutsideServerOrClient, this.noCustomCss,\n this.noProcessExitOutsideMain, this.noFunctionOutsideClass,\n this.injectAnnotationNotNeeded, this.frameworkTag, this.roleTag,\n ];\n }\n\n /**\n * Every ACTIVE run: an injected built-in validator whose `shouldRun()` is true, or an injected\n * match-rule check per configured entry that is active. Built as {@link RuleRun} value objects\n * (name + thunk) so NO DAG member is `new`-ed — the validators and the checker are injected.\n */\n private activeRuns(root: string): RuleRun[] {\n const runs: RuleRun[] = [];\n for (const v of this.builtIns()) {\n if (v.shouldRun()) runs.push(new RuleRun(v.name, () => v.run(root)));\n }\n for (const mr of this.matchRules.rules) {\n if (this.matchChecker.shouldRun(mr)) runs.push(new RuleRun(mr.name, () => this.matchChecker.runForConfig(mr, root)));\n }\n return runs;\n }\n\n /**\n * Run all configured code validators against the workspace. A validator runs only when\n * `shouldRun()` is true (mode not OFF and no branch/epoch escape hatch). Per-run isolation lives\n * in {@link RuleReporter} so one validator can never abort the rest.\n */\n async run(): Promise<ExecutorResult> {\n const runs = this.activeRuns(this.workspace.path);\n if (runs.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: ${runs.map((r: RuleRun) => r.name).join(', ')}`);\n console.log('');\n\n const result = await this.reporter.runValidators(runs);\n console.log(result.success ? '\\n✅ All code validations passed\\n' : '\\n❌ Some code validations failed\\n');\n return result;\n }\n}\n"]}
package/src/index.d.ts CHANGED
@@ -11,6 +11,8 @@ 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 { NoClientCreationOutsideServerOrClientValidator } from './validate-no-client-creation-outside-server-or-client';
15
+ export { ProjectRoleResolver } from './project-role-resolver';
14
16
  export { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';
15
17
  export { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';
16
18
  export { InjectAnnotationNotNeededForConcreteClassValidator, findRedundantInjectInSource } from './validate-inject-annotation-not-needed-for-concrete-class';
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.RoleTagValidator = exports.FrameworkTagValidator = exports.findRedundantInjectInSource = exports.InjectAnnotationNotNeededForConcreteClassValidator = exports.NoFunctionOutsideClassValidator = exports.NoProcessExitOutsideMainValidator = 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.RoleTagValidator = exports.FrameworkTagValidator = exports.findRedundantInjectInSource = exports.InjectAnnotationNotNeededForConcreteClassValidator = exports.NoFunctionOutsideClassValidator = exports.NoProcessExitOutsideMainValidator = exports.ProjectRoleResolver = exports.NoClientCreationOutsideServerOrClientValidator = 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,10 @@ 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_no_client_creation_outside_server_or_client_1 = require("./validate-no-client-creation-outside-server-or-client");
33
+ Object.defineProperty(exports, "NoClientCreationOutsideServerOrClientValidator", { enumerable: true, get: function () { return validate_no_client_creation_outside_server_or_client_1.NoClientCreationOutsideServerOrClientValidator; } });
34
+ var project_role_resolver_1 = require("./project-role-resolver");
35
+ Object.defineProperty(exports, "ProjectRoleResolver", { enumerable: true, get: function () { return project_role_resolver_1.ProjectRoleResolver; } });
32
36
  var validate_no_process_exit_outside_main_1 = require("./validate-no-process-exit-outside-main");
33
37
  Object.defineProperty(exports, "NoProcessExitOutsideMainValidator", { enumerable: true, get: function () { return validate_no_process_exit_outside_main_1.NoProcessExitOutsideMainValidator; } });
34
38
  var validate_no_function_outside_class_1 = require("./validate-no-function-outside-class");
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,iGAA4F;AAAnF,0JAAA,iCAAiC,OAAA;AAC1C,2FAAuF;AAA9E,qJAAA,+BAA+B,OAAA;AACxC,uIAA6J;AAApJ,8LAAA,kDAAkD,OAAA;AAAE,uKAAA,2BAA2B,OAAA;AACxF,mEAAiE;AAAxD,+HAAA,qBAAqB,OAAA;AAC9B,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,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 { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';\nexport { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';\nexport { InjectAnnotationNotNeededForConcreteClassValidator, findRedundantInjectInSource } from './validate-inject-annotation-not-needed-for-concrete-class';\nexport { FrameworkTagValidator } from './validate-framework-tag';\nexport { RoleTagValidator } from './validate-role-tag';\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,+HAAwH;AAA/G,sLAAA,8CAA8C,OAAA;AACvD,iEAA8D;AAArD,4HAAA,mBAAmB,OAAA;AAC5B,iGAA4F;AAAnF,0JAAA,iCAAiC,OAAA;AAC1C,2FAAuF;AAA9E,qJAAA,+BAA+B,OAAA;AACxC,uIAA6J;AAApJ,8LAAA,kDAAkD,OAAA;AAAE,uKAAA,2BAA2B,OAAA;AACxF,mEAAiE;AAAxD,+HAAA,qBAAqB,OAAA;AAC9B,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,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 { NoClientCreationOutsideServerOrClientValidator } from './validate-no-client-creation-outside-server-or-client';\nexport { ProjectRoleResolver } from './project-role-resolver';\nexport { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';\nexport { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';\nexport { InjectAnnotationNotNeededForConcreteClassValidator, findRedundantInjectInSource } from './validate-inject-annotation-not-needed-for-concrete-class';\nexport { FrameworkTagValidator } from './validate-framework-tag';\nexport { RoleTagValidator } from './validate-role-tag';\nexport { PrismaValidateDtosValidator } from './validate-dtos';\nexport { PrismaConverterValidator } from './validate-prisma-converters';\nexport { default as validateCode } from './validate-code';\n"]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Resolves the `role:` nx tag VALUE of the project owning a given source file.
3
+ *
4
+ * The role-tag rule ({@link ../tag-rule}) only checks a `role:` tag is PRESENT; a few rules
5
+ * (e.g. no-client-creation-outside-server-or-client) additionally need the tag's VALUE to decide
6
+ * whether a construct is allowed in that kind of project. This is the single home for that lookup:
7
+ * walk up from the file to its nearest `project.json`, read its `tags`, and return the first
8
+ * `role:<value>` value (or null when the file belongs to no project, or its project carries no role).
9
+ *
10
+ * Injectable so it composes into the code-rules DI DAG and can be shared by any validator.
11
+ */
12
+ export declare class ProjectRoleResolver {
13
+ /** The `role:` value of the project owning `relFile`, or null when unknown/untagged. */
14
+ roleOf(workspaceRoot: string, relFile: string): string | null;
15
+ /** Nearest ancestor directory of `relFile` that holds a project.json (repo-relative), or null. */
16
+ private findOwningProjectJson;
17
+ /** First `role:<value>` tag value in a project.json, or null. Never throws — a malformed
18
+ * project.json is the role-tag rule's concern, not this resolver's. */
19
+ private readRole;
20
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Resolves the `role:` nx tag VALUE of the project owning a given source file.
4
+ *
5
+ * The role-tag rule ({@link ../tag-rule}) only checks a `role:` tag is PRESENT; a few rules
6
+ * (e.g. no-client-creation-outside-server-or-client) additionally need the tag's VALUE to decide
7
+ * whether a construct is allowed in that kind of project. This is the single home for that lookup:
8
+ * walk up from the file to its nearest `project.json`, read its `tags`, and return the first
9
+ * `role:<value>` value (or null when the file belongs to no project, or its project carries no role).
10
+ *
11
+ * Injectable so it composes into the code-rules DI DAG and can be shared by any validator.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.ProjectRoleResolver = void 0;
15
+ const tslib_1 = require("tslib");
16
+ const fs = tslib_1.__importStar(require("fs"));
17
+ const path = tslib_1.__importStar(require("path"));
18
+ const rules_config_1 = require("@webpieces/rules-config");
19
+ const inversify_1 = require("inversify");
20
+ const ROLE_TAG_PREFIX = 'role:';
21
+ let ProjectRoleResolver = class ProjectRoleResolver {
22
+ /** The `role:` value of the project owning `relFile`, or null when unknown/untagged. */
23
+ roleOf(workspaceRoot, relFile) {
24
+ const projectJsonPath = this.findOwningProjectJson(workspaceRoot, relFile);
25
+ if (projectJsonPath === null)
26
+ return null;
27
+ return this.readRole(path.join(workspaceRoot, projectJsonPath));
28
+ }
29
+ /** Nearest ancestor directory of `relFile` that holds a project.json (repo-relative), or null. */
30
+ findOwningProjectJson(workspaceRoot, relFile) {
31
+ let dir = path.dirname(relFile);
32
+ while (true) {
33
+ const candidate = path.join(dir, 'project.json');
34
+ if (fs.existsSync(path.join(workspaceRoot, candidate))) {
35
+ return candidate;
36
+ }
37
+ const parent = path.dirname(dir);
38
+ if (parent === dir || dir === '.' || dir === '') {
39
+ return null;
40
+ }
41
+ dir = parent;
42
+ }
43
+ }
44
+ /** First `role:<value>` tag value in a project.json, or null. Never throws — a malformed
45
+ * project.json is the role-tag rule's concern, not this resolver's. */
46
+ readRole(fullPath) {
47
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
48
+ try {
49
+ const parsed = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));
50
+ const tags = Array.isArray(parsed.tags) ? parsed.tags : [];
51
+ for (const tag of tags) {
52
+ if (typeof tag !== 'string' || !tag.startsWith(ROLE_TAG_PREFIX))
53
+ continue;
54
+ const value = tag.slice(ROLE_TAG_PREFIX.length).trim();
55
+ if (value.length > 0)
56
+ return value;
57
+ }
58
+ return null;
59
+ }
60
+ catch (err) {
61
+ const error = (0, rules_config_1.toError)(err);
62
+ void error; // swallow — malformed project.json is not this resolver's concern
63
+ return null;
64
+ }
65
+ }
66
+ };
67
+ exports.ProjectRoleResolver = ProjectRoleResolver;
68
+ exports.ProjectRoleResolver = ProjectRoleResolver = tslib_1.__decorate([
69
+ (0, inversify_1.injectable)(inversify_1.bindingScopeValues.Singleton)
70
+ ], ProjectRoleResolver);
71
+ //# sourceMappingURL=project-role-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-role-resolver.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/project-role-resolver.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;AAEH,+CAAyB;AACzB,mDAA6B;AAC7B,0DAAkD;AAClD,yCAA2D;AAE3D,MAAM,eAAe,GAAG,OAAO,CAAC;AAMzB,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC5B,wFAAwF;IACxF,MAAM,CAAC,aAAqB,EAAE,OAAe;QACzC,MAAM,eAAe,GAAG,IAAI,CAAC,qBAAqB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC3E,IAAI,eAAe,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,kGAAkG;IAC1F,qBAAqB,CAAC,aAAqB,EAAE,OAAe;QAChE,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,OAAO,IAAI,EAAE,CAAC;YACV,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YACjD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;gBACrD,OAAO,SAAS,CAAC;YACrB,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,MAAM,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;gBAC9C,OAAO,IAAI,CAAC;YAChB,CAAC;YACD,GAAG,GAAG,MAAM,CAAC;QACjB,CAAC;IACL,CAAC;IAED;4EACwE;IAChE,QAAQ,CAAC,QAAgB;QAC7B,8DAA8D;QAC9D,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAmB,CAAC;YAChF,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACrB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC;oBAAE,SAAS;gBAC1E,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;gBACvD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO,KAAK,CAAC;YACvC,CAAC;YACD,OAAO,IAAI,CAAC;QAChB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,sBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,KAAK,KAAK,CAAC,CAAC,kEAAkE;YAC9E,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;CACJ,CAAA;AA3CY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;GAC5B,mBAAmB,CA2C/B","sourcesContent":["/**\n * Resolves the `role:` nx tag VALUE of the project owning a given source file.\n *\n * The role-tag rule ({@link ../tag-rule}) only checks a `role:` tag is PRESENT; a few rules\n * (e.g. no-client-creation-outside-server-or-client) additionally need the tag's VALUE to decide\n * whether a construct is allowed in that kind of project. This is the single home for that lookup:\n * walk up from the file to its nearest `project.json`, read its `tags`, and return the first\n * `role:<value>` value (or null when the file belongs to no project, or its project carries no role).\n *\n * Injectable so it composes into the code-rules DI DAG and can be shared by any validator.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { toError } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nconst ROLE_TAG_PREFIX = 'role:';\n\n/** The only field of a project.json this resolver reads. */\ntype RawProjectJson = { tags?: string[] };\n\n@injectable(bindingScopeValues.Singleton)\nexport class ProjectRoleResolver {\n /** The `role:` value of the project owning `relFile`, or null when unknown/untagged. */\n roleOf(workspaceRoot: string, relFile: string): string | null {\n const projectJsonPath = this.findOwningProjectJson(workspaceRoot, relFile);\n if (projectJsonPath === null) return null;\n return this.readRole(path.join(workspaceRoot, projectJsonPath));\n }\n\n /** Nearest ancestor directory of `relFile` that holds a project.json (repo-relative), or null. */\n private findOwningProjectJson(workspaceRoot: string, relFile: string): string | null {\n let dir = path.dirname(relFile);\n while (true) {\n const candidate = path.join(dir, 'project.json');\n if (fs.existsSync(path.join(workspaceRoot, candidate))) {\n return candidate;\n }\n const parent = path.dirname(dir);\n if (parent === dir || dir === '.' || dir === '') {\n return null;\n }\n dir = parent;\n }\n }\n\n /** First `role:<value>` tag value in a project.json, or null. Never throws — a malformed\n * project.json is the role-tag rule's concern, not this resolver's. */\n private readRole(fullPath: string): string | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const parsed = JSON.parse(fs.readFileSync(fullPath, 'utf-8')) as RawProjectJson;\n const tags = Array.isArray(parsed.tags) ? parsed.tags : [];\n for (const tag of tags) {\n if (typeof tag !== 'string' || !tag.startsWith(ROLE_TAG_PREFIX)) continue;\n const value = tag.slice(ROLE_TAG_PREFIX.length).trim();\n if (value.length > 0) return value;\n }\n return null;\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — malformed project.json is not this resolver's concern\n return null;\n }\n }\n}\n"]}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Validate No Client Creation Outside Server Or Client
3
+ *
4
+ * Flags a project that CONSTRUCTS an rpc/pubsub transport client when the project's `role:` tag is
5
+ * not one of the runnable/entrypoint roles (`allowedRoles`, default server | client | app).
6
+ *
7
+ * ============================================================================
8
+ * WHY
9
+ * ============================================================================
10
+ * The runtime architecture graph draws a `uses` edge from every client-creation site to the api's
11
+ * implementer. When the site sits in a project with a declared identity (`serviceName`) or target
12
+ * (`callsService`) — a server, a client app, an app — the edge is attributable. When it sits in a
13
+ * `role:lib`, the target can't be attributed, so the graph falls back to a fan-out: one `uses` edge
14
+ * to EVERY implementer of the api, i.e. calls that cannot happen. A company-wide api (warmup,
15
+ * browser-log, auth) then draws every caller to every server — pure fiction. This rule removes the
16
+ * failure mode by construction: a reusable library takes the api INJECTED; the server/app module
17
+ * binds it to a client.
18
+ *
19
+ * ============================================================================
20
+ * VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:
21
+ * ============================================================================
22
+ * factory.createRpcClient(SomeApi, new ClientConfig('svc'))
23
+ * clientCloudTasksFactory.createPubSubClient(SomeApi, config)
24
+ *
25
+ * ============================================================================
26
+ * ALLOWED
27
+ * ============================================================================
28
+ * - Any site in a project whose role IS in allowedRoles (server / client / app).
29
+ * - A project with NO `role:` tag (the role-tag rule owns "every project must declare a role").
30
+ * - Merely IMPORTING the api type or its DI token, or injecting the api — only constructing the
31
+ * transport (a `.createRpcClient(` / `.createPubSubClient(` CALL) is a violation.
32
+ * - Files under allowedPaths, test files, and lines carrying the webpieces-disable escape.
33
+ *
34
+ * ============================================================================
35
+ * SEVERITY (WARN first, then error)
36
+ * ============================================================================
37
+ * severity "warn" (default) prints the violations + migration but PASSES the build, so an upgrade
38
+ * can't break an un-migrated Angular repo. Flip to "error" once libraries are migrated.
39
+ */
40
+ import { NoClientCreationOutsideServerOrClientConfig } from '@webpieces/rules-config';
41
+ import { CodeValidator, ExecutorResult } from './code-validator';
42
+ import { ProjectRoleResolver } from './project-role-resolver';
43
+ export declare class NoClientCreationOutsideServerOrClientValidator extends CodeValidator<NoClientCreationOutsideServerOrClientConfig> {
44
+ private readonly roleResolver;
45
+ constructor(config: NoClientCreationOutsideServerOrClientConfig, roleResolver: ProjectRoleResolver);
46
+ run(workspaceRoot: string): Promise<ExecutorResult>;
47
+ private allowedRoles;
48
+ private disableAllowed;
49
+ private allowedPaths;
50
+ private resolveMode;
51
+ private resolveBase;
52
+ /** Violations across changed files: a creation site in a project whose role is not allowed. In
53
+ * NEW_AND_MODIFIED_CODE only sites on changed lines count; in NEW_AND_MODIFIED_FILES every site
54
+ * in a changed file counts. */
55
+ private findViolations;
56
+ private isExempt;
57
+ private isTestFile;
58
+ /** Every client-creation call site in a file, ignoring occurrences inside comments. */
59
+ private scanFile;
60
+ /** The code-only text of each line: block comments (/* … *\/) and line comments (// …) blanked
61
+ * out, so a `factory.createRpcClient(` in a JSDoc example is never matched. */
62
+ private stripComments;
63
+ private report;
64
+ }
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ /**
3
+ * Validate No Client Creation Outside Server Or Client
4
+ *
5
+ * Flags a project that CONSTRUCTS an rpc/pubsub transport client when the project's `role:` tag is
6
+ * not one of the runnable/entrypoint roles (`allowedRoles`, default server | client | app).
7
+ *
8
+ * ============================================================================
9
+ * WHY
10
+ * ============================================================================
11
+ * The runtime architecture graph draws a `uses` edge from every client-creation site to the api's
12
+ * implementer. When the site sits in a project with a declared identity (`serviceName`) or target
13
+ * (`callsService`) — a server, a client app, an app — the edge is attributable. When it sits in a
14
+ * `role:lib`, the target can't be attributed, so the graph falls back to a fan-out: one `uses` edge
15
+ * to EVERY implementer of the api, i.e. calls that cannot happen. A company-wide api (warmup,
16
+ * browser-log, auth) then draws every caller to every server — pure fiction. This rule removes the
17
+ * failure mode by construction: a reusable library takes the api INJECTED; the server/app module
18
+ * binds it to a client.
19
+ *
20
+ * ============================================================================
21
+ * VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:
22
+ * ============================================================================
23
+ * factory.createRpcClient(SomeApi, new ClientConfig('svc'))
24
+ * clientCloudTasksFactory.createPubSubClient(SomeApi, config)
25
+ *
26
+ * ============================================================================
27
+ * ALLOWED
28
+ * ============================================================================
29
+ * - Any site in a project whose role IS in allowedRoles (server / client / app).
30
+ * - A project with NO `role:` tag (the role-tag rule owns "every project must declare a role").
31
+ * - Merely IMPORTING the api type or its DI token, or injecting the api — only constructing the
32
+ * transport (a `.createRpcClient(` / `.createPubSubClient(` CALL) is a violation.
33
+ * - Files under allowedPaths, test files, and lines carrying the webpieces-disable escape.
34
+ *
35
+ * ============================================================================
36
+ * SEVERITY (WARN first, then error)
37
+ * ============================================================================
38
+ * severity "warn" (default) prints the violations + migration but PASSES the build, so an upgrade
39
+ * can't break an un-migrated Angular repo. Flip to "error" once libraries are migrated.
40
+ */
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.NoClientCreationOutsideServerOrClientValidator = void 0;
43
+ const tslib_1 = require("tslib");
44
+ const fs = tslib_1.__importStar(require("fs"));
45
+ const path = tslib_1.__importStar(require("path"));
46
+ const rules_config_1 = require("@webpieces/rules-config");
47
+ const code_validator_1 = require("./code-validator");
48
+ const inversify_1 = require("inversify");
49
+ const resolve_mode_1 = require("./resolve-mode");
50
+ const project_role_resolver_1 = require("./project-role-resolver");
51
+ const RULE_NAME = rules_config_1.RULE_NAMES.NO_CLIENT_CREATION_OUTSIDE_SERVER_OR_CLIENT;
52
+ const DEFAULT_ALLOWED_ROLES = ['server', 'client', 'app'];
53
+ // A `.createRpcClient(` / `.createPubSubClient(` method CALL — the leading dot excludes the framework
54
+ // method DEFINITIONS (`createRpcClient<T>(apiPrototype, ...)`, no receiver); the `[(<]` requires a call
55
+ // or a generic call, so a bare property reference isn't matched.
56
+ const CLIENT_CREATE_REGEX = /\.(createRpcClient|createPubSubClient)\s*[(<]/;
57
+ /** One client-creation call site found in a file. */
58
+ class CreationSite {
59
+ line;
60
+ context;
61
+ hasDisableComment;
62
+ constructor(line, context, hasDisableComment) {
63
+ this.line = line;
64
+ this.context = context;
65
+ this.hasDisableComment = hasDisableComment;
66
+ }
67
+ }
68
+ /** A reported violation: a client-creation site in a project whose role is not allowed. */
69
+ class Violation {
70
+ file;
71
+ line;
72
+ context;
73
+ role;
74
+ constructor(file, line, context, role) {
75
+ this.file = file;
76
+ this.line = line;
77
+ this.context = context;
78
+ this.role = role;
79
+ }
80
+ }
81
+ let NoClientCreationOutsideServerOrClientValidator = class NoClientCreationOutsideServerOrClientValidator extends code_validator_1.CodeValidator {
82
+ roleResolver;
83
+ constructor(config, roleResolver) {
84
+ super(config, RULE_NAME);
85
+ this.roleResolver = roleResolver;
86
+ }
87
+ async run(workspaceRoot) {
88
+ const mode = this.resolveMode(this.config.mode ?? 'OFF');
89
+ if (mode === 'OFF') {
90
+ console.log(`\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)`);
91
+ console.log('');
92
+ return { success: true };
93
+ }
94
+ const severity = this.config.severity ?? 'warn';
95
+ console.log(`\n📏 Validating No Client Creation Outside Server Or Client\n`);
96
+ console.log(` Mode: ${mode} · Severity: ${severity}`);
97
+ const base = this.resolveBase(workspaceRoot);
98
+ if (base === null)
99
+ return { success: true };
100
+ const head = process.env['NX_HEAD'];
101
+ console.log(` Base: ${base}`);
102
+ console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
103
+ console.log('');
104
+ const changedFiles = (0, rules_config_1.getChangedFiles)(workspaceRoot, base, head);
105
+ if (changedFiles.length === 0) {
106
+ console.log('✅ No TypeScript files changed');
107
+ return { success: true };
108
+ }
109
+ console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
110
+ const violations = this.findViolations(workspaceRoot, changedFiles, mode, base, head);
111
+ if (violations.length === 0) {
112
+ console.log('✅ No client-creation-in-a-library violations found');
113
+ return { success: true };
114
+ }
115
+ this.report(violations, severity);
116
+ // WARN reports but passes; only "error" fails the build.
117
+ return { success: severity !== 'error' };
118
+ }
119
+ allowedRoles() {
120
+ const configured = this.config.allowedRoles;
121
+ return configured && configured.length > 0 ? configured : DEFAULT_ALLOWED_ROLES;
122
+ }
123
+ disableAllowed() {
124
+ return this.config.disableAllowed ?? true;
125
+ }
126
+ allowedPaths() {
127
+ return this.config.allowedPaths ?? [];
128
+ }
129
+ resolveMode(normalMode) {
130
+ if (normalMode === 'OFF')
131
+ return normalMode;
132
+ const skip = (0, resolve_mode_1.shouldSkipRule)(this.config.ignoreModifiedUntilEpoch, this.config.ignoreRuleWhileOnBranch);
133
+ if (skip.skip) {
134
+ console.log(`\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})`);
135
+ console.log('');
136
+ return 'OFF';
137
+ }
138
+ return normalMode;
139
+ }
140
+ resolveBase(workspaceRoot) {
141
+ const envBase = process.env['NX_BASE'];
142
+ if (envBase)
143
+ return envBase;
144
+ const detected = (0, rules_config_1.detectBase)(workspaceRoot);
145
+ if (!detected) {
146
+ console.log(`\n⏭️ Skipping ${RULE_NAME} validation (could not detect base branch)`);
147
+ console.log('');
148
+ return null;
149
+ }
150
+ return detected;
151
+ }
152
+ /** Violations across changed files: a creation site in a project whose role is not allowed. In
153
+ * NEW_AND_MODIFIED_CODE only sites on changed lines count; in NEW_AND_MODIFIED_FILES every site
154
+ * in a changed file counts. */
155
+ findViolations(workspaceRoot, changedFiles, mode, base, head) {
156
+ const allowed = new Set(this.allowedRoles());
157
+ const violations = [];
158
+ for (const file of changedFiles) {
159
+ if (this.isExempt(file))
160
+ continue;
161
+ const role = this.roleResolver.roleOf(workspaceRoot, file);
162
+ // No role tag → role-tag rule owns it; an allowed role → fine. Either way, skip.
163
+ if (role === null || allowed.has(role))
164
+ continue;
165
+ const changedLines = mode === 'NEW_AND_MODIFIED_CODE'
166
+ ? (0, rules_config_1.getChangedLineNumbers)((0, rules_config_1.getFileDiff)(workspaceRoot, file, base, head))
167
+ : null;
168
+ if (changedLines !== null && changedLines.size === 0)
169
+ continue;
170
+ for (const site of this.scanFile(workspaceRoot, file)) {
171
+ if (this.disableAllowed() && site.hasDisableComment)
172
+ continue;
173
+ if (changedLines !== null && !changedLines.has(site.line))
174
+ continue;
175
+ violations.push(new Violation(file, site.line, site.context, role));
176
+ }
177
+ }
178
+ return violations;
179
+ }
180
+ isExempt(file) {
181
+ return this.isTestFile(file) || (0, rules_config_1.isPathExcluded)(file, this.allowedPaths());
182
+ }
183
+ isTestFile(filePath) {
184
+ return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');
185
+ }
186
+ /** Every client-creation call site in a file, ignoring occurrences inside comments. */
187
+ scanFile(workspaceRoot, relFile) {
188
+ const fullPath = path.join(workspaceRoot, relFile);
189
+ if (!fs.existsSync(fullPath))
190
+ return [];
191
+ const lines = fs.readFileSync(fullPath, 'utf-8').split('\n');
192
+ const code = this.stripComments(lines);
193
+ const sites = [];
194
+ for (let i = 0; i < code.length; i++) {
195
+ if (!CLIENT_CREATE_REGEX.test(code[i] ?? ''))
196
+ continue;
197
+ const raw = lines[i] ?? '';
198
+ const prev = i > 0 ? (lines[i - 1] ?? '') : '';
199
+ const disabled = (0, rules_config_1.hasDisable)(raw, RULE_NAME) || (0, rules_config_1.hasDisable)(prev, RULE_NAME);
200
+ sites.push(new CreationSite(i + 1, raw.trim(), disabled));
201
+ }
202
+ return sites;
203
+ }
204
+ /** The code-only text of each line: block comments (/* … *\/) and line comments (// …) blanked
205
+ * out, so a `factory.createRpcClient(` in a JSDoc example is never matched. */
206
+ stripComments(lines) {
207
+ const out = [];
208
+ let inBlock = false;
209
+ for (const line of lines) {
210
+ let result = '';
211
+ let i = 0;
212
+ while (i < line.length) {
213
+ if (inBlock) {
214
+ if (line[i] === '*' && line[i + 1] === '/') {
215
+ inBlock = false;
216
+ i += 2;
217
+ }
218
+ else {
219
+ i += 1;
220
+ }
221
+ continue;
222
+ }
223
+ if (line[i] === '/' && line[i + 1] === '*') {
224
+ inBlock = true;
225
+ i += 2;
226
+ continue;
227
+ }
228
+ if (line[i] === '/' && line[i + 1] === '/')
229
+ break;
230
+ result += line[i];
231
+ i += 1;
232
+ }
233
+ out.push(result);
234
+ }
235
+ return out;
236
+ }
237
+ // webpieces-disable max-lines-new-methods -- console guidance block + violation list
238
+ report(violations, severity) {
239
+ const icon = severity === 'error' ? '❌' : '⚠️';
240
+ console.error('');
241
+ console.error(`${icon} A library (role:lib) must NOT construct an rpc/pubsub client!`);
242
+ console.error('');
243
+ console.error(' Only a runnable entrypoint (role:server / role:client / role:app) has a declared identity');
244
+ console.error(' (serviceName) or target (callsService), so a client built there is attributable in the');
245
+ console.error(' runtime graph. A client built in a library reaches the fan-out fallback — one "uses" edge');
246
+ console.error(' to EVERY implementer of the api, i.e. calls that cannot happen.');
247
+ console.error('');
248
+ console.error(' Migrate: the library takes the api INJECTED (constructor(private readonly api: SomeApi)),');
249
+ console.error(' and the server/app DI module constructs the client with factory.createRpcClient(SomeApi, ...).');
250
+ console.error('');
251
+ for (const v of violations) {
252
+ console.error(` ${icon} ${v.file}:${v.line} (role:${v.role})`);
253
+ console.error(` ${v.context}`);
254
+ }
255
+ console.error('');
256
+ if (this.disableAllowed()) {
257
+ console.error(' Escape hatch (use sparingly):');
258
+ console.error(` // webpieces-disable ${RULE_NAME} -- <reason>`);
259
+ }
260
+ else {
261
+ console.error(' Escape hatch: DISABLED (disableAllowed: false)');
262
+ }
263
+ console.error('');
264
+ if (severity !== 'error') {
265
+ console.error(' Severity: WARN — reported but NOT failing the build. Migrate, then set');
266
+ console.error(` "severity": "error" on ${RULE_NAME} to enforce.`);
267
+ console.error('');
268
+ }
269
+ }
270
+ };
271
+ exports.NoClientCreationOutsideServerOrClientValidator = NoClientCreationOutsideServerOrClientValidator;
272
+ exports.NoClientCreationOutsideServerOrClientValidator = NoClientCreationOutsideServerOrClientValidator = tslib_1.__decorate([
273
+ (0, inversify_1.injectable)(inversify_1.bindingScopeValues.Singleton),
274
+ tslib_1.__metadata("design:paramtypes", [rules_config_1.NoClientCreationOutsideServerOrClientConfig,
275
+ project_role_resolver_1.ProjectRoleResolver])
276
+ ], NoClientCreationOutsideServerOrClientValidator);
277
+ //# sourceMappingURL=validate-no-client-creation-outside-server-or-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-no-client-creation-outside-server-or-client.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-client-creation-outside-server-or-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Client Creation Outside Server Or Client\n *\n * Flags a project that CONSTRUCTS an rpc/pubsub transport client when the project's `role:` tag is\n * not one of the runnable/entrypoint roles (`allowedRoles`, default server | client | app).\n *\n * ============================================================================\n * WHY\n * ============================================================================\n * The runtime architecture graph draws a `uses` edge from every client-creation site to the api's\n * implementer. When the site sits in a project with a declared identity (`serviceName`) or target\n * (`callsService`) — a server, a client app, an app — the edge is attributable. When it sits in a\n * `role:lib`, the target can't be attributed, so the graph falls back to a fan-out: one `uses` edge\n * to EVERY implementer of the api, i.e. calls that cannot happen. A company-wide api (warmup,\n * browser-log, auth) then draws every caller to every server — pure fiction. This rule removes the\n * failure mode by construction: a reusable library takes the api INJECTED; the server/app module\n * binds it to a client.\n *\n * ============================================================================\n * VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:\n * ============================================================================\n * factory.createRpcClient(SomeApi, new ClientConfig('svc'))\n * clientCloudTasksFactory.createPubSubClient(SomeApi, config)\n *\n * ============================================================================\n * ALLOWED\n * ============================================================================\n * - Any site in a project whose role IS in allowedRoles (server / client / app).\n * - A project with NO `role:` tag (the role-tag rule owns \"every project must declare a role\").\n * - Merely IMPORTING the api type or its DI token, or injecting the api — only constructing the\n * transport (a `.createRpcClient(` / `.createPubSubClient(` CALL) is a violation.\n * - Files under allowedPaths, test files, and lines carrying the webpieces-disable escape.\n *\n * ============================================================================\n * SEVERITY (WARN first, then error)\n * ============================================================================\n * severity \"warn\" (default) prints the violations + migration but PASSES the build, so an upgrade\n * can't break an un-migrated Angular repo. Flip to \"error\" once libraries are migrated.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n RULE_NAMES,\n isPathExcluded,\n NoClientCreationOutsideServerOrClientConfig,\n ClientCreationSeverity,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\nimport { ProjectRoleResolver } from './project-role-resolver';\n\nconst RULE_NAME = RULE_NAMES.NO_CLIENT_CREATION_OUTSIDE_SERVER_OR_CLIENT;\nconst DEFAULT_ALLOWED_ROLES = ['server', 'client', 'app'];\n// A `.createRpcClient(` / `.createPubSubClient(` method CALL — the leading dot excludes the framework\n// method DEFINITIONS (`createRpcClient<T>(apiPrototype, ...)`, no receiver); the `[(<]` requires a call\n// or a generic call, so a bare property reference isn't matched.\nconst CLIENT_CREATE_REGEX = /\\.(createRpcClient|createPubSubClient)\\s*[(<]/;\n\n/** One client-creation call site found in a file. */\nclass CreationSite {\n constructor(\n public readonly line: number,\n public readonly context: string,\n public readonly hasDisableComment: boolean,\n ) {}\n}\n\n/** A reported violation: a client-creation site in a project whose role is not allowed. */\nclass Violation {\n constructor(\n public readonly file: string,\n public readonly line: number,\n public readonly context: string,\n public readonly role: string,\n ) {}\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoClientCreationOutsideServerOrClientValidator extends CodeValidator<NoClientCreationOutsideServerOrClientConfig> {\n constructor(\n config: NoClientCreationOutsideServerOrClientConfig,\n private readonly roleResolver: ProjectRoleResolver,\n ) {\n super(config, RULE_NAME);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(this.config.mode ?? 'OFF');\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)`);\n console.log('');\n return { success: true };\n }\n\n const severity: ClientCreationSeverity = this.config.severity ?? 'warn';\n console.log(`\\n📏 Validating No Client Creation Outside Server Or Client\\n`);\n console.log(` Mode: ${mode} · Severity: ${severity}`);\n\n const base = this.resolveBase(workspaceRoot);\n if (base === null) return { success: true };\n const head = process.env['NX_HEAD'];\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 const violations = this.findViolations(workspaceRoot, changedFiles, mode, base, head);\n\n if (violations.length === 0) {\n console.log('✅ No client-creation-in-a-library violations found');\n return { success: true };\n }\n\n this.report(violations, severity);\n // WARN reports but passes; only \"error\" fails the build.\n return { success: severity !== 'error' };\n }\n\n private allowedRoles(): string[] {\n const configured = this.config.allowedRoles;\n return configured && configured.length > 0 ? configured : DEFAULT_ALLOWED_ROLES;\n }\n\n private disableAllowed(): boolean {\n return this.config.disableAllowed ?? true;\n }\n\n private allowedPaths(): string[] {\n return this.config.allowedPaths ?? [];\n }\n\n private resolveMode(normalMode: ModifiedCodeMode): ModifiedCodeMode {\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(this.config.ignoreModifiedUntilEpoch, this.config.ignoreRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n }\n\n private resolveBase(workspaceRoot: string): string | null {\n const envBase = process.env['NX_BASE'];\n if (envBase) return envBase;\n const detected = detectBase(workspaceRoot);\n if (!detected) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (could not detect base branch)`);\n console.log('');\n return null;\n }\n return detected;\n }\n\n /** Violations across changed files: a creation site in a project whose role is not allowed. In\n * NEW_AND_MODIFIED_CODE only sites on changed lines count; in NEW_AND_MODIFIED_FILES every site\n * in a changed file counts. */\n private findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n mode: ModifiedCodeMode,\n base: string,\n head: string | undefined,\n ): Violation[] {\n const allowed = new Set(this.allowedRoles());\n const violations: Violation[] = [];\n for (const file of changedFiles) {\n if (this.isExempt(file)) continue;\n\n const role = this.roleResolver.roleOf(workspaceRoot, file);\n // No role tag → role-tag rule owns it; an allowed role → fine. Either way, skip.\n if (role === null || allowed.has(role)) continue;\n\n const changedLines = mode === 'NEW_AND_MODIFIED_CODE'\n ? getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head))\n : null;\n if (changedLines !== null && changedLines.size === 0) continue;\n\n for (const site of this.scanFile(workspaceRoot, file)) {\n if (this.disableAllowed() && site.hasDisableComment) continue;\n if (changedLines !== null && !changedLines.has(site.line)) continue;\n violations.push(new Violation(file, site.line, site.context, role));\n }\n }\n return violations;\n }\n\n private isExempt(file: string): boolean {\n return this.isTestFile(file) || isPathExcluded(file, this.allowedPaths());\n }\n\n private isTestFile(filePath: string): boolean {\n return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');\n }\n\n /** Every client-creation call site in a file, ignoring occurrences inside comments. */\n private scanFile(workspaceRoot: string, relFile: string): CreationSite[] {\n const fullPath = path.join(workspaceRoot, relFile);\n if (!fs.existsSync(fullPath)) return [];\n const lines = fs.readFileSync(fullPath, 'utf-8').split('\\n');\n const code = this.stripComments(lines);\n\n const sites: CreationSite[] = [];\n for (let i = 0; i < code.length; i++) {\n if (!CLIENT_CREATE_REGEX.test(code[i] ?? '')) continue;\n const raw = lines[i] ?? '';\n const prev = i > 0 ? (lines[i - 1] ?? '') : '';\n const disabled = hasDisable(raw, RULE_NAME) || hasDisable(prev, RULE_NAME);\n sites.push(new CreationSite(i + 1, raw.trim(), disabled));\n }\n return sites;\n }\n\n /** The code-only text of each line: block comments (/* … *\\/) and line comments (// …) blanked\n * out, so a `factory.createRpcClient(` in a JSDoc example is never matched. */\n private stripComments(lines: string[]): string[] {\n const out: string[] = [];\n let inBlock = false;\n for (const line of lines) {\n let result = '';\n let i = 0;\n while (i < line.length) {\n if (inBlock) {\n if (line[i] === '*' && line[i + 1] === '/') { inBlock = false; i += 2; } else { i += 1; }\n continue;\n }\n if (line[i] === '/' && line[i + 1] === '*') { inBlock = true; i += 2; continue; }\n if (line[i] === '/' && line[i + 1] === '/') break;\n result += line[i];\n i += 1;\n }\n out.push(result);\n }\n return out;\n }\n\n // webpieces-disable max-lines-new-methods -- console guidance block + violation list\n private report(violations: Violation[], severity: ClientCreationSeverity): void {\n const icon = severity === 'error' ? '❌' : '⚠️';\n console.error('');\n console.error(`${icon} A library (role:lib) must NOT construct an rpc/pubsub client!`);\n console.error('');\n console.error(' Only a runnable entrypoint (role:server / role:client / role:app) has a declared identity');\n console.error(' (serviceName) or target (callsService), so a client built there is attributable in the');\n console.error(' runtime graph. A client built in a library reaches the fan-out fallback — one \"uses\" edge');\n console.error(' to EVERY implementer of the api, i.e. calls that cannot happen.');\n console.error('');\n console.error(' Migrate: the library takes the api INJECTED (constructor(private readonly api: SomeApi)),');\n console.error(' and the server/app DI module constructs the client with factory.createRpcClient(SomeApi, ...).');\n console.error('');\n for (const v of violations) {\n console.error(` ${icon} ${v.file}:${v.line} (role:${v.role})`);\n console.error(` ${v.context}`);\n }\n console.error('');\n if (this.disableAllowed()) {\n console.error(' Escape hatch (use sparingly):');\n console.error(` // webpieces-disable ${RULE_NAME} -- <reason>`);\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n }\n console.error('');\n if (severity !== 'error') {\n console.error(' Severity: WARN — reported but NOT failing the build. Migrate, then set');\n console.error(` \"severity\": \"error\" on ${RULE_NAME} to enforce.`);\n console.error('');\n }\n }\n}\n"]}