@webpieces/ai-hook-rules 0.3.145 → 0.3.147
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/ai-hook-rules",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.147",
|
|
4
4
|
"description": "Pluggable write-time validation framework for AI coding agents (@webpieces/ai-hook-rules). Claude Code PreToolUse + openclaw before_tool_call adapters share one rule engine.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"directory": "packages/tooling/ai-hook-rules"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@webpieces/rules-config": "0.3.
|
|
35
|
+
"@webpieces/rules-config": "0.3.147"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|
|
@@ -2,29 +2,59 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const types_1 = require("../types");
|
|
4
4
|
const SYMBOL_DI_REGEX = /=\s*Symbol(?:\.for)?\(/;
|
|
5
|
-
const ALLOWED_PATHS = [
|
|
6
|
-
/^libraries\/apis\//,
|
|
7
|
-
/^libraries\/apis-external\//,
|
|
8
|
-
/^packages\/http\/http-api\//,
|
|
9
|
-
];
|
|
10
5
|
const TEST_PATHS = [/\.test\.ts$/, /\.spec\.ts$/, /__tests__\//];
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
function globToRegex(pattern) {
|
|
7
|
+
let re = '';
|
|
8
|
+
let i = 0;
|
|
9
|
+
while (i < pattern.length) {
|
|
10
|
+
const ch = pattern[i];
|
|
11
|
+
if (ch === '*') {
|
|
12
|
+
if (pattern[i + 1] === '*') {
|
|
13
|
+
re += '.*';
|
|
14
|
+
i += 2;
|
|
15
|
+
if (pattern[i] === '/')
|
|
16
|
+
i += 1;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
re += '[^/]*';
|
|
20
|
+
i += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (ch === '?') {
|
|
24
|
+
re += '[^/]';
|
|
25
|
+
i += 1;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if ('.+^$(){}|[]\\'.includes(ch)) {
|
|
29
|
+
re += '\\' + ch;
|
|
30
|
+
i += 1;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
re += ch;
|
|
34
|
+
i += 1;
|
|
35
|
+
}
|
|
36
|
+
return new RegExp('^' + re + '$');
|
|
37
|
+
}
|
|
38
|
+
function isAllowedPath(relativePath, allowedPaths) {
|
|
39
|
+
if (TEST_PATHS.some((re) => re.test(relativePath)))
|
|
40
|
+
return true;
|
|
41
|
+
return allowedPaths.some((pattern) => globToRegex(pattern).test(relativePath));
|
|
14
42
|
}
|
|
15
43
|
const noSymbolDiTokensRule = {
|
|
16
44
|
name: 'no-symbol-di-tokens',
|
|
17
|
-
description: 'Disallow Symbol() DI tokens outside
|
|
45
|
+
description: 'Disallow Symbol() DI tokens outside explicitly configured paths. Use @provideSingleton() + inject-by-type instead.',
|
|
18
46
|
scope: 'edit',
|
|
19
47
|
files: ['**/*.ts', '**/*.tsx'],
|
|
20
|
-
defaultOptions: {},
|
|
48
|
+
defaultOptions: { allowedPaths: [] },
|
|
21
49
|
fixHint: [
|
|
22
|
-
'(
|
|
23
|
-
'
|
|
24
|
-
'External lib
|
|
50
|
+
'(OWN class) Use @provideSingleton() on the class and inject by type — no Symbol needed.',
|
|
51
|
+
'(apis-external impl) Import the Symbol from libraries/apis/** and annotate with @provideSingletonAs(TOKEN).',
|
|
52
|
+
'(External lib class: DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...) in a ContainerModule — no Symbol needed.',
|
|
53
|
+
'Last resort: add // webpieces-disable no-symbol-di-tokens -- <reason> with a clear justification.',
|
|
25
54
|
],
|
|
26
55
|
check(ctx) {
|
|
27
|
-
|
|
56
|
+
const allowedPaths = ctx.options['allowedPaths'] ?? [];
|
|
57
|
+
if (isAllowedPath(ctx.relativePath, allowedPaths))
|
|
28
58
|
return [];
|
|
29
59
|
const violations = [];
|
|
30
60
|
for (let i = 0; i < ctx.strippedLines.length; i += 1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-symbol-di-tokens.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-symbol-di-tokens.ts"],"names":[],"mappings":";;AACA,oCAA0C;AAE1C,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"no-symbol-di-tokens.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-symbol-di-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EditRule, EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\n\nconst SYMBOL_DI_REGEX = /=\\s*Symbol(?:\\.for)?\\(/;\n\nconst TEST_PATHS: RegExp[] = [/\\.test\\.ts$/, /\\.spec\\.ts$/, /__tests__\\//];\n\nfunction globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*') {\n if (pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n re += '[^/]*';\n i += 1;\n continue;\n }\n if (ch === '?') {\n re += '[^/]';\n i += 1;\n continue;\n }\n if ('.+^$(){}|[]\\\\'.includes(ch)) {\n re += '\\\\' + ch;\n i += 1;\n continue;\n }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n}\n\nfunction isAllowedPath(relativePath: string, allowedPaths: readonly string[]): boolean {\n if (TEST_PATHS.some((re: RegExp) => re.test(relativePath))) return true;\n return allowedPaths.some((pattern: string) => globToRegex(pattern).test(relativePath));\n}\n\nconst noSymbolDiTokensRule: EditRule = {\n name: 'no-symbol-di-tokens',\n description: 'Disallow Symbol() DI tokens outside explicitly configured paths. Use @provideSingleton() + inject-by-type instead.',\n scope: 'edit',\n files: ['**/*.ts', '**/*.tsx'],\n defaultOptions: { allowedPaths: [] },\n fixHint: [\n '(OWN class) Use @provideSingleton() on the class and inject by type — no Symbol needed.',\n '(apis-external impl) Import the Symbol from libraries/apis/** and annotate with @provideSingletonAs(TOKEN).',\n '(External lib class: DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...) in a ContainerModule — no Symbol needed.',\n 'Last resort: add // webpieces-disable no-symbol-di-tokens -- <reason> with a clear justification.',\n ],\n\n check(ctx: EditContext): readonly Violation[] {\n const allowedPaths = (ctx.options['allowedPaths'] as string[] | undefined) ?? [];\n if (isAllowedPath(ctx.relativePath, allowedPaths)) return [];\n\n const violations: V[] = [];\n for (let i = 0; i < ctx.strippedLines.length; i += 1) {\n const stripped = ctx.strippedLines[i];\n if (!SYMBOL_DI_REGEX.test(stripped ?? '')) continue;\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, 'no-symbol-di-tokens')) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i]?.trim() ?? '',\n 'Symbol() used as a DI token. Mostly we avoid Symbol if we can — see fix options below.',\n ));\n }\n return violations;\n },\n};\n\nexport default noSymbolDiTokensRule;\n"]}
|