@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,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.CatchErrorPatternRule = 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 a catch clause opening: } catch (paramName: typeAnnotation) {
|
|
@@ -13,18 +15,31 @@ const CATCH_PATTERN = /\bcatch\s*\(\s*(\w+)(?:\s*:\s*(\w+))?\s*\)/;
|
|
|
13
15
|
* Group 1 = variable name, group 2 = param passed to toError
|
|
14
16
|
*/
|
|
15
17
|
const TO_ERROR_PATTERN = /^\s*(?:\/\/\s*)?const\s+(\w+)\s*=\s*toError\(\s*(\w+)\s*\)\s*;?\s*$/;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
function findToErrorStatement(lines, startIndex) {
|
|
19
|
+
for (let j = startIndex; j < lines.length; j += 1) {
|
|
20
|
+
const line = lines[j].trim();
|
|
21
|
+
if (line === '' || line === '{')
|
|
22
|
+
continue;
|
|
23
|
+
const match = TO_ERROR_PATTERN.exec(line);
|
|
24
|
+
if (match) {
|
|
25
|
+
return { varName: match[1], paramName: match[2], lineIndex: j };
|
|
26
|
+
}
|
|
27
|
+
// First non-blank line is not a toError call
|
|
28
|
+
return 'not-found';
|
|
29
|
+
}
|
|
30
|
+
// Ran off the end of the edit content — can't validate further
|
|
31
|
+
return 'end-of-content';
|
|
32
|
+
}
|
|
33
|
+
class CatchErrorPatternRule extends rule_base_1.EditRuleBase {
|
|
34
|
+
constructor(config) { super(config, 'catch-error-pattern'); }
|
|
35
|
+
description = 'Catch blocks must use: catch (err: unknown) { const error = toError(err); }'; // webpieces-disable catch-error-pattern -- example text in a description string
|
|
36
|
+
files = ['**/*.ts', '**/*.tsx'];
|
|
37
|
+
fixHint = [
|
|
23
38
|
'Add as first statement inside the catch block: const error = toError(err);',
|
|
24
39
|
'To explicitly ignore the error: //const error = toError(err);',
|
|
25
|
-
'For nested catches use numbered names: catch (err2: unknown) { const error2 = toError(err2); }',
|
|
40
|
+
'For nested catches use numbered names: catch (err2: unknown) { const error2 = toError(err2); }', // webpieces-disable catch-error-pattern -- example text in a hint string
|
|
26
41
|
'To suppress this rule: // webpieces-disable catch-error-pattern -- <reason>',
|
|
27
|
-
]
|
|
42
|
+
];
|
|
28
43
|
check(ctx) {
|
|
29
44
|
const violations = [];
|
|
30
45
|
const lines = ctx.strippedLines;
|
|
@@ -74,22 +89,7 @@ const catchErrorPatternRule = {
|
|
|
74
89
|
if (violations.length > 0)
|
|
75
90
|
(0, instruct_ai_writer_1.writeTemplateIfMissing)(ctx.workspaceRoot, 'webpieces.exceptions.md');
|
|
76
91
|
return violations;
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
function findToErrorStatement(lines, startIndex) {
|
|
80
|
-
for (let j = startIndex; j < lines.length; j += 1) {
|
|
81
|
-
const line = lines[j].trim();
|
|
82
|
-
if (line === '' || line === '{')
|
|
83
|
-
continue;
|
|
84
|
-
const match = TO_ERROR_PATTERN.exec(line);
|
|
85
|
-
if (match) {
|
|
86
|
-
return { varName: match[1], paramName: match[2], lineIndex: j };
|
|
87
|
-
}
|
|
88
|
-
// First non-blank line is not a toError call
|
|
89
|
-
return 'not-found';
|
|
90
92
|
}
|
|
91
|
-
// Ran off the end of the edit content — can't validate further
|
|
92
|
-
return 'end-of-content';
|
|
93
93
|
}
|
|
94
|
-
exports.
|
|
94
|
+
exports.CatchErrorPatternRule = CatchErrorPatternRule;
|
|
95
95
|
//# sourceMappingURL=catch-error-pattern.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catch-error-pattern.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/catch-error-pattern.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"catch-error-pattern.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/catch-error-pattern.ts"],"names":[],"mappings":"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","sourcesContent":["import { CatchErrorPatternConfig, 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 a catch clause opening: } catch (paramName: typeAnnotation) {\n * Captures: group 1 = param name, group 2 = type annotation (if present)\n */\nconst CATCH_PATTERN = /\\bcatch\\s*\\(\\s*(\\w+)(?:\\s*:\\s*(\\w+))?\\s*\\)/;\n\n/**\n * Matches the required toError first statement (with or without comment-out).\n * Group 1 = variable name, group 2 = param passed to toError\n */\nconst TO_ERROR_PATTERN = /^\\s*(?:\\/\\/\\s*)?const\\s+(\\w+)\\s*=\\s*toError\\(\\s*(\\w+)\\s*\\)\\s*;?\\s*$/;\n\ninterface ToErrorMatch {\n varName: string;\n paramName: string;\n lineIndex: number;\n}\n\nfunction findToErrorStatement(lines: readonly string[], startIndex: number): ToErrorMatch | 'not-found' | 'end-of-content' {\n for (let j = startIndex; j < lines.length; j += 1) {\n const line = lines[j].trim();\n if (line === '' || line === '{') continue;\n\n const match = TO_ERROR_PATTERN.exec(line);\n if (match) {\n return { varName: match[1], paramName: match[2], lineIndex: j };\n }\n // First non-blank line is not a toError call\n return 'not-found';\n }\n // Ran off the end of the edit content — can't validate further\n return 'end-of-content';\n}\n\nexport class CatchErrorPatternRule extends EditRuleBase<CatchErrorPatternConfig> {\n constructor(config: CatchErrorPatternConfig) { super(config, 'catch-error-pattern'); }\n\n readonly description = 'Catch blocks must use: catch (err: unknown) { const error = toError(err); }'; // webpieces-disable catch-error-pattern -- example text in a description string\n override readonly files = ['**/*.ts', '**/*.tsx'];\n readonly fixHint = [\n 'Add as first statement inside the catch block: const error = toError(err);',\n 'To explicitly ignore the error: //const error = toError(err);',\n 'For nested catches use numbered names: catch (err2: unknown) { const error2 = toError(err2); }', // webpieces-disable catch-error-pattern -- example text in a hint string\n 'To suppress this rule: // webpieces-disable catch-error-pattern -- <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 const catchMatch = CATCH_PATTERN.exec(stripped);\n if (!catchMatch) continue;\n\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, RULE_NAMES.CATCH_ERROR_PATTERN)) continue;\n\n const actualParam = catchMatch[1];\n const typeAnnotation = catchMatch[2];\n\n // Determine expected names from suffix on the actual param (err, err2, err3...)\n const suffixMatch = actualParam.match(/^err(\\d*)$/);\n const suffix = suffixMatch ? suffixMatch[1] : '';\n const expectedParam = 'err' + suffix;\n const expectedVar = 'error' + suffix;\n\n // Check parameter name\n if (actualParam !== expectedParam) {\n violations.push(new V(\n lineNum,\n ctx.lines[i].trim(),\n `Catch parameter must be named \"${expectedParam}\" (or \"err2\", \"err3\" for nested catches), got \"${actualParam}\"`,\n ));\n }\n\n // Check type annotation is unknown\n if (typeAnnotation !== 'unknown') {\n const msg = typeAnnotation\n ? `Catch parameter must be typed as \"unknown\": catch (${expectedParam}: unknown), got \"${typeAnnotation}\"`\n : `Catch parameter must be typed as \"unknown\": catch (${expectedParam}: unknown)`;\n violations.push(new V(lineNum, ctx.lines[i].trim(), msg));\n }\n\n // Find next non-blank line after the catch opening to check for toError\n const toErrorResult = findToErrorStatement(lines, i + 1);\n if (toErrorResult === 'not-found') {\n violations.push(new V(\n lineNum,\n ctx.lines[i].trim(),\n `Catch block must call toError(${actualParam}) as first statement: const ${expectedVar} = toError(${actualParam}); or //const ${expectedVar} = toError(${actualParam});`,\n ));\n } else if (toErrorResult !== 'end-of-content') {\n // Validate variable name and param match\n if (toErrorResult.varName !== expectedVar) {\n const toErrorLineNum = toErrorResult.lineIndex + 1;\n violations.push(new V(\n toErrorLineNum,\n ctx.lines[toErrorResult.lineIndex].trim(),\n `Error variable must be named \"${expectedVar}\", got \"${toErrorResult.varName}\"`,\n ));\n }\n if (toErrorResult.paramName !== actualParam) {\n const toErrorLineNum = toErrorResult.lineIndex + 1;\n violations.push(new V(\n toErrorLineNum,\n ctx.lines[toErrorResult.lineIndex].trim(),\n `toError() must be called with \"${actualParam}\", got \"${toErrorResult.paramName}\"`,\n ));\n }\n }\n }\n if (violations.length > 0) writeTemplateIfMissing(ctx.workspaceRoot, 'webpieces.exceptions.md');\n return violations;\n }\n}\n"]}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { MaxFileLinesConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { FileContext, Violation } from '../types';
|
|
3
|
+
import { FileRuleBase } from '../rule-base';
|
|
4
|
+
export declare class MaxFileLinesRule extends FileRuleBase<MaxFileLinesConfig> {
|
|
5
|
+
constructor(config: MaxFileLinesConfig);
|
|
6
|
+
readonly description = "Cap file length at a configured line limit.";
|
|
7
|
+
readonly files: string[];
|
|
8
|
+
readonly defaultOptions: {
|
|
9
|
+
limit: number;
|
|
10
|
+
};
|
|
11
|
+
readonly fixHint: string[];
|
|
12
|
+
check(ctx: FileContext): readonly Violation[];
|
|
13
|
+
}
|
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.MaxFileLinesRule = 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 DEFAULT_LIMIT = 900;
|
|
6
8
|
const INSTRUCT_FILE = 'webpieces.filesize.md';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
description
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
fixHint: [
|
|
9
|
+
class MaxFileLinesRule extends rule_base_1.FileRuleBase {
|
|
10
|
+
constructor(config) { super(config, 'max-file-lines'); }
|
|
11
|
+
description = 'Cap file length at a configured line limit.';
|
|
12
|
+
files = ['**/*.ts', '**/*.tsx'];
|
|
13
|
+
defaultOptions = { limit: DEFAULT_LIMIT };
|
|
14
|
+
fixHint = [
|
|
14
15
|
'READ .webpieces/instruct-ai/webpieces.filesize.md for step-by-step refactoring guidance.',
|
|
15
16
|
'// eslint-disable-next-line @webpieces/max-file-lines (also suppresses the eslint rule)',
|
|
16
|
-
]
|
|
17
|
+
];
|
|
17
18
|
check(ctx) {
|
|
18
|
-
const limit =
|
|
19
|
-
? ctx.options['limit']
|
|
20
|
-
: DEFAULT_LIMIT;
|
|
19
|
+
const limit = this.config.limit ?? DEFAULT_LIMIT;
|
|
21
20
|
if (ctx.projectedFileLines <= limit)
|
|
22
21
|
return [];
|
|
23
22
|
(0, rules_config_1.writeTemplateIfMissing)(ctx.workspaceRoot, INSTRUCT_FILE);
|
|
24
23
|
return [new types_1.Violation(1, `(projected ${String(ctx.projectedFileLines)} lines)`, `File will be ${String(ctx.projectedFileLines)} lines, exceeding the ${String(limit)}-line limit. See .webpieces/instruct-ai/webpieces.filesize.md for detailed refactoring instructions.`)];
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
exports.
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.MaxFileLinesRule = MaxFileLinesRule;
|
|
28
27
|
//# sourceMappingURL=max-file-lines.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"max-file-lines.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/max-file-lines.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"max-file-lines.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/max-file-lines.ts"],"names":[],"mappings":";;;AAAA,0DAAqF;AAGrF,oCAA0C;AAC1C,4CAA4C;AAE5C,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAE9C,MAAa,gBAAiB,SAAQ,wBAAgC;IAClE,YAAY,MAA0B,IAAI,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEnE,WAAW,GAAG,6CAA6C,CAAC;IACnD,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChC,cAAc,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;IACnD,OAAO,GAAG;QACf,0FAA0F;QAC1F,0FAA0F;KAC7F,CAAC;IAEF,KAAK,CAAC,GAAgB;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,aAAa,CAAC;QACjD,IAAI,GAAG,CAAC,kBAAkB,IAAI,KAAK;YAAE,OAAO,EAAE,CAAC;QAC/C,IAAA,qCAAsB,EAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,iBAAC,CACT,CAAC,EACD,cAAc,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,SAAS,EACrD,gBAAgB,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,yBAAyB,MAAM,CAAC,KAAK,CAAC,sGAAsG,CAC7L,CAAC,CAAC;IACP,CAAC;CACJ;AArBD,4CAqBC","sourcesContent":["import { MaxFileLinesConfig, writeTemplateIfMissing } 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_LIMIT = 900;\nconst INSTRUCT_FILE = 'webpieces.filesize.md';\n\nexport class MaxFileLinesRule extends FileRuleBase<MaxFileLinesConfig> {\n constructor(config: MaxFileLinesConfig) { super(config, 'max-file-lines'); }\n\n readonly description = 'Cap file length at a configured line limit.';\n override readonly files = ['**/*.ts', '**/*.tsx'];\n override readonly defaultOptions = { limit: DEFAULT_LIMIT };\n readonly fixHint = [\n 'READ .webpieces/instruct-ai/webpieces.filesize.md for step-by-step refactoring guidance.',\n '// eslint-disable-next-line @webpieces/max-file-lines (also suppresses the eslint rule)',\n ];\n\n check(ctx: FileContext): readonly Violation[] {\n const limit = this.config.limit ?? DEFAULT_LIMIT;\n if (ctx.projectedFileLines <= limit) return [];\n writeTemplateIfMissing(ctx.workspaceRoot, INSTRUCT_FILE);\n return [new V(\n 1,\n `(projected ${String(ctx.projectedFileLines)} lines)`,\n `File will be ${String(ctx.projectedFileLines)} lines, exceeding the ${String(limit)}-line limit. See .webpieces/instruct-ai/webpieces.filesize.md for detailed refactoring instructions.`,\n )];\n }\n}\n"]}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { MergeInProgressGuardConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { BashContext, Violation } from '../types';
|
|
3
|
+
import { BashRuleBase } from '../rule-base';
|
|
4
|
+
export declare class MergeInProgressGuardRule extends BashRuleBase<MergeInProgressGuardConfig> {
|
|
5
|
+
constructor(config: MergeInProgressGuardConfig);
|
|
6
|
+
readonly description = "Block commit/push/merge/PR while a 3-point merge marker is unvalidated, forcing pnpm wp-git-merge-complete.";
|
|
7
|
+
readonly fixHint: readonly string[];
|
|
8
|
+
check(ctx: BashContext): readonly Violation[];
|
|
9
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MergeInProgressGuardRule = 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 FIX_HINT = [
|
|
9
11
|
'A 3-point merge is in progress and not yet validated.',
|
|
10
12
|
'Resolve the remaining conflicts in the working tree, then run:',
|
|
@@ -38,13 +40,14 @@ function isBlockedDuringMerge(cmd) {
|
|
|
38
40
|
|| /\bgit\s+rebase\b/.test(cmd)
|
|
39
41
|
|| /\bgh\s+pr\s+(create|edit|merge)\b/.test(cmd);
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
function truncate(s) {
|
|
44
|
+
const MAX = 120;
|
|
45
|
+
return s.length <= MAX ? s : s.slice(0, MAX) + '…';
|
|
46
|
+
}
|
|
47
|
+
class MergeInProgressGuardRule extends rule_base_1.BashRuleBase {
|
|
48
|
+
constructor(config) { super(config, 'merge-in-progress-guard'); }
|
|
49
|
+
description = 'Block commit/push/merge/PR while a 3-point merge marker is unvalidated, forcing pnpm wp-git-merge-complete.';
|
|
50
|
+
fixHint = FIX_HINT;
|
|
48
51
|
check(ctx) {
|
|
49
52
|
if (!isBlockedDuringMerge(ctx.command))
|
|
50
53
|
return [];
|
|
@@ -56,11 +59,7 @@ const mergeInProgressGuard = {
|
|
|
56
59
|
`Marker: ${marker}`,
|
|
57
60
|
'Finish resolving conflicts, then run: pnpm wp-git-merge-complete',
|
|
58
61
|
].join('\n'))];
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
function truncate(s) {
|
|
62
|
-
const MAX = 120;
|
|
63
|
-
return s.length <= MAX ? s : s.slice(0, MAX) + '…';
|
|
62
|
+
}
|
|
64
63
|
}
|
|
65
|
-
exports.
|
|
64
|
+
exports.MergeInProgressGuardRule = MergeInProgressGuardRule;
|
|
66
65
|
//# sourceMappingURL=merge-in-progress-guard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-in-progress-guard.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/merge-in-progress-guard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"merge-in-progress-guard.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/merge-in-progress-guard.ts"],"names":[],"mappings":";;;;AAAA,+CAAyB;AACzB,mDAA6B;AAE7B,0DAAkI;AAGlI,oCAA0C;AAC1C,4CAA4C;AAE5C,MAAM,QAAQ,GAAsB;IAChC,uDAAuD;IACvD,gEAAgE;IAChE,8BAA8B;IAC9B,sFAAsF;IACtF,gEAAgE;CACnE,CAAC;AAEF,8FAA8F;AAC9F,sFAAsF;AACtF,SAAS,oBAAoB,CAAC,aAAqB;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,gCAAiB,CAAC,CAAC;IAC3D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,+BAAgB,CAAC;YAAE,SAAS;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,qCAAsB,CAAC,CAAC;QAChE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAS;QACrC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC;IAC3D,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,kEAAkE;AAClE,SAAS,oBAAoB,CAAC,GAAW;IACrC,OAAO,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;WAC5B,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC;WAC1B,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC;WAC3B,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;WAC5B,mCAAmC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzD,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,wBAAyB,SAAQ,wBAAwC;IAClF,YAAY,MAAkC,IAAI,KAAK,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC;IAEpF,WAAW,GAAG,6GAA6G,CAAC;IAC5H,OAAO,GAAG,QAAQ,CAAC;IAE5B,KAAK,CAAC,GAAgB;QAClB,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,iBAAC,CACT,CAAC,EACD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EACrB;gBACI,yEAAyE;gBACzE,WAAW,MAAM,EAAE;gBACnB,mEAAmE;aACtE,CAAC,IAAI,CAAC,IAAI,CAAC,CACf,CAAC,CAAC;IACP,CAAC;CACJ;AApBD,4DAoBC","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nimport { WEBPIECES_TMP_DIR, MERGE_DIR_PREFIX, MERGE_IN_PROGRESS_FILE, MergeInProgressGuardConfig } from '@webpieces/rules-config';\n\nimport type { BashContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { BashRuleBase } from '../rule-base';\n\nconst FIX_HINT: readonly string[] = [\n 'A 3-point merge is in progress and not yet validated.',\n 'Resolve the remaining conflicts in the working tree, then run:',\n ' pnpm wp-git-merge-complete',\n 'That scans for leftover conflict markers and runs the build; only when green does it',\n 'commit and unblock commit/push/PR. Then run: pnpm wp-upsert-pr',\n];\n\n// Returns the path of the first UNVALIDATED merge marker found, or null. We detect validation\n// by a raw substring (no JSON.parse) so a malformed marker can never crash the guard.\nfunction findUnvalidatedMerge(workspaceRoot: string): string | null {\n const tmpDir = path.join(workspaceRoot, WEBPIECES_TMP_DIR);\n if (!fs.existsSync(tmpDir)) return null;\n for (const entry of fs.readdirSync(tmpDir)) {\n if (!entry.startsWith(MERGE_DIR_PREFIX)) continue;\n const marker = path.join(tmpDir, entry, MERGE_IN_PROGRESS_FILE);\n if (!fs.existsSync(marker)) continue;\n const raw = fs.readFileSync(marker, 'utf8');\n if (!/\"validated\"\\s*:\\s*true/.test(raw)) return marker;\n }\n return null;\n}\n\n// Operations that would let an agent route around the merge gate.\nfunction isBlockedDuringMerge(cmd: string): boolean {\n return /\\bgit\\s+commit\\b/.test(cmd)\n || /\\bgit\\s+push\\b/.test(cmd)\n || /\\bgit\\s+merge\\b/.test(cmd)\n || /\\bgit\\s+rebase\\b/.test(cmd)\n || /\\bgh\\s+pr\\s+(create|edit|merge)\\b/.test(cmd);\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 MergeInProgressGuardRule extends BashRuleBase<MergeInProgressGuardConfig> {\n constructor(config: MergeInProgressGuardConfig) { super(config, 'merge-in-progress-guard'); }\n\n readonly description = 'Block commit/push/merge/PR while a 3-point merge marker is unvalidated, forcing pnpm wp-git-merge-complete.';\n readonly fixHint = FIX_HINT;\n\n check(ctx: BashContext): readonly Violation[] {\n if (!isBlockedDuringMerge(ctx.command)) return [];\n const marker = findUnvalidatedMerge(ctx.workspaceRoot);\n if (!marker) return [];\n return [new V(\n 1,\n truncate(ctx.command),\n [\n 'A merge is in progress and not yet validated — this command is blocked.',\n `Marker: ${marker}`,\n 'Finish resolving conflicts, then run: pnpm wp-git-merge-complete',\n ].join('\\n'),\n )];\n }\n}\n"]}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { NoAnyUnknownConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { EditContext, Violation } from '../types';
|
|
3
|
+
import { EditRuleBase } from '../rule-base';
|
|
4
|
+
export declare class NoAnyUnknownRule extends EditRuleBase<NoAnyUnknownConfig> {
|
|
5
|
+
constructor(config: NoAnyUnknownConfig);
|
|
6
|
+
readonly description = "Disallow the `any` keyword. Use concrete types or interfaces.";
|
|
7
|
+
readonly files: string[];
|
|
8
|
+
readonly fixHint: string[];
|
|
9
|
+
check(ctx: EditContext): readonly Violation[];
|
|
10
|
+
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.NoAnyUnknownRule = void 0;
|
|
4
4
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
const rule_base_1 = require("../rule-base");
|
|
7
|
+
// This regex literal matches the token as text, not a TS type.
|
|
8
|
+
const ANY_PATTERN = /(?::\s*any\b|\bas\s+any\b|<any>|any\[\]|Array<any>|Promise<any>|Map<[^,<>]+,\s*any\s*>|Record<[^,<>]+,\s*any\s*>|Set<any>)/; // webpieces-disable no-any-unknown -- regex literal, not a type
|
|
9
|
+
class NoAnyUnknownRule extends rule_base_1.EditRuleBase {
|
|
10
|
+
constructor(config) { super(config, 'no-any-unknown'); }
|
|
11
|
+
description = 'Disallow the `any` keyword. Use concrete types or interfaces.';
|
|
12
|
+
files = ['**/*.ts', '**/*.tsx'];
|
|
13
|
+
fixHint = [
|
|
13
14
|
'Prefer: interface MyData { ... } or class MyData { ... }',
|
|
14
15
|
'// webpieces-disable no-any-unknown -- <one-line reason>',
|
|
15
|
-
]
|
|
16
|
+
];
|
|
16
17
|
check(ctx) {
|
|
17
18
|
const violations = [];
|
|
18
19
|
for (let i = 0; i < ctx.strippedLines.length; i += 1) {
|
|
@@ -25,7 +26,7 @@ const noAnyRule = {
|
|
|
25
26
|
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim(), '`any` erases type information. Use a concrete type, an interface, or `unknown` with type guards.'));
|
|
26
27
|
}
|
|
27
28
|
return violations;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
exports.
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.NoAnyUnknownRule = NoAnyUnknownRule;
|
|
31
32
|
//# sourceMappingURL=no-any-unknown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-any-unknown.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-any-unknown.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-any-unknown.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-any-unknown.ts"],"names":[],"mappings":";;;AAAA,0DAAyE;AAGzE,oCAA0C;AAC1C,4CAA4C;AAE5C,+DAA+D;AAC/D,MAAM,WAAW,GACb,4HAA4H,CAAC,CAAC,gEAAgE;AAElM,MAAa,gBAAiB,SAAQ,wBAAgC;IAClE,YAAY,MAA0B,IAAI,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEnE,WAAW,GAAG,+DAA+D,CAAC;IACrE,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACzC,OAAO,GAAG;QACf,8DAA8D;QAC9D,0DAA0D;KAC7D,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,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAC1C,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,yBAAU,CAAC,cAAc,CAAC;gBAAE,SAAS;YACrE,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CACjB,OAAO,EACP,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EACnB,kGAAkG,CACrG,CAAC,CAAC;QACP,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AAzBD,4CAyBC","sourcesContent":["import { NoAnyUnknownConfig, 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// This regex literal matches the token as text, not a TS type.\nconst ANY_PATTERN =\n /(?::\\s*any\\b|\\bas\\s+any\\b|<any>|any\\[\\]|Array<any>|Promise<any>|Map<[^,<>]+,\\s*any\\s*>|Record<[^,<>]+,\\s*any\\s*>|Set<any>)/; // webpieces-disable no-any-unknown -- regex literal, not a type\n\nexport class NoAnyUnknownRule extends EditRuleBase<NoAnyUnknownConfig> {\n constructor(config: NoAnyUnknownConfig) { super(config, 'no-any-unknown'); }\n\n readonly description = 'Disallow the `any` keyword. Use concrete types or interfaces.';\n override readonly files = ['**/*.ts', '**/*.tsx'];\n readonly fixHint = [\n 'Prefer: interface MyData { ... } or class MyData { ... }',\n '// webpieces-disable no-any-unknown -- <one-line 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 (!ANY_PATTERN.test(stripped)) continue;\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, RULE_NAMES.NO_ANY_UNKNOWN)) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i].trim(),\n '`any` erases type information. Use a concrete type, an interface, or `unknown` with type guards.',\n ));\n }\n return violations;\n }\n}\n"]}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { NoDestructureConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { EditContext, Violation } from '../types';
|
|
3
|
+
import { EditRuleBase } from '../rule-base';
|
|
4
|
+
export declare class NoDestructureRule extends EditRuleBase<NoDestructureConfig> {
|
|
5
|
+
constructor(config: NoDestructureConfig);
|
|
6
|
+
readonly description = "Disallow destructuring patterns. Assign the whole result and pass it around or access properties explicitly.";
|
|
7
|
+
readonly files: string[];
|
|
8
|
+
readonly defaultOptions: {
|
|
9
|
+
allowTopLevel: boolean;
|
|
10
|
+
};
|
|
11
|
+
readonly fixHint: string[];
|
|
12
|
+
check(ctx: EditContext): readonly Violation[];
|
|
13
|
+
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.NoDestructureRule = 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 VARIABLE_DESTRUCTURE = /\b(?:const|let|var)\s*\{/;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
description
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
fixHint: [
|
|
8
|
+
class NoDestructureRule extends rule_base_1.EditRuleBase {
|
|
9
|
+
constructor(config) { super(config, 'no-destructure'); }
|
|
10
|
+
description = 'Disallow destructuring patterns. Assign the whole result and pass it around or access properties explicitly.';
|
|
11
|
+
files = ['**/*.ts', '**/*.tsx'];
|
|
12
|
+
defaultOptions = { allowTopLevel: true };
|
|
13
|
+
fixHint = [
|
|
13
14
|
'Instead of: const { x, y } = methodCall(); prefer const obj = methodCall(); then pass obj to other methods or use obj.x',
|
|
14
15
|
'// webpieces-disable no-destructure -- <reason>',
|
|
15
|
-
]
|
|
16
|
+
];
|
|
16
17
|
check(ctx) {
|
|
17
18
|
const violations = [];
|
|
18
19
|
for (let i = 0; i < ctx.strippedLines.length; i += 1) {
|
|
@@ -25,7 +26,7 @@ const noDestructureRule = {
|
|
|
25
26
|
violations.push(new types_1.Violation(lineNum, ctx.lines[i].trim(), 'Destructuring pattern. Assign the whole result instead: const obj = methodCall(); then pass obj around or use obj.x'));
|
|
26
27
|
}
|
|
27
28
|
return violations;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
exports.
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.NoDestructureRule = NoDestructureRule;
|
|
31
32
|
//# sourceMappingURL=no-destructure.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-destructure.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-destructure.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-destructure.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-destructure.ts"],"names":[],"mappings":";;;AAAA,0DAA0E;AAG1E,oCAA0C;AAC1C,4CAA4C;AAE5C,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAExD,MAAa,iBAAkB,SAAQ,wBAAiC;IACpE,YAAY,MAA2B,IAAI,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEpE,WAAW,GAAG,8GAA8G,CAAC;IACpH,KAAK,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChC,cAAc,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAClD,OAAO,GAAG;QACf,yHAAyH;QACzH,iDAAiD;KACpD,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,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,SAAS;YACnD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,yBAAU,CAAC,cAAc,CAAC;gBAAE,SAAS;YACrE,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CACjB,OAAO,EACP,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EACnB,qHAAqH,CACxH,CAAC,CAAC;QACP,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AA1BD,8CA0BC","sourcesContent":["import { NoDestructureConfig, 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\nconst VARIABLE_DESTRUCTURE = /\\b(?:const|let|var)\\s*\\{/;\n\nexport class NoDestructureRule extends EditRuleBase<NoDestructureConfig> {\n constructor(config: NoDestructureConfig) { super(config, 'no-destructure'); }\n\n readonly description = 'Disallow destructuring patterns. Assign the whole result and pass it around or access properties explicitly.';\n override readonly files = ['**/*.ts', '**/*.tsx'];\n override readonly defaultOptions = { allowTopLevel: true };\n readonly fixHint = [\n 'Instead of: const { x, y } = methodCall(); prefer const obj = methodCall(); then pass obj to other methods or use obj.x',\n '// webpieces-disable no-destructure -- <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 (!VARIABLE_DESTRUCTURE.test(stripped)) continue;\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, RULE_NAMES.NO_DESTRUCTURE)) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i].trim(),\n 'Destructuring pattern. Assign the whole result instead: const obj = methodCall(); then pass obj around or use obj.x',\n ));\n }\n return violations;\n }\n}\n"]}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { NoDirectMainUpdateConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { BashContext, Violation } from '../types';
|
|
3
|
+
import { BashRuleBase } from '../rule-base';
|
|
4
|
+
export declare class NoDirectMainUpdateRule extends BashRuleBase<NoDirectMainUpdateConfig> {
|
|
5
|
+
constructor(config: NoDirectMainUpdateConfig);
|
|
6
|
+
readonly description = "Block direct git merge/rebase/pull from main on feature branches. Use the squash-update process instead.";
|
|
7
|
+
readonly fixHint: readonly string[];
|
|
8
|
+
check(ctx: BashContext): readonly Violation[];
|
|
9
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoDirectMainUpdateRule = void 0;
|
|
3
4
|
const child_process_1 = require("child_process");
|
|
4
5
|
const types_1 = require("../types");
|
|
6
|
+
const rule_base_1 = require("../rule-base");
|
|
5
7
|
const FIX_HINT = [
|
|
6
8
|
"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.",
|
|
7
9
|
];
|
|
@@ -10,13 +12,14 @@ const WRONG_UPDATE_PATTERNS = [
|
|
|
10
12
|
/git\s+rebase\s+(origin\/main|main)\b/,
|
|
11
13
|
/git\s+pull\s+origin\s+main\b/,
|
|
12
14
|
];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
function truncate(s) {
|
|
16
|
+
const MAX = 120;
|
|
17
|
+
return s.length <= MAX ? s : s.slice(0, MAX) + '…';
|
|
18
|
+
}
|
|
19
|
+
class NoDirectMainUpdateRule extends rule_base_1.BashRuleBase {
|
|
20
|
+
constructor(config) { super(config, 'no-direct-main-update'); }
|
|
21
|
+
description = 'Block direct git merge/rebase/pull from main on feature branches. Use the squash-update process instead.';
|
|
22
|
+
fixHint = FIX_HINT;
|
|
20
23
|
check(ctx) {
|
|
21
24
|
const matched = WRONG_UPDATE_PATTERNS.some((p) => p.test(ctx.command));
|
|
22
25
|
if (!matched)
|
|
@@ -39,11 +42,7 @@ const noDirectMainUpdate = {
|
|
|
39
42
|
' pnpm wp-git-update',
|
|
40
43
|
'See docs/git-workflow.md for details.',
|
|
41
44
|
].join('\n'))];
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
function truncate(s) {
|
|
45
|
-
const MAX = 120;
|
|
46
|
-
return s.length <= MAX ? s : s.slice(0, MAX) + '…';
|
|
45
|
+
}
|
|
47
46
|
}
|
|
48
|
-
exports.
|
|
47
|
+
exports.NoDirectMainUpdateRule = NoDirectMainUpdateRule;
|
|
49
48
|
//# sourceMappingURL=no-direct-main-update.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-direct-main-update.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-direct-main-update.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-direct-main-update.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-direct-main-update.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAKzC,oCAA0C;AAC1C,4CAA4C;AAE5C,MAAM,QAAQ,GAAsB;IAChC,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,sBAAuB,SAAQ,wBAAsC;IAC9E,YAAY,MAAgC,IAAI,KAAK,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAEhF,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;gBACI,4CAA4C,aAAa,eAAe;gBACxE,4CAA4C;gBAC5C,wCAAwC;gBACxC,sBAAsB;gBACtB,uCAAuC;aAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CACf,CAAC,CAAC;IACP,CAAC;CACJ;AApCD,wDAoCC","sourcesContent":["import { execSync } from 'child_process';\n\nimport { NoDirectMainUpdateConfig } from '@webpieces/rules-config';\n\nimport type { BashContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { BashRuleBase } from '../rule-base';\n\nconst FIX_HINT: readonly string[] = [\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 NoDirectMainUpdateRule extends BashRuleBase<NoDirectMainUpdateConfig> {\n constructor(config: NoDirectMainUpdateConfig) { super(config, 'no-direct-main-update'); }\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 [\n `Direct merge/rebase from main on branch '${currentBranch}' is blocked.`,\n 'This breaks the 3-point fork-point system.',\n 'Use the squash-update process instead:',\n ' pnpm wp-git-update',\n 'See docs/git-workflow.md for details.',\n ].join('\\n'),\n )];\n }\n}\n"]}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { NoEditOnMainConfig } from '@webpieces/rules-config';
|
|
2
|
+
import type { FileContext, Violation } from '../types';
|
|
3
|
+
import { FileRuleBase } from '../rule-base';
|
|
4
|
+
export declare class NoEditOnMainRule extends FileRuleBase<NoEditOnMainConfig> {
|
|
5
|
+
constructor(config: NoEditOnMainConfig);
|
|
6
|
+
readonly description = "Block file edits when on the main branch \u2014 all work must happen on a feature branch.";
|
|
7
|
+
readonly files: string[];
|
|
8
|
+
readonly defaultOptions: {
|
|
9
|
+
branchNamingConvention: string;
|
|
10
|
+
};
|
|
11
|
+
readonly fixHint: string[];
|
|
12
|
+
check(ctx: FileContext): readonly Violation[];
|
|
13
|
+
}
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoEditOnMainRule = void 0;
|
|
3
4
|
const child_process_1 = require("child_process");
|
|
4
5
|
const types_1 = require("../types");
|
|
6
|
+
const rule_base_1 = require("../rule-base");
|
|
5
7
|
const to_error_1 = require("../to-error");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
description
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
defaultOptions: {
|
|
8
|
+
class NoEditOnMainRule extends rule_base_1.FileRuleBase {
|
|
9
|
+
constructor(config) { super(config, 'no-edit-on-main'); }
|
|
10
|
+
description = 'Block file edits when on the main branch — all work must happen on a feature branch.';
|
|
11
|
+
files = ['**/*'];
|
|
12
|
+
defaultOptions = {
|
|
12
13
|
branchNamingConvention: '{whoami}/{featurename}',
|
|
13
|
-
}
|
|
14
|
-
fixHint
|
|
14
|
+
};
|
|
15
|
+
fixHint = [
|
|
15
16
|
'You should not be working on main.',
|
|
16
17
|
'Steps:',
|
|
17
18
|
' 1. git pull origin main ← get latest commits',
|
|
18
19
|
' 2. git checkout -b <branch-name> ← create feature branch',
|
|
19
20
|
'Branch naming convention is defined in webpieces.config.json under no-edit-on-main.branchNamingConvention.',
|
|
20
|
-
]
|
|
21
|
+
];
|
|
21
22
|
check(ctx) {
|
|
22
23
|
// Only apply to files inside the workspace root
|
|
23
24
|
if (ctx.relativePath.startsWith('..'))
|
|
@@ -38,15 +39,14 @@ const noEditOnMain = {
|
|
|
38
39
|
}
|
|
39
40
|
if (currentBranch !== 'main')
|
|
40
41
|
return [];
|
|
41
|
-
const convention =
|
|
42
|
-
?? 'feature/<ticket-id>-<short-description>';
|
|
42
|
+
const convention = this.config.branchNamingConvention ?? '{whoami}/{featurename}';
|
|
43
43
|
return [new types_1.Violation(1, ctx.relativePath, [
|
|
44
44
|
'You should not be working on main.',
|
|
45
45
|
'Do a `git pull origin main` to get latest, then create a feature branch based on the naming convention.',
|
|
46
46
|
`Branch naming convention (from webpieces.config.json): ${convention}`,
|
|
47
47
|
'Example: git checkout -b ' + convention.replace(/<[^>]+>/g, 'value'),
|
|
48
48
|
].join('\n'))];
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
exports.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.NoEditOnMainRule = NoEditOnMainRule;
|
|
52
52
|
//# sourceMappingURL=no-edit-on-main.js.map
|