@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.
Files changed (44) hide show
  1. package/package.json +2 -2
  2. package/src/tag-rule.d.ts +2 -2
  3. package/src/tag-rule.js +1 -1
  4. package/src/tag-rule.js.map +1 -1
  5. package/src/validate-catch-error-pattern.js +2 -2
  6. package/src/validate-catch-error-pattern.js.map +1 -1
  7. package/src/validate-dtos.js +2 -2
  8. package/src/validate-dtos.js.map +1 -1
  9. package/src/validate-inject-annotation-not-needed-for-concrete-class.js +1 -1
  10. package/src/validate-inject-annotation-not-needed-for-concrete-class.js.map +1 -1
  11. package/src/validate-match-rules.js +2 -2
  12. package/src/validate-match-rules.js.map +1 -1
  13. package/src/validate-modified-files.js +3 -3
  14. package/src/validate-modified-files.js.map +1 -1
  15. package/src/validate-modified-methods.js +3 -3
  16. package/src/validate-modified-methods.js.map +1 -1
  17. package/src/validate-new-methods.js +1 -1
  18. package/src/validate-new-methods.js.map +1 -1
  19. package/src/validate-no-any-unknown.js +2 -2
  20. package/src/validate-no-any-unknown.js.map +1 -1
  21. package/src/validate-no-client-creation-outside-server-or-client.js +1 -1
  22. package/src/validate-no-client-creation-outside-server-or-client.js.map +1 -1
  23. package/src/validate-no-custom-css.js +1 -1
  24. package/src/validate-no-custom-css.js.map +1 -1
  25. package/src/validate-no-destructure.js +2 -2
  26. package/src/validate-no-destructure.js.map +1 -1
  27. package/src/validate-no-direct-api-resolver.js +2 -2
  28. package/src/validate-no-direct-api-resolver.js.map +1 -1
  29. package/src/validate-no-function-outside-class.js +1 -1
  30. package/src/validate-no-function-outside-class.js.map +1 -1
  31. package/src/validate-no-implicit-any.js +1 -1
  32. package/src/validate-no-implicit-any.js.map +1 -1
  33. package/src/validate-no-inline-types.js +2 -2
  34. package/src/validate-no-inline-types.js.map +1 -1
  35. package/src/validate-no-process-exit-outside-main.js +1 -1
  36. package/src/validate-no-process-exit-outside-main.js.map +1 -1
  37. package/src/validate-no-symbol-di-tokens.js +1 -1
  38. package/src/validate-no-symbol-di-tokens.js.map +1 -1
  39. package/src/validate-no-unmanaged-exceptions.js +2 -2
  40. package/src/validate-no-unmanaged-exceptions.js.map +1 -1
  41. package/src/validate-prisma-converters.js +2 -2
  42. package/src/validate-prisma-converters.js.map +1 -1
  43. package/src/validate-return-types.js +2 -2
  44. package/src/validate-return-types.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"validate-new-methods.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-new-methods.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate New Methods Executor\n *\n * Validates that newly added methods don't exceed a maximum line count.\n * Runs in affected mode when:\n * 1. NX_BASE environment variable is set (via nx affected), OR\n * 2. Auto-detects base by finding merge-base with origin/main\n *\n * This validator encourages writing methods that read like a \"table of contents\"\n * where each method call describes a larger piece of work.\n *\n * Usage:\n * nx affected --target=validate-new-methods --base=origin/main\n * OR: runs automatically via build's architecture:validate-complete dependency\n *\n * Escape hatch: Add webpieces-disable max-lines-new-methods comment with justification\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 findNewMethodSignaturesInDiff,\n} from '@webpieces/rules-config';\nimport { ExecutorResult } from './code-validator';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n lines: number;\n isNew: boolean;\n limit: number;\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n lines: number;\n hasDisableComment: boolean;\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 * Check if a line contains a webpieces-disable comment that exempts from new method validation.\n * Both max-lines-new-methods AND max-lines-modified are accepted here.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n // Check the line before the method (lineNumber is 1-indexed, array is 0-indexed)\n // We need to check a few lines before in case there's JSDoc or decorators\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n // Stop if we hit another function/class/etc\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes(WEBPIECES_DISABLE)) {\n // Either escape hatch exempts from the lowLimit new method check\n if (line.includes(RULE_NAMES.MAX_LINES_NEW_METHODS) || line.includes(RULE_NAMES.MAX_LINES_MODIFIED)) {\n return true;\n }\n }\n }\n return false;\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 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 // Check if it's assigned to a variable\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 lines: endLine - startLine + 1,\n hasDisableComment: hasDisableComment(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Find new methods that exceed the line limit\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 // Get the diff to find which methods are NEW (not just modified)\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n\n if (newMethodNames.size === 0) continue;\n\n // Parse the current file to get method line counts\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (!newMethodNames.has(method.name)) continue;\n\n if (method.lines > limit) {\n if (!disableAllowed) {\n // No escape possible\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n lines: method.lines,\n isNew: true,\n limit,\n });\n } else if (!method.hasDisableComment) {\n // Escape allowed but not present\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n lines: method.lines,\n isNew: true,\n limit,\n });\n }\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to the user with helpful instructions\n */\nfunction reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c New methods exceed ' + limit + ' line limit!');\n console.error('');\n console.error('\\ud83d\\udcda Methods should read like a \"table of contents\" - each method call');\n console.error(' describes a larger piece of work.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n if (disableAllowed) {\n console.error('\\u26a0\\ufe0f VIOLATIONS (can use escape hatch):');\n } else {\n console.error('\\ud83d\\udeab VIOLATIONS (cannot be bypassed with disable comment):');\n }\n console.error('');\n for (const v of violations) {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, limit: ${limit})`);\n }\n console.error('');\n if (disableAllowed) {\n console.error(' Use escape: // webpieces-disable max-lines-new-methods -- [your reason]');\n } else {\n console.error(' These methods MUST be refactored - no escape hatch available (disableAllowed=false).');\n }\n console.error('');\n}\n\nexport async function runNewMethods(\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 new method validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // Check if running in affected mode via NX_BASE, or auto-detect\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 // Try to auto-detect base from git merge-base\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping new method validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-new-methods --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating New Method Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating New 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 new methods: ${limit} lines (${disableAllowed ? 'can escape' : 'NO escape possible'})`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Get changed TypeScript files (base to head, or working tree if head not set)\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 // Find violations\n const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);\n\n if (violations.length === 0) {\n console.log('\\u2705 All new methods are within ' + limit + ' lines');\n return { success: true };\n }\n\n // Write instructions file and report violations\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n\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 New method validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"validate-new-methods.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-new-methods.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate New Methods Executor\n *\n * Validates that newly added methods don't exceed a maximum line count.\n * Runs in affected mode when:\n * 1. NX_BASE environment variable is set (via nx affected), OR\n * 2. Auto-detects base by finding merge-base with origin/main\n *\n * This validator encourages writing methods that read like a \"table of contents\"\n * where each method call describes a larger piece of work.\n *\n * Usage:\n * nx affected --target=validate-new-methods --base=origin/main\n * OR: runs automatically via build's architecture:validate-complete dependency\n *\n * Escape hatch: Add webpieces-disable max-lines-new-methods comment with justification\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 findNewMethodSignaturesInDiff,\n} from '@webpieces/rules-config';\nimport { ExecutorResult } from './code-validator';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface MethodViolation {\n file: string;\n methodName: string;\n line: number;\n lines: number;\n isNew: boolean;\n limit: number;\n}\n\ninterface MethodInfo {\n name: string;\n line: number;\n lines: number;\n hasDisableComment: boolean;\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 * Check if a line contains a webpieces-disable comment that exempts from new method validation.\n * Both max-lines-new-methods AND max-lines-modified are accepted here.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n // Check the line before the method (lineNumber is 1-indexed, array is 0-indexed)\n // We need to check a few lines before in case there's JSDoc or decorators\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n // Stop if we hit another function/class/etc\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes(WEBPIECES_DISABLE)) {\n // Either escape hatch exempts from the lowLimit new method check\n if (line.includes(RULE_NAMES.MAX_LINES_NEW_METHODS) || line.includes(RULE_NAMES.MAX_LINES_MODIFIED)) {\n return true;\n }\n }\n }\n return false;\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 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 // Check if it's assigned to a variable\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 lines: endLine - startLine + 1,\n hasDisableComment: hasDisableComment(fileLines, startLine),\n });\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return methods;\n}\n\n/**\n * Find new methods that exceed the line limit\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 // Get the diff to find which methods are NEW (not just modified)\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const newMethodNames = findNewMethodSignaturesInDiff(diff);\n\n if (newMethodNames.size === 0) continue;\n\n // Parse the current file to get method line counts\n const methods = findMethodsInFile(file, workspaceRoot);\n\n for (const method of methods) {\n if (!newMethodNames.has(method.name)) continue;\n\n if (method.lines > limit) {\n if (!disableAllowed) {\n // No escape possible\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n lines: method.lines,\n isNew: true,\n limit,\n });\n } else if (!method.hasDisableComment) {\n // Escape allowed but not present\n violations.push({\n file,\n methodName: method.name,\n line: method.line,\n lines: method.lines,\n isNew: true,\n limit,\n });\n }\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to the user with helpful instructions\n */\nfunction reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c New methods exceed ' + limit + ' line limit!');\n console.error('');\n console.error('\\ud83d\\udcda Methods should read like a \"table of contents\" - each method call');\n console.error(' describes a larger piece of work.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n if (disableAllowed) {\n console.error('\\u26a0\\ufe0f VIOLATIONS (can use escape hatch):');\n } else {\n console.error('\\ud83d\\udeab VIOLATIONS (cannot be bypassed with disable comment):');\n }\n console.error('');\n for (const v of violations) {\n console.error(` \\u274c ${v.file}:${v.line}`);\n console.error(` Method: ${v.methodName} (${v.lines} lines, limit: ${limit})`);\n }\n console.error('');\n if (disableAllowed) {\n console.error(' Use escape: // webpieces-disable max-lines-new-methods -- [your reason]');\n } else {\n console.error(' These methods MUST be refactored - no escape hatch available (disableAllowed=false).');\n }\n console.error('');\n}\n\nexport async function runNewMethods(\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 new method validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // Check if running in affected mode via NX_BASE, or auto-detect\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 // Try to auto-detect base from git merge-base\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping new method validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-new-methods --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating New Method Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating New 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 new methods: ${limit} lines (${disableAllowed ? 'can escape' : 'NO escape possible'})`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Get changed TypeScript files (base to head, or working tree if head not set)\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 // Find violations\n const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);\n\n if (violations.length === 0) {\n console.log('\\u2705 All new methods are within ' + limit + ' lines');\n return { success: true };\n }\n\n // Write instructions file and report violations\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n\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 New method validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -281,7 +281,7 @@ function reportViolations(violations, mode) {
281
281
  console.error('');
282
282
  }
