@webpieces/code-rules 0.3.351 → 0.3.353

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 (67) hide show
  1. package/package.json +7 -2
  2. package/src/cli.d.ts +1 -1
  3. package/src/cli.js +27 -5
  4. package/src/cli.js.map +1 -1
  5. package/src/code-rules-app.d.ts +13 -0
  6. package/src/code-rules-app.js +31 -0
  7. package/src/code-rules-app.js.map +1 -0
  8. package/src/code-rules-config-table.d.ts +10 -0
  9. package/src/code-rules-config-table.js +31 -0
  10. package/src/code-rules-config-table.js.map +1 -0
  11. package/src/code-rules-context.d.ts +19 -0
  12. package/src/code-rules-context.js +28 -0
  13. package/src/code-rules-context.js.map +1 -0
  14. package/src/code-rules-engine.d.ts +67 -0
  15. package/src/code-rules-engine.js +156 -0
  16. package/src/code-rules-engine.js.map +1 -0
  17. package/src/code-validator.d.ts +10 -0
  18. package/src/code-validator.js +15 -1
  19. package/src/code-validator.js.map +1 -1
  20. package/src/rule-reporter.d.ts +15 -10
  21. package/src/rule-reporter.js +59 -47
  22. package/src/rule-reporter.js.map +1 -1
  23. package/src/validate-catch-error-pattern.js +9 -2
  24. package/src/validate-catch-error-pattern.js.map +1 -1
  25. package/src/validate-code.d.ts +8 -5
  26. package/src/validate-code.js +22 -70
  27. package/src/validate-code.js.map +1 -1
  28. package/src/validate-dtos.js +9 -2
  29. package/src/validate-dtos.js.map +1 -1
  30. package/src/validate-framework-tag.js +11 -2
  31. package/src/validate-framework-tag.js.map +1 -1
  32. package/src/validate-inject-annotation-not-needed-for-concrete-class.js +9 -2
  33. package/src/validate-inject-annotation-not-needed-for-concrete-class.js.map +1 -1
  34. package/src/validate-match-rules.d.ts +17 -11
  35. package/src/validate-match-rules.js +116 -120
  36. package/src/validate-match-rules.js.map +1 -1
  37. package/src/validate-modified-files.js +9 -2
  38. package/src/validate-modified-files.js.map +1 -1
  39. package/src/validate-modified-methods.js +9 -2
  40. package/src/validate-modified-methods.js.map +1 -1
  41. package/src/validate-no-any-unknown.js +9 -2
  42. package/src/validate-no-any-unknown.js.map +1 -1
  43. package/src/validate-no-destructure.js +9 -2
  44. package/src/validate-no-destructure.js.map +1 -1
  45. package/src/validate-no-direct-api-resolver.js +9 -2
  46. package/src/validate-no-direct-api-resolver.js.map +1 -1
  47. package/src/validate-no-function-outside-class.js +9 -2
  48. package/src/validate-no-function-outside-class.js.map +1 -1
  49. package/src/validate-no-implicit-any.js +9 -2
  50. package/src/validate-no-implicit-any.js.map +1 -1
  51. package/src/validate-no-inline-types.js +9 -2
  52. package/src/validate-no-inline-types.js.map +1 -1
  53. package/src/validate-no-process-exit-outside-main.js +9 -2
  54. package/src/validate-no-process-exit-outside-main.js.map +1 -1
  55. package/src/validate-no-symbol-di-tokens.js +9 -2
  56. package/src/validate-no-symbol-di-tokens.js.map +1 -1
  57. package/src/validate-no-unmanaged-exceptions.js +9 -2
  58. package/src/validate-no-unmanaged-exceptions.js.map +1 -1
  59. package/src/validate-prisma-converters.js +9 -2
  60. package/src/validate-prisma-converters.js.map +1 -1
  61. package/src/validate-return-types.js +9 -2
  62. package/src/validate-return-types.js.map +1 -1
  63. package/src/validate-role-tag.js +11 -2
  64. package/src/validate-role-tag.js.map +1 -1
  65. package/src/wp-ci.d.ts +1 -1
  66. package/src/wp-ci.js +20 -3
  67. package/src/wp-ci.js.map +1 -1
@@ -1,22 +1,21 @@
1
1
  "use strict";
