@webpieces/ai-hook-rules 0.3.185 → 0.3.186
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 +3 -4
- package/src/core/custom-rule-adapter.d.ts +21 -0
- package/src/core/custom-rule-adapter.js +48 -0
- package/src/core/custom-rule-adapter.js.map +1 -0
- package/src/core/load-rules.d.ts +3 -2
- package/src/core/load-rules.js +71 -50
- package/src/core/load-rules.js.map +1 -1
- package/src/core/rule-base.d.ts +38 -0
- package/src/core/rule-base.js +36 -0
- package/src/core/rule-base.js.map +1 -0
- package/src/core/rules/branch-creation-guard.d.ts +12 -3
- package/src/core/rules/branch-creation-guard.js +37 -37
- package/src/core/rules/branch-creation-guard.js.map +1 -1
- package/src/core/rules/catch-error-pattern.d.ts +10 -3
- package/src/core/rules/catch-error-pattern.js +26 -26
- package/src/core/rules/catch-error-pattern.js.map +1 -1
- package/src/core/rules/max-file-lines.d.ts +13 -3
- package/src/core/rules/max-file-lines.js +14 -15
- package/src/core/rules/max-file-lines.js.map +1 -1
- package/src/core/rules/merge-in-progress-guard.d.ts +9 -3
- package/src/core/rules/merge-in-progress-guard.js +12 -13
- package/src/core/rules/merge-in-progress-guard.js.map +1 -1
- package/src/core/rules/no-any-unknown.d.ts +10 -3
- package/src/core/rules/no-any-unknown.js +14 -13
- package/src/core/rules/no-any-unknown.js.map +1 -1
- package/src/core/rules/no-destructure.d.ts +13 -3
- package/src/core/rules/no-destructure.js +13 -12
- package/src/core/rules/no-destructure.js.map +1 -1
- package/src/core/rules/no-direct-main-update.d.ts +9 -3
- package/src/core/rules/no-direct-main-update.js +12 -13
- package/src/core/rules/no-direct-main-update.js.map +1 -1
- package/src/core/rules/no-edit-on-main.d.ts +13 -3
- package/src/core/rules/no-edit-on-main.js +14 -14
- package/src/core/rules/no-edit-on-main.js.map +1 -1
- package/src/core/rules/no-implicit-any.d.ts +10 -3
- package/src/core/rules/no-implicit-any.js +12 -12
- package/src/core/rules/no-implicit-any.js.map +1 -1
- package/src/core/rules/no-js-files.d.ts +13 -3
- package/src/core/rules/no-js-files.js +13 -16
- package/src/core/rules/no-js-files.js.map +1 -1
- package/src/core/rules/no-shell-substitution.d.ts +9 -3
- package/src/core/rules/no-shell-substitution.js +22 -23
- package/src/core/rules/no-shell-substitution.js.map +1 -1
- package/src/core/rules/no-symbol-di-tokens.d.ts +13 -3
- package/src/core/rules/no-symbol-di-tokens.js +14 -13
- package/src/core/rules/no-symbol-di-tokens.js.map +1 -1
- package/src/core/rules/no-unmanaged-exceptions.d.ts +10 -3
- package/src/core/rules/no-unmanaged-exceptions.js +17 -17
- package/src/core/rules/no-unmanaged-exceptions.js.map +1 -1
- package/src/core/rules/pr-creation-guard.d.ts +9 -3
- package/src/core/rules/pr-creation-guard.js +12 -13
- package/src/core/rules/pr-creation-guard.js.map +1 -1
- package/src/core/rules/pr-merge-cleanup.d.ts +9 -3
- package/src/core/rules/pr-merge-cleanup.js +13 -14
- package/src/core/rules/pr-merge-cleanup.js.map +1 -1
- package/src/core/rules/require-return-type.d.ts +10 -3
- package/src/core/rules/require-return-type.js +23 -23
- package/src/core/rules/require-return-type.js.map +1 -1
- package/src/core/rules/throw-cause-required.d.ts +10 -3
- package/src/core/rules/throw-cause-required.js +12 -12
- package/src/core/rules/throw-cause-required.js.map +1 -1
- package/src/core/rules/validate-ts-in-src.d.ts +14 -3
- package/src/core/rules/validate-ts-in-src.js +15 -18
- package/src/core/rules/validate-ts-in-src.js.map +1 -1
- package/src/core/runner.js +38 -67
- package/src/core/runner.js.map +1 -1
- package/src/core/types.d.ts +14 -13
- package/src/core/types.js.map +1 -1
- package/src/index.d.ts +21 -1
- package/src/index.js +47 -1
- package/src/index.js.map +1 -1
- package/src/core/configs/default.d.ts +0 -2
- package/src/core/configs/default.js +0 -22
- package/src/core/configs/default.js.map +0 -1
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrMergeCleanupRule = void 0;
|
|
3
4
|
const child_process_1 = require("child_process");
|
|
4
5
|
const types_1 = require("../types");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
const rule_base_1 = require("../rule-base");
|
|
7
|
+
function truncate(s) {
|
|
8
|
+
const MAX = 120;
|
|
9
|
+
return s.length <= MAX ? s : s.slice(0, MAX) + '…';
|
|
10
|
+
}
|
|
11
|
+
class PrMergeCleanupRule extends rule_base_1.BashRuleBase {
|
|
12
|
+
constructor(config) { super(config, 'pr-merge-cleanup'); }
|
|
13
|
+
description = 'After merging a PR, require switching to main, pulling, and deleting the local branch.';
|
|
14
|
+
fixHint = [
|
|
12
15
|
'After merging a PR you must clean up the local branch.',
|
|
13
16
|
'Run this combined command instead:',
|
|
14
17
|
' gh pr merge --squash && git checkout main && git pull && git branch -d <current-branch>',
|
|
15
|
-
]
|
|
18
|
+
];
|
|
16
19
|
check(ctx) {
|
|
17
20
|
if (!/gh\s+pr\s+merge/.test(ctx.command))
|
|
18
21
|
return [];
|
|
@@ -29,11 +32,7 @@ const prMergeCleanup = {
|
|
|
29
32
|
'Run this combined command instead:',
|
|
30
33
|
` gh pr merge --squash && git checkout main && git pull && git branch -d ${currentBranch}`,
|
|
31
34
|
].join('\n'))];
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
function truncate(s) {
|
|
35
|
-
const MAX = 120;
|
|
36
|
-
return s.length <= MAX ? s : s.slice(0, MAX) + '…';
|
|
35
|
+
}
|
|
37
36
|
}
|
|
38
|
-
exports.
|
|
37
|
+
exports.PrMergeCleanupRule = PrMergeCleanupRule;
|
|
39
38
|
//# sourceMappingURL=pr-merge-cleanup.js.map
|
|
@@ -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":"
|
|
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;AAE5C,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;IACvG,OAAO,GAAG;QACf,wDAAwD;QACxD,oCAAoC;QACpC,2FAA2F;KAC9F,CAAC;IAEF,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,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,OAAO,CAAC,IAAI,iBAAC,CACT,CAAC,EACD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EACrB;gBACI,2EAA2E;gBAC3E,oCAAoC;gBACpC,4EAA4E,aAAa,EAAE;aAC9F,CAAC,IAAI,CAAC,IAAI,CAAC,CACf,CAAC,CAAC;IACP,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';\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 readonly fixHint = [\n 'After merging a PR you must clean up the local branch.',\n 'Run this combined command instead:',\n ' gh pr merge --squash && git checkout main && git pull && git branch -d <current-branch>',\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 const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd: ctx.workspaceRoot,\n encoding: 'utf8',\n }).trim();\n\n return [new V(\n 1,\n truncate(ctx.command),\n [\n '[pr-merge-cleanup] After merging a PR you must clean up the local branch.',\n 'Run this combined command instead:',\n ` gh pr merge --squash && git checkout main && git pull && git branch -d ${currentBranch}`,\n ].join('\\n'),\n )];\n }\n}\n"]}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { RequireReturnTypeConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { EditContext, Violation } from '../types';
|
|
3
|
+
import { EditRuleBase } from '../rule-base';
|
|
4
|
+
export declare class RequireReturnTypeRule extends EditRuleBase<RequireReturnTypeConfig> {
|
|
5
|
+
constructor(config: RequireReturnTypeConfig);
|
|
6
|
+
readonly description = "Every function and method must declare its return type.";
|
|
7
|
+
readonly files: string[];
|
|
8
|
+
readonly fixHint: string[];
|
|
9
|
+
check(ctx: EditContext): readonly Violation[];
|
|
10
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.RequireReturnTypeRule = void 0;
|
|
4
4
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
const rule_base_1 = require("../rule-base");
|
|
5
7
|
// Matches function/method signatures that don't have `: ReturnType` before the `{` body opener.
|
|
6
8
|
// Pattern: function name(<params>) { — missing `: Type` between `)` and `{`
|
|
7
9
|
const FUNC_DECL_MISSING = /\bfunction\s+\w+\s*(?:<[^>]*>)?\s*\([^)]*\)\s*\{/;
|
|
@@ -13,16 +15,26 @@ const ARROW_MISSING = /\bconst\s+\w+\s*=\s*(?:async\s+)?(?:<[^>]*>)?\s*\([^)]*\)
|
|
|
13
15
|
const HAS_RETURN_TYPE = /\)\s*:\s*\S/;
|
|
14
16
|
// Skip constructors, getters, setters, and control flow keywords
|
|
15
17
|
const SKIP_PATTERN = /\b(?:constructor|get\s+\w+|set\s+\w+|if|else|while|for|switch|catch|return)\s*\(/;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
function isMissingReturnType(line) {
|
|
19
|
+
if (SKIP_PATTERN.test(line))
|
|
20
|
+
return false;
|
|
21
|
+
const isFuncLike = FUNC_DECL_MISSING.test(line) ||
|
|
22
|
+
METHOD_MISSING.test(line) ||
|
|
23
|
+
ARROW_MISSING.test(line);
|
|
24
|
+
if (!isFuncLike)
|
|
25
|
+
return false;
|
|
26
|
+
if (HAS_RETURN_TYPE.test(line))
|
|
27
|
+
return false;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
class RequireReturnTypeRule extends rule_base_1.EditRuleBase {
|
|
31
|
+
constructor(config) { super(config, 'require-return-type'); }
|
|
32
|
+
description = 'Every function and method must declare its return type.';
|
|
33
|
+
files = ['**/*.ts', '**/*.tsx'];
|
|
34
|
+
fixHint = [
|
|
23
35
|
'Add return type: function foo(x: T): ReturnType { ... }',
|
|
24
36
|
'// webpieces-disable require-return-type -- <reason>',
|
|
25
|
-
]
|
|
37
|
+
];
|
|
26
38
|
check(ctx) {
|
|
27
39
|
const violations = [];
|
|
28
40
|
for (let i = 0; i < ctx.strippedLines.length; i += 1) {
|
|
@@ -35,19 +47,7 @@ const requireReturnTypeRule = {
|
|
|
35
47
|
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim(), 'Missing return type annotation.'));
|
|
36
48
|
}
|
|
37
49
|
return violations;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
function isMissingReturnType(line) {
|
|
41
|
-
if (SKIP_PATTERN.test(line))
|
|
42
|
-
return false;
|
|
43
|
-
const isFuncLike = FUNC_DECL_MISSING.test(line) ||
|
|
44
|
-
METHOD_MISSING.test(line) ||
|
|
45
|
-
ARROW_MISSING.test(line);
|
|
46
|
-
if (!isFuncLike)
|
|
47
|
-
return false;
|
|
48
|
-
if (HAS_RETURN_TYPE.test(line))
|
|
49
|
-
return false;
|
|
50
|
-
return true;
|
|
50
|
+
}
|
|
51
51
|
}
|
|
52
|
-
exports.
|
|
52
|
+
exports.RequireReturnTypeRule = RequireReturnTypeRule;
|
|
53
53
|
//# sourceMappingURL=require-return-type.js.map
|
|
@@ -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":"
|
|
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;AAE5C,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;IACzC,OAAO,GAAG;QACf,yDAAyD;QACzD,sDAAsD;KACzD,CAAC;IAEF,KAAK,CAAC,GAAgB;QAClB,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,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,yBAAU,CAAC,mBAAmB,CAAC;gBAAE,SAAS;YAC1E,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CACjB,OAAO,EACP,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EACnB,iCAAiC,CACpC,CAAC,CAAC;QACP,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AAzBD,sDAyBC","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';\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 readonly fixHint = [\n 'Add return type: function foo(x: T): ReturnType { ... }',\n '// webpieces-disable require-return-type -- <reason>',\n ];\n\n check(ctx: EditContext): readonly Violation[] {\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 (ctx.isLineDisabled(lineNum, RULE_NAMES.REQUIRE_RETURN_TYPE)) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i].trim(),\n 'Missing return type annotation.',\n ));\n }\n return violations;\n }\n}\n"]}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { ThrowCauseRequiredConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { EditContext, Violation } from '../types';
|
|
3
|
+
import { EditRuleBase } from '../rule-base';
|
|
4
|
+
export declare class ThrowCauseRequiredRule extends EditRuleBase<ThrowCauseRequiredConfig> {
|
|
5
|
+
constructor(config: ThrowCauseRequiredConfig);
|
|
6
|
+
readonly description = "When rethrowing with added context, chain the original exception: throw new Error(\"msg\", { cause: error })";
|
|
7
|
+
readonly files: string[];
|
|
8
|
+
readonly fixHint: string[];
|
|
9
|
+
check(ctx: EditContext): readonly Violation[];
|
|
10
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.ThrowCauseRequiredRule = void 0;
|
|
4
4
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
const rule_base_1 = require("../rule-base");
|
|
5
7
|
const instruct_ai_writer_1 = require("../instruct-ai-writer");
|
|
6
8
|
/**
|
|
7
9
|
* Matches: throw new SomeClass(
|
|
@@ -15,18 +17,16 @@ const ERROR_MESSAGE_PATTERN = /\berror\d*\.message\b/;
|
|
|
15
17
|
* Matches: cause: error or cause: error2 etc. (the good pattern)
|
|
16
18
|
*/
|
|
17
19
|
const CAUSE_PATTERN = /\bcause\s*:\s*error\d*\b/;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
description
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
defaultOptions: {},
|
|
24
|
-
fixHint: [
|
|
20
|
+
class ThrowCauseRequiredRule extends rule_base_1.EditRuleBase {
|
|
21
|
+
constructor(config) { super(config, 'throw-cause-required'); }
|
|
22
|
+
description = 'When rethrowing with added context, chain the original exception: throw new Error("msg", { cause: error })';
|
|
23
|
+
files = ['**/*.ts', '**/*.tsx'];
|
|
24
|
+
fixHint = [
|
|
25
25
|
'Option 1 — Remove the try-catch entirely. Letting the original exception bubble is usually the best option.',
|
|
26
26
|
'Option 2 — throw new Error("add more info here", { cause: error }); chains the error and preserves the full stack trace.',
|
|
27
27
|
'Option 3 — throw new SpecificError("add info here", { cause: error }); e.g. new InformAiError("what happened for AI", { cause: error }).',
|
|
28
28
|
'[Only if disableAllowed:true] Option 4 — // webpieces-disable throw-cause-required -- <reason>',
|
|
29
|
-
]
|
|
29
|
+
];
|
|
30
30
|
check(ctx) {
|
|
31
31
|
const violations = [];
|
|
32
32
|
const lines = ctx.strippedLines;
|
|
@@ -46,7 +46,7 @@ const throwCauseRequiredRule = {
|
|
|
46
46
|
if (violations.length > 0)
|
|
47
47
|
(0, instruct_ai_writer_1.writeTemplateIfMissing)(ctx.workspaceRoot, 'webpieces.exceptions.md');
|
|
48
48
|
return violations;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
exports.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ThrowCauseRequiredRule = ThrowCauseRequiredRule;
|
|
52
52
|
//# sourceMappingURL=throw-cause-required.js.map
|
|
@@ -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":"
|
|
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;IACzC,OAAO,GAAG;QACf,6GAA6G;QAC7G,0HAA0H;QAC1H,0IAA0I;QAC1I,gGAAgG;KACnG,CAAC;IAEF,KAAK,CAAC,GAAgB;QAClB,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,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,yBAAU,CAAC,oBAAoB,CAAC;gBAAE,SAAS;YAE3E,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CACjB,OAAO,EACP,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EACnB,iGAAiG,CACpG,CAAC,CAAC;QACP,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;AAnCD,wDAmCC","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 { 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 readonly fixHint = [\n 'Option 1 — Remove the try-catch entirely. Letting the original exception bubble is usually the best option.',\n 'Option 2 — throw new Error(\"add more info here\", { cause: error }); chains the error and preserves the full stack trace.',\n 'Option 3 — throw new SpecificError(\"add info here\", { cause: error }); e.g. new InformAiError(\"what happened for AI\", { cause: error }).',\n '[Only if disableAllowed:true] Option 4 — // webpieces-disable throw-cause-required -- <reason>',\n ];\n\n check(ctx: EditContext): readonly Violation[] {\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 (ctx.isLineDisabled(lineNum, RULE_NAMES.THROW_CAUSE_REQUIRED)) continue;\n\n violations.push(new V(\n lineNum,\n ctx.lines[i].trim(),\n 'Rethrowing with error.message loses the original stack trace. Use { cause: error } to chain it.',\n ));\n }\n\n if (violations.length > 0) writeTemplateIfMissing(ctx.workspaceRoot, 'webpieces.exceptions.md');\n return violations;\n }\n}\n"]}
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { ValidateTsInSrcConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { FileContext, Violation } from '../types';
|
|
3
|
+
import { FileRuleBase } from '../rule-base';
|
|
4
|
+
export declare class ValidateTsInSrcRule extends FileRuleBase<ValidateTsInSrcConfig> {
|
|
5
|
+
constructor(config: ValidateTsInSrcConfig);
|
|
6
|
+
readonly description = "Every .ts file must belong to a project's src/ directory.";
|
|
7
|
+
readonly files: string[];
|
|
8
|
+
readonly defaultOptions: {
|
|
9
|
+
excludePaths: string[];
|
|
10
|
+
allowedRootFiles: string[];
|
|
11
|
+
};
|
|
12
|
+
readonly fixHint: string[];
|
|
13
|
+
check(ctx: FileContext): readonly Violation[];
|
|
14
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValidateTsInSrcRule = void 0;
|
|
3
4
|
const tslib_1 = require("tslib");
|
|
4
5
|
const fs = tslib_1.__importStar(require("fs"));
|
|
5
6
|
const path = tslib_1.__importStar(require("path"));
|
|
6
7
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
7
8
|
const types_1 = require("../types");
|
|
9
|
+
const rule_base_1 = require("../rule-base");
|
|
8
10
|
const DEFAULT_EXCLUDE_PATHS = [
|
|
9
11
|
'node_modules', 'dist', '.nx', '.git',
|
|
10
12
|
'**/*.d.ts', '**/jest.config.ts',
|
|
@@ -19,28 +21,23 @@ function findProjectRoot(filePath, workspaceRoot) {
|
|
|
19
21
|
}
|
|
20
22
|
return null;
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
description
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
defaultOptions: {
|
|
24
|
+
class ValidateTsInSrcRule extends rule_base_1.FileRuleBase {
|
|
25
|
+
constructor(config) { super(config, 'validate-ts-in-src'); }
|
|
26
|
+
description = 'Every .ts file must belong to a project\'s src/ directory.';
|
|
27
|
+
files = ['**/*.ts', '**/*.tsx'];
|
|
28
|
+
defaultOptions = {
|
|
28
29
|
excludePaths: DEFAULT_EXCLUDE_PATHS,
|
|
29
30
|
allowedRootFiles: DEFAULT_ALLOWED_ROOT_FILES,
|
|
30
|
-
}
|
|
31
|
-
fixHint
|
|
31
|
+
};
|
|
32
|
+
fixHint = [
|
|
32
33
|
'Move the file into an existing project\'s src/ directory, or create a new project with project.json that owns the directory.',
|
|
33
34
|
'Add a dir or glob (e.g. "**/codegen.ts") to validate-ts-in-src.excludePaths in webpieces.config.json',
|
|
34
|
-
]
|
|
35
|
+
];
|
|
35
36
|
check(ctx) {
|
|
36
37
|
if (ctx.tool !== 'Write')
|
|
37
38
|
return [];
|
|
38
|
-
const excludePaths =
|
|
39
|
-
|
|
40
|
-
: DEFAULT_EXCLUDE_PATHS;
|
|
41
|
-
const allowedRootFiles = Array.isArray(ctx.options['allowedRootFiles'])
|
|
42
|
-
? ctx.options['allowedRootFiles']
|
|
43
|
-
: DEFAULT_ALLOWED_ROOT_FILES;
|
|
39
|
+
const excludePaths = this.config.excludePaths ?? DEFAULT_EXCLUDE_PATHS;
|
|
40
|
+
const allowedRootFiles = this.config.allowedRootFiles ?? DEFAULT_ALLOWED_ROOT_FILES;
|
|
44
41
|
// Holistic exclusion (Layer 1 + Layer 2): bare dir names + globs.
|
|
45
42
|
if ((0, rules_config_1.isPathExcluded)(ctx.relativePath, excludePaths))
|
|
46
43
|
return [];
|
|
@@ -57,7 +54,7 @@ const validateTsInSrcRule = {
|
|
|
57
54
|
return [new types_1.Violation(1, ctx.relativePath, `File is inside project \`${projectName}\` but outside its src/ directory. Move it into src/.`)];
|
|
58
55
|
}
|
|
59
56
|
return [];
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
exports.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.ValidateTsInSrcRule = ValidateTsInSrcRule;
|
|
63
60
|
//# sourceMappingURL=validate-ts-in-src.js.map
|
|
@@ -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":"
|
|
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;AAE5C,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;QACf,8HAA8H;QAC9H,sGAAsG;KACzG,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;AAhDD,kDAgDC","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';\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 = [\n 'Move the file into an existing project\\'s src/ directory, or create a new project with project.json that owns the directory.',\n 'Add a dir or glob (e.g. \"**/codegen.ts\") to validate-ts-in-src.excludePaths in webpieces.config.json',\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
|
@@ -6,36 +6,35 @@ const tslib_1 = require("tslib");
|
|
|
6
6
|
const path = tslib_1.__importStar(require("path"));
|
|
7
7
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
8
8
|
const build_context_1 = require("./build-context");
|
|
9
|
-
const load_config_1 = require("./load-config");
|
|
10
9
|
const load_rules_1 = require("./load-rules");
|
|
11
10
|
const to_error_1 = require("./to-error");
|
|
12
11
|
const report_1 = require("./report");
|
|
13
12
|
const types_1 = require("./types");
|
|
13
|
+
const CONFIG_MISSING_REPORT = 'webpieces.config.json not found.\n' +
|
|
14
|
+
'Tell the human: run `./node_modules/.bin/wp-setup-ai-hooks` to initialize the project configuration.\n' +
|
|
15
|
+
'Do not proceed until the human has done this.';
|
|
14
16
|
function run(toolKind, input, cwd) {
|
|
15
17
|
return runInternal(toolKind, input, cwd);
|
|
16
18
|
}
|
|
17
19
|
function runInternal(toolKind, input, cwd) {
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
20
|
-
return new types_1.BlockedResult(
|
|
21
|
-
|
|
22
|
-
'Do not proceed until the human has done this.');
|
|
23
|
-
}
|
|
24
|
-
const workspaceRoot = path.dirname(config.configPath);
|
|
20
|
+
const loaded = (0, rules_config_1.loadWebpiecesRulesConfig)(cwd);
|
|
21
|
+
if (!loaded)
|
|
22
|
+
return new types_1.BlockedResult(CONFIG_MISSING_REPORT);
|
|
23
|
+
const workspaceRoot = path.dirname(loaded.configPath);
|
|
25
24
|
// Always allow edits to webpieces.config.json — it's the fix target when out of sync
|
|
26
|
-
if (path.resolve(input.filePath) === path.resolve(
|
|
25
|
+
if (path.resolve(input.filePath) === path.resolve(loaded.configPath)) {
|
|
27
26
|
return null;
|
|
28
27
|
}
|
|
29
|
-
const rules = (0, load_rules_1.loadRules)(config, workspaceRoot);
|
|
28
|
+
const rules = (0, load_rules_1.loadRules)(loaded.config, workspaceRoot);
|
|
30
29
|
if (rules.length === 0)
|
|
31
30
|
return null;
|
|
32
|
-
const outOfSync = checkConfigSync(rules, config);
|
|
31
|
+
const outOfSync = checkConfigSync(rules, loaded.config);
|
|
33
32
|
if (outOfSync)
|
|
34
33
|
return outOfSync;
|
|
35
34
|
const contexts = (0, build_context_1.buildContexts)(toolKind, input, workspaceRoot);
|
|
36
35
|
const relativePath = path.relative(workspaceRoot, input.filePath);
|
|
37
|
-
const editGroups = runEditRules(rules, contexts.editContexts
|
|
38
|
-
const fileGroups = runFileRules(rules, contexts.fileContext
|
|
36
|
+
const editGroups = runEditRules(rules, contexts.editContexts);
|
|
37
|
+
const fileGroups = runFileRules(rules, contexts.fileContext);
|
|
39
38
|
const allGroups = [...editGroups, ...fileGroups];
|
|
40
39
|
if (allGroups.length === 0)
|
|
41
40
|
return null;
|
|
@@ -46,28 +45,30 @@ function runBash(command, cwd) {
|
|
|
46
45
|
return runBashInternal(command, cwd);
|
|
47
46
|
}
|
|
48
47
|
function runBashInternal(command, cwd) {
|
|
49
|
-
const
|
|
50
|
-
if (!
|
|
51
|
-
return new types_1.BlockedResult(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
const workspaceRoot = path.dirname(config.configPath);
|
|
56
|
-
const rules = (0, load_rules_1.loadRules)(config, workspaceRoot);
|
|
48
|
+
const loaded = (0, rules_config_1.loadWebpiecesRulesConfig)(cwd);
|
|
49
|
+
if (!loaded)
|
|
50
|
+
return new types_1.BlockedResult(CONFIG_MISSING_REPORT);
|
|
51
|
+
const workspaceRoot = path.dirname(loaded.configPath);
|
|
52
|
+
const rules = (0, load_rules_1.loadRules)(loaded.config, workspaceRoot);
|
|
57
53
|
if (rules.length === 0)
|
|
58
54
|
return null;
|
|
59
|
-
const outOfSync = checkConfigSync(rules, config);
|
|
55
|
+
const outOfSync = checkConfigSync(rules, loaded.config);
|
|
60
56
|
if (outOfSync)
|
|
61
57
|
return outOfSync;
|
|
62
58
|
const ctx = (0, build_context_1.buildBashContext)(command, workspaceRoot);
|
|
63
|
-
const groups = runBashRules(rules, ctx
|
|
59
|
+
const groups = runBashRules(rules, ctx);
|
|
64
60
|
if (groups.length === 0)
|
|
65
61
|
return null;
|
|
66
62
|
const report = (0, report_1.formatReport)('<bash>', groups);
|
|
67
63
|
return new types_1.BlockedResult(report);
|
|
68
64
|
}
|
|
65
|
+
// The set of rule names explicitly present in webpieces.config.json (every key except rulesDir).
|
|
66
|
+
function configuredRuleNames(config) {
|
|
67
|
+
return new Set(Object.keys(config).filter((k) => k !== 'rulesDir'));
|
|
68
|
+
}
|
|
69
69
|
function checkConfigSync(rules, config) {
|
|
70
|
-
const
|
|
70
|
+
const configured = configuredRuleNames(config);
|
|
71
|
+
const unconfiguredRules = rules.filter((r) => !configured.has(r.name));
|
|
71
72
|
if (unconfiguredRules.length === 0)
|
|
72
73
|
return null;
|
|
73
74
|
const lines = [
|
|
@@ -112,17 +113,20 @@ function runRuleCheck(rule, ctx) {
|
|
|
112
113
|
return [new types_1.Violation(0, '', `Rule '${rule.name}' crashed: ${error.message}`)];
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
|
-
function
|
|
116
|
+
function ruleMatchesFile(rule, relativePath) {
|
|
117
|
+
for (const pattern of rule.files) {
|
|
118
|
+
if ((0, load_rules_1.globMatches)(pattern, relativePath))
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
function runBashRules(rules, bashContext) {
|
|
116
124
|
const groups = [];
|
|
117
125
|
for (const rule of rules) {
|
|
118
126
|
if (rule.scope !== 'bash')
|
|
119
127
|
continue;
|
|
120
|
-
|
|
121
|
-
if (!ruleConfig || ruleConfig.isOff)
|
|
122
|
-
continue;
|
|
123
|
-
if (isRuleSkipped(ruleConfig))
|
|
128
|
+
if (!rule.shouldRun())
|
|
124
129
|
continue;
|
|
125
|
-
bashContext.options = mergeOptions(rule.defaultOptions, ruleConfig);
|
|
126
130
|
const vs = runRuleCheck(rule, bashContext);
|
|
127
131
|
if (vs.length > 0) {
|
|
128
132
|
groups.push(new types_1.RuleGroup(rule.name, rule.description, [...rule.fixHint], [...vs]));
|
|
@@ -130,46 +134,17 @@ function runBashRules(rules, bashContext, config) {
|
|
|
130
134
|
}
|
|
131
135
|
return groups;
|
|
132
136
|
}
|
|
133
|
-
|
|
134
|
-
// (ignoreRuleWhileOnBranch) or until an epoch passes (ignoreModifiedUntilEpoch).
|
|
135
|
-
function isRuleSkipped(ruleConfig) {
|
|
136
|
-
return (0, rules_config_1.shouldSkipRule)(ruleConfig.options['ignoreModifiedUntilEpoch'], ruleConfig.options['ignoreRuleWhileOnBranch']).skip;
|
|
137
|
-
}
|
|
138
|
-
function ruleMatchesFile(rule, relativePath) {
|
|
139
|
-
for (const pattern of rule.files) {
|
|
140
|
-
if ((0, load_rules_1.globMatches)(pattern, relativePath))
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
function mergeOptions(defaultOptions, ruleConfig) {
|
|
146
|
-
// webpieces-disable no-any-unknown -- building an options bag from opaque RuleOptions
|
|
147
|
-
const out = {};
|
|
148
|
-
for (const key of Object.keys(defaultOptions))
|
|
149
|
-
out[key] = defaultOptions[key];
|
|
150
|
-
for (const key of Object.keys(ruleConfig.options)) {
|
|
151
|
-
// 'mode' is the framework-level on/off switch, not a rule option.
|
|
152
|
-
if (key === 'mode')
|
|
153
|
-
continue;
|
|
154
|
-
out[key] = ruleConfig.options[key];
|
|
155
|
-
}
|
|
156
|
-
return out;
|
|
157
|
-
}
|
|
158
|
-
function runEditRules(rules, editContexts, config) {
|
|
137
|
+
function runEditRules(rules, editContexts) {
|
|
159
138
|
const groups = [];
|
|
160
139
|
for (const rule of rules) {
|
|
161
140
|
if (rule.scope !== 'edit')
|
|
162
141
|
continue;
|
|
163
|
-
|
|
164
|
-
if (!ruleConfig || ruleConfig.isOff)
|
|
165
|
-
continue;
|
|
166
|
-
if (isRuleSkipped(ruleConfig))
|
|
142
|
+
if (!rule.shouldRun())
|
|
167
143
|
continue;
|
|
168
144
|
const allViolations = [];
|
|
169
145
|
for (const ctx of editContexts) {
|
|
170
146
|
if (!ruleMatchesFile(rule, ctx.relativePath))
|
|
171
147
|
continue;
|
|
172
|
-
ctx.options = mergeOptions(rule.defaultOptions, ruleConfig);
|
|
173
148
|
const vs = runRuleCheck(rule, ctx);
|
|
174
149
|
for (const v of vs) {
|
|
175
150
|
const copy = new types_1.Violation(v.line, v.snippet, v.message);
|
|
@@ -184,19 +159,15 @@ function runEditRules(rules, editContexts, config) {
|
|
|
184
159
|
}
|
|
185
160
|
return groups;
|
|
186
161
|
}
|
|
187
|
-
function runFileRules(rules, fileContext
|
|
162
|
+
function runFileRules(rules, fileContext) {
|
|
188
163
|
const groups = [];
|
|
189
164
|
for (const rule of rules) {
|
|
190
165
|
if (rule.scope !== 'file')
|
|
191
166
|
continue;
|
|
192
|
-
|
|
193
|
-
if (!ruleConfig || ruleConfig.isOff)
|
|
194
|
-
continue;
|
|
195
|
-
if (isRuleSkipped(ruleConfig))
|
|
167
|
+
if (!rule.shouldRun())
|
|
196
168
|
continue;
|
|
197
169
|
if (!ruleMatchesFile(rule, fileContext.relativePath))
|
|
198
170
|
continue;
|
|
199
|
-
fileContext.options = mergeOptions(rule.defaultOptions, ruleConfig);
|
|
200
171
|
const vs = runRuleCheck(rule, fileContext);
|
|
201
172
|
if (vs.length > 0) {
|
|
202
173
|
groups.push(new types_1.RuleGroup(rule.name, rule.description, [...rule.fixHint], [...vs]));
|