@webpieces/rules-config 0.3.356 → 0.3.358
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 -3
- package/src/config-file.d.ts +10 -0
- package/src/config-file.js +46 -22
- package/src/config-file.js.map +1 -1
- package/src/diff-scope.d.ts +28 -45
- package/src/diff-scope.js +193 -180
- package/src/diff-scope.js.map +1 -1
- package/src/index.d.ts +4 -4
- package/src/index.js +9 -3
- package/src/index.js.map +1 -1
- package/src/load-config.d.ts +21 -11
- package/src/load-config.js +153 -147
- package/src/load-config.js.map +1 -1
- package/src/load-template.d.ts +9 -0
- package/src/load-template.js +35 -10
- package/src/load-template.js.map +1 -1
- package/src/rules-config-design.d.ts +8 -2
- package/src/rules-config-design.js +15 -3
- package/src/rules-config-design.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/rules-config",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.358",
|
|
4
4
|
"description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@webpieces/core-context": "0.3.
|
|
18
|
-
"@webpieces/core-util": "0.3.
|
|
17
|
+
"@webpieces/core-context": "0.3.358",
|
|
18
|
+
"@webpieces/core-util": "0.3.358",
|
|
19
19
|
"@inversifyjs/binding-decorators": "1.1.5",
|
|
20
20
|
"inversify": "7.10.4",
|
|
21
21
|
"reflect-metadata": "0.2.2",
|
package/src/config-file.d.ts
CHANGED
|
@@ -9,6 +9,16 @@ export interface RawConfigFile {
|
|
|
9
9
|
rulesDir?: string[];
|
|
10
10
|
'pr-gate'?: unknown;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Locates + reads webpieces.config.json. `@provideSingleton` so it can be injected into the config
|
|
14
|
+
* loader and appear in the rules-config DI design.
|
|
15
|
+
*/
|
|
16
|
+
export declare class ConfigFile {
|
|
17
|
+
/** Walk up from `startDir` looking for webpieces.config.json. Returns its absolute path or null. */
|
|
18
|
+
findConfigFile(startDir: string): string | null;
|
|
19
|
+
/** Read + JSON.parse webpieces.config.json, surfacing parse failures as a readable InformAiError. */
|
|
20
|
+
readRawConfig(configPath: string): RawConfigFile;
|
|
21
|
+
}
|
|
12
22
|
/**
|
|
13
23
|
* Walk up from `startDir` looking for webpieces.config.json. Returns its absolute path or null.
|
|
14
24
|
*/
|
package/src/config-file.js
CHANGED
|
@@ -1,43 +1,67 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CONFIG_FILENAME = void 0;
|
|
3
|
+
exports.ConfigFile = exports.CONFIG_FILENAME = void 0;
|
|
4
4
|
exports.findConfigFile = findConfigFile;
|
|
5
5
|
exports.readRawConfig = readRawConfig;
|
|
6
6
|
const tslib_1 = require("tslib");
|
|
7
7
|
const fs = tslib_1.__importStar(require("fs"));
|
|
8
8
|
const path = tslib_1.__importStar(require("path"));
|
|
9
|
+
const core_context_1 = require("@webpieces/core-context");
|
|
10
|
+
const inversify_1 = require("inversify");
|
|
9
11
|
const inform_ai_error_1 = require("./inform-ai-error");
|
|
10
12
|
const to_error_1 = require("./to-error");
|
|
11
13
|
exports.CONFIG_FILENAME = 'webpieces.config.json';
|
|
14
|
+
/**
|
|
15
|
+
* Locates + reads webpieces.config.json. `@provideSingleton` so it can be injected into the config
|
|
16
|
+
* loader and appear in the rules-config DI design.
|
|
17
|
+
*/
|
|
18
|
+
let ConfigFile = class ConfigFile {
|
|
19
|
+
/** Walk up from `startDir` looking for webpieces.config.json. Returns its absolute path or null. */
|
|
20
|
+
findConfigFile(startDir) {
|
|
21
|
+
let dir = startDir;
|
|
22
|
+
while (true) {
|
|
23
|
+
const primary = path.join(dir, exports.CONFIG_FILENAME);
|
|
24
|
+
if (fs.existsSync(primary))
|
|
25
|
+
return primary;
|
|
26
|
+
const parent = path.dirname(dir);
|
|
27
|
+
if (parent === dir)
|
|
28
|
+
return null;
|
|
29
|
+
dir = parent;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Read + JSON.parse webpieces.config.json, surfacing parse failures as a readable InformAiError. */
|
|
33
|
+
readRawConfig(configPath) {
|
|
34
|
+
const raw = fs.readFileSync(configPath, 'utf8');
|
|
35
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(raw);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const error = (0, to_error_1.toError)(err);
|
|
41
|
+
throw new inform_ai_error_1.InformAiError(`webpieces.config.json has invalid JSON — fix the file, then retry.\n` +
|
|
42
|
+
`Parse error: ${error.message}\n` +
|
|
43
|
+
`File: ${configPath}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.ConfigFile = ConfigFile;
|
|
48
|
+
exports.ConfigFile = ConfigFile = tslib_1.__decorate([
|
|
49
|
+
(0, core_context_1.provideSingleton)(),
|
|
50
|
+
(0, inversify_1.injectable)()
|
|
51
|
+
], ConfigFile);
|
|
52
|
+
// Temporary migration delegators — consumers migrate to injecting ConfigFile over follow-up PRs, then
|
|
53
|
+
// these free functions are removed. Declarations kept identical to the originals (unchanged lines).
|
|
54
|
+
const configFileSvc = new ConfigFile();
|
|
12
55
|
/**
|
|
13
56
|
* Walk up from `startDir` looking for webpieces.config.json. Returns its absolute path or null.
|
|
14
57
|
*/
|
|
15
58
|
function findConfigFile(startDir) {
|
|
16
|
-
|
|
17
|
-
while (true) {
|
|
18
|
-
const primary = path.join(dir, exports.CONFIG_FILENAME);
|
|
19
|
-
if (fs.existsSync(primary))
|
|
20
|
-
return primary;
|
|
21
|
-
const parent = path.dirname(dir);
|
|
22
|
-
if (parent === dir)
|
|
23
|
-
return null;
|
|
24
|
-
dir = parent;
|
|
25
|
-
}
|
|
59
|
+
return configFileSvc.findConfigFile(startDir);
|
|
26
60
|
}
|
|
27
61
|
/**
|
|
28
62
|
* Read + JSON.parse webpieces.config.json, surfacing parse failures as a readable InformAiError.
|
|
29
63
|
*/
|
|
30
64
|
function readRawConfig(configPath) {
|
|
31
|
-
|
|
32
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
33
|
-
try {
|
|
34
|
-
return JSON.parse(raw);
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
const error = (0, to_error_1.toError)(err);
|
|
38
|
-
throw new inform_ai_error_1.InformAiError(`webpieces.config.json has invalid JSON — fix the file, then retry.\n` +
|
|
39
|
-
`Parse error: ${error.message}\n` +
|
|
40
|
-
`File: ${configPath}`);
|
|
41
|
-
}
|
|
65
|
+
return configFileSvc.readRawConfig(configPath);
|
|
42
66
|
}
|
|
43
67
|
//# sourceMappingURL=config-file.js.map
|
package/src/config-file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-file.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/config-file.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"config-file.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/config-file.ts"],"names":[],"mappings":";;;AAiFA,wCAEC;AAKD,sCAEC;;AA1FD,+CAAyB;AACzB,mDAA6B;AAC7B,0DAA2D;AAC3D,yCAAuC;AAEvC,uDAAkD;AAClD,yCAAqC;AAExB,QAAA,eAAe,GAAG,uBAAuB,CAAC;AA8BvD;;;GAGG;AAGI,IAAM,UAAU,GAAhB,MAAM,UAAU;IACnB,oGAAoG;IACpG,cAAc,CAAC,QAAgB;QAC3B,IAAI,GAAG,GAAG,QAAQ,CAAC;QACnB,OAAO,IAAI,EAAE,CAAC;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,uBAAe,CAAC,CAAC;YAChD,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,OAAO,OAAO,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,MAAM,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YAChC,GAAG,GAAG,MAAM,CAAC;QACjB,CAAC;IACL,CAAC;IAED,qGAAqG;IACrG,aAAa,CAAC,UAAkB;QAC5B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAChD,8DAA8D;QAC9D,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,kBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,MAAM,IAAI,+BAAa,CACnB,sEAAsE;gBACtE,gBAAgB,KAAK,CAAC,OAAO,IAAI;gBACjC,SAAS,UAAU,EAAE,CACxB,CAAC;QACN,CAAC;IACL,CAAC;CACJ,CAAA;AA5BY,gCAAU;qBAAV,UAAU;IAFtB,IAAA,+BAAgB,GAAE;IAClB,IAAA,sBAAU,GAAE;GACA,UAAU,CA4BtB;AAED,sGAAsG;AACtG,oGAAoG;AACpG,MAAM,aAAa,GAAG,IAAI,UAAU,EAAE,CAAC;AAEvC;;GAEG;AACH,SAAgB,cAAc,CAAC,QAAgB;IAC3C,OAAO,aAAa,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,UAAkB;IAC5C,OAAO,aAAa,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;AACnD,CAAC","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\n\nimport { InformAiError } from './inform-ai-error';\nimport { toError } from './to-error';\n\nexport const CONFIG_FILENAME = 'webpieces.config.json';\n\n// Raw shape of webpieces.config.json as parsed from JSON, before validation/typing.\n// - `rules` — code-style validators (scope edit/file).\n// - `hookGuards` — git/PR/branch protection guards (scope bash).\n// - `commands` — gated command config the guards point at; `pr-gate` lives inside it. Carried as\n// opaque JSON because its nested `gates` array can't be expressed in the FieldDef\n// schema; validated structurally by validateCommandsSection.\n// - `pr-gate` — DEPRECATED top-level block (pre-migration layout). Read only as a back-compat\n// fallback / to emit a \"move it under commands\" migration error.\n// webpieces-disable no-any-unknown -- consumer JSON config has opaque rule option values\nexport interface RawConfigFile {\n extends?: string;\n rules?: Record<string, Record<string, unknown>>;\n hookGuards?: Record<string, Record<string, unknown>>;\n // webpieces-disable no-any-unknown -- opaque commands JSON, validated by validateCommandsSection\n commands?: unknown;\n // REQUIRED top-level block: two glob lists that suppress hook enforcement per file path.\n // Opaque here (validated structurally by validateExcludePaths, then parsed into ExcludePaths).\n // webpieces-disable no-any-unknown -- opaque excludePaths JSON, validated by validateExcludePaths\n excludePaths?: unknown;\n // REQUIRED top-level array of client-authored content guards (regex patterns + message + scoping).\n // Opaque here; validated structurally by validateMatchRulesSection, then parsed into MatchRuleConfig[].\n // webpieces-disable no-any-unknown -- opaque match-rules JSON, validated by validateMatchRulesSection\n 'match-rules'?: unknown;\n rulesDir?: string[];\n // webpieces-disable no-any-unknown -- DEPRECATED top-level pr-gate, migrated under `commands`\n 'pr-gate'?: unknown;\n}\n\n/**\n * Locates + reads webpieces.config.json. `@provideSingleton` so it can be injected into the config\n * loader and appear in the rules-config DI design.\n */\n@provideSingleton()\n@injectable()\nexport class ConfigFile {\n /** Walk up from `startDir` looking for webpieces.config.json. Returns its absolute path or null. */\n findConfigFile(startDir: string): string | null {\n let dir = startDir;\n while (true) {\n const primary = path.join(dir, CONFIG_FILENAME);\n if (fs.existsSync(primary)) return primary;\n const parent = path.dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n }\n\n /** Read + JSON.parse webpieces.config.json, surfacing parse failures as a readable InformAiError. */\n readRawConfig(configPath: string): RawConfigFile {\n const raw = fs.readFileSync(configPath, 'utf8');\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return JSON.parse(raw) as RawConfigFile;\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(\n `webpieces.config.json has invalid JSON — fix the file, then retry.\\n` +\n `Parse error: ${error.message}\\n` +\n `File: ${configPath}`,\n );\n }\n }\n}\n\n// Temporary migration delegators — consumers migrate to injecting ConfigFile over follow-up PRs, then\n// these free functions are removed. Declarations kept identical to the originals (unchanged lines).\nconst configFileSvc = new ConfigFile();\n\n/**\n * Walk up from `startDir` looking for webpieces.config.json. Returns its absolute path or null.\n */\nexport function findConfigFile(startDir: string): string | null {\n return configFileSvc.findConfigFile(startDir);\n}\n\n/**\n * Read + JSON.parse webpieces.config.json, surfacing parse failures as a readable InformAiError.\n */\nexport function readRawConfig(configPath: string): RawConfigFile {\n return configFileSvc.readRawConfig(configPath);\n}\n"]}
|
package/src/diff-scope.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared git-diff + diff-scoping
|
|
3
|
-
* (nx-webpieces-rules). Centralized here in rules-config because it is the one package both
|
|
4
|
-
* those depend on, and it already shells out to git (see skip-rule.ts).
|
|
2
|
+
* Shared git-diff + diff-scoping service for ALL rule validators (code-rules) and nx executors
|
|
3
|
+
* (nx-webpieces-rules). Centralized here in rules-config because it is the one package both depend on.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - `getChangedFiles(..., { tsOnly: false })` reproduces validate-dtos' all-files diff.
|
|
10
|
-
* - `detectBase` replaces both the nested-try and the ref-loop spellings (identical behavior).
|
|
5
|
+
* `@provideSingleton` so it can be injected and appear in the rules-config DI design. Free-function
|
|
6
|
+
* delegators are kept temporarily so the many existing consumers stay green; they migrate to injecting
|
|
7
|
+
* {@link DiffScope} over follow-up PRs, then the delegators are removed.
|
|
11
8
|
*/
|
|
12
9
|
/** A git diff range: the base ref to compare against and an optional head (else the working tree). */
|
|
13
10
|
export declare class DiffRange {
|
|
@@ -18,48 +15,34 @@ export declare class DiffRange {
|
|
|
18
15
|
export declare class ChangedFilesOptions {
|
|
19
16
|
tsOnly?: boolean;
|
|
20
17
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
export declare class DiffScope {
|
|
19
|
+
/** Auto-detect the diff base: merge-base of HEAD with origin/main, falling back to local main. */
|
|
20
|
+
detectBase(workspaceRoot: string): string | null;
|
|
21
|
+
/** Resolve the diff range a rule should compare against (honors nx's NX_BASE / NX_HEAD). */
|
|
22
|
+
resolveBase(workspaceRoot: string): DiffRange;
|
|
23
|
+
/**
|
|
24
|
+
* Changed files between base and head (or base→working-tree when head is omitted). Untracked files
|
|
25
|
+
* are unioned in for the working-tree case. `tsOnly` (default true) restricts to *.ts/*.tsx and
|
|
26
|
+
* drops test files. Deletions are excluded (`--diff-filter=d`).
|
|
27
|
+
*/
|
|
28
|
+
getChangedFiles(workspaceRoot: string, base: string, head?: string, opts?: ChangedFilesOptions): string[];
|
|
29
|
+
/** Diff content for a single file (synthetic all-added diff for an untracked file with no head). */
|
|
30
|
+
getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string;
|
|
31
|
+
/** Added/changed line numbers (the `+` lines per hunk) — basis of NEW_AND_MODIFIED_CODE scoping. */
|
|
32
|
+
getChangedLineNumbers(diffContent: string): Set<number>;
|
|
33
|
+
/** Method names whose signature line is a `+` addition in the diff — the basis of "NEW" methods. */
|
|
34
|
+
findNewMethodSignaturesInDiff(diffContent: string): Set<string>;
|
|
35
|
+
/** True if any line in [startLine, endLine] is in the changedLines set. */
|
|
36
|
+
hasChangesInRange(startLine: number, endLine: number, changedLines: Set<number>): boolean;
|
|
37
|
+
/** True if a node (method/function) is newly added or has any changed line in its range. */
|
|
38
|
+
isNewOrModified(name: string, startLine: number, endLine: number, changedLines: Set<number>, newMethodNames: Set<string>): boolean;
|
|
39
|
+
private isTestFile;
|
|
40
|
+
}
|
|
26
41
|
export declare function detectBase(workspaceRoot: string): string | null;
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the diff range a rule should compare against. Honors nx's NX_BASE / NX_HEAD (set by
|
|
29
|
-
* `nx affected --base=.. --head=..`); when NX_BASE is unset, auto-detects via detectBase. A returned
|
|
30
|
-
* `base` of undefined means "could not determine a base" (caller should skip).
|
|
31
|
-
*/
|
|
32
42
|
export declare function resolveBase(workspaceRoot: string): DiffRange;
|
|
33
|
-
/**
|
|
34
|
-
* Changed files between base and head (or base→working-tree when head is omitted). When head is
|
|
35
|
-
* omitted, untracked files are unioned in too (matching `nx affected`). `tsOnly` (default true)
|
|
36
|
-
* restricts to *.ts/*.tsx and drops test files; pass false for an all-files diff.
|
|
37
|
-
*
|
|
38
|
-
* Deletions are excluded (`--diff-filter=d`): every consumer reasons about a file's current
|
|
39
|
-
* content or location, and a path that no longer exists can't violate anything. This also fixes
|
|
40
|
-
* renames — without rename detection git reports a rename as delete+add, so filtering the delete
|
|
41
|
-
* side leaves only the file's NEW path in the list.
|
|
42
|
-
*/
|
|
43
43
|
export declare function getChangedFiles(workspaceRoot: string, base: string, head?: string, opts?: ChangedFilesOptions): string[];
|
|
44
|
-
/**
|
|
45
|
-
* Diff content for a single file. When the file is untracked (and no head is given) a synthetic
|
|
46
|
-
* all-added diff is produced so new files count as fully-changed.
|
|
47
|
-
*/
|
|
48
44
|
export declare function getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string;
|
|
49
|
-
/**
|
|
50
|
-
* Parse a unified diff and return the set of added/changed line numbers (the `+` lines per hunk).
|
|
51
|
-
* This is the basis of NEW_AND_MODIFIED_CODE (line-level) scoping.
|
|
52
|
-
*/
|
|
53
45
|
export declare function getChangedLineNumbers(diffContent: string): Set<number>;
|
|
54
|
-
/**
|
|
55
|
-
* Method names whose signature line is a `+` addition in the diff — the basis of "NEW" methods.
|
|
56
|
-
*/
|
|
57
46
|
export declare function findNewMethodSignaturesInDiff(diffContent: string): Set<string>;
|
|
58
|
-
/**
|
|
59
|
-
* True if any line in [startLine, endLine] is in the changedLines set.
|
|
60
|
-
*/
|
|
61
47
|
export declare function hasChangesInRange(startLine: number, endLine: number, changedLines: Set<number>): boolean;
|
|
62
|
-
/**
|
|
63
|
-
* True if a node (method/function) is newly added or has any changed line in its range.
|
|
64
|
-
*/
|
|
65
48
|
export declare function isNewOrModified(name: string, startLine: number, endLine: number, changedLines: Set<number>, newMethodNames: Set<string>): boolean;
|