2
2
  /**
3
- * Validate a single `match-rules` entry (a client-authored content guard) at build time.
3
+ * Validate `match-rules` entries (client-authored content guards) at build time.
4
4
  *
5
- * One MatchRulesValidator is constructed PER entry of the `match-rules` array (see validate-code.ts),
6
- * so `shouldRun()` / mode / epoch apply per entry and the report shows the entry name. The regex
7
- * matching + allowedPath/test-file exemption is shared with the ai-hook engine via
8
- * findMatchRuleViolations; this validator adds diff-scoping (mode), the `// webpieces-disable <name>`
9
- * filter, and the console report (renderMatchRuleMessage the same text the ai-hook FixHint renders).
5
+ * A config-free, injected checker: the {@link CodeRulesEngine} injects ONE MatchRulesChecker and runs
6
+ * it once per `match-rules` entry (config passed to the method), so there is no `new` of a DAG member.
7
+ * `shouldRun` / mode / epoch apply per entry and the report shows the entry name. The regex matching +
8
+ * allowedPath/test-file exemption is shared with the ai-hook engine via findMatchRuleViolations; this
9
+ * adds diff-scoping (mode), the `// webpieces-disable <name>` filter, and the console report.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.MatchRulesValidator = exports.MatchViolationInfo = void 0;
13
- exports.findViolationsInFile = findViolationsInFile;
12
+ exports.MatchRulesChecker = exports.MatchViolationInfo = void 0;
14
13
  const tslib_1 = require("tslib");
15
14
  const fs = tslib_1.__importStar(require("fs"));
16
15
  const path = tslib_1.__importStar(require("path"));
17
16
  const rules_config_1 = require("@webpieces/rules-config");
18
- const code_validator_1 = require("./code-validator");
19
- const resolve_mode_1 = require("./resolve-mode");
17
+ const core_context_1 = require("@webpieces/core-context");
18
+ const inversify_1 = require("inversify");
20
19
  class MatchViolation {
21
20
  file;
22
21
  line;
@@ -38,125 +37,122 @@ class MatchViolationInfo {
38
37
  }
39
38
  }
40
39
  exports.MatchViolationInfo = MatchViolationInfo;
41
- function findViolationsInFile(filePath, workspaceRoot, config) {
42
- const fullPath = path.join(workspaceRoot, filePath);
43
- if (!fs.existsSync(fullPath))
44
- return [];
45
- const content = fs.readFileSync(fullPath, 'utf-8');
46
- const lines = content.split('\n');
47
- // Shared engine applies allowedPaths + test-file exemption and regex matching.
48
- const hits = (0, rules_config_1.findMatchRuleViolations)(lines, filePath, config);
49
- const disableAllowed = config.disableAllowed ?? true;
50
- return hits.map((hit) => {
51
- const line = lines[hit.line - 1] ?? '';
52
- const prevLine = hit.line > 1 ? (lines[hit.line - 2] ?? '') : '';
53
- const disabled = (0, rules_config_1.hasDisable)(line, config.name) || (0, rules_config_1.hasDisable)(prevLine, config.name);
54
- return new MatchViolationInfo(hit.line, hit.context, disableAllowed && disabled);
55
- });
56
- }
57
- function findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config) {
58
- const violations = [];
59
- for (const file of changedFiles) {
60
- const diff = (0, rules_config_1.getFileDiff)(workspaceRoot, file, base, head);
61
- const changedLines = (0, rules_config_1.getChangedLineNumbers)(diff);
62
- if (changedLines.size === 0)
63
- continue;
64
- for (const v of findViolationsInFile(file, workspaceRoot, config)) {
65
- if (v.hasDisableComment)
66
- continue;
67
- if (!changedLines.has(v.line))
68
- continue;
69
- violations.push(new MatchViolation(file, v.line, v.context));
70
- }
40
+ let MatchRulesChecker = class MatchRulesChecker {
41
+ /** True unless this entry is `mode: "OFF"` or skipped by a branch/epoch escape hatch. */
42
+ shouldRun(config) {
43
+ if ((config.mode ?? 'OFF') === 'OFF')
44
+ return false;
45
+ return !(0, rules_config_1.shouldSkipRule)(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch).skip;
71
46
  }
