@webpieces/ai-hook-rules 0.3.227 → 0.3.229
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/core/custom-rule-adapter.d.ts +2 -1
- package/src/core/custom-rule-adapter.js.map +1 -1
- package/src/core/fix-hint.d.ts +42 -0
- package/src/core/fix-hint.js +60 -0
- package/src/core/fix-hint.js.map +1 -0
- package/src/core/report.js +21 -5
- package/src/core/report.js.map +1 -1
- package/src/core/rule-base.d.ts +4 -3
- package/src/core/rule-base.js.map +1 -1
- package/src/core/rules/branch-creation-guard.d.ts +2 -1
- package/src/core/rules/branch-creation-guard.js +8 -7
- package/src/core/rules/branch-creation-guard.js.map +1 -1
- package/src/core/rules/catch-error-pattern.d.ts +2 -1
- package/src/core/rules/catch-error-pattern.js +9 -7
- package/src/core/rules/catch-error-pattern.js.map +1 -1
- package/src/core/rules/feature-branch-guard.d.ts +2 -1
- package/src/core/rules/feature-branch-guard.js +6 -6
- package/src/core/rules/feature-branch-guard.js.map +1 -1
- package/src/core/rules/max-file-lines.d.ts +2 -1
- package/src/core/rules/max-file-lines.js +4 -4
- package/src/core/rules/max-file-lines.js.map +1 -1
- package/src/core/rules/merge-in-progress-guard.d.ts +2 -1
- package/src/core/rules/merge-in-progress-guard.js +8 -12
- package/src/core/rules/merge-in-progress-guard.js.map +1 -1
- package/src/core/rules/no-any-unknown.d.ts +2 -1
- package/src/core/rules/no-any-unknown.js +7 -6
- package/src/core/rules/no-any-unknown.js.map +1 -1
- package/src/core/rules/no-destructure.d.ts +2 -1
- package/src/core/rules/no-destructure.js +7 -6
- package/src/core/rules/no-destructure.js.map +1 -1
- package/src/core/rules/no-implicit-any.d.ts +2 -1
- package/src/core/rules/no-implicit-any.js +6 -5
- package/src/core/rules/no-implicit-any.js.map +1 -1
- package/src/core/rules/no-js-files.d.ts +2 -1
- package/src/core/rules/no-js-files.js +6 -5
- package/src/core/rules/no-js-files.js.map +1 -1
- package/src/core/rules/no-symbol-di-tokens.d.ts +2 -1
- package/src/core/rules/no-symbol-di-tokens.js +11 -8
- package/src/core/rules/no-symbol-di-tokens.js.map +1 -1
- package/src/core/rules/no-unmanaged-exceptions.d.ts +2 -1
- package/src/core/rules/no-unmanaged-exceptions.js +15 -13
- package/src/core/rules/no-unmanaged-exceptions.js.map +1 -1
- package/src/core/rules/pr-creation-guard.d.ts +2 -1
- package/src/core/rules/pr-creation-guard.js +8 -13
- package/src/core/rules/pr-creation-guard.js.map +1 -1
- package/src/core/rules/pr-merge-cleanup.d.ts +3 -1
- package/src/core/rules/pr-merge-cleanup.js +11 -11
- package/src/core/rules/pr-merge-cleanup.js.map +1 -1
- package/src/core/rules/redirect-how-to-merge-main.d.ts +2 -1
- package/src/core/rules/redirect-how-to-merge-main.js +3 -10
- package/src/core/rules/redirect-how-to-merge-main.js.map +1 -1
- package/src/core/rules/require-return-type.d.ts +2 -1
- package/src/core/rules/require-return-type.js +7 -6
- package/src/core/rules/require-return-type.js.map +1 -1
- package/src/core/rules/throw-cause-required.d.ts +2 -1
- package/src/core/rules/throw-cause-required.js +11 -8
- package/src/core/rules/throw-cause-required.js.map +1 -1
- package/src/core/rules/validate-ts-in-src.d.ts +2 -1
- package/src/core/rules/validate-ts-in-src.js +5 -4
- package/src/core/rules/validate-ts-in-src.js.map +1 -1
- package/src/core/runner.js +3 -3
- package/src/core/runner.js.map +1 -1
- package/src/core/types.d.ts +6 -5
- package/src/core/types.js +3 -0
- package/src/core/types.js.map +1 -1
- package/src/index.d.ts +1 -0
- package/src/index.js +6 -1
- package/src/index.js.map +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { NoUnmanagedExceptionsConfig } from '@webpieces/rules-config';
|
|
2
2
|
import type { EditContext, Violation } from '../types';
|
|
3
3
|
import { EditRuleBase } from '../rule-base';
|
|
4
|
+
import { FixHint } from '../fix-hint';
|
|
4
5
|
export declare class NoUnmanagedExceptionsRule extends EditRuleBase<NoUnmanagedExceptionsConfig> {
|
|
5
6
|
constructor(config: NoUnmanagedExceptionsConfig);
|
|
6
7
|
readonly description = "try/catch is generally not allowed. Only allowed in chokepoints (filter, globalErrorHandler) or other rare locations.";
|
|
7
8
|
readonly files: string[];
|
|
8
|
-
|
|
9
|
+
get fixHint(): FixHint;
|
|
9
10
|
check(ctx: EditContext): readonly Violation[];
|
|
10
11
|
}
|
|
@@ -4,6 +4,7 @@ exports.NoUnmanagedExceptionsRule = void 0;
|
|
|
4
4
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const rule_base_1 = require("../rule-base");
|
|
7
|
+
const fix_hint_1 = require("../fix-hint");
|
|
7
8
|
const instruct_ai_writer_1 = require("../instruct-ai-writer");
|
|
8
9
|
const TRY_PATTERN = /\btry\s*\{/;
|
|
9
10
|
// Both webpieces-disable and the existing ESLint directive suppress this rule
|
|
@@ -18,28 +19,29 @@ class NoUnmanagedExceptionsRule extends rule_base_1.EditRuleBase {
|
|
|
18
19
|
constructor(config) { super(config, 'no-unmanaged-exceptions'); }
|
|
19
20
|
description = 'try/catch is generally not allowed. Only allowed in chokepoints (filter, globalErrorHandler) or other rare locations.';
|
|
20
21
|
files = ['**/*.ts', '**/*.tsx'];
|
|
21
|
-
fixHint
|
|
22
|
-
'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
get fixHint() {
|
|
23
|
+
return new fix_hint_1.FixHint('try/catch is generally not allowed. READ .webpieces/instruct-ai/webpieces.exceptions.md. Only chokepoints (filter, globalErrorHandler) may catch exceptions.', 'Pick one (NOTE: for external calls — execSync, fs, network — the preferred option is almost always right; let it throw, the top-level runner reports it):', [
|
|
24
|
+
new fix_hint_1.Option('Remove the try/catch — let the exception bubble to the top-level chokepoint (filter, globalErrorHandler) where it is already logged and handled.', true),
|
|
25
|
+
new fix_hint_1.Option('If you genuinely believe this IS a chokepoint, STOP and ask the human first:\n'
|
|
26
|
+
+ ' - What exception could be thrown here\n'
|
|
27
|
+
+ ' - What the current top-level chokepoint is (the try/catch at the top of the call stack)\n'
|
|
28
|
+
+ ' - Why throwing to that chokepoint would be wrong in this specific case\n'
|
|
29
|
+
+ ' Then ask whether to remove the try/catch or add a disable comment.'),
|
|
30
|
+
], new fix_hint_1.DisableEscape(this.config.disableAllowed ?? true, '// webpieces-disable no-unmanaged-exceptions -- <reason>'));
|
|
31
|
+
}
|
|
31
32
|
check(ctx) {
|
|
33
|
+
const disableAllowed = this.config.disableAllowed ?? true;
|
|
32
34
|
const violations = [];
|
|
33
35
|
for (let i = 0; i < ctx.strippedLines.length; i += 1) {
|
|
34
36
|
const stripped = ctx.strippedLines[i];
|
|
35
37
|
if (!TRY_PATTERN.test(stripped))
|
|
36
38
|
continue;
|
|
37
39
|
const lineNum = i + 1;
|
|
38
|
-
if (ctx.isLineDisabled(lineNum, rules_config_1.RULE_NAMES.NO_UNMANAGED_EXCEPTIONS))
|
|
40
|
+
if (disableAllowed && ctx.isLineDisabled(lineNum, rules_config_1.RULE_NAMES.NO_UNMANAGED_EXCEPTIONS))
|
|
39
41
|
continue;
|
|
40
|
-
if (hasPrecedingDisable(ctx.lines, i))
|
|
42
|
+
if (disableAllowed && hasPrecedingDisable(ctx.lines, i))
|
|
41
43
|
continue;
|
|
42
|
-
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim()
|
|
44
|
+
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim()));
|
|
43
45
|
}
|
|
44
46
|
if (violations.length > 0)
|
|
45
47
|
(0, instruct_ai_writer_1.writeTemplateIfMissing)(ctx.workspaceRoot, 'webpieces.exceptions.md');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-unmanaged-exceptions.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-unmanaged-exceptions.ts"],"names":[],"mappings":";;;AAAA,0DAAkF;AAGlF,oCAA0C;AAC1C,4CAA4C;AAC5C,8DAA+D;AAE/D,MAAM,WAAW,GAAG,YAAY,CAAC;AAEjC,8EAA8E;AAC9E,MAAM,eAAe,GAAG,gGAAgG,CAAC;AAEzH,SAAS,mBAAmB,CAAC,KAAwB,EAAE,GAAW;IAC9D,IAAI,GAAG,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAChC,OAAO,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,MAAa,yBAA0B,SAAQ,wBAAyC;IACpF,YAAY,MAAmC,IAAI,KAAK,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC;IAErF,WAAW,GAAG,uHAAuH,CAAC;IAC7H,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"no-unmanaged-exceptions.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-unmanaged-exceptions.ts"],"names":[],"mappings":";;;AAAA,0DAAkF;AAGlF,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAA6D;AAC7D,8DAA+D;AAE/D,MAAM,WAAW,GAAG,YAAY,CAAC;AAEjC,8EAA8E;AAC9E,MAAM,eAAe,GAAG,gGAAgG,CAAC;AAEzH,SAAS,mBAAmB,CAAC,KAAwB,EAAE,GAAW;IAC9D,IAAI,GAAG,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAChC,OAAO,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,MAAa,yBAA0B,SAAQ,wBAAyC;IACpF,YAAY,MAAmC,IAAI,KAAK,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC;IAErF,WAAW,GAAG,uHAAuH,CAAC;IAC7H,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAClD,IAAI,OAAO;QACP,OAAO,IAAI,kBAAO,CACd,8JAA8J,EAC9J,2JAA2J,EAC3J;YACI,IAAI,iBAAM,CAAC,kJAAkJ,EAAE,IAAI,CAAC;YACpK,IAAI,iBAAM,CACN,gFAAgF;kBAC9E,2CAA2C;kBAC3C,6FAA6F;kBAC7F,4EAA4E;kBAC5E,sEAAsE,CAC3E;SACJ,EACD,IAAI,wBAAa,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,EAAE,0DAA0D,CAAC,CACpH,CAAC;IACN,CAAC;IAED,KAAK,CAAC,GAAgB;QAClB,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,CAAC;QAC1D,MAAM,UAAU,GAAQ,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAC1C,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,cAAc,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,yBAAU,CAAC,uBAAuB,CAAC;gBAAE,SAAS;YAChG,IAAI,cAAc,IAAI,mBAAmB,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;gBAAE,SAAS;YAClE,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YAAE,IAAA,2CAAsB,EAAC,GAAG,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC;QAChG,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AArCD,8DAqCC","sourcesContent":["import { NoUnmanagedExceptionsConfig, RULE_NAMES } from '@webpieces/rules-config';\n\nimport type { EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { EditRuleBase } from '../rule-base';\nimport { FixHint, Option, DisableEscape } from '../fix-hint';\nimport { writeTemplateIfMissing } from '../instruct-ai-writer';\n\nconst TRY_PATTERN = /\\btry\\s*\\{/;\n\n// Both webpieces-disable and the existing ESLint directive suppress this rule\nconst DISABLE_PATTERN = /@webpieces\\/no-unmanaged-exceptions|webpieces-disable\\s+(?:[\\w-]+,\\s*)*no-unmanaged-exceptions/;\n\nfunction hasPrecedingDisable(lines: readonly string[], idx: number): boolean {\n if (idx === 0) return false;\n const prevLine = lines[idx - 1];\n return DISABLE_PATTERN.test(prevLine);\n}\n\nexport class NoUnmanagedExceptionsRule extends EditRuleBase<NoUnmanagedExceptionsConfig> {\n constructor(config: NoUnmanagedExceptionsConfig) { super(config, 'no-unmanaged-exceptions'); }\n\n readonly description = 'try/catch is generally not allowed. Only allowed in chokepoints (filter, globalErrorHandler) or other rare locations.';\n override readonly files = ['**/*.ts', '**/*.tsx'];\n get fixHint(): FixHint {\n return new FixHint(\n 'try/catch is generally not allowed. READ .webpieces/instruct-ai/webpieces.exceptions.md. Only chokepoints (filter, globalErrorHandler) may catch exceptions.',\n 'Pick one (NOTE: for external calls — execSync, fs, network — the preferred option is almost always right; let it throw, the top-level runner reports it):',\n [\n new Option('Remove the try/catch — let the exception bubble to the top-level chokepoint (filter, globalErrorHandler) where it is already logged and handled.', true),\n new Option(\n 'If you genuinely believe this IS a chokepoint, STOP and ask the human first:\\n'\n + ' - What exception could be thrown here\\n'\n + ' - What the current top-level chokepoint is (the try/catch at the top of the call stack)\\n'\n + ' - Why throwing to that chokepoint would be wrong in this specific case\\n'\n + ' Then ask whether to remove the try/catch or add a disable comment.',\n ),\n ],\n new DisableEscape(this.config.disableAllowed ?? true, '// webpieces-disable no-unmanaged-exceptions -- <reason>'),\n );\n }\n\n check(ctx: EditContext): readonly Violation[] {\n const disableAllowed = this.config.disableAllowed ?? true;\n const violations: V[] = [];\n for (let i = 0; i < ctx.strippedLines.length; i += 1) {\n const stripped = ctx.strippedLines[i];\n if (!TRY_PATTERN.test(stripped)) continue;\n const lineNum = i + 1;\n if (disableAllowed && ctx.isLineDisabled(lineNum, RULE_NAMES.NO_UNMANAGED_EXCEPTIONS)) continue;\n if (disableAllowed && hasPrecedingDisable(ctx.lines, i)) continue;\n violations.push(new V(lineNum, ctx.lines[i].trim()));\n }\n if (violations.length > 0) writeTemplateIfMissing(ctx.workspaceRoot, 'webpieces.exceptions.md');\n return violations;\n }\n}\n"]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { PrCreationGuardConfig } from '@webpieces/rules-config';
|
|
2
2
|
import type { BashContext, Violation } from '../types';
|
|
3
3
|
import { BashRuleBase } from '../rule-base';
|
|
4
|
+
import { FixHint } from '../fix-hint';
|
|
4
5
|
export declare class PrCreationGuardRule extends BashRuleBase<PrCreationGuardConfig> {
|
|
5
6
|
private readonly upsertPrCommand;
|
|
6
7
|
constructor(config: PrCreationGuardConfig);
|
|
7
8
|
readonly description = "Block direct PR creation/edit (gh pr / gh api / curl) so PRs go only through the gated upsert-pr command.";
|
|
8
|
-
get fixHint():
|
|
9
|
+
get fixHint(): FixHint;
|
|
9
10
|
check(ctx: BashContext): readonly Violation[];
|
|
10
11
|
}
|
|
@@ -3,16 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PrCreationGuardRule = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const rule_base_1 = require("../rule-base");
|
|
6
|
+
const fix_hint_1 = require("../fix-hint");
|
|
6
7
|
const DEFAULT_UPSERT_PR_COMMAND = 'pnpm wp-start-upsert-pr';
|
|
7
8
|
function fixHintFor(upsertPrCommand) {
|
|
8
|
-
return
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'There is nothing to paste or attest to; the commands do the work.',
|
|
15
|
-
];
|
|
9
|
+
return new fix_hint_1.FixHint('Direct PR creation/update is blocked.', 'Create or update a PR ONLY via the gated flow:\n'
|
|
10
|
+
+ ` ${upsertPrCommand}\n`
|
|
11
|
+
+ 'It updates the branch from main (3-point merge) and runs the real build (nx affected), then\n'
|
|
12
|
+
+ 'instructs you to write review.json and run `pnpm wp-finish-upsert-pr`, which assembles the\n'
|
|
13
|
+
+ 'dashboard and creates/updates the PR itself. A failing build = no PR.\n'
|
|
14
|
+
+ 'There is nothing to paste or attest to; the commands do the work.');
|
|
16
15
|
}
|
|
17
16
|
// Detect every way an agent could open/update a PR directly, so the ONLY path left is the gated
|
|
18
17
|
// flow (wp-start-upsert-pr → wp-finish-upsert-pr, whose internal `gh pr create` runs as a child
|
|
@@ -45,11 +44,7 @@ class PrCreationGuardRule extends rule_base_1.BashRuleBase {
|
|
|
45
44
|
check(ctx) {
|
|
46
45
|
if (!isDirectPrCreation(ctx.command))
|
|
47
46
|
return [];
|
|
48
|
-
return [new types_1.Violation(1, truncate(ctx.command)
|
|
49
|
-
'Direct PR creation/update is blocked.',
|
|
50
|
-
'Use the gated command instead — it runs the build and builds the dashboard:',
|
|
51
|
-
` ${this.upsertPrCommand}`,
|
|
52
|
-
].join('\n'))];
|
|
47
|
+
return [new types_1.Violation(1, truncate(ctx.command))];
|
|
53
48
|
}
|
|
54
49
|
}
|
|
55
50
|
exports.PrCreationGuardRule = PrCreationGuardRule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-creation-guard.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/pr-creation-guard.ts"],"names":[],"mappings":";;;AAGA,oCAA0C;AAC1C,4CAA4C;
|
|
1
|
+
{"version":3,"file":"pr-creation-guard.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/pr-creation-guard.ts"],"names":[],"mappings":";;;AAGA,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAAsC;AAEtC,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAE5D,SAAS,UAAU,CAAC,eAAuB;IACvC,OAAO,IAAI,kBAAO,CACd,uCAAuC,EACvC,kDAAkD;UAChD,KAAK,eAAe,IAAI;UACxB,+FAA+F;UAC/F,8FAA8F;UAC9F,yEAAyE;UACzE,mEAAmE,CACxE,CAAC;AACN,CAAC;AAED,gGAAgG;AAChG,gGAAgG;AAChG,2GAA2G;AAC3G,SAAS,kBAAkB,CAAC,GAAW;IACnC,IAAI,6BAA6B,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzD,MAAM,UAAU,GAAG,6BAA6B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,UAAU,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC9I,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,SAAS,GAAG,+CAA+C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5E,IAAI,SAAS,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC1G,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACvB,MAAM,GAAG,GAAG,GAAG,CAAC;IAChB,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;AACvD,CAAC;AAED,MAAa,mBAAoB,SAAQ,wBAAmC;IACvD,eAAe,CAAS;IAEzC,YAAY,MAA6B;QACrC,KAAK,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,yBAAyB,CAAC;IAC/E,CAAC;IAEQ,WAAW,GAAG,2GAA2G,CAAC;IACnI,IAAI,OAAO,KAAc,OAAO,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAEnE,KAAK,CAAC,GAAgB;QAClB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QAChD,OAAO,CAAC,IAAI,iBAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;CACJ;AAfD,kDAeC","sourcesContent":["import { PrCreationGuardConfig } from '@webpieces/rules-config';\n\nimport type { BashContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { BashRuleBase } from '../rule-base';\nimport { FixHint } from '../fix-hint';\n\nconst DEFAULT_UPSERT_PR_COMMAND = 'pnpm wp-start-upsert-pr';\n\nfunction fixHintFor(upsertPrCommand: string): FixHint {\n return new FixHint(\n 'Direct PR creation/update is blocked.',\n 'Create or update a PR ONLY via the gated flow:\\n'\n + ` ${upsertPrCommand}\\n`\n + 'It updates the branch from main (3-point merge) and runs the real build (nx affected), then\\n'\n + 'instructs you to write review.json and run `pnpm wp-finish-upsert-pr`, which assembles the\\n'\n + 'dashboard and creates/updates the PR itself. A failing build = no PR.\\n'\n + 'There is nothing to paste or attest to; the commands do the work.',\n );\n}\n\n// Detect every way an agent could open/update a PR directly, so the ONLY path left is the gated\n// flow (wp-start-upsert-pr → wp-finish-upsert-pr, whose internal `gh pr create` runs as a child\n// process the hook never sees). Read-only `gh pr list` / `gh api .../pulls` GET are intentionally allowed.\nfunction isDirectPrCreation(cmd: string): boolean {\n if (/\\bgh\\s+pr\\s+(create|edit)\\b/.test(cmd)) return true;\n\n const ghApiPulls = /\\bgh\\s+api\\b[^\\n]*\\/pulls\\b/.test(cmd);\n if (ghApiPulls && (/--method\\s+POST/i.test(cmd) || /-X\\s+POST/i.test(cmd) || /\\s-f\\b/.test(cmd) || /\\s-F\\b/.test(cmd) || /--field\\b/.test(cmd))) {\n return true;\n }\n\n const curlPulls = /\\bcurl\\b[^\\n]*api\\.github\\.com[^\\n]*\\/pulls\\b/.test(cmd);\n if (curlPulls && (/-X\\s*POST/i.test(cmd) || /--request\\s+POST/i.test(cmd) || /(\\s-d\\b|--data\\b)/.test(cmd))) {\n return true;\n }\n return false;\n}\n\nfunction truncate(s: string): string {\n const MAX = 120;\n return s.length <= MAX ? s : s.slice(0, MAX) + '…';\n}\n\nexport class PrCreationGuardRule extends BashRuleBase<PrCreationGuardConfig> {\n private readonly upsertPrCommand: string;\n\n constructor(config: PrCreationGuardConfig) {\n super(config, 'pr-creation-guard');\n this.upsertPrCommand = config.upsertPrCommand ?? DEFAULT_UPSERT_PR_COMMAND;\n }\n\n readonly description = 'Block direct PR creation/edit (gh pr / gh api / curl) so PRs go only through the gated upsert-pr command.';\n get fixHint(): FixHint { return fixHintFor(this.upsertPrCommand); }\n\n check(ctx: BashContext): readonly Violation[] {\n if (!isDirectPrCreation(ctx.command)) return [];\n return [new V(1, truncate(ctx.command))];\n }\n}\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { PrMergeCleanupConfig } from '@webpieces/rules-config';
|
|
2
2
|
import type { BashContext, Violation } from '../types';
|
|
3
3
|
import { BashRuleBase } from '../rule-base';
|
|
4
|
+
import { FixHint } from '../fix-hint';
|
|
4
5
|
export declare class PrMergeCleanupRule extends BashRuleBase<PrMergeCleanupConfig> {
|
|
5
6
|
constructor(config: PrMergeCleanupConfig);
|
|
6
7
|
readonly description = "After merging a PR, require switching to main, pulling, and deleting the local branch.";
|
|
7
|
-
|
|
8
|
+
private currentBranch;
|
|
9
|
+
get fixHint(): FixHint;
|
|
8
10
|
check(ctx: BashContext): readonly Violation[];
|
|
9
11
|
}
|
|
@@ -4,6 +4,7 @@ exports.PrMergeCleanupRule = void 0;
|
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const rule_base_1 = require("../rule-base");
|
|
7
|
+
const fix_hint_1 = require("../fix-hint");
|
|
7
8
|
function truncate(s) {
|
|
8
9
|
const MAX = 120;
|
|
9
10
|
return s.length <= MAX ? s : s.slice(0, MAX) + '…';
|
|
@@ -11,11 +12,14 @@ function truncate(s) {
|
|
|
11
12
|
class PrMergeCleanupRule extends rule_base_1.BashRuleBase {
|
|
12
13
|
constructor(config) { super(config, 'pr-merge-cleanup'); }
|
|
13
14
|
description = 'After merging a PR, require switching to main, pulling, and deleting the local branch.';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
// Substituted with the real branch name in check(); the getter reads it. Placeholder until then.
|
|
16
|
+
currentBranch = '<current-branch>';
|
|
17
|
+
// Single fix, no distinct options — the whole guidance lives in mainMessage so it renders as
|
|
18
|
+
// one coherent block (never split into fake "Fix Option 1/2/3").
|
|
19
|
+
get fixHint() {
|
|
20
|
+
return new fix_hint_1.FixHint('After merging a PR you must clean up the local branch.', 'Run this combined command instead:\n'
|
|
21
|
+
+ ` gh pr merge --squash && git checkout main && git pull && git branch -d ${this.currentBranch}`);
|
|
22
|
+
}
|
|
19
23
|
check(ctx) {
|
|
20
24
|
if (!/gh\s+pr\s+merge/.test(ctx.command))
|
|
21
25
|
return [];
|
|
@@ -23,15 +27,11 @@ class PrMergeCleanupRule extends rule_base_1.BashRuleBase {
|
|
|
23
27
|
const hasDelete = /git\s+branch\s+-[dD]/.test(ctx.command);
|
|
24
28
|
if (hasCheckout && hasDelete)
|
|
25
29
|
return [];
|
|
26
|
-
|
|
30
|
+
this.currentBranch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
|
|
27
31
|
cwd: ctx.workspaceRoot,
|
|
28
32
|
encoding: 'utf8',
|
|
29
33
|
}).trim();
|
|
30
|
-
return [new types_1.Violation(1, truncate(ctx.command)
|
|
31
|
-
'[pr-merge-cleanup] After merging a PR you must clean up the local branch.',
|
|
32
|
-
'Run this combined command instead:',
|
|
33
|
-
` gh pr merge --squash && git checkout main && git pull && git branch -d ${currentBranch}`,
|
|
34
|
-
].join('\n'))];
|
|
34
|
+
return [new types_1.Violation(1, truncate(ctx.command))];
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
exports.PrMergeCleanupRule = PrMergeCleanupRule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-merge-cleanup.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/pr-merge-cleanup.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAKzC,oCAA0C;AAC1C,4CAA4C;
|
|
1
|
+
{"version":3,"file":"pr-merge-cleanup.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/pr-merge-cleanup.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAKzC,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAAsC;AAEtC,SAAS,QAAQ,CAAC,CAAS;IACvB,MAAM,GAAG,GAAG,GAAG,CAAC;IAChB,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;AACvD,CAAC;AAED,MAAa,kBAAmB,SAAQ,wBAAkC;IACtE,YAAY,MAA4B,IAAI,KAAK,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAEvE,WAAW,GAAG,wFAAwF,CAAC;IAEhH,iGAAiG;IACzF,aAAa,GAAG,kBAAkB,CAAC;IAE3C,6FAA6F;IAC7F,iEAAiE;IACjE,IAAI,OAAO;QACP,OAAO,IAAI,kBAAO,CACd,wDAAwD,EACxD,sCAAsC;cACpC,4EAA4E,IAAI,CAAC,aAAa,EAAE,CACrG,CAAC;IACN,CAAC;IAED,KAAK,CAAC,GAAgB;QAClB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QAEpD,MAAM,WAAW,GAAG,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvE,MAAM,SAAS,GAAG,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,WAAW,IAAI,SAAS;YAAE,OAAO,EAAE,CAAC;QAExC,IAAI,CAAC,aAAa,GAAG,IAAA,wBAAQ,EAAC,iCAAiC,EAAE;YAC7D,GAAG,EAAE,GAAG,CAAC,aAAa;YACtB,QAAQ,EAAE,MAAM;SACnB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,OAAO,CAAC,IAAI,iBAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;CACJ;AAjCD,gDAiCC","sourcesContent":["import { execSync } from 'child_process';\n\nimport { PrMergeCleanupConfig } from '@webpieces/rules-config';\n\nimport type { BashContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { BashRuleBase } from '../rule-base';\nimport { FixHint } from '../fix-hint';\n\nfunction truncate(s: string): string {\n const MAX = 120;\n return s.length <= MAX ? s : s.slice(0, MAX) + '…';\n}\n\nexport class PrMergeCleanupRule extends BashRuleBase<PrMergeCleanupConfig> {\n constructor(config: PrMergeCleanupConfig) { super(config, 'pr-merge-cleanup'); }\n\n readonly description = 'After merging a PR, require switching to main, pulling, and deleting the local branch.';\n\n // Substituted with the real branch name in check(); the getter reads it. Placeholder until then.\n private currentBranch = '<current-branch>';\n\n // Single fix, no distinct options — the whole guidance lives in mainMessage so it renders as\n // one coherent block (never split into fake \"Fix Option 1/2/3\").\n get fixHint(): FixHint {\n return new FixHint(\n 'After merging a PR you must clean up the local branch.',\n 'Run this combined command instead:\\n'\n + ` gh pr merge --squash && git checkout main && git pull && git branch -d ${this.currentBranch}`,\n );\n }\n\n check(ctx: BashContext): readonly Violation[] {\n if (!/gh\\s+pr\\s+merge/.test(ctx.command)) return [];\n\n const hasCheckout = /git\\s+(checkout|switch)\\s+main/.test(ctx.command);\n const hasDelete = /git\\s+branch\\s+-[dD]/.test(ctx.command);\n\n if (hasCheckout && hasDelete) return [];\n\n this.currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd: ctx.workspaceRoot,\n encoding: 'utf8',\n }).trim();\n\n return [new V(1, truncate(ctx.command))];\n }\n}\n"]}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { RedirectHowToMergeMainConfig } from '@webpieces/rules-config';
|
|
2
2
|
import type { BashContext, Violation } from '../types';
|
|
3
3
|
import { BashRuleBase } from '../rule-base';
|
|
4
|
+
import { FixHint } from '../fix-hint';
|
|
4
5
|
export declare class RedirectHowToMergeMainRule extends BashRuleBase<RedirectHowToMergeMainConfig> {
|
|
5
6
|
constructor(config: RedirectHowToMergeMainConfig);
|
|
6
7
|
readonly description = "Block direct git merge/rebase/pull from main on feature branches. Use the squash-update process instead.";
|
|
7
|
-
readonly fixHint:
|
|
8
|
+
readonly fixHint: FixHint;
|
|
8
9
|
check(ctx: BashContext): readonly Violation[];
|
|
9
10
|
}
|
|
@@ -4,9 +4,8 @@ exports.RedirectHowToMergeMainRule = void 0;
|
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const rule_base_1 = require("../rule-base");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
];
|
|
7
|
+
const fix_hint_1 = require("../fix-hint");
|
|
8
|
+
const FIX_HINT = new fix_hint_1.FixHint('Direct merge/rebase/pull from main on a feature branch is blocked.', "Run 'pnpm wp-git-update' to squash-update from main. This preserves the 3-point fork-point system (fork-point=A, feature-HEAD=B, main-HEAD=C) needed for clean PR diffs. See docs/git-workflow.md for details.");
|
|
10
9
|
const WRONG_UPDATE_PATTERNS = [
|
|
11
10
|
/git\s+merge\s+(origin\/main|main)\b/,
|
|
12
11
|
/git\s+rebase\s+(origin\/main|main)\b/,
|
|
@@ -35,13 +34,7 @@ class RedirectHowToMergeMainRule extends rule_base_1.BashRuleBase {
|
|
|
35
34
|
if (currentBranch === 'main') {
|
|
36
35
|
return [];
|
|
37
36
|
}
|
|
38
|
-
return [new types_1.Violation(1, truncate(ctx.command),
|
|
39
|
-
`Direct merge/rebase from main on branch '${currentBranch}' is blocked.`,
|
|
40
|
-
'This breaks the 3-point fork-point system.',
|
|
41
|
-
'Use the squash-update process instead:',
|
|
42
|
-
' pnpm wp-git-update',
|
|
43
|
-
'See docs/git-workflow.md for details.',
|
|
44
|
-
].join('\n'))];
|
|
37
|
+
return [new types_1.Violation(1, truncate(ctx.command), `Direct merge/rebase from main on branch '${currentBranch}' is blocked.`)];
|
|
45
38
|
}
|
|
46
39
|
}
|
|
47
40
|
exports.RedirectHowToMergeMainRule = RedirectHowToMergeMainRule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirect-how-to-merge-main.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/redirect-how-to-merge-main.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAKzC,oCAA0C;AAC1C,4CAA4C;
|
|
1
|
+
{"version":3,"file":"redirect-how-to-merge-main.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/redirect-how-to-merge-main.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAKzC,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAAsC;AAEtC,MAAM,QAAQ,GAAG,IAAI,kBAAO,CACxB,oEAAoE,EACpE,gNAAgN,CACnN,CAAC;AAEF,MAAM,qBAAqB,GAAa;IACpC,qCAAqC;IACrC,sCAAsC;IACtC,8BAA8B;CACjC,CAAC;AAEF,SAAS,QAAQ,CAAC,CAAS;IACvB,MAAM,GAAG,GAAG,GAAG,CAAC;IAChB,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;AACvD,CAAC;AAED,MAAa,0BAA2B,SAAQ,wBAA0C;IACtF,YAAY,MAAoC,IAAI,KAAK,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC,CAAC,CAAC;IAEzF,WAAW,GAAG,0GAA0G,CAAC;IACzH,OAAO,GAAG,QAAQ,CAAC;IAE5B,KAAK,CAAC,GAAgB;QAClB,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC/E,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QAExB,0GAA0G;QAC1G,IAAI,oCAAoC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACzD,OAAO,EAAE,CAAC;QACd,CAAC;QAED,MAAM,aAAa,GAAG,IAAA,wBAAQ,EAAC,iCAAiC,EAAE;YAC9D,GAAG,EAAE,GAAG,CAAC,aAAa;YACtB,QAAQ,EAAE,MAAM;SACnB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;YAC3B,OAAO,EAAE,CAAC;QACd,CAAC;QAED,OAAO,CAAC,IAAI,iBAAC,CACT,CAAC,EACD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EACrB,4CAA4C,aAAa,eAAe,CAC3E,CAAC,CAAC;IACP,CAAC;CACJ;AA9BD,gEA8BC","sourcesContent":["import { execSync } from 'child_process';\n\nimport { RedirectHowToMergeMainConfig } from '@webpieces/rules-config';\n\nimport type { BashContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { BashRuleBase } from '../rule-base';\nimport { FixHint } from '../fix-hint';\n\nconst FIX_HINT = new FixHint(\n 'Direct merge/rebase/pull from main on a feature branch is blocked.',\n \"Run 'pnpm wp-git-update' to squash-update from main. This preserves the 3-point fork-point system (fork-point=A, feature-HEAD=B, main-HEAD=C) needed for clean PR diffs. See docs/git-workflow.md for details.\",\n);\n\nconst WRONG_UPDATE_PATTERNS: RegExp[] = [\n /git\\s+merge\\s+(origin\\/main|main)\\b/,\n /git\\s+rebase\\s+(origin\\/main|main)\\b/,\n /git\\s+pull\\s+origin\\s+main\\b/,\n];\n\nfunction truncate(s: string): string {\n const MAX = 120;\n return s.length <= MAX ? s : s.slice(0, MAX) + '…';\n}\n\nexport class RedirectHowToMergeMainRule extends BashRuleBase<RedirectHowToMergeMainConfig> {\n constructor(config: RedirectHowToMergeMainConfig) { super(config, 'redirect-how-to-merge-main'); }\n\n readonly description = 'Block direct git merge/rebase/pull from main on feature branches. Use the squash-update process instead.';\n readonly fixHint = FIX_HINT;\n\n check(ctx: BashContext): readonly Violation[] {\n const matched = WRONG_UPDATE_PATTERNS.some((p: RegExp) => p.test(ctx.command));\n if (!matched) return [];\n\n // Allow 'git checkout main && git pull origin main' — switching to main first is the recommended workflow\n if (/git\\s+(?:checkout|switch)\\s+main\\b/.test(ctx.command)) {\n return [];\n }\n\n const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd: ctx.workspaceRoot,\n encoding: 'utf8',\n }).trim();\n\n if (currentBranch === 'main') {\n return [];\n }\n\n return [new V(\n 1,\n truncate(ctx.command),\n `Direct merge/rebase from main on branch '${currentBranch}' is blocked.`,\n )];\n }\n}\n"]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { RequireReturnTypeConfig } from '@webpieces/rules-config';
|
|
2
2
|
import type { EditContext, Violation } from '../types';
|
|
3
3
|
import { EditRuleBase } from '../rule-base';
|
|
4
|
+
import { FixHint } from '../fix-hint';
|
|
4
5
|
export declare class RequireReturnTypeRule extends EditRuleBase<RequireReturnTypeConfig> {
|
|
5
6
|
constructor(config: RequireReturnTypeConfig);
|
|
6
7
|
readonly description = "Every function and method must declare its return type.";
|
|
7
8
|
readonly files: string[];
|
|
8
|
-
|
|
9
|
+
get fixHint(): FixHint;
|
|
9
10
|
check(ctx: EditContext): readonly Violation[];
|
|
10
11
|
}
|
|
@@ -4,6 +4,7 @@ exports.RequireReturnTypeRule = void 0;
|
|
|
4
4
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const rule_base_1 = require("../rule-base");
|
|
7
|
+
const fix_hint_1 = require("../fix-hint");
|
|
7
8
|
// Matches function/method signatures that don't have `: ReturnType` before the `{` body opener.
|
|
8
9
|
// Pattern: function name(<params>) { — missing `: Type` between `)` and `{`
|
|
9
10
|
const FUNC_DECL_MISSING = /\bfunction\s+\w+\s*(?:<[^>]*>)?\s*\([^)]*\)\s*\{/;
|
|
@@ -31,20 +32,20 @@ class RequireReturnTypeRule extends rule_base_1.EditRuleBase {
|
|
|
31
32
|
constructor(config) { super(config, 'require-return-type'); }
|
|
32
33
|
description = 'Every function and method must declare its return type.';
|
|
33
34
|
files = ['**/*.ts', '**/*.tsx'];
|
|
34
|
-
fixHint
|
|
35
|
-
'Add return type: function foo(x: T): ReturnType { ... }',
|
|
36
|
-
|
|
37
|
-
];
|
|
35
|
+
get fixHint() {
|
|
36
|
+
return new fix_hint_1.FixHint('Missing return type annotation.', 'Add a return type: function foo(x: T): ReturnType { ... }.', [], new fix_hint_1.DisableEscape(this.config.disableAllowed ?? true, '// webpieces-disable require-return-type -- <reason>'));
|
|
37
|
+
}
|
|
38
38
|
check(ctx) {
|
|
39
|
+
const disableAllowed = this.config.disableAllowed ?? true;
|
|
39
40
|
const violations = [];
|
|
40
41
|
for (let i = 0; i < ctx.strippedLines.length; i += 1) {
|
|
41
42
|
const stripped = ctx.strippedLines[i];
|
|
42
43
|
if (!isMissingReturnType(stripped))
|
|
43
44
|
continue;
|
|
44
45
|
const lineNum = i + 1;
|
|
45
|
-
if (ctx.isLineDisabled(lineNum, rules_config_1.RULE_NAMES.REQUIRE_RETURN_TYPE))
|
|
46
|
+
if (disableAllowed && ctx.isLineDisabled(lineNum, rules_config_1.RULE_NAMES.REQUIRE_RETURN_TYPE))
|
|
46
47
|
continue;
|
|
47
|
-
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim()
|
|
48
|
+
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim()));
|
|
48
49
|
}
|
|
49
50
|
return violations;
|
|
50
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"require-return-type.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/require-return-type.ts"],"names":[],"mappings":";;;AAAA,0DAA8E;AAG9E,oCAA0C;AAC1C,4CAA4C;
|
|
1
|
+
{"version":3,"file":"require-return-type.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/require-return-type.ts"],"names":[],"mappings":";;;AAAA,0DAA8E;AAG9E,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAAqD;AAErD,gGAAgG;AAChG,4EAA4E;AAC5E,MAAM,iBAAiB,GAAG,kDAAkD,CAAC;AAE7E,8EAA8E;AAC9E,MAAM,cAAc,GAAG,yDAAyD,CAAC;AAEjF,qFAAqF;AACrF,MAAM,aAAa,GAAG,gEAAgE,CAAC;AAEvF,qEAAqE;AACrE,MAAM,eAAe,GAAG,aAAa,CAAC;AAEtC,iEAAiE;AACjE,MAAM,YAAY,GAAG,kFAAkF,CAAC;AAExG,SAAS,mBAAmB,CAAC,IAAY;IACrC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,UAAU,GACZ,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QACzB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9B,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,MAAa,qBAAsB,SAAQ,wBAAqC;IAC5E,YAAY,MAA+B,IAAI,KAAK,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAE7E,WAAW,GAAG,yDAAyD,CAAC;IAC/D,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAClD,IAAI,OAAO;QACP,OAAO,IAAI,kBAAO,CACd,iCAAiC,EACjC,4DAA4D,EAC5D,EAAE,EACF,IAAI,wBAAa,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,EAAE,sDAAsD,CAAC,CAChH,CAAC;IACN,CAAC;IAED,KAAK,CAAC,GAAgB;QAClB,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,CAAC;QAC1D,MAAM,UAAU,GAAQ,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAC7C,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,cAAc,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,yBAAU,CAAC,mBAAmB,CAAC;gBAAE,SAAS;YAC5F,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AA1BD,sDA0BC","sourcesContent":["import { RequireReturnTypeConfig, RULE_NAMES } from '@webpieces/rules-config';\n\nimport type { EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { EditRuleBase } from '../rule-base';\nimport { FixHint, DisableEscape } from '../fix-hint';\n\n// Matches function/method signatures that don't have `: ReturnType` before the `{` body opener.\n// Pattern: function name(<params>) { — missing `: Type` between `)` and `{`\nconst FUNC_DECL_MISSING = /\\bfunction\\s+\\w+\\s*(?:<[^>]*>)?\\s*\\([^)]*\\)\\s*\\{/;\n\n// Matches class method signatures: indented, optional async, name(<params>) {\nconst METHOD_MISSING = /^\\s{2,}(?:async\\s+)?\\w+\\s*(?:<[^>]*>)?\\s*\\([^)]*\\)\\s*\\{/;\n\n// Arrow function: const name = (async)? (<params>) => — missing `: Type` before `=>`\nconst ARROW_MISSING = /\\bconst\\s+\\w+\\s*=\\s*(?:async\\s+)?(?:<[^>]*>)?\\s*\\([^)]*\\)\\s*=>/;\n\n// Lines that have ): ReturnType before { or => — these are COMPLIANT\nconst HAS_RETURN_TYPE = /\\)\\s*:\\s*\\S/;\n\n// Skip constructors, getters, setters, and control flow keywords\nconst SKIP_PATTERN = /\\b(?:constructor|get\\s+\\w+|set\\s+\\w+|if|else|while|for|switch|catch|return)\\s*\\(/;\n\nfunction isMissingReturnType(line: string): boolean {\n if (SKIP_PATTERN.test(line)) return false;\n const isFuncLike =\n FUNC_DECL_MISSING.test(line) ||\n METHOD_MISSING.test(line) ||\n ARROW_MISSING.test(line);\n if (!isFuncLike) return false;\n if (HAS_RETURN_TYPE.test(line)) return false;\n return true;\n}\n\nexport class RequireReturnTypeRule extends EditRuleBase<RequireReturnTypeConfig> {\n constructor(config: RequireReturnTypeConfig) { super(config, 'require-return-type'); }\n\n readonly description = 'Every function and method must declare its return type.';\n override readonly files = ['**/*.ts', '**/*.tsx'];\n get fixHint(): FixHint {\n return new FixHint(\n 'Missing return type annotation.',\n 'Add a return type: function foo(x: T): ReturnType { ... }.',\n [],\n new DisableEscape(this.config.disableAllowed ?? true, '// webpieces-disable require-return-type -- <reason>'),\n );\n }\n\n check(ctx: EditContext): readonly Violation[] {\n const disableAllowed = this.config.disableAllowed ?? true;\n const violations: V[] = [];\n for (let i = 0; i < ctx.strippedLines.length; i += 1) {\n const stripped = ctx.strippedLines[i];\n if (!isMissingReturnType(stripped)) continue;\n const lineNum = i + 1;\n if (disableAllowed && ctx.isLineDisabled(lineNum, RULE_NAMES.REQUIRE_RETURN_TYPE)) continue;\n violations.push(new V(lineNum, ctx.lines[i].trim()));\n }\n return violations;\n }\n}\n"]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ThrowCauseRequiredConfig } from '@webpieces/rules-config';
|
|
2
2
|
import type { EditContext, Violation } from '../types';
|
|
3
3
|
import { EditRuleBase } from '../rule-base';
|
|
4
|
+
import { FixHint } from '../fix-hint';
|
|
4
5
|
export declare class ThrowCauseRequiredRule extends EditRuleBase<ThrowCauseRequiredConfig> {
|
|
5
6
|
constructor(config: ThrowCauseRequiredConfig);
|
|
6
7
|
readonly description = "When rethrowing with added context, chain the original exception: throw new Error(\"msg\", { cause: error })";
|
|
7
8
|
readonly files: string[];
|
|
8
|
-
|
|
9
|
+
get fixHint(): FixHint;
|
|
9
10
|
check(ctx: EditContext): readonly Violation[];
|
|
10
11
|
}
|
|
@@ -4,6 +4,7 @@ exports.ThrowCauseRequiredRule = void 0;
|
|
|
4
4
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const rule_base_1 = require("../rule-base");
|
|
7
|
+
const fix_hint_1 = require("../fix-hint");
|
|
7
8
|
const instruct_ai_writer_1 = require("../instruct-ai-writer");
|
|
8
9
|
/**
|
|
9
10
|
* Matches: throw new SomeClass(
|
|
@@ -21,13 +22,15 @@ class ThrowCauseRequiredRule extends rule_base_1.EditRuleBase {
|
|
|
21
22
|
constructor(config) { super(config, 'throw-cause-required'); }
|
|
22
23
|
description = 'When rethrowing with added context, chain the original exception: throw new Error("msg", { cause: error })';
|
|
23
24
|
files = ['**/*.ts', '**/*.tsx'];
|
|
24
|
-
fixHint
|
|
25
|
-
'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
get fixHint() {
|
|
26
|
+
return new fix_hint_1.FixHint('Rethrowing with error.message loses the original stack trace. Use { cause: error } to chain it.', 'Pick one:', [
|
|
27
|
+
new fix_hint_1.Option('Remove the try-catch entirely. Letting the original exception bubble is usually the best option.', true),
|
|
28
|
+
new fix_hint_1.Option('throw new Error("add more info here", { cause: error }); chains the error and preserves the full stack trace.'),
|
|
29
|
+
new fix_hint_1.Option('throw new SpecificError("add info here", { cause: error }); e.g. new InformAiError("what happened for AI", { cause: error }).'),
|
|
30
|
+
], new fix_hint_1.DisableEscape(this.config.disableAllowed ?? true, '// webpieces-disable throw-cause-required -- <reason>'));
|
|
31
|
+
}
|
|
30
32
|
check(ctx) {
|
|
33
|
+
const disableAllowed = this.config.disableAllowed ?? true;
|
|
31
34
|
const violations = [];
|
|
32
35
|
const lines = ctx.strippedLines;
|
|
33
36
|
for (let i = 0; i < lines.length; i += 1) {
|
|
@@ -39,9 +42,9 @@ class ThrowCauseRequiredRule extends rule_base_1.EditRuleBase {
|
|
|
39
42
|
if (CAUSE_PATTERN.test(stripped))
|
|
40
43
|
continue;
|
|
41
44
|
const lineNum = i + 1;
|
|
42
|
-
if (ctx.isLineDisabled(lineNum, rules_config_1.RULE_NAMES.THROW_CAUSE_REQUIRED))
|
|
45
|
+
if (disableAllowed && ctx.isLineDisabled(lineNum, rules_config_1.RULE_NAMES.THROW_CAUSE_REQUIRED))
|
|
43
46
|
continue;
|
|
44
|
-
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim()
|
|
47
|
+
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim()));
|
|
45
48
|
}
|
|
46
49
|
if (violations.length > 0)
|
|
47
50
|
(0, instruct_ai_writer_1.writeTemplateIfMissing)(ctx.workspaceRoot, 'webpieces.exceptions.md');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throw-cause-required.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/throw-cause-required.ts"],"names":[],"mappings":";;;AAAA,0DAA+E;AAG/E,oCAA0C;AAC1C,4CAA4C;AAC5C,8DAA+D;AAE/D;;GAEG;AACH,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;AAErD;;GAEG;AACH,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAEtD;;GAEG;AACH,MAAM,aAAa,GAAG,0BAA0B,CAAC;AAEjD,MAAa,sBAAuB,SAAQ,wBAAsC;IAC9E,YAAY,MAAgC,IAAI,KAAK,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAE/E,WAAW,GAAG,4GAA4G,CAAC;IAClH,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"throw-cause-required.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/throw-cause-required.ts"],"names":[],"mappings":";;;AAAA,0DAA+E;AAG/E,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAA6D;AAC7D,8DAA+D;AAE/D;;GAEG;AACH,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;AAErD;;GAEG;AACH,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAEtD;;GAEG;AACH,MAAM,aAAa,GAAG,0BAA0B,CAAC;AAEjD,MAAa,sBAAuB,SAAQ,wBAAsC;IAC9E,YAAY,MAAgC,IAAI,KAAK,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAE/E,WAAW,GAAG,4GAA4G,CAAC;IAClH,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAClD,IAAI,OAAO;QACP,OAAO,IAAI,kBAAO,CACd,iGAAiG,EACjG,WAAW,EACX;YACI,IAAI,iBAAM,CAAC,kGAAkG,EAAE,IAAI,CAAC;YACpH,IAAI,iBAAM,CAAC,+GAA+G,CAAC;YAC3H,IAAI,iBAAM,CAAC,+HAA+H,CAAC;SAC9I,EACD,IAAI,wBAAa,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,EAAE,uDAAuD,CAAC,CACjH,CAAC;IACN,CAAC;IAED,KAAK,CAAC,GAAgB;QAClB,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,IAAI,CAAC;QAC1D,MAAM,UAAU,GAAQ,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC;QAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAChD,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,SAAS;YACpD,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,cAAc,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,yBAAU,CAAC,oBAAoB,CAAC;gBAAE,SAAS;YAE7F,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YAAE,IAAA,2CAAsB,EAAC,GAAG,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC;QAChG,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AAtCD,wDAsCC","sourcesContent":["import { ThrowCauseRequiredConfig, RULE_NAMES } from '@webpieces/rules-config';\n\nimport type { EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { EditRuleBase } from '../rule-base';\nimport { FixHint, Option, DisableEscape } from '../fix-hint';\nimport { writeTemplateIfMissing } from '../instruct-ai-writer';\n\n/**\n * Matches: throw new SomeClass(\n */\nconst THROW_NEW_PATTERN = /\\bthrow\\s+new\\s+\\w+\\s*\\(/;\n\n/**\n * Matches: error.message or error2.message or error3.message\n */\nconst ERROR_MESSAGE_PATTERN = /\\berror\\d*\\.message\\b/;\n\n/**\n * Matches: cause: error or cause: error2 etc. (the good pattern)\n */\nconst CAUSE_PATTERN = /\\bcause\\s*:\\s*error\\d*\\b/;\n\nexport class ThrowCauseRequiredRule extends EditRuleBase<ThrowCauseRequiredConfig> {\n constructor(config: ThrowCauseRequiredConfig) { super(config, 'throw-cause-required'); }\n\n readonly description = 'When rethrowing with added context, chain the original exception: throw new Error(\"msg\", { cause: error })';\n override readonly files = ['**/*.ts', '**/*.tsx'];\n get fixHint(): FixHint {\n return new FixHint(\n 'Rethrowing with error.message loses the original stack trace. Use { cause: error } to chain it.',\n 'Pick one:',\n [\n new Option('Remove the try-catch entirely. Letting the original exception bubble is usually the best option.', true),\n new Option('throw new Error(\"add more info here\", { cause: error }); chains the error and preserves the full stack trace.'),\n new Option('throw new SpecificError(\"add info here\", { cause: error }); e.g. new InformAiError(\"what happened for AI\", { cause: error }).'),\n ],\n new DisableEscape(this.config.disableAllowed ?? true, '// webpieces-disable throw-cause-required -- <reason>'),\n );\n }\n\n check(ctx: EditContext): readonly Violation[] {\n const disableAllowed = this.config.disableAllowed ?? true;\n const violations: V[] = [];\n const lines = ctx.strippedLines;\n\n for (let i = 0; i < lines.length; i += 1) {\n const stripped = lines[i];\n if (!THROW_NEW_PATTERN.test(stripped)) continue;\n if (!ERROR_MESSAGE_PATTERN.test(stripped)) continue;\n if (CAUSE_PATTERN.test(stripped)) continue;\n\n const lineNum = i + 1;\n if (disableAllowed && ctx.isLineDisabled(lineNum, RULE_NAMES.THROW_CAUSE_REQUIRED)) continue;\n\n violations.push(new V(lineNum, ctx.lines[i].trim()));\n }\n\n if (violations.length > 0) writeTemplateIfMissing(ctx.workspaceRoot, 'webpieces.exceptions.md');\n return violations;\n }\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ValidateTsInSrcConfig } from '@webpieces/rules-config';
|
|
2
2
|
import type { FileContext, Violation } from '../types';
|
|
3
3
|
import { FileRuleBase } from '../rule-base';
|
|
4
|
+
import { FixHint } from '../fix-hint';
|
|
4
5
|
export declare class ValidateTsInSrcRule extends FileRuleBase<ValidateTsInSrcConfig> {
|
|
5
6
|
constructor(config: ValidateTsInSrcConfig);
|
|
6
7
|
readonly description = "Every .ts file must belong to a project's src/ directory.";
|
|
@@ -9,6 +10,6 @@ export declare class ValidateTsInSrcRule extends FileRuleBase<ValidateTsInSrcCon
|
|
|
9
10
|
excludePaths: string[];
|
|
10
11
|
allowedRootFiles: string[];
|
|
11
12
|
};
|
|
12
|
-
readonly fixHint:
|
|
13
|
+
readonly fixHint: FixHint;
|
|
13
14
|
check(ctx: FileContext): readonly Violation[];
|
|
14
15
|
}
|
|
@@ -7,6 +7,7 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
7
7
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
8
8
|
const types_1 = require("../types");
|
|
9
9
|
const rule_base_1 = require("../rule-base");
|
|
10
|
+
const fix_hint_1 = require("../fix-hint");
|
|
10
11
|
const DEFAULT_EXCLUDE_PATHS = [
|
|
11
12
|
'node_modules', 'dist', '.nx', '.git',
|
|
12
13
|
'**/*.d.ts', '**/jest.config.ts',
|
|
@@ -29,10 +30,10 @@ class ValidateTsInSrcRule extends rule_base_1.FileRuleBase {
|
|
|
29
30
|
excludePaths: DEFAULT_EXCLUDE_PATHS,
|
|
30
31
|
allowedRootFiles: DEFAULT_ALLOWED_ROOT_FILES,
|
|
31
32
|
};
|
|
32
|
-
fixHint = [
|
|
33
|
-
'Move the file into an existing project\'s src/ directory, or create a new project with project.json that owns the directory.',
|
|
34
|
-
'Add a dir or glob (e.g. "**/codegen.ts") to validate-ts-in-src.excludePaths in webpieces.config.json',
|
|
35
|
-
];
|
|
33
|
+
fixHint = new fix_hint_1.FixHint('TypeScript file is outside a project src/ directory.', 'Fix by one of:', [
|
|
34
|
+
new fix_hint_1.Option('Move the file into an existing project\'s src/ directory, or create a new project with project.json that owns the directory.', true),
|
|
35
|
+
new fix_hint_1.Option('Add a dir or glob (e.g. "**/codegen.ts") to validate-ts-in-src.excludePaths in webpieces.config.json'),
|
|
36
|
+
]);
|
|
36
37
|
check(ctx) {
|
|
37
38
|
if (ctx.tool !== 'Write')
|
|
38
39
|
return [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-ts-in-src.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/validate-ts-in-src.ts"],"names":[],"mappings":";;;;AAAA,+CAAyB;AACzB,mDAA6B;AAE7B,0DAAgF;AAGhF,oCAA0C;AAC1C,4CAA4C;
|
|
1
|
+
{"version":3,"file":"validate-ts-in-src.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/validate-ts-in-src.ts"],"names":[],"mappings":";;;;AAAA,+CAAyB;AACzB,mDAA6B;AAE7B,0DAAgF;AAGhF,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAA8C;AAE9C,MAAM,qBAAqB,GAAG;IAC1B,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IACrC,WAAW,EAAE,mBAAmB;CACnC,CAAC;AACF,MAAM,0BAA0B,GAAG,CAAC,eAAe,CAAC,CAAC;AAErD,SAAS,eAAe,CAAC,QAAgB,EAAE,aAAqB;IAC5D,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,OAAO,GAAG,KAAK,aAAa,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC5D,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QAC9D,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,MAAa,mBAAoB,SAAQ,wBAAmC;IACxE,YAAY,MAA6B,IAAI,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAE1E,WAAW,GAAG,4DAA4D,CAAC;IAClE,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChC,cAAc,GAAG;QAC/B,YAAY,EAAE,qBAAqB;QACnC,gBAAgB,EAAE,0BAA0B;KAC/C,CAAC;IACO,OAAO,GAAG,IAAI,kBAAO,CAC1B,sDAAsD,EACtD,gBAAgB,EAChB;QACI,IAAI,iBAAM,CAAC,8HAA8H,EAAE,IAAI,CAAC;QAChJ,IAAI,iBAAM,CAAC,sGAAsG,CAAC;KACrH,CACJ,CAAC;IAEF,KAAK,CAAC,GAAgB;QAClB,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,EAAE,CAAC;QAEpC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,qBAAqB,CAAC;QACvE,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,IAAI,0BAA0B,CAAC;QAEpF,kEAAkE;QAClE,IAAI,IAAA,6BAAc,EAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;YAAE,OAAO,EAAE,CAAC;QAE9D,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,gBAAgB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QAEzF,MAAM,WAAW,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QAErE,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,iBAAC,CACT,CAAC,EACD,GAAG,CAAC,YAAY,EAChB,8EAA8E,CACjF,CAAC,CAAC;QACP,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,KAAK,KAAK,EAAE,CAAC;YACvE,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;YAClE,OAAO,CAAC,IAAI,iBAAC,CACT,CAAC,EACD,GAAG,CAAC,YAAY,EAChB,4BAA4B,WAAW,uDAAuD,CACjG,CAAC,CAAC;QACP,CAAC;QAED,OAAO,EAAE,CAAC;IACd,CAAC;CACJ;AApDD,kDAoDC","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nimport { ValidateTsInSrcConfig, isPathExcluded } from '@webpieces/rules-config';\n\nimport type { FileContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { FileRuleBase } from '../rule-base';\nimport { FixHint, Option } from '../fix-hint';\n\nconst DEFAULT_EXCLUDE_PATHS = [\n 'node_modules', 'dist', '.nx', '.git',\n '**/*.d.ts', '**/jest.config.ts',\n];\nconst DEFAULT_ALLOWED_ROOT_FILES = ['jest.setup.ts'];\n\nfunction findProjectRoot(filePath: string, workspaceRoot: string): string | null {\n let dir = path.dirname(filePath);\n while (dir !== workspaceRoot && dir.startsWith(workspaceRoot)) {\n if (fs.existsSync(path.join(dir, 'project.json'))) return dir;\n dir = path.dirname(dir);\n }\n return null;\n}\n\nexport class ValidateTsInSrcRule extends FileRuleBase<ValidateTsInSrcConfig> {\n constructor(config: ValidateTsInSrcConfig) { super(config, 'validate-ts-in-src'); }\n\n readonly description = 'Every .ts file must belong to a project\\'s src/ directory.';\n override readonly files = ['**/*.ts', '**/*.tsx'];\n override readonly defaultOptions = {\n excludePaths: DEFAULT_EXCLUDE_PATHS,\n allowedRootFiles: DEFAULT_ALLOWED_ROOT_FILES,\n };\n readonly fixHint = new FixHint(\n 'TypeScript file is outside a project src/ directory.',\n 'Fix by one of:',\n [\n new Option('Move the file into an existing project\\'s src/ directory, or create a new project with project.json that owns the directory.', true),\n new Option('Add a dir or glob (e.g. \"**/codegen.ts\") to validate-ts-in-src.excludePaths in webpieces.config.json'),\n ],\n );\n\n check(ctx: FileContext): readonly Violation[] {\n if (ctx.tool !== 'Write') return [];\n\n const excludePaths = this.config.excludePaths ?? DEFAULT_EXCLUDE_PATHS;\n const allowedRootFiles = this.config.allowedRootFiles ?? DEFAULT_ALLOWED_ROOT_FILES;\n\n // Holistic exclusion (Layer 1 + Layer 2): bare dir names + globs.\n if (isPathExcluded(ctx.relativePath, excludePaths)) return [];\n\n const relParts = ctx.relativePath.split(path.sep);\n if (relParts.length === 1 && allowedRootFiles.indexOf(relParts[0] ?? '') >= 0) return [];\n\n const projectRoot = findProjectRoot(ctx.filePath, ctx.workspaceRoot);\n\n if (!projectRoot) {\n return [new V(\n 1,\n ctx.relativePath,\n 'File is not inside any Nx project. Move it into a project\\'s src/ directory.',\n )];\n }\n\n const relToProject = path.relative(projectRoot, ctx.filePath);\n if (!relToProject.startsWith('src' + path.sep) && relToProject !== 'src') {\n const projectName = path.relative(ctx.workspaceRoot, projectRoot);\n return [new V(\n 1,\n ctx.relativePath,\n `File is inside project \\`${projectName}\\` but outside its src/ directory. Move it into src/.`,\n )];\n }\n\n return [];\n }\n}\n"]}
|
package/src/core/runner.js
CHANGED
|
@@ -229,7 +229,7 @@ function runBashRules(rules, bashContext) {
|
|
|
229
229
|
continue;
|
|
230
230
|
const vs = runRuleCheck(rule, bashContext);
|
|
231
231
|
if (vs.length > 0) {
|
|
232
|
-
groups.push(new types_1.RuleGroup(rule.name, rule.description,
|
|
232
|
+
groups.push(new types_1.RuleGroup(rule.name, rule.description, rule.fixHint, [...vs]));
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
return groups;
|
|
@@ -254,7 +254,7 @@ function runEditRules(rules, editContexts) {
|
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
if (allViolations.length > 0) {
|
|
257
|
-
groups.push(new types_1.RuleGroup(rule.name, rule.description,
|
|
257
|
+
groups.push(new types_1.RuleGroup(rule.name, rule.description, rule.fixHint, allViolations));
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
return groups;
|
|
@@ -270,7 +270,7 @@ function runFileRules(rules, fileContext) {
|
|
|
270
270
|
continue;
|
|
271
271
|
const vs = runRuleCheck(rule, fileContext);
|
|
272
272
|
if (vs.length > 0) {
|
|
273
|
-
groups.push(new types_1.RuleGroup(rule.name, rule.description,
|
|
273
|
+
groups.push(new types_1.RuleGroup(rule.name, rule.description, rule.fixHint, [...vs]));
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
return groups;
|