@webpieces/code-rules 0.4.490 → 0.4.492
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 +2 -2
- package/src/tag-rule.d.ts +2 -2
- package/src/tag-rule.js +1 -1
- package/src/tag-rule.js.map +1 -1
- package/src/validate-catch-error-pattern.js +2 -2
- package/src/validate-catch-error-pattern.js.map +1 -1
- package/src/validate-dtos.js +2 -2
- package/src/validate-dtos.js.map +1 -1
- package/src/validate-inject-annotation-not-needed-for-concrete-class.js +1 -1
- package/src/validate-inject-annotation-not-needed-for-concrete-class.js.map +1 -1
- package/src/validate-match-rules.js +2 -2
- package/src/validate-match-rules.js.map +1 -1
- package/src/validate-modified-files.js +3 -3
- package/src/validate-modified-files.js.map +1 -1
- package/src/validate-modified-methods.js +3 -3
- package/src/validate-modified-methods.js.map +1 -1
- package/src/validate-new-methods.js +1 -1
- package/src/validate-new-methods.js.map +1 -1
- package/src/validate-no-any-unknown.js +2 -2
- package/src/validate-no-any-unknown.js.map +1 -1
- package/src/validate-no-client-creation-outside-server-or-client.js +1 -1
- package/src/validate-no-client-creation-outside-server-or-client.js.map +1 -1
- package/src/validate-no-custom-css.js +1 -1
- package/src/validate-no-custom-css.js.map +1 -1
- package/src/validate-no-destructure.js +2 -2
- package/src/validate-no-destructure.js.map +1 -1
- package/src/validate-no-direct-api-resolver.js +2 -2
- package/src/validate-no-direct-api-resolver.js.map +1 -1
- package/src/validate-no-function-outside-class.js +1 -1
- package/src/validate-no-function-outside-class.js.map +1 -1
- package/src/validate-no-implicit-any.js +1 -1
- package/src/validate-no-implicit-any.js.map +1 -1
- package/src/validate-no-inline-types.js +2 -2
- package/src/validate-no-inline-types.js.map +1 -1
- package/src/validate-no-process-exit-outside-main.js +1 -1
- package/src/validate-no-process-exit-outside-main.js.map +1 -1
- package/src/validate-no-symbol-di-tokens.js +1 -1
- package/src/validate-no-symbol-di-tokens.js.map +1 -1
- package/src/validate-no-unmanaged-exceptions.js +2 -2
- package/src/validate-no-unmanaged-exceptions.js.map +1 -1
- package/src/validate-prisma-converters.js +2 -2
- package/src/validate-prisma-converters.js.map +1 -1
- package/src/validate-return-types.js +2 -2
- package/src/validate-return-types.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-inject-annotation-not-needed-for-concrete-class.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-inject-annotation-not-needed-for-concrete-class.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Inject Annotation Not Needed For Concrete Class\n *\n * Flags a REDUNDANT `@inject(X)` on a CONSTRUCTOR parameter whose token is textually identical to the\n * parameter's own declared type:\n *\n * BAD: constructor(@inject(RequestContextHeaders) private readonly h: RequestContextHeaders) {}\n * GOOD: constructor(private readonly h: RequestContextHeaders) {}\n *\n * WHY: in this inversify setup a constructor parameter is auto-resolved by its class TYPE via\n * reflect-metadata (`emitDecoratorMetadata` emits `design:paramtypes`). So `private readonly h: Foo`\n * already binds `Foo` — the `@inject(Foo)` adds nothing (see CLAUDE.md, and the sibling\n * no-symbol-di-tokens rule that pushes the same inject-by-type pattern). AI keeps carpet-bombing\n * `@inject`; this fails the build on the redundant form so it stops.\n *\n * Uses the TypeScript AST (not a regex) so \"token equals the parameter type\" is decided precisely.\n * That single rule is what makes every LEGITIMATE token pass untouched — a real token never equals the\n * type it resolves:\n * - `@inject(TASK_PROXY_CLIENT_PROVIDER) x: Provider<TaskProxyClient>` (Symbol token ≠ type)\n * - `@inject(WEBPIECES_CONFIG_TOKEN) c: WebpiecesConfig` (Symbol ≠ interface type)\n * - `@inject('some-string') x: Foo` (string token ≠ type)\n * - `@inject(Symbol.for('X')) x: Foo` (not a bare identifier)\n *\n * SCOPE: only CONSTRUCTOR parameters. Property injection (`@inject(Foo) private foo: Foo` on a class\n * field) genuinely REQUIRES `@inject` in inversify — there is no design:type auto-wiring for properties\n * — so it is left alone.\n *\n * ALLOWED (skip — NOT violations)\n * - Any `@inject(TOKEN)` whose token differs from the parameter's type (Symbols, string tokens,\n * provider tokens, interface tokens).\n * - Property/field injection, and any parameter without an `@inject` decorator.\n * - Test files (*.test.ts, *.spec.ts, __tests__/**).\n * - Files under a configured `allowedPaths` glob (shared isPathExcluded glob/prefix/segment semantics).\n * - Lines with `// webpieces-disable inject-annotation-not-needed-for-concrete-class -- <reason>`\n * (only when disableAllowed).\n *\n * MODES (AST + LINE-SCOPED)\n * - OFF: Skip.\n * - NEW_AND_MODIFIED_CODE: Flag only on changed lines (diff hunks).\n * - NEW_AND_MODIFIED_FILES: Flag every occurrence in any modified file.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport { hasDisable, RULE_NAMES, InjectAnnotationNotNeededForConcreteClassConfig, ModifiedCodeMode, detectBase, getChangedFiles, getFileDiff, getChangedLineNumbers, isPathExcluded } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\nconst RULE_NAME = RULE_NAMES.INJECT_ANNOTATION_NOT_NEEDED_FOR_CONCRETE_CLASS;\n\nconst SHARED_MESSAGE = `@inject(Foo) on a constructor parameter typed \\`: Foo\\` is noise — inversify resolves a constructor\nparameter by its class type via reflect-metadata, so \\`private readonly foo: Foo\\` already binds it\n(see CLAUDE.md). Pick one:\n Fix Option 1 (PREFERRED): delete the decorator — constructor(private readonly foo: Foo) {}\n Fix Option 2: if you actually need a DIFFERENT binding token (a Symbol for a generated\n http-client-node / cloud-tasks client, or an interface/config with multiple impls), inject that\n token so it DIFFERS from the type: @inject(FOO_TOKEN) foo: SomeInterface.\nProperty injection (@inject on a class field, not a constructor param) is NOT flagged — it genuinely\nneeds @inject. Only a constructor param whose token equals its own type is redundant.`;\n\ninterface InjectViolation {\n file: string;\n line: number;\n column: number;\n context: string;\n}\n\ninterface InjectViolationInfo {\n line: number;\n column: number;\n context: string;\n hasDisableComment: boolean;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction isTestFile(filePath: string): boolean {\n return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction isDeclarationFile(filePath: string): boolean {\n return filePath.endsWith('.d.ts');\n}\n\n// The violation line (or the line just above it) carries the disable comment.\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction hasDisableOnLine(fileLines: string[], lineNumber: number): boolean {\n const current = fileLines[lineNumber - 1] ?? '';\n const previous = lineNumber >= 2 ? (fileLines[lineNumber - 2] ?? '') : '';\n return hasDisable(current, RULE_NAME) || hasDisable(previous, RULE_NAME);\n}\n\n// The `@inject(X)` decorator's single argument, when it is a BARE identifier (a class/token name).\n// Returns null for Symbol.for(...), property-access (`Symbol.x`), string literals, or a non-inject\n// decorator — those can never equal the parameter type, so they are never redundant.\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction injectIdentifierArg(decorator: ts.Decorator): string | null {\n const expr = decorator.expression;\n if (!ts.isCallExpression(expr)) return null;\n if (!ts.isIdentifier(expr.expression) || expr.expression.text !== 'inject') return null;\n if (expr.arguments.length !== 1) return null;\n const arg = expr.arguments[0];\n return arg && ts.isIdentifier(arg) ? arg.text : null;\n}\n\n// The parameter's declared type when it is a simple `TypeReference` with an identifier name\n// (`Foo`, or `Foo<Bar>` → `Foo`). Qualified names (`ns.Foo`) and non-references return null.\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction paramTypeName(param: ts.ParameterDeclaration): string | null {\n const typeNode = param.type;\n if (!typeNode || !ts.isTypeReferenceNode(typeNode)) return null;\n return ts.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : null;\n}\n\n// AST scan: a CONSTRUCTOR parameter is a violation when it carries `@inject(X)` and its declared type\n// is exactly `X`. Property injection and method params are ignored (only constructor params).\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nexport function findRedundantInjectInSource(content: string, filePath: string, disableAllowed: boolean): InjectViolationInfo[] {\n if (isDeclarationFile(filePath)) return [];\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n const violations: InjectViolationInfo[] = [];\n\n function checkParameter(param: ts.ParameterDeclaration): void {\n const decorators = ts.canHaveDecorators(param) ? ts.getDecorators(param) : undefined;\n if (!decorators) return;\n const typeName = paramTypeName(param);\n if (!typeName) return;\n for (const decorator of decorators) {\n if (injectIdentifierArg(decorator) === typeName) {\n recordViolation(param, `@inject(${typeName}) is redundant — the parameter is typed \\`: ${typeName}\\` and resolves by type`, fileLines, sourceFile, violations, disableAllowed);\n return;\n }\n }\n }\n\n function visit(node: ts.Node): void {\n if (ts.isConstructorDeclaration(node)) {\n for (const param of node.parameters) checkParameter(param);\n }\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return violations;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction recordViolation(\n node: ts.Node,\n context: string,\n fileLines: string[],\n sourceFile: ts.SourceFile,\n violations: InjectViolationInfo[],\n disableAllowed: boolean,\n): void {\n const startPos = node.getStart(sourceFile);\n if (startPos < 0) return;\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const disabled = hasDisableOnLine(fileLines, line);\n // When disableAllowed is false, a disable comment does NOT clear the violation.\n const effectiveDisabled = disableAllowed ? disabled : false;\n violations.push({ line, column, context, hasDisableComment: effectiveDisabled });\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction findRedundantInjectInFile(filePath: string, workspaceRoot: string, disableAllowed: boolean, allowedPaths: string[]): InjectViolationInfo[] {\n if (isTestFile(filePath)) return [];\n if (isPathExcluded(filePath, allowedPaths)) return [];\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n const content = fs.readFileSync(fullPath, 'utf-8');\n return findRedundantInjectInSource(content, filePath, disableAllowed);\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction findViolationsForModifiedCode(workspaceRoot: string, changedFiles: string[], base: string, head: string | undefined, disableAllowed: boolean, allowedPaths: string[]): InjectViolation[] {\n const violations: InjectViolation[] = [];\n for (const file of changedFiles) {\n const changedLines = getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head));\n if (changedLines.size === 0) continue;\n for (const v of findRedundantInjectInFile(file, workspaceRoot, disableAllowed, allowedPaths)) {\n if (disableAllowed && v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n violations.push({ file, line: v.line, column: v.column, context: v.context });\n }\n }\n return violations;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean, allowedPaths: string[]): InjectViolation[] {\n const violations: InjectViolation[] = [];\n for (const file of changedFiles) {\n for (const v of findRedundantInjectInFile(file, workspaceRoot, disableAllowed, allowedPaths)) {\n if (disableAllowed && v.hasDisableComment) continue;\n violations.push({ file, line: v.line, column: v.column, context: v.context });\n }\n }\n return violations;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction reportViolations(violations: InjectViolation[], mode: ModifiedCodeMode, disableAllowed: boolean): void {\n console.error('');\n console.error('❌ Redundant @inject — the parameter\\'s type already resolves it.');\n console.error('');\n console.error(SHARED_MESSAGE);\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}:${v.column}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n console.error(disableAllowed\n ? ` Escape hatch (use sparingly): // webpieces-disable ${RULE_NAME} -- <reason>`\n : ' Escape hatch: DISABLED (disableAllowed: false)');\n console.error(` Whole-tree exemption: add a glob to ${RULE_NAME}.allowedPaths in webpieces.config.json`);\n console.error(`\\n Current mode: ${mode}\\n`);\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction resolveMode(normalMode: ModifiedCodeMode, epoch: number | undefined, branchPattern: string | undefined): ModifiedCodeMode {\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(epoch, branchPattern);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})\\n`);\n return 'OFF';\n }\n return normalMode;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nasync function runValidatorImpl(options: InjectAnnotationNotNeededForConcreteClassConfig, workspaceRoot: string): Promise<ExecutorResult> {\n const mode: ModifiedCodeMode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch);\n const disableAllowed = options.disableAllowed ?? true;\n const allowedPaths = options.allowedPaths ?? [];\n\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)\\n`);\n return { success: true };\n }\n\n console.log(`\\n📏 Validating ${RULE_NAME}\\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 ${RULE_NAME} validation (could not detect base branch)\\n`);\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\\n`);\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: InjectViolation[] = [];\n if (mode === 'NEW_AND_MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed, allowedPaths);\n } else if (mode === 'NEW_AND_MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed, allowedPaths);\n }\n\n if (violations.length === 0) {\n console.log('✅ No redundant-@inject violations found');\n return { success: true };\n }\n\n reportViolations(violations, mode, disableAllowed);\n return { success: false };\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class InjectAnnotationNotNeededForConcreteClassValidator extends CodeValidator<InjectAnnotationNotNeededForConcreteClassConfig> {\n constructor(config: InjectAnnotationNotNeededForConcreteClassConfig) {\n super(config, RULE_NAME);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validate-inject-annotation-not-needed-for-concrete-class.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-inject-annotation-not-needed-for-concrete-class.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Inject Annotation Not Needed For Concrete Class\n *\n * Flags a REDUNDANT `@inject(X)` on a CONSTRUCTOR parameter whose token is textually identical to the\n * parameter's own declared type:\n *\n * BAD: constructor(@inject(RequestContextHeaders) private readonly h: RequestContextHeaders) {}\n * GOOD: constructor(private readonly h: RequestContextHeaders) {}\n *\n * WHY: in this inversify setup a constructor parameter is auto-resolved by its class TYPE via\n * reflect-metadata (`emitDecoratorMetadata` emits `design:paramtypes`). So `private readonly h: Foo`\n * already binds `Foo` — the `@inject(Foo)` adds nothing (see CLAUDE.md, and the sibling\n * no-symbol-di-tokens rule that pushes the same inject-by-type pattern). AI keeps carpet-bombing\n * `@inject`; this fails the build on the redundant form so it stops.\n *\n * Uses the TypeScript AST (not a regex) so \"token equals the parameter type\" is decided precisely.\n * That single rule is what makes every LEGITIMATE token pass untouched — a real token never equals the\n * type it resolves:\n * - `@inject(TASK_PROXY_CLIENT_PROVIDER) x: Provider<TaskProxyClient>` (Symbol token ≠ type)\n * - `@inject(WEBPIECES_CONFIG_TOKEN) c: WebpiecesConfig` (Symbol ≠ interface type)\n * - `@inject('some-string') x: Foo` (string token ≠ type)\n * - `@inject(Symbol.for('X')) x: Foo` (not a bare identifier)\n *\n * SCOPE: only CONSTRUCTOR parameters. Property injection (`@inject(Foo) private foo: Foo` on a class\n * field) genuinely REQUIRES `@inject` in inversify — there is no design:type auto-wiring for properties\n * — so it is left alone.\n *\n * ALLOWED (skip — NOT violations)\n * - Any `@inject(TOKEN)` whose token differs from the parameter's type (Symbols, string tokens,\n * provider tokens, interface tokens).\n * - Property/field injection, and any parameter without an `@inject` decorator.\n * - Test files (*.test.ts, *.spec.ts, __tests__/**).\n * - Files under a configured `allowedPaths` glob (shared isPathExcluded glob/prefix/segment semantics).\n * - Lines with `// webpieces-disable inject-annotation-not-needed-for-concrete-class -- <reason>`\n * (only when disableAllowed).\n *\n * MODES (AST + LINE-SCOPED)\n * - OFF: Skip.\n * - NEW_AND_MODIFIED_CODE: Flag only on changed lines (diff hunks).\n * - NEW_AND_MODIFIED_FILES: Flag every occurrence in any modified file.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport { hasDisable, RULE_NAMES, InjectAnnotationNotNeededForConcreteClassConfig, ModifiedCodeMode, detectBase, getChangedFiles, getFileDiff, getChangedLineNumbers, isPathExcluded } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\nconst RULE_NAME = RULE_NAMES.INJECT_ANNOTATION_NOT_NEEDED_FOR_CONCRETE_CLASS;\n\nconst SHARED_MESSAGE = `@inject(Foo) on a constructor parameter typed \\`: Foo\\` is noise — inversify resolves a constructor\nparameter by its class type via reflect-metadata, so \\`private readonly foo: Foo\\` already binds it\n(see CLAUDE.md). Pick one:\n Fix Option 1 (PREFERRED): delete the decorator — constructor(private readonly foo: Foo) {}\n Fix Option 2: if you actually need a DIFFERENT binding token (a Symbol for a generated\n http-client-node / cloud-tasks client, or an interface/config with multiple impls), inject that\n token so it DIFFERS from the type: @inject(FOO_TOKEN) foo: SomeInterface.\nProperty injection (@inject on a class field, not a constructor param) is NOT flagged — it genuinely\nneeds @inject. Only a constructor param whose token equals its own type is redundant.`;\n\ninterface InjectViolation {\n file: string;\n line: number;\n column: number;\n context: string;\n}\n\ninterface InjectViolationInfo {\n line: number;\n column: number;\n context: string;\n hasDisableComment: boolean;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction isTestFile(filePath: string): boolean {\n return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction isDeclarationFile(filePath: string): boolean {\n return filePath.endsWith('.d.ts');\n}\n\n// The violation line (or the line just above it) carries the disable comment.\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction hasDisableOnLine(fileLines: string[], lineNumber: number): boolean {\n const current = fileLines[lineNumber - 1] ?? '';\n const previous = lineNumber >= 2 ? (fileLines[lineNumber - 2] ?? '') : '';\n return hasDisable(current, RULE_NAME) || hasDisable(previous, RULE_NAME);\n}\n\n// The `@inject(X)` decorator's single argument, when it is a BARE identifier (a class/token name).\n// Returns null for Symbol.for(...), property-access (`Symbol.x`), string literals, or a non-inject\n// decorator — those can never equal the parameter type, so they are never redundant.\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction injectIdentifierArg(decorator: ts.Decorator): string | null {\n const expr = decorator.expression;\n if (!ts.isCallExpression(expr)) return null;\n if (!ts.isIdentifier(expr.expression) || expr.expression.text !== 'inject') return null;\n if (expr.arguments.length !== 1) return null;\n const arg = expr.arguments[0];\n return arg && ts.isIdentifier(arg) ? arg.text : null;\n}\n\n// The parameter's declared type when it is a simple `TypeReference` with an identifier name\n// (`Foo`, or `Foo<Bar>` → `Foo`). Qualified names (`ns.Foo`) and non-references return null.\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction paramTypeName(param: ts.ParameterDeclaration): string | null {\n const typeNode = param.type;\n if (!typeNode || !ts.isTypeReferenceNode(typeNode)) return null;\n return ts.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : null;\n}\n\n// AST scan: a CONSTRUCTOR parameter is a violation when it carries `@inject(X)` and its declared type\n// is exactly `X`. Property injection and method params are ignored (only constructor params).\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nexport function findRedundantInjectInSource(content: string, filePath: string, disableAllowed: boolean): InjectViolationInfo[] {\n if (isDeclarationFile(filePath)) return [];\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n const violations: InjectViolationInfo[] = [];\n\n function checkParameter(param: ts.ParameterDeclaration): void {\n const decorators = ts.canHaveDecorators(param) ? ts.getDecorators(param) : undefined;\n if (!decorators) return;\n const typeName = paramTypeName(param);\n if (!typeName) return;\n for (const decorator of decorators) {\n if (injectIdentifierArg(decorator) === typeName) {\n recordViolation(param, `@inject(${typeName}) is redundant — the parameter is typed \\`: ${typeName}\\` and resolves by type`, fileLines, sourceFile, violations, disableAllowed);\n return;\n }\n }\n }\n\n function visit(node: ts.Node): void {\n if (ts.isConstructorDeclaration(node)) {\n for (const param of node.parameters) checkParameter(param);\n }\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return violations;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction recordViolation(\n node: ts.Node,\n context: string,\n fileLines: string[],\n sourceFile: ts.SourceFile,\n violations: InjectViolationInfo[],\n disableAllowed: boolean,\n): void {\n const startPos = node.getStart(sourceFile);\n if (startPos < 0) return;\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const disabled = hasDisableOnLine(fileLines, line);\n // When disableAllowed is false, a disable comment does NOT clear the violation.\n const effectiveDisabled = disableAllowed ? disabled : false;\n violations.push({ line, column, context, hasDisableComment: effectiveDisabled });\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction findRedundantInjectInFile(filePath: string, workspaceRoot: string, disableAllowed: boolean, allowedPaths: string[]): InjectViolationInfo[] {\n if (isTestFile(filePath)) return [];\n if (isPathExcluded(filePath, allowedPaths)) return [];\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n const content = fs.readFileSync(fullPath, 'utf-8');\n return findRedundantInjectInSource(content, filePath, disableAllowed);\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction findViolationsForModifiedCode(workspaceRoot: string, changedFiles: string[], base: string, head: string | undefined, disableAllowed: boolean, allowedPaths: string[]): InjectViolation[] {\n const violations: InjectViolation[] = [];\n for (const file of changedFiles) {\n const changedLines = getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head));\n if (changedLines.size === 0) continue;\n for (const v of findRedundantInjectInFile(file, workspaceRoot, disableAllowed, allowedPaths)) {\n if (disableAllowed && v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n violations.push({ file, line: v.line, column: v.column, context: v.context });\n }\n }\n return violations;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean, allowedPaths: string[]): InjectViolation[] {\n const violations: InjectViolation[] = [];\n for (const file of changedFiles) {\n for (const v of findRedundantInjectInFile(file, workspaceRoot, disableAllowed, allowedPaths)) {\n if (disableAllowed && v.hasDisableComment) continue;\n violations.push({ file, line: v.line, column: v.column, context: v.context });\n }\n }\n return violations;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction reportViolations(violations: InjectViolation[], mode: ModifiedCodeMode, disableAllowed: boolean): void {\n console.error('');\n console.error('❌ Redundant @inject — the parameter\\'s type already resolves it.');\n console.error('');\n console.error(SHARED_MESSAGE);\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}:${v.column}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n console.error(disableAllowed\n ? ` Escape hatch (use sparingly): // webpieces-disable ${RULE_NAME} -- <reason>`\n : ' Escape hatch: DISABLED (disableAllowed: false)');\n console.error(` Whole-tree exemption: add a glob to ${RULE_NAME}.allowedPaths in webpieces.config.json`);\n console.error(`\\n Current mode: ${mode}\\n`);\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nfunction resolveMode(normalMode: ModifiedCodeMode, epoch: number | undefined, branchPattern: string | undefined): ModifiedCodeMode {\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(epoch, branchPattern);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})\\n`);\n return 'OFF';\n }\n return normalMode;\n}\n\n// webpieces-disable no-function-outside-class -- the rule engine is inherently functional; validators can't be class members\nasync function runValidatorImpl(options: InjectAnnotationNotNeededForConcreteClassConfig, workspaceRoot: string): Promise<ExecutorResult> {\n const mode: ModifiedCodeMode = resolveMode(options.mode ?? 'OFF', options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined));\n const disableAllowed = options.disableAllowed ?? true;\n const allowedPaths = options.allowedPaths ?? [];\n\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)\\n`);\n return { success: true };\n }\n\n console.log(`\\n📏 Validating ${RULE_NAME}\\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 ${RULE_NAME} validation (could not detect base branch)\\n`);\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\\n`);\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: InjectViolation[] = [];\n if (mode === 'NEW_AND_MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed, allowedPaths);\n } else if (mode === 'NEW_AND_MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed, allowedPaths);\n }\n\n if (violations.length === 0) {\n console.log('✅ No redundant-@inject violations found');\n return { success: true };\n }\n\n reportViolations(violations, mode, disableAllowed);\n return { success: false };\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class InjectAnnotationNotNeededForConcreteClassValidator extends CodeValidator<InjectAnnotationNotNeededForConcreteClassConfig> {\n constructor(config: InjectAnnotationNotNeededForConcreteClassConfig) {\n super(config, RULE_NAME);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
|
|
@@ -41,7 +41,7 @@ let MatchRulesChecker = class MatchRulesChecker {
|
|
|
41
41
|
shouldRun(config) {
|
|
42
42
|
if ((config.mode ?? 'OFF') === 'OFF')
|
|
43
43
|
return false;
|
|
44
|
-
return !(0, rules_config_1.shouldSkipRule)(config.
|
|
44
|
+
return !(0, rules_config_1.shouldSkipRule)(config.turnOffRuleUntilEpoch, config.turnOffRuleWhileOnBranch).skip;
|
|
45
45
|
}
|
|
46
46
|
/** Run one `match-rules` entry against the workspace (per-entry mode/diff-scoping/report). */
|
|
47
47
|
async runForConfig(config, workspaceRoot) {
|
|
@@ -141,7 +141,7 @@ let MatchRulesChecker = class MatchRulesChecker {
|
|
|
141
141
|
const normalMode = config.mode ?? 'OFF';
|
|
142
142
|
if (normalMode === 'OFF')
|
|
143
143
|
return normalMode;
|
|
144
|
-
const skip = (0, rules_config_1.shouldSkipRule)(config.
|
|
144
|
+
const skip = (0, rules_config_1.shouldSkipRule)(config.turnOffRuleUntilEpoch, config.turnOffRuleWhileOnBranch);
|
|
145
145
|
if (skip.skip) {
|
|
146
146
|
console.log(`\n⏭️ Skipping ${config.name} validation (${skip.reason})\n`);
|
|
147
147
|
return 'OFF';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-match-rules.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-match-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate `match-rules` entries (client-authored content guards) at build time.\n *\n * A config-free, injected checker: the {@link CodeRulesEngine} injects ONE MatchRulesChecker and runs\n * it once per `match-rules` entry (config passed to the method), so there is no `new` of a DAG member.\n * `shouldRun` / mode / epoch apply per entry and the report shows the entry name. The regex matching +\n * allowedPath/test-file exemption is shared with the ai-hook engine via findMatchRuleViolations; this\n * adds diff-scoping (mode), the `// webpieces-disable <name>` filter, and the console report.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n renderMatchRuleMessage,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n shouldSkipRule,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { ExecutorResult } from './code-validator';\n\nclass MatchViolation {\n readonly file: string;\n readonly line: number;\n readonly context: string;\n\n constructor(file: string, line: number, context: string) {\n this.file = file;\n this.line = line;\n this.context = context;\n }\n}\n\nexport class MatchViolationInfo {\n readonly line: number;\n readonly context: string;\n readonly hasDisableComment: boolean;\n\n constructor(line: number, context: string, hasDisableComment: boolean) {\n this.line = line;\n this.context = context;\n this.hasDisableComment = hasDisableComment;\n }\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class MatchRulesChecker {\n /** True unless this entry is `mode: \"OFF\"` or skipped by a branch/epoch escape hatch. */\n shouldRun(config: MatchRuleConfig): boolean {\n if ((config.mode ?? 'OFF') === 'OFF') return false;\n return !shouldSkipRule(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch).skip;\n }\n\n /** Run one `match-rules` entry against the workspace (per-entry mode/diff-scoping/report). */\n async runForConfig(config: MatchRuleConfig, workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(config);\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${config.name} validation (mode: OFF)\\n`);\n return { success: true };\n }\n\n console.log(`\\n📏 Validating match-rule: ${config.name}\\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 ${config.name} validation (could not detect base branch)\\n`);\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\\n`);\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 = mode === 'NEW_AND_MODIFIED_CODE'\n ? this.findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config)\n : this.findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);\n\n if (violations.length === 0) {\n console.log(`✅ No ${config.name} violations found`);\n return { success: true };\n }\n\n this.reportViolations(config, violations, mode);\n return { success: false };\n }\n\n findViolationsInFile(filePath: string, workspaceRoot: string, config: MatchRuleConfig): MatchViolationInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n\n // Shared engine applies allowedPaths + test-file exemption and regex matching.\n const hits = findMatchRuleViolations(lines, filePath, config);\n const disableAllowed = config.disableAllowed ?? true;\n\n return hits.map((hit: MatchRuleViolation) => {\n const line = lines[hit.line - 1] ?? '';\n const prevLine = hit.line > 1 ? (lines[hit.line - 2] ?? '') : '';\n const disabled = hasDisable(line, config.name) || hasDisable(prevLine, config.name);\n return new MatchViolationInfo(hit.line, hit.context, disableAllowed && disabled);\n });\n }\n\n private findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n config: MatchRuleConfig,\n ): MatchViolation[] {\n const violations: MatchViolation[] = [];\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 this.findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n }\n\n private findViolationsForModifiedFiles(\n workspaceRoot: string,\n changedFiles: string[],\n config: MatchRuleConfig,\n ): MatchViolation[] {\n const violations: MatchViolation[] = [];\n for (const file of changedFiles) {\n for (const v of this.findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n }\n\n private reportViolations(config: MatchRuleConfig, violations: MatchViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error(`❌ [${config.name}] matched disallowed pattern(s)!`);\n console.error('');\n console.error(renderMatchRuleMessage(config));\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n }\n\n private resolveMode(config: MatchRuleConfig): 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 ${config.name} validation (${skip.reason})\\n`);\n return 'OFF';\n }\n return normalMode;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validate-match-rules.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-match-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate `match-rules` entries (client-authored content guards) at build time.\n *\n * A config-free, injected checker: the {@link CodeRulesEngine} injects ONE MatchRulesChecker and runs\n * it once per `match-rules` entry (config passed to the method), so there is no `new` of a DAG member.\n * `shouldRun` / mode / epoch apply per entry and the report shows the entry name. The regex matching +\n * allowedPath/test-file exemption is shared with the ai-hook engine via findMatchRuleViolations; this\n * adds diff-scoping (mode), the `// webpieces-disable <name>` filter, and the console report.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n renderMatchRuleMessage,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n shouldSkipRule,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { ExecutorResult } from './code-validator';\n\nclass MatchViolation {\n readonly file: string;\n readonly line: number;\n readonly context: string;\n\n constructor(file: string, line: number, context: string) {\n this.file = file;\n this.line = line;\n this.context = context;\n }\n}\n\nexport class MatchViolationInfo {\n readonly line: number;\n readonly context: string;\n readonly hasDisableComment: boolean;\n\n constructor(line: number, context: string, hasDisableComment: boolean) {\n this.line = line;\n this.context = context;\n this.hasDisableComment = hasDisableComment;\n }\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class MatchRulesChecker {\n /** True unless this entry is `mode: \"OFF\"` or skipped by a branch/epoch escape hatch. */\n shouldRun(config: MatchRuleConfig): boolean {\n if ((config.mode ?? 'OFF') === 'OFF') return false;\n return !shouldSkipRule(config.turnOffRuleUntilEpoch, config.turnOffRuleWhileOnBranch).skip;\n }\n\n /** Run one `match-rules` entry against the workspace (per-entry mode/diff-scoping/report). */\n async runForConfig(config: MatchRuleConfig, workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(config);\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${config.name} validation (mode: OFF)\\n`);\n return { success: true };\n }\n\n console.log(`\\n📏 Validating match-rule: ${config.name}\\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 ${config.name} validation (could not detect base branch)\\n`);\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\\n`);\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 = mode === 'NEW_AND_MODIFIED_CODE'\n ? this.findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config)\n : this.findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);\n\n if (violations.length === 0) {\n console.log(`✅ No ${config.name} violations found`);\n return { success: true };\n }\n\n this.reportViolations(config, violations, mode);\n return { success: false };\n }\n\n findViolationsInFile(filePath: string, workspaceRoot: string, config: MatchRuleConfig): MatchViolationInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n\n // Shared engine applies allowedPaths + test-file exemption and regex matching.\n const hits = findMatchRuleViolations(lines, filePath, config);\n const disableAllowed = config.disableAllowed ?? true;\n\n return hits.map((hit: MatchRuleViolation) => {\n const line = lines[hit.line - 1] ?? '';\n const prevLine = hit.line > 1 ? (lines[hit.line - 2] ?? '') : '';\n const disabled = hasDisable(line, config.name) || hasDisable(prevLine, config.name);\n return new MatchViolationInfo(hit.line, hit.context, disableAllowed && disabled);\n });\n }\n\n private findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n config: MatchRuleConfig,\n ): MatchViolation[] {\n const violations: MatchViolation[] = [];\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 this.findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n }\n\n private findViolationsForModifiedFiles(\n workspaceRoot: string,\n changedFiles: string[],\n config: MatchRuleConfig,\n ): MatchViolation[] {\n const violations: MatchViolation[] = [];\n for (const file of changedFiles) {\n for (const v of this.findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n }\n\n private reportViolations(config: MatchRuleConfig, violations: MatchViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error(`❌ [${config.name}] matched disallowed pattern(s)!`);\n console.error('');\n console.error(renderMatchRuleMessage(config));\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n }\n\n private resolveMode(config: MatchRuleConfig): ModifiedCodeMode {\n const normalMode: ModifiedCodeMode = config.mode ?? 'OFF';\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(config.turnOffRuleUntilEpoch, config.turnOffRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${config.name} validation (${skip.reason})\\n`);\n return 'OFF';\n }\n return normalMode;\n }\n}\n"]}
|
|
@@ -191,11 +191,11 @@ function reportViolations(violations, limit, disableAllowed) {
|
|
|
191
191
|
console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');
|
|
192
192
|
console.error(' You MUST refactor to reduce file size.');
|
|
193
193
|
console.error('');
|
|
194
|
-
console.error(' For a major refactor, a human can add "
|
|
194
|
+
console.error(' For a major refactor, a human can add "turnOffRuleUntilEpoch" to nx.json validate-code options.');
|
|
195
195
|
console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');
|
|
196
196
|
console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');
|
|
197
197
|
console.error(' each PR reduces files as they get touched.');
|
|
198
|
-
console.error(' AI agents should NOT add
|
|
198
|
+
console.error(' AI agents should NOT add turnOffRuleUntilEpoch - ask a human to do it.');
|
|
199
199
|
console.error('');
|
|
200
200
|
}
|
|
201
201
|
}
|
|
@@ -203,7 +203,7 @@ async function runValidatorImpl(options, workspaceRoot) {
|
|
|
203
203
|
const limit = options.limit ?? 900;
|
|
204
204
|
const disableAllowed = options.disableAllowed ?? true;
|
|
205
205
|
const rawMode = options.mode ?? 'NEW_AND_MODIFIED_FILES';
|
|
206
|
-
const skip = rawMode !== 'OFF' ? (0, resolve_mode_1.shouldSkipRule)(options.
|
|
206
|
+
const skip = rawMode !== 'OFF' ? (0, resolve_mode_1.shouldSkipRule)(options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined)) : { skip: false };
|
|
207
207
|
const mode = skip.skip ? 'OFF' : rawMode;
|
|
208
208
|
// Skip validation entirely if mode is OFF
|
|
209
209
|
if (mode === 'OFF') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-modified-files.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-modified-files.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Files Executor\n *\n * Validates that modified files don't exceed a maximum line count (default 900).\n * This encourages keeping files small and focused - when you touch a file,\n * you must bring it under the limit.\n *\n * Usage:\n * nx affected --target=validate-modified-files --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified-files comment with date and justification\n * Format: // webpieces-disable max-lines-modified-files 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { writeTemplate, hasDisable, RULE_NAMES, MaxFileLinesConfig, FileLimitMode, detectBase, getChangedFiles } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface FileViolation {\n file: string;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_MD_FILE = 'webpieces.filesize.md';\n\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n return writeTemplate(workspaceRoot, TMP_MD_FILE);\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\ninterface DisableStatus {\n hasDisable: boolean;\n isValid: boolean;\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check if a file has a valid, non-expired disable comment at the top (within first 5 lines).\n * Returns status object with details about the disable comment.\n */\n// webpieces-disable max-lines-new-methods -- Date validation logic requires checking multiple conditions\nfunction checkDisableComment(content: string): DisableStatus {\n const lines = content.split('\\n').slice(0, 5);\n\n for (const line of lines) {\n if (hasDisable(line, RULE_NAMES.MAX_LINES_MODIFIED_FILES)) {\n // Found disable comment, now check for date\n // Format: // webpieces-disable max-lines-modified-files yyyy/mm/dd -- reason\n const dateMatch = line.match(/max-lines-modified-files\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - invalid disable comment\n return { hasDisable: true, isValid: false, isExpired: false };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format\n return { hasDisable: true, isValid: false, isExpired: false, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { hasDisable: true, isValid: true, isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n }\n\n return { hasDisable: false, isValid: false, isExpired: false };\n}\n\n/**\n * Count lines in a file and check for violations\n */\n// webpieces-disable max-lines-new-methods -- File iteration with disable checking logic\nfunction findViolations(workspaceRoot: string, changedFiles: string[], limit: number, disableAllowed: boolean): FileViolation[] {\n const violations: FileViolation[] = [];\n\n for (const file of changedFiles) {\n const fullPath = path.join(workspaceRoot, file);\n\n if (!fs.existsSync(fullPath)) continue;\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lineCount = content.split('\\n').length;\n\n // Skip files under the limit\n if (lineCount <= limit) continue;\n\n // When disableAllowed is false, ignore all disable comments\n if (!disableAllowed) {\n violations.push({ file, lines: lineCount });\n continue;\n }\n\n // Check for disable comment\n const disableStatus = checkDisableComment(content);\n\n if (disableStatus.hasDisable) {\n if (disableStatus.isValid && !disableStatus.isExpired) {\n // Valid, non-expired disable - skip this file\n continue;\n }\n\n if (disableStatus.isExpired) {\n // Expired disable - report as violation with expired info\n violations.push({\n file,\n lines: lineCount,\n expiredDisable: true,\n expiredDate: disableStatus.date,\n });\n continue;\n }\n\n // Invalid disable (missing/bad date) - fall through to report as violation\n }\n\n violations.push({\n file,\n lines: lineCount,\n });\n }\n\n return violations;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: FileViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c YOU MUST FIX THIS AND NOT be more than ' + limit + ' lines of code per file');\n console.error(' as it slows down IDEs AND is VERY VERY EASY to refactor.');\n console.error('');\n console.error('\\ud83d\\udcda With stateless systems + dependency injection, refactor is trivial:');\n console.error(' Pick a method or a few and move to new class XXXXX, then inject XXXXX');\n console.error(' into all users of those methods via the constructor.');\n console.error(' Delete those methods from original class.');\n console.error(' 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.filesize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate} has expired (>1 month old).`);\n console.error(` You must either FIX the file or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified-files ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce file size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"ignoreModifiedUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');\n console.error(' each PR reduces files as they get touched.');\n console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nasync function runValidatorImpl(\n options: MaxFileLinesConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const limit = options.limit ?? 900;\n const disableAllowed = options.disableAllowed ?? true;\n\n const rawMode: FileLimitMode = options.mode ?? 'NEW_AND_MODIFIED_FILES';\n const skip = rawMode !== 'OFF' ? shouldSkipRule(options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch) : { skip: false };\n const mode: FileLimitMode = skip.skip ? 'OFF' : rawMode;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n const reason = skip.skip ? skip.reason : 'mode: OFF';\n console.log(`\\n\\u23ed\\ufe0f Skipping modified files validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping modified files validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-files --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Max lines for modified files: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, limit, disableAllowed);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified files are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n //const error = toError(err);\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified files validation failed:', error.message);\n return { success: false };\n }\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class MaxFileLinesValidator extends CodeValidator<MaxFileLinesConfig> {\n constructor(config: MaxFileLinesConfig) {\n super(config, 'max-file-lines');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validate-modified-files.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-modified-files.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Files Executor\n *\n * Validates that modified files don't exceed a maximum line count (default 900).\n * This encourages keeping files small and focused - when you touch a file,\n * you must bring it under the limit.\n *\n * Usage:\n * nx affected --target=validate-modified-files --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified-files comment with date and justification\n * Format: // webpieces-disable max-lines-modified-files 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { writeTemplate, hasDisable, RULE_NAMES, MaxFileLinesConfig, FileLimitMode, detectBase, getChangedFiles } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface FileViolation {\n file: string;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_MD_FILE = 'webpieces.filesize.md';\n\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n return writeTemplate(workspaceRoot, TMP_MD_FILE);\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\ninterface DisableStatus {\n hasDisable: boolean;\n isValid: boolean;\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check if a file has a valid, non-expired disable comment at the top (within first 5 lines).\n * Returns status object with details about the disable comment.\n */\n// webpieces-disable max-lines-new-methods -- Date validation logic requires checking multiple conditions\nfunction checkDisableComment(content: string): DisableStatus {\n const lines = content.split('\\n').slice(0, 5);\n\n for (const line of lines) {\n if (hasDisable(line, RULE_NAMES.MAX_LINES_MODIFIED_FILES)) {\n // Found disable comment, now check for date\n // Format: // webpieces-disable max-lines-modified-files yyyy/mm/dd -- reason\n const dateMatch = line.match(/max-lines-modified-files\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - invalid disable comment\n return { hasDisable: true, isValid: false, isExpired: false };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format\n return { hasDisable: true, isValid: false, isExpired: false, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { hasDisable: true, isValid: true, isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n }\n\n return { hasDisable: false, isValid: false, isExpired: false };\n}\n\n/**\n * Count lines in a file and check for violations\n */\n// webpieces-disable max-lines-new-methods -- File iteration with disable checking logic\nfunction findViolations(workspaceRoot: string, changedFiles: string[], limit: number, disableAllowed: boolean): FileViolation[] {\n const violations: FileViolation[] = [];\n\n for (const file of changedFiles) {\n const fullPath = path.join(workspaceRoot, file);\n\n if (!fs.existsSync(fullPath)) continue;\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lineCount = content.split('\\n').length;\n\n // Skip files under the limit\n if (lineCount <= limit) continue;\n\n // When disableAllowed is false, ignore all disable comments\n if (!disableAllowed) {\n violations.push({ file, lines: lineCount });\n continue;\n }\n\n // Check for disable comment\n const disableStatus = checkDisableComment(content);\n\n if (disableStatus.hasDisable) {\n if (disableStatus.isValid && !disableStatus.isExpired) {\n // Valid, non-expired disable - skip this file\n continue;\n }\n\n if (disableStatus.isExpired) {\n // Expired disable - report as violation with expired info\n violations.push({\n file,\n lines: lineCount,\n expiredDisable: true,\n expiredDate: disableStatus.date,\n });\n continue;\n }\n\n // Invalid disable (missing/bad date) - fall through to report as violation\n }\n\n violations.push({\n file,\n lines: lineCount,\n });\n }\n\n return violations;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: FileViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c YOU MUST FIX THIS AND NOT be more than ' + limit + ' lines of code per file');\n console.error(' as it slows down IDEs AND is VERY VERY EASY to refactor.');\n console.error('');\n console.error('\\ud83d\\udcda With stateless systems + dependency injection, refactor is trivial:');\n console.error(' Pick a method or a few and move to new class XXXXX, then inject XXXXX');\n console.error(' into all users of those methods via the constructor.');\n console.error(' Delete those methods from original class.');\n console.error(' 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.filesize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate} has expired (>1 month old).`);\n console.error(` You must either FIX the file or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified-files ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce file size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"turnOffRuleUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');\n console.error(' each PR reduces files as they get touched.');\n console.error(' AI agents should NOT add turnOffRuleUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nasync function runValidatorImpl(\n options: MaxFileLinesConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const limit = options.limit ?? 900;\n const disableAllowed = options.disableAllowed ?? true;\n\n const rawMode: FileLimitMode = options.mode ?? 'NEW_AND_MODIFIED_FILES';\n const skip = rawMode !== 'OFF' ? shouldSkipRule(options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined)) : { skip: false };\n const mode: FileLimitMode = skip.skip ? 'OFF' : rawMode;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n const reason = skip.skip ? skip.reason : 'mode: OFF';\n console.log(`\\n\\u23ed\\ufe0f Skipping modified files validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping modified files validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-files --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Max lines for modified files: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, limit, disableAllowed);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified files are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n //const error = toError(err);\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified files validation failed:', error.message);\n return { success: false };\n }\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class MaxFileLinesValidator extends CodeValidator<MaxFileLinesConfig> {\n constructor(config: MaxFileLinesConfig) {\n super(config, 'max-file-lines');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
|
|
@@ -331,11 +331,11 @@ function reportViolations(violations, limit, disableAllowed) {
|
|
|
331
331
|
console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');
|
|
332
332
|
console.error(' You MUST refactor to reduce method size.');
|
|
333
333
|
console.error('');
|
|
334
|
-
console.error(' For a major refactor, a human can add "
|
|
334
|
+
console.error(' For a major refactor, a human can add "turnOffRuleUntilEpoch" to nx.json validate-code options.');
|
|
335
335
|
console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');
|
|
336
336
|
console.error(' Sometimes for speed, we allow methods to expand during a refactor and over time,');
|
|
337
337
|
console.error(' each PR reduces methods as they get touched.');
|
|
338
|
-
console.error(' AI agents should NOT add
|
|
338
|
+
console.error(' AI agents should NOT add turnOffRuleUntilEpoch - ask a human to do it.');
|
|
339
339
|
console.error('');
|
|
340
340
|
}
|
|
341
341
|
}
|
|
@@ -343,7 +343,7 @@ async function runModifiedMethods(options, workspaceRoot) {
|
|
|
343
343
|
const limit = options.limit ?? 80;
|
|
344
344
|
const disableAllowed = options.disableAllowed ?? true;
|
|
345
345
|
const rawMode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';
|
|
346
|
-
const skip = rawMode !== 'OFF' ? (0, resolve_mode_1.shouldSkipRule)(options.
|
|
346
|
+
const skip = rawMode !== 'OFF' ? (0, resolve_mode_1.shouldSkipRule)(options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined)) : { skip: false };
|
|
347
347
|
const mode = skip.skip ? 'OFF' : rawMode;
|
|
348
348
|
// Skip validation entirely if mode is OFF
|
|
349
349
|
if (mode === 'OFF') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-modified-methods.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-modified-methods.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Methods Executor\n *\n * Validates that modified methods don't exceed a maximum line count (default 80).\n * This encourages gradual cleanup of legacy long methods - when you touch a method,\n * you must bring it under the limit.\n *\n * Combined with validate-new-methods, this creates a gradual\n * transition to cleaner code:\n * - New methods: must be under limit\n * - Modified methods: must be under limit (cleanup when touched)\n * - Untouched methods: no limit (legacy allowed)\n *\n * Usage:\n * nx affected --target=validate-modified-methods --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified comment with date and justification\n * Format: // webpieces-disable max-lines-modified 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport {\n writeTemplate,\n RULE_NAMES,\n WEBPIECES_DISABLE,\n MaxMethodLinesConfig,\n MethodLimitMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n findNewMethodSignaturesInDiff,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\nimport { runNewMethods } from './validate-new-methods';\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_MD_FILE = 'webpieces.methodsize.md';\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n return writeTemplate(workspaceRoot, TMP_MD_FILE);\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\ninterface DisableInfo {\n type: 'full' | 'new-only' | 'none';\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check what kind of webpieces-disable comment is present for a method.\n * Returns: DisableInfo with type, expiration status, and date\n * - 'full': max-lines-modified (ultimate escape, skips both validators)\n * - 'new-only': max-lines-new-methods (escaped 30-line check, still needs 80-line check)\n * - 'none': no escape hatch\n */\n// webpieces-disable max-lines-new-methods -- Complex validation logic with multiple escape hatch types\nfunction getDisableInfo(lines: string[], lineNumber: number): DisableInfo {\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes(WEBPIECES_DISABLE)) {\n if (line.includes(RULE_NAMES.MAX_LINES_MODIFIED)) {\n // Check for date in format: max-lines-modified yyyy/mm/dd\n const dateMatch = line.match(/max-lines-modified\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'full', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'full', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'full', isExpired: false, date: dateStr };\n }\n if (line.includes(RULE_NAMES.MAX_LINES_NEW_METHODS)) {\n // Check for date in format: max-lines-new-methods yyyy/mm/dd\n const dateMatch = line.match(/max-lines-new-methods\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'new-only', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n }\n }\n return { type: 'none', isExpired: false };\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n endLine: number;\n lines: number;\n disableInfo: DisableInfo;\n}\n\n/**\n * Parse a TypeScript file and find methods with their line counts\n */\n// webpieces-disable max-lines-new-methods -- AST traversal requires inline visitor function\nfunction findMethodsInFile(filePath: string, workspaceRoot: string): MethodInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const methods: MethodInfo[] = [];\n\n // webpieces-disable max-lines-new-methods -- AST visitor pattern requires handling multiple node types\n function visit(node: ts.Node): void {\n let methodName: string | undefined;\n let startLine: number | undefined;\n let endLine: number | undefined;\n\n if (ts.isMethodDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n } else if (ts.isFunctionDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n } else if (ts.isArrowFunction(node)) {\n if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {\n methodName = node.parent.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n }\n }\n\n if (methodName && startLine !== undefined && endLine !== undefined) {\n methods.push({\n name: methodName,\n line: startLine,\n endLine: endLine,\n lines: endLine - startLine + 1,\n disableInfo: getDisableInfo(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Check if a method has any changes within its line range\n */\nfunction methodHasChanges(method: MethodInfo, changedLineNumbers: Set<number>): boolean {\n for (let line = method.line; line <= method.endLine; line++) {\n if (changedLineNumbers.has(line)) return true;\n }\n return false;\n}\n\n/**\n * Check a NEW method and return violation if applicable\n */\nfunction checkNewMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const disableType = method.disableInfo.type;\n const isExpired = method.disableInfo.isExpired;\n const disableDate = method.disableInfo.date;\n\n if (!disableAllowed) {\n // When disableAllowed is false, skip NEW methods without escape (let validate-new-methods handle)\n if (disableType === 'none') return null;\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n if (disableType !== 'new-only') return null;\n\n if (isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Check a MODIFIED method and return violation if applicable\n */\nfunction checkModifiedMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const disableType = method.disableInfo.type;\n const isExpired = method.disableInfo.isExpired;\n const disableDate = method.disableInfo.date;\n\n if (!disableAllowed) {\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n if (disableType === 'full' && !isExpired) {\n // Valid escape, no violation\n return null;\n }\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Find methods that exceed the limit.\n * Checks NEW methods with escape hatches and MODIFIED methods.\n */\nfunction findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n limit: number,\n disableAllowed: boolean,\n head?: string\n): MethodViolation[] {\n const violations: MethodViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n if (!diff) continue;\n\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n const changedLineNumbers = getChangedLineNumbers(diff);\n if (changedLineNumbers.size === 0) continue;\n\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n const disableType = method.disableInfo.type;\n const isExpired = method.disableInfo.isExpired;\n\n // Skip methods with valid, non-expired full escape - unless disableAllowed is false\n if (disableAllowed && disableType === 'full' && !isExpired) continue;\n if (method.lines <= limit) continue;\n\n const isNewMethod = newMethodNames.has(method.name);\n\n if (isNewMethod) {\n const violation = checkNewMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n } else if (methodHasChanges(method, changedLineNumbers)) {\n const violation = checkModifiedMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c Modified methods exceed ' + limit + ' lines!');\n console.error('');\n console.error('\\ud83d\\udcda When you modify a method, you must bring it under ' + limit + ' lines.');\n console.error(' This rule encourages GRADUAL cleanup so even though you did not cause it,');\n console.error(' you touched it, so you should fix now as part of your PR');\n console.error(' (this is for vibe coding and AI to fix as it touches things).');\n console.error(' You can refactor to stay under the limit 50% of the time. If not feasible, use the escape hatch.');\n console.error('');\n console.error(\n '\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f'\n );\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate ?? 'unknown'} has expired (>1 month old).`);\n console.error(` You must either FIX the method or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of methods can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce method size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"ignoreModifiedUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow methods to expand during a refactor and over time,');\n console.error(' each PR reduces methods as they get touched.');\n console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nexport async function runModifiedMethods(\n options: MaxMethodLinesConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const limit = options.limit ?? 80;\n const disableAllowed = options.disableAllowed ?? true;\n\n const rawMode: MethodLimitMode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';\n const skip = rawMode !== 'OFF' ? shouldSkipRule(options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch) : { skip: false };\n const mode: MethodLimitMode = skip.skip ? 'OFF' : rawMode;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n const reason = skip.skip ? skip.reason : 'mode: OFF';\n console.log(`\\n\\u23ed\\ufe0f Skipping modified method validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping modified method validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-methods --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Limit for modified methods: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified methods are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n //const error = toError(err);\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified method validation failed:', error.message);\n return { success: false };\n }\n}\n\n/**\n * MaxMethodLinesValidator — the single 'max-method-lines' validator.\n *\n * Reproduces the previous `runMethodValidators` orchestration: depending on the\n * configured mode it runs the new-methods sub-check and/or the modified-methods\n * sub-check.\n * - NEW_METHODS -> new-methods only\n * - NEW_AND_MODIFIED_METHODS -> new-methods + modified-methods\n * - NEW_AND_MODIFIED_FILES -> modified-methods only\n */\n@injectable(bindingScopeValues.Singleton)\nexport class MaxMethodLinesValidator extends CodeValidator<MaxMethodLinesConfig> {\n constructor(config: MaxMethodLinesConfig) {\n super(config, 'max-method-lines');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const mode: MethodLimitMode = this.config.mode ?? 'NEW_AND_MODIFIED_METHODS';\n const runNew = mode === 'NEW_METHODS' || mode === 'NEW_AND_MODIFIED_METHODS';\n const runModified = mode === 'NEW_AND_MODIFIED_METHODS' || mode === 'NEW_AND_MODIFIED_FILES';\n\n const results: ExecutorResult[] = [];\n if (runNew) {\n results.push(await runNewMethods(this.config, workspaceRoot));\n }\n if (runModified) {\n results.push(await runModifiedMethods(this.config, workspaceRoot));\n }\n return { success: results.every((r) => r.success) };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validate-modified-methods.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-modified-methods.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Methods Executor\n *\n * Validates that modified methods don't exceed a maximum line count (default 80).\n * This encourages gradual cleanup of legacy long methods - when you touch a method,\n * you must bring it under the limit.\n *\n * Combined with validate-new-methods, this creates a gradual\n * transition to cleaner code:\n * - New methods: must be under limit\n * - Modified methods: must be under limit (cleanup when touched)\n * - Untouched methods: no limit (legacy allowed)\n *\n * Usage:\n * nx affected --target=validate-modified-methods --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified comment with date and justification\n * Format: // webpieces-disable max-lines-modified 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport {\n writeTemplate,\n RULE_NAMES,\n WEBPIECES_DISABLE,\n MaxMethodLinesConfig,\n MethodLimitMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n findNewMethodSignaturesInDiff,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\nimport { runNewMethods } from './validate-new-methods';\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_MD_FILE = 'webpieces.methodsize.md';\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n return writeTemplate(workspaceRoot, TMP_MD_FILE);\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\ninterface DisableInfo {\n type: 'full' | 'new-only' | 'none';\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check what kind of webpieces-disable comment is present for a method.\n * Returns: DisableInfo with type, expiration status, and date\n * - 'full': max-lines-modified (ultimate escape, skips both validators)\n * - 'new-only': max-lines-new-methods (escaped 30-line check, still needs 80-line check)\n * - 'none': no escape hatch\n */\n// webpieces-disable max-lines-new-methods -- Complex validation logic with multiple escape hatch types\nfunction getDisableInfo(lines: string[], lineNumber: number): DisableInfo {\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes(WEBPIECES_DISABLE)) {\n if (line.includes(RULE_NAMES.MAX_LINES_MODIFIED)) {\n // Check for date in format: max-lines-modified yyyy/mm/dd\n const dateMatch = line.match(/max-lines-modified\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'full', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'full', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'full', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'full', isExpired: false, date: dateStr };\n }\n if (line.includes(RULE_NAMES.MAX_LINES_NEW_METHODS)) {\n // Check for date in format: max-lines-new-methods yyyy/mm/dd\n const dateMatch = line.match(/max-lines-new-methods\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - treat as expired (invalid)\n return { type: 'new-only', isExpired: true, date: undefined };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format - treat as expired\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { type: 'new-only', isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { type: 'new-only', isExpired: false, date: dateStr };\n }\n }\n }\n return { type: 'none', isExpired: false };\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n endLine: number;\n lines: number;\n disableInfo: DisableInfo;\n}\n\n/**\n * Parse a TypeScript file and find methods with their line counts\n */\n// webpieces-disable max-lines-new-methods -- AST traversal requires inline visitor function\nfunction findMethodsInFile(filePath: string, workspaceRoot: string): MethodInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const methods: MethodInfo[] = [];\n\n // webpieces-disable max-lines-new-methods -- AST visitor pattern requires handling multiple node types\n function visit(node: ts.Node): void {\n let methodName: string | undefined;\n let startLine: number | undefined;\n let endLine: number | undefined;\n\n if (ts.isMethodDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n } else if (ts.isFunctionDeclaration(node) && node.name) {\n methodName = node.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n } else if (ts.isArrowFunction(node)) {\n if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {\n methodName = node.parent.name.getText(sourceFile);\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n startLine = start.line + 1;\n endLine = end.line + 1;\n }\n }\n\n if (methodName && startLine !== undefined && endLine !== undefined) {\n methods.push({\n name: methodName,\n line: startLine,\n endLine: endLine,\n lines: endLine - startLine + 1,\n disableInfo: getDisableInfo(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Check if a method has any changes within its line range\n */\nfunction methodHasChanges(method: MethodInfo, changedLineNumbers: Set<number>): boolean {\n for (let line = method.line; line <= method.endLine; line++) {\n if (changedLineNumbers.has(line)) return true;\n }\n return false;\n}\n\n/**\n * Check a NEW method and return violation if applicable\n */\nfunction checkNewMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const disableType = method.disableInfo.type;\n const isExpired = method.disableInfo.isExpired;\n const disableDate = method.disableInfo.date;\n\n if (!disableAllowed) {\n // When disableAllowed is false, skip NEW methods without escape (let validate-new-methods handle)\n if (disableType === 'none') return null;\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n if (disableType !== 'new-only') return null;\n\n if (isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Check a MODIFIED method and return violation if applicable\n */\nfunction checkModifiedMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {\n const disableType = method.disableInfo.type;\n const isExpired = method.disableInfo.isExpired;\n const disableDate = method.disableInfo.date;\n\n if (!disableAllowed) {\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n }\n if (disableType === 'full' && !isExpired) {\n // Valid escape, no violation\n return null;\n }\n if (disableType === 'full' && isExpired) {\n return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };\n }\n return { file, methodName: method.name, line: method.line, lines: method.lines };\n}\n\n/**\n * Find methods that exceed the limit.\n * Checks NEW methods with escape hatches and MODIFIED methods.\n */\nfunction findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n limit: number,\n disableAllowed: boolean,\n head?: string\n): MethodViolation[] {\n const violations: MethodViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n if (!diff) continue;\n\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n const changedLineNumbers = getChangedLineNumbers(diff);\n if (changedLineNumbers.size === 0) continue;\n\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n const disableType = method.disableInfo.type;\n const isExpired = method.disableInfo.isExpired;\n\n // Skip methods with valid, non-expired full escape - unless disableAllowed is false\n if (disableAllowed && disableType === 'full' && !isExpired) continue;\n if (method.lines <= limit) continue;\n\n const isNewMethod = newMethodNames.has(method.name);\n\n if (isNewMethod) {\n const violation = checkNewMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n } else if (methodHasChanges(method, changedLineNumbers)) {\n const violation = checkModifiedMethodViolation(file, method, disableAllowed);\n if (violation) violations.push(violation);\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c Modified methods exceed ' + limit + ' lines!');\n console.error('');\n console.error('\\ud83d\\udcda When you modify a method, you must bring it under ' + limit + ' lines.');\n console.error(' This rule encourages GRADUAL cleanup so even though you did not cause it,');\n console.error(' you touched it, so you should fix now as part of your PR');\n console.error(' (this is for vibe coding and AI to fix as it touches things).');\n console.error(' You can refactor to stay under the limit 50% of the time. If not feasible, use the escape hatch.');\n console.error('');\n console.error(\n '\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f'\n );\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate ?? 'unknown'} has expired (>1 month old).`);\n console.error(` You must either FIX the method or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of methods can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce method size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"turnOffRuleUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow methods to expand during a refactor and over time,');\n console.error(' each PR reduces methods as they get touched.');\n console.error(' AI agents should NOT add turnOffRuleUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nexport async function runModifiedMethods(\n options: MaxMethodLinesConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const limit = options.limit ?? 80;\n const disableAllowed = options.disableAllowed ?? true;\n\n const rawMode: MethodLimitMode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';\n const skip = rawMode !== 'OFF' ? shouldSkipRule(options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined)) : { skip: false };\n const mode: MethodLimitMode = skip.skip ? 'OFF' : rawMode;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n const reason = skip.skip ? skip.reason : 'mode: OFF';\n console.log(`\\n\\u23ed\\ufe0f Skipping modified method validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping modified method validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-methods --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified Method Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Limit for modified methods: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified methods are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n //const error = toError(err);\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified method validation failed:', error.message);\n return { success: false };\n }\n}\n\n/**\n * MaxMethodLinesValidator — the single 'max-method-lines' validator.\n *\n * Reproduces the previous `runMethodValidators` orchestration: depending on the\n * configured mode it runs the new-methods sub-check and/or the modified-methods\n * sub-check.\n * - NEW_METHODS -> new-methods only\n * - NEW_AND_MODIFIED_METHODS -> new-methods + modified-methods\n * - NEW_AND_MODIFIED_FILES -> modified-methods only\n */\n@injectable(bindingScopeValues.Singleton)\nexport class MaxMethodLinesValidator extends CodeValidator<MaxMethodLinesConfig> {\n constructor(config: MaxMethodLinesConfig) {\n super(config, 'max-method-lines');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const mode: MethodLimitMode = this.config.mode ?? 'NEW_AND_MODIFIED_METHODS';\n const runNew = mode === 'NEW_METHODS' || mode === 'NEW_AND_MODIFIED_METHODS';\n const runModified = mode === 'NEW_AND_MODIFIED_METHODS' || mode === 'NEW_AND_MODIFIED_FILES';\n\n const results: ExecutorResult[] = [];\n if (runNew) {\n results.push(await runNewMethods(this.config, workspaceRoot));\n }\n if (runModified) {\n results.push(await runModifiedMethods(this.config, workspaceRoot));\n }\n return { success: results.every((r) => r.success) };\n }\n}\n"]}
|
|
@@ -188,7 +188,7 @@ async function runNewMethods(options, workspaceRoot) {
|
|
|
188
188
|
const limit = options.limit ?? 80;
|
|
189
189
|
const disableAllowed = options.disableAllowed ?? true;
|
|
190
190
|
const rawMode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';
|
|
191
|
-
const skip = rawMode !== 'OFF' ? (0, resolve_mode_1.shouldSkipRule)(options.
|
|
191
|
+
const skip = rawMode !== 'OFF' ? (0, resolve_mode_1.shouldSkipRule)(options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined)) : { skip: false };
|
|
192
192
|
const mode = skip.skip ? 'OFF' : rawMode;
|
|
193
193
|
// Skip validation entirely if mode is OFF
|
|
194
194
|
if (mode === 'OFF') {
|