@webpieces/dev-config 0.2.75 → 0.2.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/architecture/executors/validate-code/executor.d.ts +14 -6
- package/architecture/executors/validate-code/executor.js +61 -37
- package/architecture/executors/validate-code/executor.js.map +1 -1
- package/architecture/executors/validate-code/executor.ts +94 -58
- package/architecture/executors/validate-code/schema.json +48 -29
- package/architecture/executors/validate-modified-files/executor.d.ts +4 -3
- package/architecture/executors/validate-modified-files/executor.js +32 -30
- package/architecture/executors/validate-modified-files/executor.js.map +1 -1
- package/architecture/executors/validate-modified-files/executor.ts +36 -33
- package/architecture/executors/validate-modified-files/schema.json +9 -4
- package/architecture/executors/validate-modified-methods/executor.d.ts +7 -6
- package/architecture/executors/validate-modified-methods/executor.js +53 -47
- package/architecture/executors/validate-modified-methods/executor.js.map +1 -1
- package/architecture/executors/validate-modified-methods/executor.ts +57 -51
- package/architecture/executors/validate-modified-methods/schema.json +10 -5
- package/architecture/executors/validate-new-methods/executor.d.ts +4 -4
- package/architecture/executors/validate-new-methods/executor.js +64 -83
- package/architecture/executors/validate-new-methods/executor.js.map +1 -1
- package/architecture/executors/validate-new-methods/executor.ts +75 -96
- package/architecture/executors/validate-new-methods/schema.json +11 -10
- package/architecture/executors/validate-no-any-unknown/executor.d.ts +1 -2
- package/architecture/executors/validate-no-any-unknown/executor.js +57 -55
- package/architecture/executors/validate-no-any-unknown/executor.js.map +1 -1
- package/architecture/executors/validate-no-any-unknown/executor.ts +62 -57
- package/architecture/executors/validate-no-any-unknown/schema.json +2 -2
- package/architecture/executors/validate-no-inline-types/executor.d.ts +1 -2
- package/architecture/executors/validate-no-inline-types/executor.js +25 -58
- package/architecture/executors/validate-no-inline-types/executor.js.map +1 -1
- package/architecture/executors/validate-no-inline-types/executor.ts +26 -59
- package/architecture/executors/validate-no-inline-types/schema.json +2 -2
- package/architecture/executors/validate-return-types/executor.d.ts +1 -2
- package/architecture/executors/validate-return-types/executor.js +25 -58
- package/architecture/executors/validate-return-types/executor.js.map +1 -1
- package/architecture/executors/validate-return-types/executor.ts +26 -59
- package/architecture/executors/validate-return-types/schema.json +2 -2
- package/package.json +1 -1
- package/plugin.js +24 -7
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* This encourages gradual cleanup of legacy long methods - when you touch a method,
|
|
6
6
|
* you must bring it under the limit.
|
|
7
7
|
*
|
|
8
|
-
* Combined with validate-new-methods
|
|
8
|
+
* Combined with validate-new-methods, this creates a gradual
|
|
9
9
|
* transition to cleaner code:
|
|
10
|
-
* - New methods:
|
|
11
|
-
* - Modified methods:
|
|
10
|
+
* - New methods: must be under limit
|
|
11
|
+
* - Modified methods: must be under limit (cleanup when touched)
|
|
12
12
|
* - Untouched methods: no limit (legacy allowed)
|
|
13
13
|
*
|
|
14
14
|
* Usage:
|
|
@@ -25,11 +25,12 @@ import * as fs from 'fs';
|
|
|
25
25
|
import * as path from 'path';
|
|
26
26
|
import * as ts from 'typescript';
|
|
27
27
|
|
|
28
|
-
export type
|
|
28
|
+
export type MethodMaxLimitMode = 'OFF' | 'NEW_METHODS' | 'NEW_AND_MODIFIED_METHODS' | 'MODIFIED_FILES';
|
|
29
29
|
|
|
30
30
|
export interface ValidateModifiedMethodsOptions {
|
|
31
|
-
|
|
32
|
-
mode?:
|
|
31
|
+
limit?: number;
|
|
32
|
+
mode?: MethodMaxLimitMode;
|
|
33
|
+
disableAllowed?: boolean;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export interface ExecutorResult {
|
|
@@ -52,10 +53,8 @@ const METHODSIZE_DOC_CONTENT = `# Instructions: Method Too Long
|
|
|
52
53
|
|
|
53
54
|
## Requirement
|
|
54
55
|
|
|
55
|
-
**~
|
|
56
|
+
**~99% of the time**, you can stay under the \`limit\` from nx.json
|
|
56
57
|
by extracting logical units into well-named methods.
|
|
57
|
-
|
|
58
|
-
**~99% of the time**, you can stay under the \`modifiedAndNewMethodsMaxLines\` limit from nx.json.
|
|
59
58
|
Nearly all software can be written with methods under this size.
|
|
60
59
|
Take the extra time to refactor - it's worth it for long-term maintainability.
|
|
61
60
|
|
|
@@ -78,8 +77,8 @@ Methods under reasonable limits are:
|
|
|
78
77
|
## Gradual Cleanup Strategy
|
|
79
78
|
|
|
80
79
|
This codebase uses a gradual cleanup approach:
|
|
81
|
-
- **New methods**: Must be under \`
|
|
82
|
-
- **Modified methods**: Must be under \`
|
|
80
|
+
- **New methods**: Must be under \`limit\` from nx.json
|
|
81
|
+
- **Modified methods**: Must be under \`limit\` from nx.json
|
|
83
82
|
- **Untouched methods**: No limit (legacy code is allowed until touched)
|
|
84
83
|
|
|
85
84
|
## How to Refactor
|
|
@@ -557,11 +556,11 @@ function methodHasChanges(method: MethodInfo, changedLineNumbers: Set<number>):
|
|
|
557
556
|
/**
|
|
558
557
|
* Check a NEW method and return violation if applicable
|
|
559
558
|
*/
|
|
560
|
-
function checkNewMethodViolation(file: string, method: MethodInfo,
|
|
559
|
+
function checkNewMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {
|
|
561
560
|
const { type: disableType, isExpired, date: disableDate } = method.disableInfo;
|
|
562
561
|
|
|
563
|
-
if (
|
|
564
|
-
// When
|
|
562
|
+
if (!disableAllowed) {
|
|
563
|
+
// When disableAllowed is false, skip NEW methods without escape (let validate-new-methods handle)
|
|
565
564
|
if (disableType === 'none') return null;
|
|
566
565
|
return { file, methodName: method.name, line: method.line, lines: method.lines };
|
|
567
566
|
}
|
|
@@ -580,12 +579,16 @@ function checkNewMethodViolation(file: string, method: MethodInfo, mode: Validat
|
|
|
580
579
|
/**
|
|
581
580
|
* Check a MODIFIED method and return violation if applicable
|
|
582
581
|
*/
|
|
583
|
-
function checkModifiedMethodViolation(file: string, method: MethodInfo,
|
|
582
|
+
function checkModifiedMethodViolation(file: string, method: MethodInfo, disableAllowed: boolean): MethodViolation | null {
|
|
584
583
|
const { type: disableType, isExpired, date: disableDate } = method.disableInfo;
|
|
585
584
|
|
|
586
|
-
if (
|
|
585
|
+
if (!disableAllowed) {
|
|
587
586
|
return { file, methodName: method.name, line: method.line, lines: method.lines };
|
|
588
587
|
}
|
|
588
|
+
if (disableType === 'full' && !isExpired) {
|
|
589
|
+
// Valid escape, no violation
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
589
592
|
if (disableType === 'full' && isExpired) {
|
|
590
593
|
return { file, methodName: method.name, line: method.line, lines: method.lines, expiredDisable: true, expiredDate: disableDate };
|
|
591
594
|
}
|
|
@@ -593,15 +596,15 @@ function checkModifiedMethodViolation(file: string, method: MethodInfo, mode: Va
|
|
|
593
596
|
}
|
|
594
597
|
|
|
595
598
|
/**
|
|
596
|
-
* Find methods that exceed the
|
|
599
|
+
* Find methods that exceed the limit.
|
|
597
600
|
* Checks NEW methods with escape hatches and MODIFIED methods.
|
|
598
601
|
*/
|
|
599
602
|
function findViolations(
|
|
600
603
|
workspaceRoot: string,
|
|
601
604
|
changedFiles: string[],
|
|
602
605
|
base: string,
|
|
603
|
-
|
|
604
|
-
|
|
606
|
+
limit: number,
|
|
607
|
+
disableAllowed: boolean,
|
|
605
608
|
head?: string
|
|
606
609
|
): MethodViolation[] {
|
|
607
610
|
const violations: MethodViolation[] = [];
|
|
@@ -619,17 +622,18 @@ function findViolations(
|
|
|
619
622
|
for (const method of methods) {
|
|
620
623
|
const { type: disableType, isExpired } = method.disableInfo;
|
|
621
624
|
|
|
622
|
-
// Skip methods with valid, non-expired full escape - unless
|
|
623
|
-
if (
|
|
624
|
-
if (method.lines <=
|
|
625
|
+
// Skip methods with valid, non-expired full escape - unless disableAllowed is false
|
|
626
|
+
if (disableAllowed && disableType === 'full' && !isExpired) continue;
|
|
627
|
+
if (method.lines <= limit) continue;
|
|
625
628
|
|
|
626
629
|
const isNewMethod = newMethodNames.has(method.name);
|
|
627
630
|
|
|
628
631
|
if (isNewMethod) {
|
|
629
|
-
const violation = checkNewMethodViolation(file, method,
|
|
632
|
+
const violation = checkNewMethodViolation(file, method, disableAllowed);
|
|
630
633
|
if (violation) violations.push(violation);
|
|
631
634
|
} else if (methodHasChanges(method, changedLineNumbers)) {
|
|
632
|
-
|
|
635
|
+
const violation = checkModifiedMethodViolation(file, method, disableAllowed);
|
|
636
|
+
if (violation) violations.push(violation);
|
|
633
637
|
}
|
|
634
638
|
}
|
|
635
639
|
}
|
|
@@ -673,44 +677,44 @@ function detectBase(workspaceRoot: string): string | null {
|
|
|
673
677
|
* Report violations to console
|
|
674
678
|
*/
|
|
675
679
|
// webpieces-disable max-lines-new-methods -- Error output formatting with multiple message sections
|
|
676
|
-
function reportViolations(violations: MethodViolation[],
|
|
680
|
+
function reportViolations(violations: MethodViolation[], limit: number, disableAllowed: boolean): void {
|
|
677
681
|
console.error('');
|
|
678
|
-
console.error('
|
|
682
|
+
console.error('\u274c Modified methods exceed ' + limit + ' lines!');
|
|
679
683
|
console.error('');
|
|
680
|
-
console.error('
|
|
684
|
+
console.error('\ud83d\udcda When you modify a method, you must bring it under ' + limit + ' lines.');
|
|
681
685
|
console.error(' This rule encourages GRADUAL cleanup so even though you did not cause it,');
|
|
682
686
|
console.error(' you touched it, so you should fix now as part of your PR');
|
|
683
687
|
console.error(' (this is for vibe coding and AI to fix as it touches things).');
|
|
684
688
|
console.error(' You can refactor to stay under the limit 50% of the time. If not feasible, use the escape hatch.');
|
|
685
689
|
console.error('');
|
|
686
690
|
console.error(
|
|
687
|
-
'
|
|
691
|
+
'\u26a0\ufe0f *** READ tmp/webpieces/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \u26a0\ufe0f'
|
|
688
692
|
);
|
|
689
693
|
console.error('');
|
|
690
694
|
|
|
691
695
|
for (const v of violations) {
|
|
692
696
|
if (v.expiredDisable) {
|
|
693
|
-
console.error(`
|
|
694
|
-
console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${
|
|
695
|
-
console.error(`
|
|
697
|
+
console.error(` \u274c ${v.file}:${v.line}`);
|
|
698
|
+
console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);
|
|
699
|
+
console.error(` \u23f0 EXPIRED DISABLE: Your disable comment dated ${v.expiredDate ?? 'unknown'} has expired (>1 month old).`);
|
|
696
700
|
console.error(` You must either FIX the method or UPDATE the date to get another month.`);
|
|
697
701
|
} else {
|
|
698
|
-
console.error(`
|
|
699
|
-
console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${
|
|
702
|
+
console.error(` \u274c ${v.file}:${v.line}`);
|
|
703
|
+
console.error(` Method: ${v.methodName} (${v.lines} lines, max: ${limit})`);
|
|
700
704
|
}
|
|
701
705
|
}
|
|
702
706
|
console.error('');
|
|
703
707
|
|
|
704
|
-
// Only show escape hatch instructions when
|
|
705
|
-
if (
|
|
708
|
+
// Only show escape hatch instructions when disableAllowed is true
|
|
709
|
+
if (disableAllowed) {
|
|
706
710
|
console.error(' You can disable this error, but you will be forced to fix again in 1 month');
|
|
707
|
-
console.error(' since 99% of methods can be less than ' +
|
|
711
|
+
console.error(' since 99% of methods can be less than ' + limit + ' lines of code.');
|
|
708
712
|
console.error('');
|
|
709
713
|
console.error(' Use escape with DATE (expires in 1 month):');
|
|
710
714
|
console.error(` // webpieces-disable max-lines-modified ${getTodayDateString()} -- [your reason]`);
|
|
711
715
|
console.error('');
|
|
712
716
|
} else {
|
|
713
|
-
console.error('
|
|
717
|
+
console.error(' \u26a0\ufe0f disableAllowed is false - disable comments are NOT allowed.');
|
|
714
718
|
console.error(' You MUST refactor to reduce method size.');
|
|
715
719
|
console.error('');
|
|
716
720
|
}
|
|
@@ -721,12 +725,13 @@ export default async function runExecutor(
|
|
|
721
725
|
context: ExecutorContext
|
|
722
726
|
): Promise<ExecutorResult> {
|
|
723
727
|
const workspaceRoot = context.root;
|
|
724
|
-
const
|
|
725
|
-
const mode:
|
|
728
|
+
const limit = options.limit ?? 80;
|
|
729
|
+
const mode: MethodMaxLimitMode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';
|
|
730
|
+
const disableAllowed = options.disableAllowed ?? true;
|
|
726
731
|
|
|
727
732
|
// Skip validation entirely if mode is OFF
|
|
728
733
|
if (mode === 'OFF') {
|
|
729
|
-
console.log('\n
|
|
734
|
+
console.log('\n\u23ed\ufe0f Skipping modified method validation (mode: OFF)');
|
|
730
735
|
console.log('');
|
|
731
736
|
return { success: true };
|
|
732
737
|
}
|
|
@@ -739,46 +744,47 @@ export default async function runExecutor(
|
|
|
739
744
|
base = detectBase(workspaceRoot) ?? undefined;
|
|
740
745
|
|
|
741
746
|
if (!base) {
|
|
742
|
-
console.log('\n
|
|
747
|
+
console.log('\n\u23ed\ufe0f Skipping modified method validation (could not detect base branch)');
|
|
743
748
|
console.log(' To run explicitly: nx affected --target=validate-modified-methods --base=origin/main');
|
|
744
749
|
console.log('');
|
|
745
750
|
return { success: true };
|
|
746
751
|
}
|
|
747
752
|
|
|
748
|
-
console.log('\n
|
|
753
|
+
console.log('\n\ud83d\udccf Validating Modified Method Sizes (auto-detected base)\n');
|
|
749
754
|
} else {
|
|
750
|
-
console.log('\n
|
|
755
|
+
console.log('\n\ud83d\udccf Validating Modified Method Sizes\n');
|
|
751
756
|
}
|
|
752
757
|
|
|
753
758
|
console.log(` Base: ${base}`);
|
|
754
759
|
console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
|
|
755
|
-
console.log(`
|
|
756
|
-
console.log(`
|
|
760
|
+
console.log(` Mode: ${mode}`);
|
|
761
|
+
console.log(` Limit for modified methods: ${limit}`);
|
|
762
|
+
console.log(` Disable allowed: ${disableAllowed}${!disableAllowed ? ' (no escape hatch)' : ''}`);
|
|
757
763
|
console.log('');
|
|
758
764
|
|
|
759
765
|
try {
|
|
760
766
|
const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
|
|
761
767
|
|
|
762
768
|
if (changedFiles.length === 0) {
|
|
763
|
-
console.log('
|
|
769
|
+
console.log('\u2705 No TypeScript files changed');
|
|
764
770
|
return { success: true };
|
|
765
771
|
}
|
|
766
772
|
|
|
767
|
-
console.log(
|
|
773
|
+
console.log(`\ud83d\udcc2 Checking ${changedFiles.length} changed file(s)...`);
|
|
768
774
|
|
|
769
|
-
const violations = findViolations(workspaceRoot, changedFiles, base,
|
|
775
|
+
const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);
|
|
770
776
|
|
|
771
777
|
if (violations.length === 0) {
|
|
772
|
-
console.log('
|
|
778
|
+
console.log('\u2705 All modified methods are under ' + limit + ' lines');
|
|
773
779
|
return { success: true };
|
|
774
780
|
}
|
|
775
781
|
|
|
776
782
|
writeTmpInstructions(workspaceRoot);
|
|
777
|
-
reportViolations(violations,
|
|
783
|
+
reportViolations(violations, limit, disableAllowed);
|
|
778
784
|
return { success: false };
|
|
779
785
|
} catch (err: unknown) {
|
|
780
786
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
781
|
-
console.error('
|
|
787
|
+
console.error('\u274c Modified method validation failed:', error.message);
|
|
782
788
|
return { success: false };
|
|
783
789
|
}
|
|
784
790
|
}
|
|
@@ -4,16 +4,21 @@
|
|
|
4
4
|
"description": "Validates that modified methods don't exceed a maximum line count. Encourages gradual cleanup of legacy long methods.",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
|
-
"
|
|
7
|
+
"limit": {
|
|
8
8
|
"type": "number",
|
|
9
|
-
"description": "Maximum
|
|
9
|
+
"description": "Maximum lines allowed for modified methods",
|
|
10
10
|
"default": 80
|
|
11
11
|
},
|
|
12
12
|
"mode": {
|
|
13
13
|
"type": "string",
|
|
14
|
-
"enum": ["
|
|
15
|
-
"description": "
|
|
16
|
-
"default": "
|
|
14
|
+
"enum": ["OFF", "NEW_METHODS", "NEW_AND_MODIFIED_METHODS", "MODIFIED_FILES"],
|
|
15
|
+
"description": "OFF: skip validation. NEW_AND_MODIFIED_METHODS: new methods + methods with changes. MODIFIED_FILES: all methods in modified files.",
|
|
16
|
+
"default": "NEW_AND_MODIFIED_METHODS"
|
|
17
|
+
},
|
|
18
|
+
"disableAllowed": {
|
|
19
|
+
"type": "boolean",
|
|
20
|
+
"description": "Whether disable comments work. When false, no escape hatch (like old STRICT mode).",
|
|
21
|
+
"default": true
|
|
17
22
|
}
|
|
18
23
|
},
|
|
19
24
|
"required": []
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
* Escape hatch: Add webpieces-disable max-lines-new-methods comment with justification
|
|
17
17
|
*/
|
|
18
18
|
import type { ExecutorContext } from '@nx/devkit';
|
|
19
|
-
export type
|
|
19
|
+
export type MethodMaxLimitMode = 'OFF' | 'NEW_METHODS' | 'NEW_AND_MODIFIED_METHODS' | 'MODIFIED_FILES';
|
|
20
20
|
export interface ValidateNewMethodsOptions {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
limit?: number;
|
|
22
|
+
mode?: MethodMaxLimitMode;
|
|
23
|
+
disableAllowed?: boolean;
|
|
24
24
|
}
|
|
25
25
|
export interface ExecutorResult {
|
|
26
26
|
success: boolean;
|
|
@@ -29,10 +29,8 @@ const METHODSIZE_DOC_CONTENT = `# Instructions: New Method Too Long
|
|
|
29
29
|
|
|
30
30
|
## Requirement
|
|
31
31
|
|
|
32
|
-
**~
|
|
32
|
+
**~99% of the time**, you can stay under the \`limit\` from nx.json
|
|
33
33
|
by extracting logical units into well-named methods.
|
|
34
|
-
|
|
35
|
-
**~99% of the time**, you can stay under the \`modifiedAndNewMethodsMaxLines\` limit from nx.json.
|
|
36
34
|
Nearly all software can be written with methods under this size.
|
|
37
35
|
|
|
38
36
|
## The "Table of Contents" Principle
|
|
@@ -270,8 +268,6 @@ function findNewMethodSignaturesInDiff(diffContent) {
|
|
|
270
268
|
/**
|
|
271
269
|
* Check if a line contains a webpieces-disable comment that exempts from new method validation.
|
|
272
270
|
* Both max-lines-new-methods AND max-lines-modified are accepted here.
|
|
273
|
-
* - max-lines-new-methods: Exempts from 30-line check, still checked by 80-line validator
|
|
274
|
-
* - max-lines-modified: Exempts from both validators (ultimate escape hatch)
|
|
275
271
|
*/
|
|
276
272
|
function hasDisableComment(lines, lineNumber) {
|
|
277
273
|
// Check the line before the method (lineNumber is 1-indexed, array is 0-indexed)
|
|
@@ -284,7 +280,7 @@ function hasDisableComment(lines, lineNumber) {
|
|
|
284
280
|
break;
|
|
285
281
|
}
|
|
286
282
|
if (line.includes('webpieces-disable')) {
|
|
287
|
-
// Either escape hatch exempts from the
|
|
283
|
+
// Either escape hatch exempts from the lowLimit new method check
|
|
288
284
|
if (line.includes('max-lines-new-methods') || line.includes('max-lines-modified')) {
|
|
289
285
|
return true;
|
|
290
286
|
}
|
|
@@ -295,6 +291,7 @@ function hasDisableComment(lines, lineNumber) {
|
|
|
295
291
|
/**
|
|
296
292
|
* Parse a TypeScript file and find methods with their line counts
|
|
297
293
|
*/
|
|
294
|
+
// webpieces-disable max-lines-new-methods -- AST traversal requires inline visitor function
|
|
298
295
|
function findMethodsInFile(filePath, workspaceRoot) {
|
|
299
296
|
const fullPath = path.join(workspaceRoot, filePath);
|
|
300
297
|
if (!fs.existsSync(fullPath))
|
|
@@ -347,7 +344,7 @@ function findMethodsInFile(filePath, workspaceRoot) {
|
|
|
347
344
|
/**
|
|
348
345
|
* Find new methods that exceed the line limit
|
|
349
346
|
*/
|
|
350
|
-
function findViolations(workspaceRoot, changedFiles, base,
|
|
347
|
+
function findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head) {
|
|
351
348
|
const violations = [];
|
|
352
349
|
for (const file of changedFiles) {
|
|
353
350
|
// Get the diff to find which methods are NEW (not just modified)
|
|
@@ -360,29 +357,29 @@ function findViolations(workspaceRoot, changedFiles, base, maxLines, strictMaxLi
|
|
|
360
357
|
for (const method of methods) {
|
|
361
358
|
if (!newMethodNames.has(method.name))
|
|
362
359
|
continue;
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
360
|
+
if (method.lines > limit) {
|
|
361
|
+
if (!disableAllowed) {
|
|
362
|
+
// No escape possible
|
|
363
|
+
violations.push({
|
|
364
|
+
file,
|
|
365
|
+
methodName: method.name,
|
|
366
|
+
line: method.line,
|
|
367
|
+
lines: method.lines,
|
|
368
|
+
isNew: true,
|
|
369
|
+
limit,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
else if (!method.hasDisableComment) {
|
|
373
|
+
// Escape allowed but not present
|
|
374
|
+
violations.push({
|
|
375
|
+
file,
|
|
376
|
+
methodName: method.name,
|
|
377
|
+
line: method.line,
|
|
378
|
+
lines: method.lines,
|
|
379
|
+
isNew: true,
|
|
380
|
+
limit,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
386
383
|
}
|
|
387
384
|
}
|
|
388
385
|
}
|
|
@@ -425,54 +422,43 @@ function detectBase(workspaceRoot) {
|
|
|
425
422
|
/**
|
|
426
423
|
* Report violations to the user with helpful instructions
|
|
427
424
|
*/
|
|
428
|
-
|
|
429
|
-
function reportViolations(violations, maxLines, strictMaxLines) {
|
|
430
|
-
const hardViolations = violations.filter((v) => v.isHardLimit);
|
|
431
|
-
const softViolations = violations.filter((v) => !v.isHardLimit);
|
|
425
|
+
function reportViolations(violations, limit, disableAllowed) {
|
|
432
426
|
console.error('');
|
|
433
|
-
console.error('
|
|
427
|
+
console.error('\u274c New methods exceed ' + limit + ' line limit!');
|
|
434
428
|
console.error('');
|
|
435
|
-
console.error('
|
|
436
|
-
console.error(' describes a larger piece of work.
|
|
437
|
-
console.error(' to stay under ' + maxLines + ' lines 50% of the time.');
|
|
429
|
+
console.error('\ud83d\udcda Methods should read like a "table of contents" - each method call');
|
|
430
|
+
console.error(' describes a larger piece of work.');
|
|
438
431
|
console.error('');
|
|
439
|
-
console.error('
|
|
432
|
+
console.error('\u26a0\ufe0f *** READ tmp/webpieces/webpieces.methodsize.md for detailed guidance on how to fix this easily *** \u26a0\ufe0f');
|
|
440
433
|
console.error('');
|
|
441
|
-
if (
|
|
442
|
-
console.error('
|
|
443
|
-
console.error('');
|
|
444
|
-
for (const v of hardViolations) {
|
|
445
|
-
console.error(` ❌ ${v.file}:${v.line}`);
|
|
446
|
-
console.error(` Method: ${v.methodName} (${v.lines} lines, hard max: ${strictMaxLines})`);
|
|
447
|
-
}
|
|
448
|
-
console.error('');
|
|
449
|
-
console.error(' These methods MUST be refactored - no escape hatch available.');
|
|
450
|
-
console.error('');
|
|
434
|
+
if (disableAllowed) {
|
|
435
|
+
console.error('\u26a0\ufe0f VIOLATIONS (can use escape hatch):');
|
|
451
436
|
}
|
|
452
|
-
|
|
453
|
-
console.error('
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
console.error(` NOTE: Even with escape, you cannot exceed the hard limit of ${strictMaxLines} lines.`);
|
|
464
|
-
}
|
|
465
|
-
console.error('');
|
|
437
|
+
else {
|
|
438
|
+
console.error('\ud83d\udeab VIOLATIONS (cannot be bypassed with disable comment):');
|
|
439
|
+
}
|
|
440
|
+
console.error('');
|
|
441
|
+
for (const v of violations) {
|
|
442
|
+
console.error(` \u274c ${v.file}:${v.line}`);
|
|
443
|
+
console.error(` Method: ${v.methodName} (${v.lines} lines, limit: ${limit})`);
|
|
444
|
+
}
|
|
445
|
+
console.error('');
|
|
446
|
+
if (disableAllowed) {
|
|
447
|
+
console.error(' Use escape: // webpieces-disable max-lines-new-methods -- [your reason]');
|
|
466
448
|
}
|
|
449
|
+
else {
|
|
450
|
+
console.error(' These methods MUST be refactored - no escape hatch available (disableAllowed=false).');
|
|
451
|
+
}
|
|
452
|
+
console.error('');
|
|
467
453
|
}
|
|
468
454
|
async function runExecutor(options, context) {
|
|
469
455
|
const workspaceRoot = context.root;
|
|
470
|
-
const
|
|
471
|
-
const
|
|
472
|
-
const
|
|
456
|
+
const limit = options.limit ?? 80;
|
|
457
|
+
const mode = options.mode ?? 'NEW_AND_MODIFIED_METHODS';
|
|
458
|
+
const disableAllowed = options.disableAllowed ?? true;
|
|
473
459
|
// Skip validation entirely if mode is OFF
|
|
474
460
|
if (mode === 'OFF') {
|
|
475
|
-
console.log('\n
|
|
461
|
+
console.log('\n\u23ed\ufe0f Skipping new method validation (mode: OFF)');
|
|
476
462
|
console.log('');
|
|
477
463
|
return { success: true };
|
|
478
464
|
}
|
|
@@ -484,48 +470,43 @@ async function runExecutor(options, context) {
|
|
|
484
470
|
// Try to auto-detect base from git merge-base
|
|
485
471
|
base = detectBase(workspaceRoot) ?? undefined;
|
|
486
472
|
if (!base) {
|
|
487
|
-
console.log('\n
|
|
473
|
+
console.log('\n\u23ed\ufe0f Skipping new method validation (could not detect base branch)');
|
|
488
474
|
console.log(' To run explicitly: nx affected --target=validate-new-methods --base=origin/main');
|
|
489
475
|
console.log('');
|
|
490
476
|
return { success: true };
|
|
491
477
|
}
|
|
492
|
-
console.log('\n
|
|
478
|
+
console.log('\n\ud83d\udccf Validating New Method Sizes (auto-detected base)\n');
|
|
493
479
|
}
|
|
494
480
|
else {
|
|
495
|
-
console.log('\n
|
|
481
|
+
console.log('\n\ud83d\udccf Validating New Method Sizes\n');
|
|
496
482
|
}
|
|
497
483
|
console.log(` Base: ${base}`);
|
|
498
484
|
console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
|
|
499
|
-
console.log(`
|
|
500
|
-
|
|
501
|
-
console.log(` Hard limit for new methods: ${strictMaxLines} lines (NO escape possible)`);
|
|
502
|
-
}
|
|
485
|
+
console.log(` Mode: ${mode}`);
|
|
486
|
+
console.log(` Limit for new methods: ${limit} lines (${disableAllowed ? 'can escape' : 'NO escape possible'})`);
|
|
503
487
|
console.log('');
|
|
504
488
|
try {
|
|
505
489
|
// Get changed TypeScript files (base to head, or working tree if head not set)
|
|
506
490
|
const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
|
|
507
491
|
if (changedFiles.length === 0) {
|
|
508
|
-
console.log('
|
|
492
|
+
console.log('\u2705 No TypeScript files changed');
|
|
509
493
|
return { success: true };
|
|
510
494
|
}
|
|
511
|
-
console.log(
|
|
495
|
+
console.log(`\ud83d\udcc2 Checking ${changedFiles.length} changed file(s)...`);
|
|
512
496
|
// Find violations
|
|
513
|
-
const violations = findViolations(workspaceRoot, changedFiles, base,
|
|
497
|
+
const violations = findViolations(workspaceRoot, changedFiles, base, limit, disableAllowed, head);
|
|
514
498
|
if (violations.length === 0) {
|
|
515
|
-
|
|
516
|
-
? `soft limit (${maxLines}) or hard limit (${strictMaxLines})`
|
|
517
|
-
: `${maxLines} lines`;
|
|
518
|
-
console.log('✅ All new methods are within ' + limitMsg);
|
|
499
|
+
console.log('\u2705 All new methods are within ' + limit + ' lines');
|
|
519
500
|
return { success: true };
|
|
520
501
|
}
|
|
521
502
|
// Write instructions file and report violations
|
|
522
503
|
writeTmpInstructions(workspaceRoot);
|
|
523
|
-
reportViolations(violations,
|
|
504
|
+
reportViolations(violations, limit, disableAllowed);
|
|
524
505
|
return { success: false };
|
|
525
506
|
}
|
|
526
507
|
catch (err) {
|
|
527
508
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
528
|
-
console.error('
|
|
509
|
+
console.error('\u274c New method validation failed:', error.message);
|
|
529
510
|
return { success: false };
|
|
530
511
|
}
|
|
531
512
|
}
|