283
283
  /**
284
- * Resolve mode considering ignoreModifiedUntilEpoch override.
284
+ * Resolve mode considering turnOffRuleUntilEpoch override.
285
285
  * When active, downgrades to OFF. When expired, logs a warning.
286
286
  */
287
287
  function resolveMode(normalMode, epoch, branchPattern) {
@@ -297,7 +297,7 @@ function resolveMode(normalMode, epoch, branchPattern) {
297
297
  return normalMode;
298
298
  }
299
299
  async function runValidatorImpl(options, workspaceRoot) {
300
- const mode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch);
300
+ const mode = resolveMode(options.mode ?? 'OFF', options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined));
301
301
  const disableAllowed = options.disableAllowed ?? true;
302
302
  if (mode === 'OFF') {
303
303
  console.log('\n⏭️ Skipping no-any-unknown validation (mode: OFF)');
@@ -1 +1 @@
1
- {"version":3,"file":"validate-no-any-unknown.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-any-unknown.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Any Unknown Executor\n *\n * Validates that `any` and `unknown` TypeScript keywords are not used.\n * Uses LINE-BASED detection (not method-based) for git diff filtering.\n *\n * ============================================================================\n * VIOLATIONS (BAD) - These patterns are flagged:\n * ============================================================================\n *\n * - const x: any = ...\n * - function foo(arg: any): any { }\n * - const data = response as any;\n * - type T = any;\n * - const x: unknown = ...\n * - function foo(arg: unknown): unknown { }\n *\n * ============================================================================\n * MODES (LINE-BASED)\n * ============================================================================\n * - OFF: Skip validation entirely\n * - NEW_AND_MODIFIED_CODE: Flag any/unknown on changed lines (lines in diff hunks)\n * - NEW_AND_MODIFIED_FILES: Flag ALL any/unknown in files that were modified\n *\n * ============================================================================\n * ESCAPE HATCH\n * ============================================================================\n * Add comment above the violation:\n * // webpieces-disable no-any-unknown -- [your justification]\n * const x: any = ...;\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport { hasDisable, RULE_NAMES, NoAnyUnknownConfig, ModifiedCodeMode, detectBase, getChangedFiles, getFileDiff, getChangedLineNumbers } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface AnyUnknownViolation {\n file: string;\n line: number;\n column: number;\n keyword: 'any' | 'unknown';\n context: string;\n}\n\n/**\n * Check if a line contains a webpieces-disable comment for no-any-unknown.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\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 (hasDisable(line, RULE_NAMES.NO_ANY_UNKNOWN)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Get a description of the context where the any/unknown keyword appears.\n */\n// webpieces-disable max-lines-new-methods -- Context detection requires checking many AST node types\nfunction getViolationContext(node: ts.Node, sourceFile: ts.SourceFile): string {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n let current: ts.Node = node;\n while (current.parent) {\n const parent = current.parent;\n if (ts.isParameter(parent)) {\n return 'parameter type';\n }\n if (ts.isFunctionDeclaration(parent) || ts.isMethodDeclaration(parent) || ts.isArrowFunction(parent)) {\n if (parent.type === current) {\n return 'return type';\n }\n }\n if (ts.isVariableDeclaration(parent)) {\n return 'variable type';\n }\n if (ts.isPropertyDeclaration(parent) || ts.isPropertySignature(parent)) {\n return 'property type';\n }\n if (ts.isAsExpression(parent)) {\n return 'type assertion';\n }\n if (ts.isTypeAliasDeclaration(parent)) {\n return 'type alias';\n }\n if (ts.isTypeReferenceNode(parent)) {\n return 'generic argument';\n }\n if (ts.isArrayTypeNode(parent)) {\n return 'array element type';\n }\n if (ts.isUnionTypeNode(parent) || ts.isIntersectionTypeNode(parent)) {\n return 'union/intersection type';\n }\n current = parent;\n }\n return 'type position';\n } catch (err: unknown) {\n //const error = toError(err);\n return 'type position';\n }\n}\n\ninterface AnyUnknownInfo {\n line: number;\n column: number;\n keyword: 'any' | 'unknown';\n context: string;\n hasDisableComment: boolean;\n}\n\n/**\n * Check if a node is in a catch clause variable declaration.\n * This allows `catch (err: unknown)` and `catch (err: unknown)` patterns.\n */\nfunction isInCatchClause(node: ts.Node): boolean {\n let current: ts.Node | undefined = node.parent;\n while (current) {\n if (ts.isCatchClause(current)) {\n // We're somewhere in a catch clause - check if we're in the variable declaration\n const catchClause = current as ts.CatchClause;\n if (catchClause.variableDeclaration) {\n // Walk back up from the original node to see if we're part of the variable declaration\n let checkNode: ts.Node | undefined = node.parent;\n while (checkNode && checkNode !== current) {\n if (checkNode === catchClause.variableDeclaration) {\n return true;\n }\n checkNode = checkNode.parent;\n }\n }\n }\n current = current.parent;\n }\n return false;\n}\n\n/**\n * Find all `any` and `unknown` keywords in a file using AST.\n */\n// webpieces-disable max-lines-new-methods -- AST traversal with nested visitor function for keyword detection\nfunction findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnknownInfo[] {\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 violations: AnyUnknownInfo[] = [];\n\n // webpieces-disable max-lines-new-methods -- AST visitor needs to handle both any and unknown keywords with full context detection\n function visit(node: ts.Node): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Detect `any` keyword\n if (node.kind === ts.SyntaxKind.AnyKeyword) {\n // Skip catch clause variable types: catch (err: unknown) is allowed\n if (isInCatchClause(node)) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const startPos = node.getStart(sourceFile);\n if (startPos >= 0) {\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const context = getViolationContext(node, sourceFile);\n const disabled = hasDisableComment(fileLines, line);\n\n violations.push({\n line,\n column,\n keyword: 'any',\n context,\n hasDisableComment: disabled,\n });\n }\n }\n\n // Detect `unknown` keyword\n if (node.kind === ts.SyntaxKind.UnknownKeyword) {\n // Skip catch clause variable types: catch (err: unknown) is allowed\n if (isInCatchClause(node)) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const startPos = node.getStart(sourceFile);\n if (startPos >= 0) {\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const context = getViolationContext(node, sourceFile);\n const disabled = hasDisableComment(fileLines, line);\n\n violations.push({\n line,\n column,\n keyword: 'unknown',\n context,\n hasDisableComment: disabled,\n });\n }\n }\n } catch (err: unknown) {\n //const error = toError(err);\n // Skip nodes that cause errors during analysis\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return violations;\n}\n\n/**\n * NEW_AND_MODIFIED_CODE mode: Flag violations on changed lines in diff hunks.\n * This is LINE-BASED detection.\n */\n// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and line filtering\nfunction findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean\n): AnyUnknownViolation[] {\n const violations: AnyUnknownViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n\n if (changedLines.size === 0) continue;\n\n const allViolations = findAnyUnknownInFile(file, workspaceRoot);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n // LINE-BASED: Only include if the violation is on a changed line\n if (!changedLines.has(v.line)) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n keyword: v.keyword,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * NEW_AND_MODIFIED_FILES mode: Flag ALL violations in files that were modified.\n */\nfunction findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean): AnyUnknownViolation[] {\n const violations: AnyUnknownViolation[] = [];\n\n for (const file of changedFiles) {\n const allViolations = findAnyUnknownInFile(file, workspaceRoot);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n keyword: v.keyword,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to console.\n */\nfunction reportViolations(violations: AnyUnknownViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error('❌ `any` and `unknown` keywords found! Use specific types instead.');\n console.error('');\n console.error('📚 Avoiding any/unknown improves type safety:');\n console.error('');\n console.error(' BAD: const data: any = fetchData();');\n console.error(' GOOD: const data: UserData = fetchData();');\n console.error('');\n console.error(' BAD: function process(input: unknown): unknown { }');\n console.error(' GOOD: function process(input: ValidInput): ValidOutput { }');\n console.error('');\n\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}:${v.column}`);\n console.error(` \\`${v.keyword}\\` keyword in ${v.context}`);\n }\n console.error('');\n\n console.error(' To fix: Replace with specific types or interfaces');\n console.error('');\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable no-any-unknown -- [your reason]');\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\n/**\n * Resolve mode considering ignoreModifiedUntilEpoch override.\n * When active, downgrades to OFF. When expired, logs a warning.\n */\nfunction resolveMode(normalMode: ModifiedCodeMode, epoch: number | undefined, branchPattern: string | undefined): ModifiedCodeMode {\n if (normalMode === 'OFF') {\n return normalMode;\n }\n const skip = shouldSkipRule(epoch, branchPattern);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping no-any-unknown validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\nasync function runValidatorImpl(\n options: NoAnyUnknownConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const mode: ModifiedCodeMode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch);\n const disableAllowed = options.disableAllowed ?? true;\n\n if (mode === 'OFF') {\n console.log('\\n⏭️ Skipping no-any-unknown validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n📏 Validating No Any/Unknown\\n');\n console.log(` Mode: ${mode}`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n⏭️ Skipping no-any-unknown validation (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\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: AnyUnknownViolation[] = [];\n\n if (mode === 'NEW_AND_MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);\n } else if (mode === 'NEW_AND_MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);\n }\n\n if (violations.length === 0) {\n console.log('✅ No any/unknown keywords found');\n return { success: true };\n }\n\n reportViolations(violations, mode);\n\n return { success: false };\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoAnyUnknownValidator extends CodeValidator<NoAnyUnknownConfig> {\n constructor(config: NoAnyUnknownConfig) {\n super(config, 'no-any-unknown');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
1
+ {"version":3,"file":"validate-no-any-unknown.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-any-unknown.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Any Unknown Executor\n *\n * Validates that `any` and `unknown` TypeScript keywords are not used.\n * Uses LINE-BASED detection (not method-based) for git diff filtering.\n *\n * ============================================================================\n * VIOLATIONS (BAD) - These patterns are flagged:\n * ============================================================================\n *\n * - const x: any = ...\n * - function foo(arg: any): any { }\n * - const data = response as any;\n * - type T = any;\n * - const x: unknown = ...\n * - function foo(arg: unknown): unknown { }\n *\n * ============================================================================\n * MODES (LINE-BASED)\n * ============================================================================\n * - OFF: Skip validation entirely\n * - NEW_AND_MODIFIED_CODE: Flag any/unknown on changed lines (lines in diff hunks)\n * - NEW_AND_MODIFIED_FILES: Flag ALL any/unknown in files that were modified\n *\n * ============================================================================\n * ESCAPE HATCH\n * ============================================================================\n * Add comment above the violation:\n * // webpieces-disable no-any-unknown -- [your justification]\n * const x: any = ...;\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport { hasDisable, RULE_NAMES, NoAnyUnknownConfig, ModifiedCodeMode, detectBase, getChangedFiles, getFileDiff, getChangedLineNumbers } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface AnyUnknownViolation {\n file: string;\n line: number;\n column: number;\n keyword: 'any' | 'unknown';\n context: string;\n}\n\n/**\n * Check if a line contains a webpieces-disable comment for no-any-unknown.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\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 (hasDisable(line, RULE_NAMES.NO_ANY_UNKNOWN)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Get a description of the context where the any/unknown keyword appears.\n */\n// webpieces-disable max-lines-new-methods -- Context detection requires checking many AST node types\nfunction getViolationContext(node: ts.Node, sourceFile: ts.SourceFile): string {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n let current: ts.Node = node;\n while (current.parent) {\n const parent = current.parent;\n if (ts.isParameter(parent)) {\n return 'parameter type';\n }\n if (ts.isFunctionDeclaration(parent) || ts.isMethodDeclaration(parent) || ts.isArrowFunction(parent)) {\n if (parent.type === current) {\n return 'return type';\n }\n }\n if (ts.isVariableDeclaration(parent)) {\n return 'variable type';\n }\n if (ts.isPropertyDeclaration(parent) || ts.isPropertySignature(parent)) {\n return 'property type';\n }\n if (ts.isAsExpression(parent)) {\n return 'type assertion';\n }\n if (ts.isTypeAliasDeclaration(parent)) {\n return 'type alias';\n }\n if (ts.isTypeReferenceNode(parent)) {\n return 'generic argument';\n }\n if (ts.isArrayTypeNode(parent)) {\n return 'array element type';\n }\n if (ts.isUnionTypeNode(parent) || ts.isIntersectionTypeNode(parent)) {\n return 'union/intersection type';\n }\n current = parent;\n }\n return 'type position';\n } catch (err: unknown) {\n //const error = toError(err);\n return 'type position';\n }\n}\n\ninterface AnyUnknownInfo {\n line: number;\n column: number;\n keyword: 'any' | 'unknown';\n context: string;\n hasDisableComment: boolean;\n}\n\n/**\n * Check if a node is in a catch clause variable declaration.\n * This allows `catch (err: unknown)` and `catch (err: unknown)` patterns.\n */\nfunction isInCatchClause(node: ts.Node): boolean {\n let current: ts.Node | undefined = node.parent;\n while (current) {\n if (ts.isCatchClause(current)) {\n // We're somewhere in a catch clause - check if we're in the variable declaration\n const catchClause = current as ts.CatchClause;\n if (catchClause.variableDeclaration) {\n // Walk back up from the original node to see if we're part of the variable declaration\n let checkNode: ts.Node | undefined = node.parent;\n while (checkNode && checkNode !== current) {\n if (checkNode === catchClause.variableDeclaration) {\n return true;\n }\n checkNode = checkNode.parent;\n }\n }\n }\n current = current.parent;\n }\n return false;\n}\n\n/**\n * Find all `any` and `unknown` keywords in a file using AST.\n */\n// webpieces-disable max-lines-new-methods -- AST traversal with nested visitor function for keyword detection\nfunction findAnyUnknownInFile(filePath: string, workspaceRoot: string): AnyUnknownInfo[] {\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 violations: AnyUnknownInfo[] = [];\n\n // webpieces-disable max-lines-new-methods -- AST visitor needs to handle both any and unknown keywords with full context detection\n function visit(node: ts.Node): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Detect `any` keyword\n if (node.kind === ts.SyntaxKind.AnyKeyword) {\n // Skip catch clause variable types: catch (err: unknown) is allowed\n if (isInCatchClause(node)) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const startPos = node.getStart(sourceFile);\n if (startPos >= 0) {\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const context = getViolationContext(node, sourceFile);\n const disabled = hasDisableComment(fileLines, line);\n\n violations.push({\n line,\n column,\n keyword: 'any',\n context,\n hasDisableComment: disabled,\n });\n }\n }\n\n // Detect `unknown` keyword\n if (node.kind === ts.SyntaxKind.UnknownKeyword) {\n // Skip catch clause variable types: catch (err: unknown) is allowed\n if (isInCatchClause(node)) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const startPos = node.getStart(sourceFile);\n if (startPos >= 0) {\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const context = getViolationContext(node, sourceFile);\n const disabled = hasDisableComment(fileLines, line);\n\n violations.push({\n line,\n column,\n keyword: 'unknown',\n context,\n hasDisableComment: disabled,\n });\n }\n }\n } catch (err: unknown) {\n //const error = toError(err);\n // Skip nodes that cause errors during analysis\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return violations;\n}\n\n/**\n * NEW_AND_MODIFIED_CODE mode: Flag violations on changed lines in diff hunks.\n * This is LINE-BASED detection.\n */\n// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and line filtering\nfunction findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean\n): AnyUnknownViolation[] {\n const violations: AnyUnknownViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n\n if (changedLines.size === 0) continue;\n\n const allViolations = findAnyUnknownInFile(file, workspaceRoot);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n // LINE-BASED: Only include if the violation is on a changed line\n if (!changedLines.has(v.line)) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n keyword: v.keyword,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * NEW_AND_MODIFIED_FILES mode: Flag ALL violations in files that were modified.\n */\nfunction findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean): AnyUnknownViolation[] {\n const violations: AnyUnknownViolation[] = [];\n\n for (const file of changedFiles) {\n const allViolations = findAnyUnknownInFile(file, workspaceRoot);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n keyword: v.keyword,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to console.\n */\nfunction reportViolations(violations: AnyUnknownViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error('❌ `any` and `unknown` keywords found! Use specific types instead.');\n console.error('');\n console.error('📚 Avoiding any/unknown improves type safety:');\n console.error('');\n console.error(' BAD: const data: any = fetchData();');\n console.error(' GOOD: const data: UserData = fetchData();');\n console.error('');\n console.error(' BAD: function process(input: unknown): unknown { }');\n console.error(' GOOD: function process(input: ValidInput): ValidOutput { }');\n console.error('');\n\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}:${v.column}`);\n console.error(` \\`${v.keyword}\\` keyword in ${v.context}`);\n }\n console.error('');\n\n console.error(' To fix: Replace with specific types or interfaces');\n console.error('');\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable no-any-unknown -- [your reason]');\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\n/**\n * Resolve mode considering turnOffRuleUntilEpoch override.\n * When active, downgrades to OFF. When expired, logs a warning.\n */\nfunction resolveMode(normalMode: ModifiedCodeMode, epoch: number | undefined, branchPattern: string | undefined): ModifiedCodeMode {\n if (normalMode === 'OFF') {\n return normalMode;\n }\n const skip = shouldSkipRule(epoch, branchPattern);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping no-any-unknown validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\nasync function runValidatorImpl(\n options: NoAnyUnknownConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const mode: ModifiedCodeMode = resolveMode(options.mode ?? 'OFF', options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined));\n const disableAllowed = options.disableAllowed ?? true;\n\n if (mode === 'OFF') {\n console.log('\\n⏭️ Skipping no-any-unknown validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n📏 Validating No Any/Unknown\\n');\n console.log(` Mode: ${mode}`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n⏭️ Skipping no-any-unknown validation (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\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: AnyUnknownViolation[] = [];\n\n if (mode === 'NEW_AND_MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);\n } else if (mode === 'NEW_AND_MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);\n }\n\n if (violations.length === 0) {\n console.log('✅ No any/unknown keywords found');\n return { success: true };\n }\n\n reportViolations(violations, mode);\n\n return { success: false };\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoAnyUnknownValidator extends CodeValidator<NoAnyUnknownConfig> {\n constructor(config: NoAnyUnknownConfig) {\n super(config, 'no-any-unknown');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
@@ -129,7 +129,7 @@ let NoClientCreationOutsideServerOrClientValidator = class NoClientCreationOutsi
129
129
  resolveMode(normalMode) {
130
130
  if (normalMode === 'OFF')
131
131
  return normalMode;
132
- const skip = (0, resolve_mode_1.shouldSkipRule)(this.config.ignoreModifiedUntilEpoch, this.config.ignoreRuleWhileOnBranch);
132
+ const skip = (0, resolve_mode_1.shouldSkipRule)(this.config.turnOffRuleUntilEpoch, this.config.turnOffRuleWhileOnBranch);
133
133
  if (skip.skip) {
134
134
  console.log(`\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})`);
135
135
  console.log('');
@@ -1 +1 @@
1
- {"version":3,"file":"validate-no-client-creation-outside-server-or-client.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-client-creation-outside-server-or-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Client Creation Outside Server Or Client\n *\n * Flags a project that CONSTRUCTS an rpc/pubsub transport client when the project's `role:` tag is\n * not one of the runnable/entrypoint roles (`allowedRoles`, default server | client | app).\n *\n * ============================================================================\n * WHY\n * ============================================================================\n * The runtime architecture graph draws a `uses` edge from every client-creation site to the api's\n * implementer. When the site sits in a project with a declared identity (`serviceName`) or target\n * (`callsService`) — a server, a client app, an app — the edge is attributable. When it sits in a\n * `role:lib`, the target can't be attributed, so the graph falls back to a fan-out: one `uses` edge\n * to EVERY implementer of the api, i.e. calls that cannot happen. A company-wide api (warmup,\n * browser-log, auth) then draws every caller to every server — pure fiction. This rule removes the\n * failure mode by construction: a reusable library takes the api INJECTED; the server/app module\n * binds it to a client.\n *\n * ============================================================================\n * VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:\n * ============================================================================\n * factory.createRpcClient(SomeApi, new ClientConfig('svc'))\n * clientCloudTasksFactory.createPubSubClient(SomeApi, config)\n *\n * ============================================================================\n * ALLOWED\n * ============================================================================\n * - Any site in a project whose role IS in allowedRoles (server / client / app).\n * - A project with NO `role:` tag (the role-tag rule owns \"every project must declare a role\").\n * - Merely IMPORTING the api type or its DI token, or injecting the api — only constructing the\n * transport (a `.createRpcClient(` / `.createPubSubClient(` CALL) is a violation.\n * - Files under allowedPaths, test files, and lines carrying the webpieces-disable escape.\n *\n * ============================================================================\n * SEVERITY (WARN first, then error)\n * ============================================================================\n * severity \"warn\" (default) prints the violations + migration but PASSES the build, so an upgrade\n * can't break an un-migrated Angular repo. Flip to \"error\" once libraries are migrated.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n RULE_NAMES,\n isPathExcluded,\n NoClientCreationOutsideServerOrClientConfig,\n ClientCreationSeverity,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\nimport { ProjectRoleResolver } from './project-role-resolver';\n\nconst RULE_NAME = RULE_NAMES.NO_CLIENT_CREATION_OUTSIDE_SERVER_OR_CLIENT;\nconst DEFAULT_ALLOWED_ROLES = ['server', 'client', 'app'];\n// A `.createRpcClient(` / `.createPubSubClient(` method CALL — the leading dot excludes the framework\n// method DEFINITIONS (`createRpcClient<T>(apiPrototype, ...)`, no receiver); the `[(<]` requires a call\n// or a generic call, so a bare property reference isn't matched.\nconst CLIENT_CREATE_REGEX = /\\.(createRpcClient|createPubSubClient)\\s*[(<]/;\n\n/** One client-creation call site found in a file. */\nclass CreationSite {\n constructor(\n public readonly line: number,\n public readonly context: string,\n public readonly hasDisableComment: boolean,\n ) {}\n}\n\n/** A reported violation: a client-creation site in a project whose role is not allowed. */\nclass Violation {\n constructor(\n public readonly file: string,\n public readonly line: number,\n public readonly context: string,\n public readonly role: string,\n ) {}\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoClientCreationOutsideServerOrClientValidator extends CodeValidator<NoClientCreationOutsideServerOrClientConfig> {\n constructor(\n config: NoClientCreationOutsideServerOrClientConfig,\n private readonly roleResolver: ProjectRoleResolver,\n ) {\n super(config, RULE_NAME);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(this.config.mode ?? 'OFF');\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)`);\n console.log('');\n return { success: true };\n }\n\n const severity: ClientCreationSeverity = this.config.severity ?? 'warn';\n console.log(`\\n📏 Validating No Client Creation Outside Server Or Client\\n`);\n console.log(` Mode: ${mode} · Severity: ${severity}`);\n\n const base = this.resolveBase(workspaceRoot);\n if (base === null) return { success: true };\n const head = process.env['NX_HEAD'];\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n const violations = this.findViolations(workspaceRoot, changedFiles, mode, base, head);\n\n if (violations.length === 0) {\n console.log('✅ No client-creation-in-a-library violations found');\n return { success: true };\n }\n\n this.report(violations, severity);\n // WARN reports but passes; only \"error\" fails the build.\n return { success: severity !== 'error' };\n }\n\n private allowedRoles(): string[] {\n const configured = this.config.allowedRoles;\n return configured && configured.length > 0 ? configured : DEFAULT_ALLOWED_ROLES;\n }\n\n private disableAllowed(): boolean {\n return this.config.disableAllowed ?? true;\n }\n\n private allowedPaths(): string[] {\n return this.config.allowedPaths ?? [];\n }\n\n private resolveMode(normalMode: ModifiedCodeMode): ModifiedCodeMode {\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(this.config.ignoreModifiedUntilEpoch, this.config.ignoreRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n }\n\n private resolveBase(workspaceRoot: string): string | null {\n const envBase = process.env['NX_BASE'];\n if (envBase) return envBase;\n const detected = detectBase(workspaceRoot);\n if (!detected) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (could not detect base branch)`);\n console.log('');\n return null;\n }\n return detected;\n }\n\n /** Violations across changed files: a creation site in a project whose role is not allowed. In\n * NEW_AND_MODIFIED_CODE only sites on changed lines count; in NEW_AND_MODIFIED_FILES every site\n * in a changed file counts. */\n private findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n mode: ModifiedCodeMode,\n base: string,\n head: string | undefined,\n ): Violation[] {\n const allowed = new Set(this.allowedRoles());\n const violations: Violation[] = [];\n for (const file of changedFiles) {\n if (this.isExempt(file)) continue;\n\n const role = this.roleResolver.roleOf(workspaceRoot, file);\n // No role tag → role-tag rule owns it; an allowed role → fine. Either way, skip.\n if (role === null || allowed.has(role)) continue;\n\n const changedLines = mode === 'NEW_AND_MODIFIED_CODE'\n ? getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head))\n : null;\n if (changedLines !== null && changedLines.size === 0) continue;\n\n for (const site of this.scanFile(workspaceRoot, file)) {\n if (this.disableAllowed() && site.hasDisableComment) continue;\n if (changedLines !== null && !changedLines.has(site.line)) continue;\n violations.push(new Violation(file, site.line, site.context, role));\n }\n }\n return violations;\n }\n\n private isExempt(file: string): boolean {\n return this.isTestFile(file) || isPathExcluded(file, this.allowedPaths());\n }\n\n private isTestFile(filePath: string): boolean {\n return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');\n }\n\n /** Every client-creation call site in a file, ignoring occurrences inside comments. */\n private scanFile(workspaceRoot: string, relFile: string): CreationSite[] {\n const fullPath = path.join(workspaceRoot, relFile);\n if (!fs.existsSync(fullPath)) return [];\n const lines = fs.readFileSync(fullPath, 'utf-8').split('\\n');\n const code = this.stripComments(lines);\n\n const sites: CreationSite[] = [];\n for (let i = 0; i < code.length; i++) {\n if (!CLIENT_CREATE_REGEX.test(code[i] ?? '')) continue;\n const raw = lines[i] ?? '';\n const prev = i > 0 ? (lines[i - 1] ?? '') : '';\n const disabled = hasDisable(raw, RULE_NAME) || hasDisable(prev, RULE_NAME);\n sites.push(new CreationSite(i + 1, raw.trim(), disabled));\n }\n return sites;\n }\n\n /** The code-only text of each line: block comments (/* … *\\/) and line comments (// …) blanked\n * out, so a `factory.createRpcClient(` in a JSDoc example is never matched. */\n private stripComments(lines: string[]): string[] {\n const out: string[] = [];\n let inBlock = false;\n for (const line of lines) {\n let result = '';\n let i = 0;\n while (i < line.length) {\n if (inBlock) {\n if (line[i] === '*' && line[i + 1] === '/') { inBlock = false; i += 2; } else { i += 1; }\n continue;\n }\n if (line[i] === '/' && line[i + 1] === '*') { inBlock = true; i += 2; continue; }\n if (line[i] === '/' && line[i + 1] === '/') break;\n result += line[i];\n i += 1;\n }\n out.push(result);\n }\n return out;\n }\n\n // webpieces-disable max-lines-new-methods -- console guidance block + violation list\n private report(violations: Violation[], severity: ClientCreationSeverity): void {\n const icon = severity === 'error' ? '❌' : '⚠️';\n console.error('');\n console.error(`${icon} A library (role:lib) must NOT construct an rpc/pubsub client!`);\n console.error('');\n console.error(' Only a runnable entrypoint (role:server / role:client / role:app) has a declared identity');\n console.error(' (serviceName) or target (callsService), so a client built there is attributable in the');\n console.error(' runtime graph. A client built in a library reaches the fan-out fallback — one \"uses\" edge');\n console.error(' to EVERY implementer of the api, i.e. calls that cannot happen.');\n console.error('');\n console.error(' Migrate: the library takes the api INJECTED (constructor(private readonly api: SomeApi)),');\n console.error(' and the server/app DI module constructs the client with factory.createRpcClient(SomeApi, ...).');\n console.error('');\n for (const v of violations) {\n console.error(` ${icon} ${v.file}:${v.line} (role:${v.role})`);\n console.error(` ${v.context}`);\n }\n console.error('');\n if (this.disableAllowed()) {\n console.error(' Escape hatch (use sparingly):');\n console.error(` // webpieces-disable ${RULE_NAME} -- <reason>`);\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n }\n console.error('');\n if (severity !== 'error') {\n console.error(' Severity: WARN — reported but NOT failing the build. Migrate, then set');\n console.error(` \"severity\": \"error\" on ${RULE_NAME} to enforce.`);\n console.error('');\n }\n }\n}\n"]}
1
+ {"version":3,"file":"validate-no-client-creation-outside-server-or-client.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-client-creation-outside-server-or-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Client Creation Outside Server Or Client\n *\n * Flags a project that CONSTRUCTS an rpc/pubsub transport client when the project's `role:` tag is\n * not one of the runnable/entrypoint roles (`allowedRoles`, default server | client | app).\n *\n * ============================================================================\n * WHY\n * ============================================================================\n * The runtime architecture graph draws a `uses` edge from every client-creation site to the api's\n * implementer. When the site sits in a project with a declared identity (`serviceName`) or target\n * (`callsService`) — a server, a client app, an app — the edge is attributable. When it sits in a\n * `role:lib`, the target can't be attributed, so the graph falls back to a fan-out: one `uses` edge\n * to EVERY implementer of the api, i.e. calls that cannot happen. A company-wide api (warmup,\n * browser-log, auth) then draws every caller to every server — pure fiction. This rule removes the\n * failure mode by construction: a reusable library takes the api INJECTED; the server/app module\n * binds it to a client.\n *\n * ============================================================================\n * VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:\n * ============================================================================\n * factory.createRpcClient(SomeApi, new ClientConfig('svc'))\n * clientCloudTasksFactory.createPubSubClient(SomeApi, config)\n *\n * ============================================================================\n * ALLOWED\n * ============================================================================\n * - Any site in a project whose role IS in allowedRoles (server / client / app).\n * - A project with NO `role:` tag (the role-tag rule owns \"every project must declare a role\").\n * - Merely IMPORTING the api type or its DI token, or injecting the api — only constructing the\n * transport (a `.createRpcClient(` / `.createPubSubClient(` CALL) is a violation.\n * - Files under allowedPaths, test files, and lines carrying the webpieces-disable escape.\n *\n * ============================================================================\n * SEVERITY (WARN first, then error)\n * ============================================================================\n * severity \"warn\" (default) prints the violations + migration but PASSES the build, so an upgrade\n * can't break an un-migrated Angular repo. Flip to \"error\" once libraries are migrated.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n RULE_NAMES,\n isPathExcluded,\n NoClientCreationOutsideServerOrClientConfig,\n ClientCreationSeverity,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\nimport { ProjectRoleResolver } from './project-role-resolver';\n\nconst RULE_NAME = RULE_NAMES.NO_CLIENT_CREATION_OUTSIDE_SERVER_OR_CLIENT;\nconst DEFAULT_ALLOWED_ROLES = ['server', 'client', 'app'];\n// A `.createRpcClient(` / `.createPubSubClient(` method CALL — the leading dot excludes the framework\n// method DEFINITIONS (`createRpcClient<T>(apiPrototype, ...)`, no receiver); the `[(<]` requires a call\n// or a generic call, so a bare property reference isn't matched.\nconst CLIENT_CREATE_REGEX = /\\.(createRpcClient|createPubSubClient)\\s*[(<]/;\n\n/** One client-creation call site found in a file. */\nclass CreationSite {\n constructor(\n public readonly line: number,\n public readonly context: string,\n public readonly hasDisableComment: boolean,\n ) {}\n}\n\n/** A reported violation: a client-creation site in a project whose role is not allowed. */\nclass Violation {\n constructor(\n public readonly file: string,\n public readonly line: number,\n public readonly context: string,\n public readonly role: string,\n ) {}\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoClientCreationOutsideServerOrClientValidator extends CodeValidator<NoClientCreationOutsideServerOrClientConfig> {\n constructor(\n config: NoClientCreationOutsideServerOrClientConfig,\n private readonly roleResolver: ProjectRoleResolver,\n ) {\n super(config, RULE_NAME);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(this.config.mode ?? 'OFF');\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)`);\n console.log('');\n return { success: true };\n }\n\n const severity: ClientCreationSeverity = this.config.severity ?? 'warn';\n console.log(`\\n📏 Validating No Client Creation Outside Server Or Client\\n`);\n console.log(` Mode: ${mode} · Severity: ${severity}`);\n\n const base = this.resolveBase(workspaceRoot);\n if (base === null) return { success: true };\n const head = process.env['NX_HEAD'];\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n const violations = this.findViolations(workspaceRoot, changedFiles, mode, base, head);\n\n if (violations.length === 0) {\n console.log('✅ No client-creation-in-a-library violations found');\n return { success: true };\n }\n\n this.report(violations, severity);\n // WARN reports but passes; only \"error\" fails the build.\n return { success: severity !== 'error' };\n }\n\n private allowedRoles(): string[] {\n const configured = this.config.allowedRoles;\n return configured && configured.length > 0 ? configured : DEFAULT_ALLOWED_ROLES;\n }\n\n private disableAllowed(): boolean {\n return this.config.disableAllowed ?? true;\n }\n\n private allowedPaths(): string[] {\n return this.config.allowedPaths ?? [];\n }\n\n private resolveMode(normalMode: ModifiedCodeMode): ModifiedCodeMode {\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(this.config.turnOffRuleUntilEpoch, this.config.turnOffRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n }\n\n private resolveBase(workspaceRoot: string): string | null {\n const envBase = process.env['NX_BASE'];\n if (envBase) return envBase;\n const detected = detectBase(workspaceRoot);\n if (!detected) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (could not detect base branch)`);\n console.log('');\n return null;\n }\n return detected;\n }\n\n /** Violations across changed files: a creation site in a project whose role is not allowed. In\n * NEW_AND_MODIFIED_CODE only sites on changed lines count; in NEW_AND_MODIFIED_FILES every site\n * in a changed file counts. */\n private findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n mode: ModifiedCodeMode,\n base: string,\n head: string | undefined,\n ): Violation[] {\n const allowed = new Set(this.allowedRoles());\n const violations: Violation[] = [];\n for (const file of changedFiles) {\n if (this.isExempt(file)) continue;\n\n const role = this.roleResolver.roleOf(workspaceRoot, file);\n // No role tag → role-tag rule owns it; an allowed role → fine. Either way, skip.\n if (role === null || allowed.has(role)) continue;\n\n const changedLines = mode === 'NEW_AND_MODIFIED_CODE'\n ? getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head))\n : null;\n if (changedLines !== null && changedLines.size === 0) continue;\n\n for (const site of this.scanFile(workspaceRoot, file)) {\n if (this.disableAllowed() && site.hasDisableComment) continue;\n if (changedLines !== null && !changedLines.has(site.line)) continue;\n violations.push(new Violation(file, site.line, site.context, role));\n }\n }\n return violations;\n }\n\n private isExempt(file: string): boolean {\n return this.isTestFile(file) || isPathExcluded(file, this.allowedPaths());\n }\n\n private isTestFile(filePath: string): boolean {\n return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');\n }\n\n /** Every client-creation call site in a file, ignoring occurrences inside comments. */\n private scanFile(workspaceRoot: string, relFile: string): CreationSite[] {\n const fullPath = path.join(workspaceRoot, relFile);\n if (!fs.existsSync(fullPath)) return [];\n const lines = fs.readFileSync(fullPath, 'utf-8').split('\\n');\n const code = this.stripComments(lines);\n\n const sites: CreationSite[] = [];\n for (let i = 0; i < code.length; i++) {\n if (!CLIENT_CREATE_REGEX.test(code[i] ?? '')) continue;\n const raw = lines[i] ?? '';\n const prev = i > 0 ? (lines[i - 1] ?? '') : '';\n const disabled = hasDisable(raw, RULE_NAME) || hasDisable(prev, RULE_NAME);\n sites.push(new CreationSite(i + 1, raw.trim(), disabled));\n }\n return sites;\n }\n\n /** The code-only text of each line: block comments (/* … *\\/) and line comments (// …) blanked\n * out, so a `factory.createRpcClient(` in a JSDoc example is never matched. */\n private stripComments(lines: string[]): string[] {\n const out: string[] = [];\n let inBlock = false;\n for (const line of lines) {\n let result = '';\n let i = 0;\n while (i < line.length) {\n if (inBlock) {\n if (line[i] === '*' && line[i + 1] === '/') { inBlock = false; i += 2; } else { i += 1; }\n continue;\n }\n if (line[i] === '/' && line[i + 1] === '*') { inBlock = true; i += 2; continue; }\n if (line[i] === '/' && line[i + 1] === '/') break;\n result += line[i];\n i += 1;\n }\n out.push(result);\n }\n return out;\n }\n\n // webpieces-disable max-lines-new-methods -- console guidance block + violation list\n private report(violations: Violation[], severity: ClientCreationSeverity): void {\n const icon = severity === 'error' ? '❌' : '⚠️';\n console.error('');\n console.error(`${icon} A library (role:lib) must NOT construct an rpc/pubsub client!`);\n console.error('');\n console.error(' Only a runnable entrypoint (role:server / role:client / role:app) has a declared identity');\n console.error(' (serviceName) or target (callsService), so a client built there is attributable in the');\n console.error(' runtime graph. A client built in a library reaches the fan-out fallback — one \"uses\" edge');\n console.error(' to EVERY implementer of the api, i.e. calls that cannot happen.');\n console.error('');\n console.error(' Migrate: the library takes the api INJECTED (constructor(private readonly api: SomeApi)),');\n console.error(' and the server/app DI module constructs the client with factory.createRpcClient(SomeApi, ...).');\n console.error('');\n for (const v of violations) {\n console.error(` ${icon} ${v.file}:${v.line} (role:${v.role})`);\n console.error(` ${v.context}`);\n }\n console.error('');\n if (this.disableAllowed()) {\n console.error(' Escape hatch (use sparingly):');\n console.error(` // webpieces-disable ${RULE_NAME} -- <reason>`);\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n }\n console.error('');\n if (severity !== 'error') {\n console.error(' Severity: WARN — reported but NOT failing the build. Migrate, then set');\n console.error(` \"severity\": \"error\" on ${RULE_NAME} to enforce.`);\n console.error('');\n }\n }\n}\n"]}
@@ -68,7 +68,7 @@ let NoCustomCssValidator = class NoCustomCssValidator extends code_validator_1.C
68
68
  }
69
69
  async run(workspaceRoot) {
70
70
  const opts = this.config;
71
- const mode = this.resolveMode(opts.mode ?? 'OFF', opts.ignoreModifiedUntilEpoch, opts.ignoreRuleWhileOnBranch);
71
+ const mode = this.resolveMode(opts.mode ?? 'OFF', opts.turnOffRuleUntilEpoch, opts.turnOffRuleWhileOnBranch ?? undefined);
72
72
  const disableAllowed = opts.disableAllowed ?? true;
73
73
  if (mode === 'OFF') {
74
74
  console.log('\n⏭️ Skipping no-custom-css validation (mode: OFF)\n');
@@ -1 +1 @@
1
- {"version":3,"file":"validate-no-custom-css.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-custom-css.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Custom CSS Executor\n *\n * Enforces Tailwind-first styling in Angular sources by banning hand-written CSS on CHANGED code:\n * - `.ts` — `styles:` / `styleUrls:` / `styleUrl:` inside an `@Component({...})` decorator\n * (detected via the TypeScript AST, so only the real decorator triggers it).\n * - `.html` — a static `style=\"…\"` attribute, a `[style]` / `[style.x]` binding, or `[ngStyle]`\n * (line/regex scan — Angular templates have no TS AST).\n *\n * Unlike an ESLint rule (which lints whole files), this is diff-scoped: NEW_AND_MODIFIED_CODE only\n * flags violations on changed lines, so a legacy Angular app is never retroactively flooded — the\n * rule bites when a file is next edited.\n *\n * MODES: OFF | NEW_AND_MODIFIED_CODE (changed lines) | NEW_AND_MODIFIED_FILES (all in changed files).\n *\n * ESCAPE HATCH (a genuinely dynamic runtime value):\n * .ts: // webpieces-disable no-custom-css -- <reason>\n * .html: <!-- webpieces-disable no-custom-css -- <reason> -->\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport {\n hasDisable,\n RULE_NAMES,\n NoCustomCssConfig,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\n// @Component decorator properties that inject hand-written CSS.\nconst STYLE_PROPS = new Set(['styles', 'styleUrls', 'styleUrl']);\nconst TEST_PATHS: RegExp[] = [/\\.test\\.ts$/, /\\.spec\\.ts$/, /__tests__\\//];\n\n// Template patterns. `[style.width]=\"x\"` is preceded by `[`, so the inline-style regex's\n// `(^|\\s)style=` boundary keeps it apart from the binding forms.\nconst RE_INLINE_STYLE = /(^|\\s)style\\s*=\\s*[\"']/;\nconst RE_NG_STYLE = /\\[?ngStyle\\]?\\s*=/;\nconst RE_STYLE_BINDING = /\\[style(?:\\.[\\w.-]+)?\\]/;\n\nexport class CssViolation {\n constructor(\n readonly file: string,\n readonly line: number,\n readonly column: number,\n readonly detail: string,\n ) {}\n}\n\nexport class CssHit {\n constructor(\n readonly line: number,\n readonly column: number,\n readonly detail: string,\n readonly hasDisableComment: boolean,\n ) {}\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoCustomCssValidator extends CodeValidator<NoCustomCssConfig> {\n constructor(config: NoCustomCssConfig) {\n super(config, 'no-custom-css');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const opts = this.config;\n const mode = this.resolveMode(opts.mode ?? 'OFF', opts.ignoreModifiedUntilEpoch, opts.ignoreRuleWhileOnBranch);\n const disableAllowed = opts.disableAllowed ?? true;\n if (mode === 'OFF') {\n console.log('\\n⏭️ Skipping no-custom-css validation (mode: OFF)\\n');\n return { success: true };\n }\n\n console.log('\\n📏 Validating No Custom CSS (Tailwind-first)\\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 no-custom-css validation (could not detect base branch)\\n');\n return { success: true };\n }\n }\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\\n`);\n\n // tsOnly:false so changed .html templates are included; then filter to relevant files.\n const changedFiles = getChangedFiles(workspaceRoot, base, head, { tsOnly: false }).filter((f: string) => this.isRelevantFile(f));\n if (changedFiles.length === 0) {\n console.log('✅ No Angular .ts/.html files changed');\n return { success: true };\n }\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations =\n mode === 'NEW_AND_MODIFIED_CODE'\n ? this.findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed)\n : this.findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);\n\n if (violations.length === 0) {\n console.log('✅ No custom CSS found');\n return { success: true };\n }\n this.reportViolations(violations, mode);\n return { success: false };\n }\n\n /** A changed file this rule cares about: an Angular .ts/.tsx or .html, excluding test files. */\n isRelevantFile(file: string): boolean {\n if (TEST_PATHS.some((re: RegExp) => re.test(file))) return false;\n return file.endsWith('.html') || file.endsWith('.ts') || file.endsWith('.tsx');\n }\n\n /** All banned-CSS hits in a single file (dispatches to the .ts AST or the .html line scan). */\n findHitsForFile(file: string, workspaceRoot: string): CssHit[] {\n if (file.endsWith('.html')) return this.findCustomCssInHtmlFile(file, workspaceRoot);\n if (file.endsWith('.ts') || file.endsWith('.tsx')) return this.findCustomCssInTsFile(file, workspaceRoot);\n return [];\n }\n\n /** NEW_AND_MODIFIED_CODE: only hits whose line is in the diff hunks. */\n private findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean,\n ): CssViolation[] {\n const violations: CssViolation[] = [];\n for (const file of changedFiles) {\n const changedLines = getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head));\n if (changedLines.size === 0) continue;\n for (const h of this.findHitsForFile(file, workspaceRoot)) {\n if (disableAllowed && h.hasDisableComment) continue;\n if (!changedLines.has(h.line)) continue;\n violations.push(new CssViolation(file, h.line, h.column, h.detail));\n }\n }\n return violations;\n }\n\n /** NEW_AND_MODIFIED_FILES: all hits in any changed file. */\n private findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean): CssViolation[] {\n const violations: CssViolation[] = [];\n for (const file of changedFiles) {\n for (const h of this.findHitsForFile(file, workspaceRoot)) {\n if (disableAllowed && h.hasDisableComment) continue;\n violations.push(new CssViolation(file, h.line, h.column, h.detail));\n }\n }\n return violations;\n }\n\n /** Flag styles:/styleUrls:/styleUrl: properties inside an `@Component({...})` decorator. */\n private findCustomCssInTsFile(filePath: string, workspaceRoot: string): CssHit[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\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 const hits: CssHit[] = [];\n this.collectTsHits(sourceFile, sourceFile, fileLines, hits);\n return hits;\n }\n\n /** Recurse the AST; every `@Component(...)` decorator contributes its banned style props. */\n private collectTsHits(node: ts.Node, sourceFile: ts.SourceFile, fileLines: string[], hits: CssHit[]): void {\n if (ts.isDecorator(node)) this.collectComponentStyleProps(node, sourceFile, fileLines, hits);\n ts.forEachChild(node, (child: ts.Node) => this.collectTsHits(child, sourceFile, fileLines, hits));\n }\n\n /** Pull the banned style props out of a single `@Component(...)` decorator node. */\n private collectComponentStyleProps(node: ts.Decorator, sourceFile: ts.SourceFile, fileLines: string[], hits: CssHit[]): void {\n const expr = node.expression;\n if (!ts.isCallExpression(expr) || !ts.isIdentifier(expr.expression) || expr.expression.text !== 'Component') return;\n const arg = expr.arguments[0];\n if (!arg || !ts.isObjectLiteralExpression(arg)) return;\n for (const prop of arg.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n const name = prop.name.text;\n if (!STYLE_PROPS.has(name)) continue;\n const pos = sourceFile.getLineAndCharacterOfPosition(prop.getStart(sourceFile));\n const line = pos.line + 1;\n hits.push(new CssHit(line, pos.character + 1, `\\`${name}\\` block in @Component`, this.hasDisableComment(fileLines, line)));\n }\n }\n\n /** Flag inline style=, [style.x]/[style], and [ngStyle] in an Angular template via a line scan. */\n private findCustomCssInHtmlFile(filePath: string, workspaceRoot: string): CssHit[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n const fileLines = fs.readFileSync(fullPath, 'utf-8').split('\\n');\n const hits: CssHit[] = [];\n for (let i = 0; i < fileLines.length; i++) {\n const detail = this.detailForTemplateLine(fileLines[i] ?? '');\n if (!detail) continue;\n const line = i + 1;\n hits.push(new CssHit(line, 1, detail, this.hasDisableComment(fileLines, line)));\n }\n return hits;\n }\n\n /** The banned-pattern label for a template line, or '' when the line is clean. */\n private detailForTemplateLine(raw: string): string {\n if (RE_NG_STYLE.test(raw)) return 'inline `[ngStyle]`';\n if (RE_STYLE_BINDING.test(raw)) return 'inline `[style.x]` binding';\n if (RE_INLINE_STYLE.test(raw)) return 'inline `style=` attribute';\n return '';\n }\n\n /** True if a `webpieces-disable no-custom-css` marker sits on this line or up to 3 lines above. */\n private hasDisableComment(lines: string[], lineNumber: number): boolean {\n const start = Math.max(0, lineNumber - 4);\n for (let i = lineNumber - 1; i >= start; i--) {\n if (hasDisable(lines[i] ?? '', RULE_NAMES.NO_CUSTOM_CSS)) return true;\n }\n return false;\n }\n\n private 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 no-custom-css validation (${skip.reason})\\n`);\n return 'OFF';\n }\n return normalMode;\n }\n\n private reportViolations(violations: CssViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error('❌ Custom CSS found in Angular source! Style with Tailwind utility classes instead.');\n console.error('');\n console.error('📚 Tailwind-first keeps styling in the template, greppable and consistent:');\n console.error(' BAD: styles: [\".card { display: flex; gap: 1rem; }\"]');\n console.error(' GOOD: class=\"flex gap-4\"');\n console.error(' BAD: <div style=\"width: 240px\"> | [style.width] | [ngStyle]');\n console.error(' GOOD: <div class=\"w-[240px]\"> | [class.x] toggles');\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}:${v.column}`);\n console.error(` ${v.detail}`);\n }\n console.error('');\n console.error(' To fix: delete the CSS and use Tailwind utility classes (arbitrary values like');\n console.error(' `bg-[#fffde7]` / `grid-cols-[2fr_2fr_2fr_48px]` cover the long tail).');\n console.error('');\n console.error(' Escape hatch (genuinely dynamic runtime value, use sparingly):');\n console.error(' .ts // webpieces-disable no-custom-css -- <reason>');\n console.error(' .html <!-- webpieces-disable no-custom-css -- <reason> -->');\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n }\n}\n"]}
1
+ {"version":3,"file":"validate-no-custom-css.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-custom-css.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Custom CSS Executor\n *\n * Enforces Tailwind-first styling in Angular sources by banning hand-written CSS on CHANGED code:\n * - `.ts` — `styles:` / `styleUrls:` / `styleUrl:` inside an `@Component({...})` decorator\n * (detected via the TypeScript AST, so only the real decorator triggers it).\n * - `.html` — a static `style=\"…\"` attribute, a `[style]` / `[style.x]` binding, or `[ngStyle]`\n * (line/regex scan — Angular templates have no TS AST).\n *\n * Unlike an ESLint rule (which lints whole files), this is diff-scoped: NEW_AND_MODIFIED_CODE only\n * flags violations on changed lines, so a legacy Angular app is never retroactively flooded — the\n * rule bites when a file is next edited.\n *\n * MODES: OFF | NEW_AND_MODIFIED_CODE (changed lines) | NEW_AND_MODIFIED_FILES (all in changed files).\n *\n * ESCAPE HATCH (a genuinely dynamic runtime value):\n * .ts: // webpieces-disable no-custom-css -- <reason>\n * .html: <!-- webpieces-disable no-custom-css -- <reason> -->\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport {\n hasDisable,\n RULE_NAMES,\n NoCustomCssConfig,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\n// @Component decorator properties that inject hand-written CSS.\nconst STYLE_PROPS = new Set(['styles', 'styleUrls', 'styleUrl']);\nconst TEST_PATHS: RegExp[] = [/\\.test\\.ts$/, /\\.spec\\.ts$/, /__tests__\\//];\n\n// Template patterns. `[style.width]=\"x\"` is preceded by `[`, so the inline-style regex's\n// `(^|\\s)style=` boundary keeps it apart from the binding forms.\nconst RE_INLINE_STYLE = /(^|\\s)style\\s*=\\s*[\"']/;\nconst RE_NG_STYLE = /\\[?ngStyle\\]?\\s*=/;\nconst RE_STYLE_BINDING = /\\[style(?:\\.[\\w.-]+)?\\]/;\n\nexport class CssViolation {\n constructor(\n readonly file: string,\n readonly line: number,\n readonly column: number,\n readonly detail: string,\n ) {}\n}\n\nexport class CssHit {\n constructor(\n readonly line: number,\n readonly column: number,\n readonly detail: string,\n readonly hasDisableComment: boolean,\n ) {}\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoCustomCssValidator extends CodeValidator<NoCustomCssConfig> {\n constructor(config: NoCustomCssConfig) {\n super(config, 'no-custom-css');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const opts = this.config;\n const mode = this.resolveMode(opts.mode ?? 'OFF', opts.turnOffRuleUntilEpoch, opts.turnOffRuleWhileOnBranch ?? undefined);\n const disableAllowed = opts.disableAllowed ?? true;\n if (mode === 'OFF') {\n console.log('\\n⏭️ Skipping no-custom-css validation (mode: OFF)\\n');\n return { success: true };\n }\n\n console.log('\\n📏 Validating No Custom CSS (Tailwind-first)\\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 no-custom-css validation (could not detect base branch)\\n');\n return { success: true };\n }\n }\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\\n`);\n\n // tsOnly:false so changed .html templates are included; then filter to relevant files.\n const changedFiles = getChangedFiles(workspaceRoot, base, head, { tsOnly: false }).filter((f: string) => this.isRelevantFile(f));\n if (changedFiles.length === 0) {\n console.log('✅ No Angular .ts/.html files changed');\n return { success: true };\n }\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations =\n mode === 'NEW_AND_MODIFIED_CODE'\n ? this.findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed)\n : this.findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);\n\n if (violations.length === 0) {\n console.log('✅ No custom CSS found');\n return { success: true };\n }\n this.reportViolations(violations, mode);\n return { success: false };\n }\n\n /** A changed file this rule cares about: an Angular .ts/.tsx or .html, excluding test files. */\n isRelevantFile(file: string): boolean {\n if (TEST_PATHS.some((re: RegExp) => re.test(file))) return false;\n return file.endsWith('.html') || file.endsWith('.ts') || file.endsWith('.tsx');\n }\n\n /** All banned-CSS hits in a single file (dispatches to the .ts AST or the .html line scan). */\n findHitsForFile(file: string, workspaceRoot: string): CssHit[] {\n if (file.endsWith('.html')) return this.findCustomCssInHtmlFile(file, workspaceRoot);\n if (file.endsWith('.ts') || file.endsWith('.tsx')) return this.findCustomCssInTsFile(file, workspaceRoot);\n return [];\n }\n\n /** NEW_AND_MODIFIED_CODE: only hits whose line is in the diff hunks. */\n private findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean,\n ): CssViolation[] {\n const violations: CssViolation[] = [];\n for (const file of changedFiles) {\n const changedLines = getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head));\n if (changedLines.size === 0) continue;\n for (const h of this.findHitsForFile(file, workspaceRoot)) {\n if (disableAllowed && h.hasDisableComment) continue;\n if (!changedLines.has(h.line)) continue;\n violations.push(new CssViolation(file, h.line, h.column, h.detail));\n }\n }\n return violations;\n }\n\n /** NEW_AND_MODIFIED_FILES: all hits in any changed file. */\n private findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean): CssViolation[] {\n const violations: CssViolation[] = [];\n for (const file of changedFiles) {\n for (const h of this.findHitsForFile(file, workspaceRoot)) {\n if (disableAllowed && h.hasDisableComment) continue;\n violations.push(new CssViolation(file, h.line, h.column, h.detail));\n }\n }\n return violations;\n }\n\n /** Flag styles:/styleUrls:/styleUrl: properties inside an `@Component({...})` decorator. */\n private findCustomCssInTsFile(filePath: string, workspaceRoot: string): CssHit[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\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 const hits: CssHit[] = [];\n this.collectTsHits(sourceFile, sourceFile, fileLines, hits);\n return hits;\n }\n\n /** Recurse the AST; every `@Component(...)` decorator contributes its banned style props. */\n private collectTsHits(node: ts.Node, sourceFile: ts.SourceFile, fileLines: string[], hits: CssHit[]): void {\n if (ts.isDecorator(node)) this.collectComponentStyleProps(node, sourceFile, fileLines, hits);\n ts.forEachChild(node, (child: ts.Node) => this.collectTsHits(child, sourceFile, fileLines, hits));\n }\n\n /** Pull the banned style props out of a single `@Component(...)` decorator node. */\n private collectComponentStyleProps(node: ts.Decorator, sourceFile: ts.SourceFile, fileLines: string[], hits: CssHit[]): void {\n const expr = node.expression;\n if (!ts.isCallExpression(expr) || !ts.isIdentifier(expr.expression) || expr.expression.text !== 'Component') return;\n const arg = expr.arguments[0];\n if (!arg || !ts.isObjectLiteralExpression(arg)) return;\n for (const prop of arg.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n const name = prop.name.text;\n if (!STYLE_PROPS.has(name)) continue;\n const pos = sourceFile.getLineAndCharacterOfPosition(prop.getStart(sourceFile));\n const line = pos.line + 1;\n hits.push(new CssHit(line, pos.character + 1, `\\`${name}\\` block in @Component`, this.hasDisableComment(fileLines, line)));\n }\n }\n\n /** Flag inline style=, [style.x]/[style], and [ngStyle] in an Angular template via a line scan. */\n private findCustomCssInHtmlFile(filePath: string, workspaceRoot: string): CssHit[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n const fileLines = fs.readFileSync(fullPath, 'utf-8').split('\\n');\n const hits: CssHit[] = [];\n for (let i = 0; i < fileLines.length; i++) {\n const detail = this.detailForTemplateLine(fileLines[i] ?? '');\n if (!detail) continue;\n const line = i + 1;\n hits.push(new CssHit(line, 1, detail, this.hasDisableComment(fileLines, line)));\n }\n return hits;\n }\n\n /** The banned-pattern label for a template line, or '' when the line is clean. */\n private detailForTemplateLine(raw: string): string {\n if (RE_NG_STYLE.test(raw)) return 'inline `[ngStyle]`';\n if (RE_STYLE_BINDING.test(raw)) return 'inline `[style.x]` binding';\n if (RE_INLINE_STYLE.test(raw)) return 'inline `style=` attribute';\n return '';\n }\n\n /** True if a `webpieces-disable no-custom-css` marker sits on this line or up to 3 lines above. */\n private hasDisableComment(lines: string[], lineNumber: number): boolean {\n const start = Math.max(0, lineNumber - 4);\n for (let i = lineNumber - 1; i >= start; i--) {\n if (hasDisable(lines[i] ?? '', RULE_NAMES.NO_CUSTOM_CSS)) return true;\n }\n return false;\n }\n\n private 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 no-custom-css validation (${skip.reason})\\n`);\n return 'OFF';\n }\n return normalMode;\n }\n\n private reportViolations(violations: CssViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error('❌ Custom CSS found in Angular source! Style with Tailwind utility classes instead.');\n console.error('');\n console.error('📚 Tailwind-first keeps styling in the template, greppable and consistent:');\n console.error(' BAD: styles: [\".card { display: flex; gap: 1rem; }\"]');\n console.error(' GOOD: class=\"flex gap-4\"');\n console.error(' BAD: <div style=\"width: 240px\"> | [style.width] | [ngStyle]');\n console.error(' GOOD: <div class=\"w-[240px]\"> | [class.x] toggles');\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}:${v.column}`);\n console.error(` ${v.detail}`);\n }\n console.error('');\n console.error(' To fix: delete the CSS and use Tailwind utility classes (arbitrary values like');\n console.error(' `bg-[#fffde7]` / `grid-cols-[2fr_2fr_2fr_48px]` cover the long tail).');\n console.error('');\n console.error(' Escape hatch (genuinely dynamic runtime value, use sparingly):');\n console.error(' .ts // webpieces-disable no-custom-css -- <reason>');\n console.error(' .html <!-- webpieces-disable no-custom-css -- <reason> -->');\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n }\n}\n"]}
@@ -319,7 +319,7 @@ function reportViolations(violations, mode, disableAllowed) {
319
319
  console.error('');
320
320
  }
321
321
  /**
322
- * Resolve mode considering ignoreModifiedUntilEpoch override.
322
+ * Resolve mode considering turnOffRuleUntilEpoch override.
323
323
  * When active, downgrades to OFF. When expired, logs a warning.
324
324
  */
325
325
  function resolveNoDestructureMode(normalMode, epoch, branchPattern) {
@@ -335,7 +335,7 @@ function resolveNoDestructureMode(normalMode, epoch, branchPattern) {
335
335
  return normalMode;
336
336
  }
337
337
  async function runValidatorImpl(options, workspaceRoot) {
338
- const mode = resolveNoDestructureMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch);
338
+ const mode = resolveNoDestructureMode(options.mode ?? 'OFF', options.turnOffRuleUntilEpoch, (options.turnOffRuleWhileOnBranch ?? undefined));
339
339
  const disableAllowed = options.disableAllowed ?? true;
340
340
  const allowedPaths = options.allowedPaths ?? [];
341
341
  if (mode === 'OFF') {