72
- return violations;
73
- }
74
- function findViolationsForModifiedFiles(workspaceRoot, changedFiles, config) {
75
- const violations = [];
76
- for (const file of changedFiles) {
77
- for (const v of findViolationsInFile(file, workspaceRoot, config)) {
78
- if (v.hasDisableComment)
79
- continue;
80
- violations.push(new MatchViolation(file, v.line, v.context));
47
+ /** Run one `match-rules` entry against the workspace (per-entry mode/diff-scoping/report). */
48
+ async runForConfig(config, workspaceRoot) {
49
+ const mode = this.resolveMode(config);
50
+ if (mode === 'OFF') {
51
+ console.log(`\n⏭️ Skipping ${config.name} validation (mode: OFF)\n`);
52
+ return { success: true };
81
53
  }
82
- }
83
- return violations;
84
- }
85
- function reportViolations(config, violations, mode) {
86
- console.error('');
87
- console.error(`❌ [${config.name}] matched disallowed pattern(s)!`);
88
- console.error('');
89
- console.error((0, rules_config_1.renderMatchRuleMessage)(config));
90
- console.error('');
91
- for (const v of violations) {
92
- console.error(` ❌ ${v.file}:${v.line}`);
93
- console.error(` ${v.context}`);
94
- }
95
- console.error('');
96
- console.error(` Current mode: ${mode}`);
97
- console.error('');
98
- }
99
- function resolveMode(config) {
100
- const normalMode = config.mode ?? 'OFF';
101
- if (normalMode === 'OFF')
102
- return normalMode;
103
- const skip = (0, resolve_mode_1.shouldSkipRule)(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch);
104
- if (skip.skip) {
105
- console.log(`\n⏭️ Skipping ${config.name} validation (${skip.reason})`);
106
- console.log('');
107
- return 'OFF';
108
- }
109
- return normalMode;
110
- }
111
- async function runValidatorImpl(config, workspaceRoot) {
112
- const mode = resolveMode(config);
113
- if (mode === 'OFF') {
114
- console.log(`\n⏭️ Skipping ${config.name} validation (mode: OFF)`);
115
- console.log('');
116
- return { success: true };
117
- }
118
- console.log(`\n📏 Validating match-rule: ${config.name}\n`);
119
- console.log(` Mode: ${mode}`);
120
- let base = process.env['NX_BASE'];
121
- const head = process.env['NX_HEAD'];
122
- if (!base) {
123
- base = (0, rules_config_1.detectBase)(workspaceRoot) ?? undefined;
54
+ console.log(`\n📏 Validating match-rule: ${config.name}\n`);
55
+ console.log(` Mode: ${mode}`);
56
+ let base = process.env['NX_BASE'];
57
+ const head = process.env['NX_HEAD'];
124
58
  if (!base) {
125
- console.log(`\n⏭️ Skipping ${config.name} validation (could not detect base branch)`);
126
- console.log('');
59
+ base = (0, rules_config_1.detectBase)(workspaceRoot) ?? undefined;
60
+ if (!base) {
61
+ console.log(`\n⏭️ Skipping ${config.name} validation (could not detect base branch)\n`);
62
+ return { success: true };
63
+ }
64
+ }
65
+ console.log(` Base: ${base}`);
66
+ console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\n`);
67
+ const changedFiles = (0, rules_config_1.getChangedFiles)(workspaceRoot, base, head);
68
+ if (changedFiles.length === 0) {
69
+ console.log('✅ No TypeScript files changed');
127
70
  return { success: true };
128
71
  }
72
+ console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
73
+ const violations = mode === 'NEW_AND_MODIFIED_CODE'
74
+ ? this.findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config)
75
+ : this.findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);
76
+ if (violations.length === 0) {
77
+ console.log(`✅ No ${config.name} violations found`);
78
+ return { success: true };
79
+ }
80
+ this.reportViolations(config, violations, mode);
81
+ return { success: false };
129
82
  }
130
- console.log(` Base: ${base}`);
131
- console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
132
- console.log('');
133
- const changedFiles = (0, rules_config_1.getChangedFiles)(workspaceRoot, base, head);
134
- if (changedFiles.length === 0) {
135
- console.log('✅ No TypeScript files changed');
136
- return { success: true };
137
- }
138
- console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);
139
- let violations = [];
140
- if (mode === 'NEW_AND_MODIFIED_CODE') {
141
- violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config);
83
+ findViolationsInFile(filePath, workspaceRoot, config) {
84
+ const fullPath = path.join(workspaceRoot, filePath);
85
+ if (!fs.existsSync(fullPath))
86
+ return [];
87
+ const content = fs.readFileSync(fullPath, 'utf-8');
88
+ const lines = content.split('\n');
89
+ // Shared engine applies allowedPaths + test-file exemption and regex matching.
90
+ const hits = (0, rules_config_1.findMatchRuleViolations)(lines, filePath, config);
91
+ const disableAllowed = config.disableAllowed ?? true;
92
+ return hits.map((hit) => {
93
+ const line = lines[hit.line - 1] ?? '';
94
+ const prevLine = hit.line > 1 ? (lines[hit.line - 2] ?? '') : '';
95
+ const disabled = (0, rules_config_1.hasDisable)(line, config.name) || (0, rules_config_1.hasDisable)(prevLine, config.name);
96
+ return new MatchViolationInfo(hit.line, hit.context, disableAllowed && disabled);
97
+ });
142
98
  }
143
- else if (mode === 'NEW_AND_MODIFIED_FILES') {
144
- violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);
99
+ findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config) {
100
+ const violations = [];
101
+ for (const file of changedFiles) {
102
+ const diff = (0, rules_config_1.getFileDiff)(workspaceRoot, file, base, head);
103
+ const changedLines = (0, rules_config_1.getChangedLineNumbers)(diff);
104
+ if (changedLines.size === 0)
105
+ continue;
106
+ for (const v of this.findViolationsInFile(file, workspaceRoot, config)) {
107
+ if (v.hasDisableComment)
108
+ continue;
109
+ if (!changedLines.has(v.line))
110
+ continue;
111
+ violations.push(new MatchViolation(file, v.line, v.context));
112
+ }
113
+ }
114
+ return violations;
145
115
  }
146
- if (violations.length === 0) {
147
- console.log(`✅ No ${config.name} violations found`);
148
- return { success: true };
116
+ findViolationsForModifiedFiles(workspaceRoot, changedFiles, config) {
117
+ const violations = [];
118
+ for (const file of changedFiles) {
119
+ for (const v of this.findViolationsInFile(file, workspaceRoot, config)) {
120
+ if (v.hasDisableComment)
121
+ continue;
122
+ violations.push(new MatchViolation(file, v.line, v.context));
123
+ }
124
+ }
125
+ return violations;
149
126
  }
150
- reportViolations(config, violations, mode);
151
- return { success: false };
152
- }
153
- class MatchRulesValidator extends code_validator_1.CodeValidator {
154
- constructor(config) {
155
- super(config, config.name);
127
+ reportViolations(config, violations, mode) {
128
+ console.error('');
129
+ console.error(`❌ [${config.name}] matched disallowed pattern(s)!`);
130
+ console.error('');
131
+ console.error((0, rules_config_1.renderMatchRuleMessage)(config));
132
+ console.error('');
133
+ for (const v of violations) {
134
+ console.error(` ❌ ${v.file}:${v.line}`);
135
+ console.error(` ${v.context}`);
136
+ }
137
+ console.error('');
138
+ console.error(` Current mode: ${mode}`);
139
+ console.error('');
156
140
  }
157
- async run(workspaceRoot) {
158
- return runValidatorImpl(this.config, workspaceRoot);
141
+ resolveMode(config) {
142
+ const normalMode = config.mode ?? 'OFF';
143
+ if (normalMode === 'OFF')
144
+ return normalMode;
145
+ const skip = (0, rules_config_1.shouldSkipRule)(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch);
146
+ if (skip.skip) {
147
+ console.log(`\n⏭️ Skipping ${config.name} validation (${skip.reason})\n`);
148
+ return 'OFF';
149
+ }
150
+ return normalMode;
159
151
  }
160
- }
161
- exports.MatchRulesValidator = MatchRulesValidator;
152
+ };
153
+ exports.MatchRulesChecker = MatchRulesChecker;
154
+ exports.MatchRulesChecker = MatchRulesChecker = tslib_1.__decorate([
155
+ (0, core_context_1.provideSingleton)(),
156
+ (0, inversify_1.injectable)()
157
+ ], MatchRulesChecker);
162
158
  //# sourceMappingURL=validate-match-rules.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-match-rules.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-match-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate a single `match-rules` entry (a client-authored content guard) at build time.\n *\n * One MatchRulesValidator is constructed PER entry of the `match-rules` array (see validate-code.ts),\n * so `shouldRun()` / mode / epoch apply per entry and the report shows the entry name. The regex\n * matching + allowedPath/test-file exemption is shared with the ai-hook engine via\n * findMatchRuleViolations; this validator adds diff-scoping (mode), the `// webpieces-disable <name>`\n * filter, and the console report (renderMatchRuleMessage — the same text the ai-hook FixHint renders).\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n renderMatchRuleMessage,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { shouldSkipRule } from './resolve-mode';\n\nclass MatchViolation {\n readonly file: string;\n readonly line: number;\n readonly context: string;\n\n constructor(file: string, line: number, context: string) {\n this.file = file;\n this.line = line;\n this.context = context;\n }\n}\n\nexport class MatchViolationInfo {\n readonly line: number;\n readonly context: string;\n readonly hasDisableComment: boolean;\n\n constructor(line: number, context: string, hasDisableComment: boolean) {\n this.line = line;\n this.context = context;\n this.hasDisableComment = hasDisableComment;\n }\n}\n\nexport function findViolationsInFile(\n filePath: string,\n workspaceRoot: string,\n config: MatchRuleConfig,\n): MatchViolationInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n\n // Shared engine applies allowedPaths + test-file exemption and regex matching.\n const hits = findMatchRuleViolations(lines, filePath, config);\n const disableAllowed = config.disableAllowed ?? true;\n\n return hits.map((hit: MatchRuleViolation) => {\n const line = lines[hit.line - 1] ?? '';\n const prevLine = hit.line > 1 ? (lines[hit.line - 2] ?? '') : '';\n const disabled = hasDisable(line, config.name) || hasDisable(prevLine, config.name);\n return new MatchViolationInfo(hit.line, hit.context, disableAllowed && disabled);\n });\n}\n\nfunction findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n config: MatchRuleConfig,\n): MatchViolation[] {\n const violations: MatchViolation[] = [];\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n if (changedLines.size === 0) continue;\n\n for (const v of findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n}\n\nfunction findViolationsForModifiedFiles(\n workspaceRoot: string,\n changedFiles: string[],\n config: MatchRuleConfig,\n): MatchViolation[] {\n const violations: MatchViolation[] = [];\n for (const file of changedFiles) {\n for (const v of findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n}\n\nfunction reportViolations(config: MatchRuleConfig, violations: MatchViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error(`❌ [${config.name}] matched disallowed pattern(s)!`);\n console.error('');\n console.error(renderMatchRuleMessage(config));\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\nfunction resolveMode(config: MatchRuleConfig): ModifiedCodeMode {\n const normalMode: ModifiedCodeMode = config.mode ?? 'OFF';\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${config.name} validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n}\n\nasync function runValidatorImpl(config: MatchRuleConfig, workspaceRoot: string): Promise<ExecutorResult> {\n const mode = resolveMode(config);\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${config.name} validation (mode: OFF)`);\n console.log('');\n return { success: true };\n }\n\n console.log(`\\n📏 Validating match-rule: ${config.name}\\n`);\n console.log(` Mode: ${mode}`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n if (!base) {\n console.log(`\\n⏭️ Skipping ${config.name} validation (could not detect base branch)`);\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n\n let violations: MatchViolation[] = [];\n if (mode === 'NEW_AND_MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config);\n } else if (mode === 'NEW_AND_MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);\n }\n\n if (violations.length === 0) {\n console.log(`✅ No ${config.name} violations found`);\n return { success: true };\n }\n\n reportViolations(config, violations, mode);\n return { success: false };\n}\n\nexport class MatchRulesValidator extends CodeValidator<MatchRuleConfig> {\n constructor(config: MatchRuleConfig) {\n super(config, config.name);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
1
+ {"version":3,"file":"validate-match-rules.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-match-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate `match-rules` entries (client-authored content guards) at build time.\n *\n * A config-free, injected checker: the {@link CodeRulesEngine} injects ONE MatchRulesChecker and runs\n * it once per `match-rules` entry (config passed to the method), so there is no `new` of a DAG member.\n * `shouldRun` / mode / epoch apply per entry and the report shows the entry name. The regex matching +\n * allowedPath/test-file exemption is shared with the ai-hook engine via findMatchRuleViolations; this\n * adds diff-scoping (mode), the `// webpieces-disable <name>` filter, and the console report.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n renderMatchRuleMessage,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n shouldSkipRule,\n} from '@webpieces/rules-config';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\nimport { ExecutorResult } from './code-validator';\n\nclass MatchViolation {\n readonly file: string;\n readonly line: number;\n readonly context: string;\n\n constructor(file: string, line: number, context: string) {\n this.file = file;\n this.line = line;\n this.context = context;\n }\n}\n\nexport class MatchViolationInfo {\n readonly line: number;\n readonly context: string;\n readonly hasDisableComment: boolean;\n\n constructor(line: number, context: string, hasDisableComment: boolean) {\n this.line = line;\n this.context = context;\n this.hasDisableComment = hasDisableComment;\n }\n}\n\n@provideSingleton()\n@injectable()\nexport class MatchRulesChecker {\n /** True unless this entry is `mode: \"OFF\"` or skipped by a branch/epoch escape hatch. */\n shouldRun(config: MatchRuleConfig): boolean {\n if ((config.mode ?? 'OFF') === 'OFF') return false;\n return !shouldSkipRule(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch).skip;\n }\n\n /** Run one `match-rules` entry against the workspace (per-entry mode/diff-scoping/report). */\n async runForConfig(config: MatchRuleConfig, workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(config);\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${config.name} validation (mode: OFF)\\n`);\n return { success: true };\n }\n\n console.log(`\\n📏 Validating match-rule: ${config.name}\\n`);\n console.log(` Mode: ${mode}`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n if (!base) {\n console.log(`\\n⏭️ Skipping ${config.name} validation (could not detect base branch)\\n`);\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}\\n`);\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n const violations = mode === 'NEW_AND_MODIFIED_CODE'\n ? this.findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, config)\n : this.findViolationsForModifiedFiles(workspaceRoot, changedFiles, config);\n\n if (violations.length === 0) {\n console.log(`✅ No ${config.name} violations found`);\n return { success: true };\n }\n\n this.reportViolations(config, violations, mode);\n return { success: false };\n }\n\n findViolationsInFile(filePath: string, workspaceRoot: string, config: MatchRuleConfig): MatchViolationInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n\n // Shared engine applies allowedPaths + test-file exemption and regex matching.\n const hits = findMatchRuleViolations(lines, filePath, config);\n const disableAllowed = config.disableAllowed ?? true;\n\n return hits.map((hit: MatchRuleViolation) => {\n const line = lines[hit.line - 1] ?? '';\n const prevLine = hit.line > 1 ? (lines[hit.line - 2] ?? '') : '';\n const disabled = hasDisable(line, config.name) || hasDisable(prevLine, config.name);\n return new MatchViolationInfo(hit.line, hit.context, disableAllowed && disabled);\n });\n }\n\n private findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n config: MatchRuleConfig,\n ): MatchViolation[] {\n const violations: MatchViolation[] = [];\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n if (changedLines.size === 0) continue;\n\n for (const v of this.findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n if (!changedLines.has(v.line)) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n }\n\n private findViolationsForModifiedFiles(\n workspaceRoot: string,\n changedFiles: string[],\n config: MatchRuleConfig,\n ): MatchViolation[] {\n const violations: MatchViolation[] = [];\n for (const file of changedFiles) {\n for (const v of this.findViolationsInFile(file, workspaceRoot, config)) {\n if (v.hasDisableComment) continue;\n violations.push(new MatchViolation(file, v.line, v.context));\n }\n }\n return violations;\n }\n\n private reportViolations(config: MatchRuleConfig, violations: MatchViolation[], mode: ModifiedCodeMode): void {\n console.error('');\n console.error(`❌ [${config.name}] matched disallowed pattern(s)!`);\n console.error('');\n console.error(renderMatchRuleMessage(config));\n console.error('');\n for (const v of violations) {\n console.error(` ❌ ${v.file}:${v.line}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n }\n\n private resolveMode(config: MatchRuleConfig): ModifiedCodeMode {\n const normalMode: ModifiedCodeMode = config.mode ?? 'OFF';\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(config.ignoreModifiedUntilEpoch, config.ignoreRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${config.name} validation (${skip.reason})\\n`);\n return 'OFF';\n }\n return normalMode;\n }\n}\n"]}
@@ -20,6 +20,8 @@ const fs = tslib_1.__importStar(require("fs"));
20
20
  const path = tslib_1.__importStar(require("path"));
21
21
  const rules_config_1 = require("@webpieces/rules-config");
22
22
  const code_validator_1 = require("./code-validator");
23
+ const core_context_1 = require("@webpieces/core-context");
24
+ const inversify_1 = require("inversify");
23
25
  const resolve_mode_1 = require("./resolve-mode");
24
26
  const TMP_MD_FILE = 'webpieces.filesize.md';
25
27
  /**
@@ -257,13 +259,18 @@ async function runValidatorImpl(options, workspaceRoot) {
257
259
  return { success: false };
258
260
  }
259
261
  }
260
- class MaxFileLinesValidator extends code_validator_1.CodeValidator {
262
+ let MaxFileLinesValidator = class MaxFileLinesValidator extends code_validator_1.CodeValidator {
261
263
  constructor(config) {
262
264
  super(config, 'max-file-lines');
263
265
  }
264
266
  async run(workspaceRoot) {
265
267
  return runValidatorImpl(this.config, workspaceRoot);
266
268
  }
267
- }
269
+ };
268
270
  exports.MaxFileLinesValidator = MaxFileLinesValidator;
271
+ exports.MaxFileLinesValidator = MaxFileLinesValidator = tslib_1.__decorate([
272
+ (0, core_context_1.provideSingleton)(),
273
+ (0, inversify_1.injectable)(),
274
+ tslib_1.__metadata("design:paramtypes", [rules_config_1.MaxFileLinesConfig])
275
+ ], MaxFileLinesValidator);
269
276
  //# sourceMappingURL=validate-modified-files.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-modified-files.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-modified-files.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Files Executor\n *\n * Validates that modified files don't exceed a maximum line count (default 900).\n * This encourages keeping files small and focused - when you touch a file,\n * you must bring it under the limit.\n *\n * Usage:\n * nx affected --target=validate-modified-files --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified-files comment with date and justification\n * Format: // webpieces-disable max-lines-modified-files 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { writeTemplate, hasDisable, RULE_NAMES, MaxFileLinesConfig, FileLimitMode, detectBase, getChangedFiles } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface FileViolation {\n file: string;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_MD_FILE = 'webpieces.filesize.md';\n\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n return writeTemplate(workspaceRoot, TMP_MD_FILE);\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\ninterface DisableStatus {\n hasDisable: boolean;\n isValid: boolean;\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check if a file has a valid, non-expired disable comment at the top (within first 5 lines).\n * Returns status object with details about the disable comment.\n */\n// webpieces-disable max-lines-new-methods -- Date validation logic requires checking multiple conditions\nfunction checkDisableComment(content: string): DisableStatus {\n const lines = content.split('\\n').slice(0, 5);\n\n for (const line of lines) {\n if (hasDisable(line, RULE_NAMES.MAX_LINES_MODIFIED_FILES)) {\n // Found disable comment, now check for date\n // Format: // webpieces-disable max-lines-modified-files yyyy/mm/dd -- reason\n const dateMatch = line.match(/max-lines-modified-files\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - invalid disable comment\n return { hasDisable: true, isValid: false, isExpired: false };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format\n return { hasDisable: true, isValid: false, isExpired: false, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { hasDisable: true, isValid: true, isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n }\n\n return { hasDisable: false, isValid: false, isExpired: false };\n}\n\n/**\n * Count lines in a file and check for violations\n */\n// webpieces-disable max-lines-new-methods -- File iteration with disable checking logic\nfunction findViolations(workspaceRoot: string, changedFiles: string[], limit: number, disableAllowed: boolean): FileViolation[] {\n const violations: FileViolation[] = [];\n\n for (const file of changedFiles) {\n const fullPath = path.join(workspaceRoot, file);\n\n if (!fs.existsSync(fullPath)) continue;\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lineCount = content.split('\\n').length;\n\n // Skip files under the limit\n if (lineCount <= limit) continue;\n\n // When disableAllowed is false, ignore all disable comments\n if (!disableAllowed) {\n violations.push({ file, lines: lineCount });\n continue;\n }\n\n // Check for disable comment\n const disableStatus = checkDisableComment(content);\n\n if (disableStatus.hasDisable) {\n if (disableStatus.isValid && !disableStatus.isExpired) {\n // Valid, non-expired disable - skip this file\n continue;\n }\n\n if (disableStatus.isExpired) {\n // Expired disable - report as violation with expired info\n violations.push({\n file,\n lines: lineCount,\n expiredDisable: true,\n expiredDate: disableStatus.date,\n });\n continue;\n }\n\n // Invalid disable (missing/bad date) - fall through to report as violation\n }\n\n violations.push({\n file,\n lines: lineCount,\n });\n }\n\n return violations;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: FileViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c YOU MUST FIX THIS AND NOT be more than ' + limit + ' lines of code per file');\n console.error(' as it slows down IDEs AND is VERY VERY EASY to refactor.');\n console.error('');\n console.error('\\ud83d\\udcda With stateless systems + dependency injection, refactor is trivial:');\n console.error(' Pick a method or a few and move to new class XXXXX, then inject XXXXX');\n console.error(' into all users of those methods via the constructor.');\n console.error(' Delete those methods from original class.');\n console.error(' 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.filesize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate} has expired (>1 month old).`);\n console.error(` You must either FIX the file or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified-files ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce file size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"ignoreModifiedUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');\n console.error(' each PR reduces files as they get touched.');\n console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nasync function runValidatorImpl(\n options: MaxFileLinesConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const limit = options.limit ?? 900;\n const disableAllowed = options.disableAllowed ?? true;\n\n const rawMode: FileLimitMode = options.mode ?? 'NEW_AND_MODIFIED_FILES';\n const skip = rawMode !== 'OFF' ? shouldSkipRule(options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch) : { skip: false };\n const mode: FileLimitMode = skip.skip ? 'OFF' : rawMode;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n const reason = skip.skip ? skip.reason : 'mode: OFF';\n console.log(`\\n\\u23ed\\ufe0f Skipping modified files validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping modified files validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-files --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Max lines for modified files: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, limit, disableAllowed);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified files are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n //const error = toError(err);\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified files validation failed:', error.message);\n return { success: false };\n }\n}\n\nexport class MaxFileLinesValidator extends CodeValidator<MaxFileLinesConfig> {\n constructor(config: MaxFileLinesConfig) {\n super(config, 'max-file-lines');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
1
+ {"version":3,"file":"validate-modified-files.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-modified-files.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Modified Files Executor\n *\n * Validates that modified files don't exceed a maximum line count (default 900).\n * This encourages keeping files small and focused - when you touch a file,\n * you must bring it under the limit.\n *\n * Usage:\n * nx affected --target=validate-modified-files --base=origin/main\n *\n * Escape hatch: Add webpieces-disable max-lines-modified-files comment with date and justification\n * Format: // webpieces-disable max-lines-modified-files 2025/01/15 -- [reason]\n * The disable expires after 1 month from the date specified.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { writeTemplate, hasDisable, RULE_NAMES, MaxFileLinesConfig, FileLimitMode, detectBase, getChangedFiles } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\n\ninterface FileViolation {\n file: string;\n lines: number;\n expiredDisable?: boolean;\n expiredDate?: string;\n}\n\nconst TMP_MD_FILE = 'webpieces.filesize.md';\n\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructions(workspaceRoot: string): string {\n return writeTemplate(workspaceRoot, TMP_MD_FILE);\n}\n\n/**\n * Parse a date string in yyyy/mm/dd format and return a Date object.\n * Returns null if the format is invalid.\n */\nfunction parseDisableDate(dateStr: string): Date | null {\n // Match yyyy/mm/dd format\n const match = dateStr.match(/^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/);\n if (!match) return null;\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10) - 1; // JS months are 0-indexed\n const day = parseInt(match[3], 10);\n\n const date = new Date(year, month, day);\n\n // Validate the date is valid (e.g., not Feb 30)\n if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {\n return null;\n }\n\n return date;\n}\n\n/**\n * Check if a date is within the last month (not expired).\n */\nfunction isDateWithinMonth(date: Date): boolean {\n const now = new Date();\n const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());\n return date >= oneMonthAgo;\n}\n\ninterface DisableStatus {\n hasDisable: boolean;\n isValid: boolean;\n isExpired: boolean;\n date?: string;\n}\n\n/**\n * Check if a file has a valid, non-expired disable comment at the top (within first 5 lines).\n * Returns status object with details about the disable comment.\n */\n// webpieces-disable max-lines-new-methods -- Date validation logic requires checking multiple conditions\nfunction checkDisableComment(content: string): DisableStatus {\n const lines = content.split('\\n').slice(0, 5);\n\n for (const line of lines) {\n if (hasDisable(line, RULE_NAMES.MAX_LINES_MODIFIED_FILES)) {\n // Found disable comment, now check for date\n // Format: // webpieces-disable max-lines-modified-files yyyy/mm/dd -- reason\n const dateMatch = line.match(/max-lines-modified-files\\s+(\\d{4}\\/\\d{2}\\/\\d{2}|XXXX\\/XX\\/XX)/);\n\n if (!dateMatch) {\n // No date found - invalid disable comment\n return { hasDisable: true, isValid: false, isExpired: false };\n }\n\n const dateStr = dateMatch[1];\n\n // Secret permanent disable\n if (dateStr === 'XXXX/XX/XX') {\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n\n const date = parseDisableDate(dateStr);\n if (!date) {\n // Invalid date format\n return { hasDisable: true, isValid: false, isExpired: false, date: dateStr };\n }\n\n if (!isDateWithinMonth(date)) {\n // Date is expired (older than 1 month)\n return { hasDisable: true, isValid: true, isExpired: true, date: dateStr };\n }\n\n // Valid and not expired\n return { hasDisable: true, isValid: true, isExpired: false, date: dateStr };\n }\n }\n\n return { hasDisable: false, isValid: false, isExpired: false };\n}\n\n/**\n * Count lines in a file and check for violations\n */\n// webpieces-disable max-lines-new-methods -- File iteration with disable checking logic\nfunction findViolations(workspaceRoot: string, changedFiles: string[], limit: number, disableAllowed: boolean): FileViolation[] {\n const violations: FileViolation[] = [];\n\n for (const file of changedFiles) {\n const fullPath = path.join(workspaceRoot, file);\n\n if (!fs.existsSync(fullPath)) continue;\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lineCount = content.split('\\n').length;\n\n // Skip files under the limit\n if (lineCount <= limit) continue;\n\n // When disableAllowed is false, ignore all disable comments\n if (!disableAllowed) {\n violations.push({ file, lines: lineCount });\n continue;\n }\n\n // Check for disable comment\n const disableStatus = checkDisableComment(content);\n\n if (disableStatus.hasDisable) {\n if (disableStatus.isValid && !disableStatus.isExpired) {\n // Valid, non-expired disable - skip this file\n continue;\n }\n\n if (disableStatus.isExpired) {\n // Expired disable - report as violation with expired info\n violations.push({\n file,\n lines: lineCount,\n expiredDisable: true,\n expiredDate: disableStatus.date,\n });\n continue;\n }\n\n // Invalid disable (missing/bad date) - fall through to report as violation\n }\n\n violations.push({\n file,\n lines: lineCount,\n });\n }\n\n return violations;\n}\n\n/**\n * Get today's date in yyyy/mm/dd format for error messages\n */\nfunction getTodayDateString(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n return `${year}/${month}/${day}`;\n}\n\n/**\n * Report violations to console\n */\n// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections\nfunction reportViolations(violations: FileViolation[], limit: number, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c YOU MUST FIX THIS AND NOT be more than ' + limit + ' lines of code per file');\n console.error(' as it slows down IDEs AND is VERY VERY EASY to refactor.');\n console.error('');\n console.error('\\ud83d\\udcda With stateless systems + dependency injection, refactor is trivial:');\n console.error(' Pick a method or a few and move to new class XXXXX, then inject XXXXX');\n console.error(' into all users of those methods via the constructor.');\n console.error(' Delete those methods from original class.');\n console.error(' 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error('\\u26a0\\ufe0f *** READ .webpieces/instruct-ai/webpieces.filesize.md for detailed guidance on how to fix this easily *** \\u26a0\\ufe0f');\n console.error('');\n\n for (const v of violations) {\n if (v.expiredDisable) {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n console.error(` \\u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate} has expired (>1 month old).`);\n console.error(` You must either FIX the file or UPDATE the date to get another month.`);\n } else {\n console.error(` \\u274c ${v.file} (${v.lines} lines, max: ${limit})`);\n }\n }\n console.error('');\n\n // Only show escape hatch instructions when disableAllowed is true\n if (disableAllowed) {\n console.error(' You can disable this error, but you will be forced to fix again in 1 month');\n console.error(' since 99% of files can be less than ' + limit + ' lines of code.');\n console.error('');\n console.error(' Use escape with DATE (expires in 1 month):');\n console.error(` // webpieces-disable max-lines-modified-files ${getTodayDateString()} -- [your reason]`);\n console.error('');\n } else {\n console.error(' \\u26a0\\ufe0f disableAllowed is false - disable comments are NOT allowed.');\n console.error(' This rule must be met and cannot be disabled since nx.json disableAllowed is set to false.');\n console.error(' You MUST refactor to reduce file size.');\n console.error('');\n console.error(' For a major refactor, a human can add \"ignoreModifiedUntilEpoch\" to nx.json validate-code options.');\n console.error(' This is an expiry timestamp (epoch ms) for when we start forcing everyone to meet size rules again.');\n console.error(' Sometimes for speed, we allow files to expand during a refactor and over time,');\n console.error(' each PR reduces files as they get touched.');\n console.error(' AI agents should NOT add ignoreModifiedUntilEpoch - ask a human to do it.');\n console.error('');\n }\n}\n\nasync function runValidatorImpl(\n options: MaxFileLinesConfig,\n workspaceRoot: string\n): Promise<ExecutorResult> {\n const limit = options.limit ?? 900;\n const disableAllowed = options.disableAllowed ?? true;\n\n const rawMode: FileLimitMode = options.mode ?? 'NEW_AND_MODIFIED_FILES';\n const skip = rawMode !== 'OFF' ? shouldSkipRule(options.ignoreModifiedUntilEpoch, options.ignoreRuleWhileOnBranch) : { skip: false };\n const mode: FileLimitMode = skip.skip ? 'OFF' : rawMode;\n\n // Skip validation entirely if mode is OFF\n if (mode === 'OFF') {\n const reason = skip.skip ? skip.reason : 'mode: OFF';\n console.log(`\\n\\u23ed\\ufe0f Skipping modified files validation (${reason})`);\n console.log('');\n return { success: true };\n }\n\n // If NX_HEAD is set (via nx affected --head=X), use it; otherwise compare to working tree\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping modified files validation (could not detect base branch)');\n console.log(' To run explicitly: nx affected --target=validate-modified-files --base=origin/main');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes (auto-detected base)\\n');\n } else {\n console.log('\\n\\ud83d\\udccf Validating Modified File Sizes\\n');\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log(` Mode: ${mode}`);\n console.log(` Max lines for modified files: ${limit}`);\n console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);\n console.log('');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n const violations = findViolations(workspaceRoot, changedFiles, limit, disableAllowed);\n\n if (violations.length === 0) {\n console.log('\\u2705 All modified files are under ' + limit + ' lines');\n return { success: true };\n }\n\n writeTmpInstructions(workspaceRoot);\n reportViolations(violations, limit, disableAllowed);\n return { success: false };\n } catch (err: unknown) {\n //const error = toError(err);\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('\\u274c Modified files validation failed:', error.message);\n return { success: false };\n }\n}\n\n@provideSingleton()\n@injectable()\nexport class MaxFileLinesValidator extends CodeValidator<MaxFileLinesConfig> {\n constructor(config: MaxFileLinesConfig) {\n super(config, 'max-file-lines');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runValidatorImpl(this.config, workspaceRoot);\n }\n}\n"]}
@@ -28,6 +28,8 @@ const path = tslib_1.__importStar(require("path"));
28
28
  const ts = tslib_1.__importStar(require("typescript"));
29
29
  const rules_config_1 = require("@webpieces/rules-config");
30
30
  const code_validator_1 = require("./code-validator");
31
+ const core_context_1 = require("@webpieces/core-context");
32
+ const inversify_1 = require("inversify");
31
33
  const resolve_mode_1 = require("./resolve-mode");
32
34
  const validate_new_methods_1 = require("./validate-new-methods");
33
35
  const TMP_MD_FILE = 'webpieces.methodsize.md';
@@ -407,7 +409,7 @@ async function runModifiedMethods(options, workspaceRoot) {
407
409
  * - NEW_AND_MODIFIED_METHODS -> new-methods + modified-methods
408
410
  * - NEW_AND_MODIFIED_FILES -> modified-methods only
409
411
  */
410
- class MaxMethodLinesValidator extends code_validator_1.CodeValidator {
412
+ let MaxMethodLinesValidator = class MaxMethodLinesValidator extends code_validator_1.CodeValidator {
411
413
  constructor(config) {
412
414
  super(config, 'max-method-lines');
413
415
  }
@@ -424,6 +426,11 @@ class MaxMethodLinesValidator extends code_validator_1.CodeValidator {
424
426
  }
425
427
  return { success: results.every((r) => r.success) };
426
428
  }
427
- }
429
+ };
428
430
  exports.MaxMethodLinesValidator = MaxMethodLinesValidator;
431
+ exports.MaxMethodLinesValidator = MaxMethodLinesValidator = tslib_1.__decorate([
432
+ (0, core_context_1.provideSingleton)(),
433
+ (0, inversify_1.injectable)(),
434
+ tslib_1.__metadata("design:paramtypes", [rules_config_1.MaxMethodLinesConfig])
435
+ ], MaxMethodLinesValidator);
429
436
  //# sourceMappingURL=validate-modified-methods.js.map