@webpieces/rules-config 0.3.357 → 0.3.359
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/branch-mutation-log.d.ts +13 -5
- package/src/branch-mutation-log.js +86 -76
- package/src/branch-mutation-log.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 +3 -3
- package/src/index.js +7 -2
- package/src/index.js.map +1 -1
- package/src/review-json.d.ts +13 -5
- package/src/review-json.js +106 -87
- package/src/review-json.js.map +1 -1
- package/src/rules-config-design.d.ts +7 -1
- package/src/rules-config-design.js +14 -2
- 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.359",
|
|
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.359",
|
|
18
|
+
"@webpieces/core-util": "0.3.359",
|
|
19
19
|
"@inversifyjs/binding-decorators": "1.1.5",
|
|
20
20
|
"inversify": "7.10.4",
|
|
21
21
|
"reflect-metadata": "0.2.2",
|
|
@@ -13,10 +13,18 @@ export declare class BranchMutationEvent {
|
|
|
13
13
|
artifacts: string[];
|
|
14
14
|
constructor(verb: MutationVerb, phase: MutationPhase);
|
|
15
15
|
}
|
|
16
|
+
/** Appends branch-mutation audit lines. `@provideSingleton` so it's injectable + drawn in the design. */
|
|
17
|
+
export declare class BranchMutationLog {
|
|
18
|
+
branchMutationLogPath(root: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Append one tab-separated line per branch-mutation event to
|
|
21
|
+
* `.webpieces/hooks/branch-mutations.log`. Swallows all errors — logging must NEVER block or fail
|
|
22
|
+
* the workflow it is observing.
|
|
23
|
+
*/
|
|
24
|
+
logBranchMutation(root: string, event: BranchMutationEvent): void;
|
|
25
|
+
private formatDetail;
|
|
26
|
+
private oneLine;
|
|
27
|
+
private rotateLogFile;
|
|
28
|
+
}
|
|
16
29
|
export declare function branchMutationLogPath(root: string): string;
|
|
17
|
-
/**
|
|
18
|
-
* Append one tab-separated line per branch-mutation event to `.webpieces/hooks/branch-mutations.log`.
|
|
19
|
-
* `root` is the workspace root holding `.webpieces`. Swallows all errors — logging must NEVER block or
|
|
20
|
-
* fail the workflow it is observing (mirrors logSyncEvent's contract).
|
|
21
|
-
*/
|
|
22
30
|
export declare function logBranchMutation(root: string, event: BranchMutationEvent): void;
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BranchMutationEvent = void 0;
|
|
3
|
+
exports.BranchMutationLog = exports.BranchMutationEvent = void 0;
|
|
4
4
|
exports.branchMutationLogPath = branchMutationLogPath;
|
|
5
5
|
exports.logBranchMutation = logBranchMutation;
|
|
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 constants_1 = require("./constants");
|
|
10
12
|
const to_error_1 = require("./to-error");
|
|
11
|
-
// The BRANCH-MUTATION log — an audit trail for every workflow verb that RENAMES or MOVES branches
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// the agent (backup, checkout main, pull, squash-merge, rename) with ONLY `git reflog` as evidence —
|
|
15
|
-
// nothing in `.webpieces/`. This log records START / each phase boundary / END-with-outcome so the
|
|
16
|
-
// next agent (or a human) can reconstruct what the tooling did to the branches and where the merge/PR
|
|
17
|
-
// artifacts landed. Kept SEPARATE from the read-only refresher log (guard-async-work.log) so that log
|
|
18
|
-
// stays purely about the async cache. Writes to `.webpieces/hooks/branch-mutations.log`.
|
|
19
|
-
//
|
|
13
|
+
// The BRANCH-MUTATION log — an audit trail for every workflow verb that RENAMES or MOVES branches.
|
|
14
|
+
// Records START / each phase boundary / END-with-outcome so the next agent (or a human) can
|
|
15
|
+
// reconstruct what the tooling did to the branches. Writes to `.webpieces/hooks/branch-mutations.log`.
|
|
20
16
|
// Lives in rules-config (the shared dep of pr-gate) so the pr-gate scripts can call it directly.
|
|
21
17
|
const HOOKS_DIR = 'hooks';
|
|
22
18
|
const LOG_FILE = 'branch-mutations.log';
|
|
23
19
|
const LOG_FILE_PREV = 'branch-mutations.1.log';
|
|
24
20
|
const MAX_LOG_BYTES = 512 * 1024; // 512 KB — rotate when exceeded (mirrors the other webpieces logs)
|
|
25
21
|
const MAX_DETAIL_LEN = 400;
|
|
26
|
-
// Data-only record of one branch-mutation event (per CLAUDE.md: classes for data, explicit
|
|
27
|
-
// construction). `verb` + `phase` are always set; the rest describe the transition and default to
|
|
28
|
-
// empty so a call site fills only what that phase knows (e.g. RENAME sets from/to, PULL sets
|
|
29
|
-
// oldMain/newMain, CONFLICT sets conflictFiles + artifacts, END sets outcome).
|
|
22
|
+
// Data-only record of one branch-mutation event (per CLAUDE.md: classes for data, explicit construction).
|
|
30
23
|
class BranchMutationEvent {
|
|
31
24
|
verb;
|
|
32
25
|
phase;
|
|
@@ -44,71 +37,88 @@ class BranchMutationEvent {
|
|
|
44
37
|
}
|
|
45
38
|
}
|
|
46
39
|
exports.BranchMutationEvent = BranchMutationEvent;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
* Append one tab-separated line per branch-mutation event to `.webpieces/hooks/branch-mutations.log`.
|
|
52
|
-
* `root` is the workspace root holding `.webpieces`. Swallows all errors — logging must NEVER block or
|
|
53
|
-
* fail the workflow it is observing (mirrors logSyncEvent's contract).
|
|
54
|
-
*/
|
|
55
|
-
function logBranchMutation(root, event) {
|
|
56
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
57
|
-
try {
|
|
58
|
-
const timestamp = new Date().toISOString();
|
|
59
|
-
const hooksDir = path.join(root, constants_1.WEBPIECES_TMP_DIR, HOOKS_DIR);
|
|
60
|
-
fs.mkdirSync(hooksDir, { recursive: true });
|
|
61
|
-
const logPath = path.join(hooksDir, LOG_FILE);
|
|
62
|
-
rotateLogFile(logPath, path.join(hooksDir, LOG_FILE_PREV));
|
|
63
|
-
const line = [
|
|
64
|
-
`[${timestamp}]`,
|
|
65
|
-
event.verb,
|
|
66
|
-
event.phase,
|
|
67
|
-
oneLine(formatDetail(event)),
|
|
68
|
-
].join('\t') + '\n';
|
|
69
|
-
fs.appendFileSync(logPath, line);
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
const error = (0, to_error_1.toError)(err);
|
|
73
|
-
void error;
|
|
40
|
+
/** Appends branch-mutation audit lines. `@provideSingleton` so it's injectable + drawn in the design. */
|
|
41
|
+
let BranchMutationLog = class BranchMutationLog {
|
|
42
|
+
branchMutationLogPath(root) {
|
|
43
|
+
return path.join(root, constants_1.WEBPIECES_TMP_DIR, HOOKS_DIR, LOG_FILE);
|
|
74
44
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
function rotateLogFile(logPath, prevPath) {
|
|
100
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
101
|
-
try {
|
|
102
|
-
const stat = fs.statSync(logPath);
|
|
103
|
-
if (stat.size > MAX_LOG_BYTES) {
|
|
104
|
-
if (fs.existsSync(prevPath))
|
|
105
|
-
fs.unlinkSync(prevPath);
|
|
106
|
-
fs.renameSync(logPath, prevPath);
|
|
45
|
+
/**
|
|
46
|
+
* Append one tab-separated line per branch-mutation event to
|
|
47
|
+
* `.webpieces/hooks/branch-mutations.log`. Swallows all errors — logging must NEVER block or fail
|
|
48
|
+
* the workflow it is observing.
|
|
49
|
+
*/
|
|
50
|
+
logBranchMutation(root, event) {
|
|
51
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
52
|
+
try {
|
|
53
|
+
const timestamp = new Date().toISOString();
|
|
54
|
+
const hooksDir = path.join(root, constants_1.WEBPIECES_TMP_DIR, HOOKS_DIR);
|
|
55
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
56
|
+
const logPath = path.join(hooksDir, LOG_FILE);
|
|
57
|
+
this.rotateLogFile(logPath, path.join(hooksDir, LOG_FILE_PREV));
|
|
58
|
+
const line = [
|
|
59
|
+
`[${timestamp}]`,
|
|
60
|
+
event.verb,
|
|
61
|
+
event.phase,
|
|
62
|
+
this.oneLine(this.formatDetail(event)),
|
|
63
|
+
].join('\t') + '\n';
|
|
64
|
+
fs.appendFileSync(logPath, line);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const error = (0, to_error_1.toError)(err);
|
|
68
|
+
void error;
|
|
107
69
|
}
|
|
108
70
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
71
|
+
// Render only the fields this event actually set, as `key=value` tokens — greppable on one line.
|
|
72
|
+
formatDetail(event) {
|
|
73
|
+
const parts = [];
|
|
74
|
+
if (event.fromBranch !== '' || event.toBranch !== '')
|
|
75
|
+
parts.push(`from=${event.fromBranch || '?'} to=${event.toBranch || '?'}`);
|
|
76
|
+
if (event.oldMain !== '' || event.newMain !== '')
|
|
77
|
+
parts.push(`oldMain=${event.oldMain || '?'} newMain=${event.newMain || '?'}`);
|
|
78
|
+
if (event.conflict)
|
|
79
|
+
parts.push('conflict=true');
|
|
80
|
+
if (event.conflictFiles.length > 0)
|
|
81
|
+
parts.push(`conflictFiles=${event.conflictFiles.length}(${event.conflictFiles.join(',')})`);
|
|
82
|
+
if (event.outcome !== '')
|
|
83
|
+
parts.push(`outcome=${event.outcome}`);
|
|
84
|
+
for (const artifact of event.artifacts)
|
|
85
|
+
parts.push(`artifact=${artifact}`);
|
|
86
|
+
return parts.join(' ');
|
|
112
87
|
}
|
|
88
|
+
// Collapse newlines/tabs and cap length so one event is always exactly one log line.
|
|
89
|
+
oneLine(value) {
|
|
90
|
+
const flat = value.replace(/[\t\r\n]+/g, ' ').trim();
|
|
91
|
+
return flat.length <= MAX_DETAIL_LEN ? flat : flat.slice(0, MAX_DETAIL_LEN) + '…';
|
|
92
|
+
}
|
|
93
|
+
rotateLogFile(logPath, prevPath) {
|
|
94
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
95
|
+
try {
|
|
96
|
+
const stat = fs.statSync(logPath);
|
|
97
|
+
if (stat.size > MAX_LOG_BYTES) {
|
|
98
|
+
if (fs.existsSync(prevPath))
|
|
99
|
+
fs.unlinkSync(prevPath);
|
|
100
|
+
fs.renameSync(logPath, prevPath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const error = (0, to_error_1.toError)(err);
|
|
105
|
+
void error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
exports.BranchMutationLog = BranchMutationLog;
|
|
110
|
+
exports.BranchMutationLog = BranchMutationLog = tslib_1.__decorate([
|
|
111
|
+
(0, core_context_1.provideSingleton)(),
|
|
112
|
+
(0, inversify_1.injectable)()
|
|
113
|
+
], BranchMutationLog);
|
|
114
|
+
// Temporary migration delegators to BranchMutationLog — removed once consumers inject it.
|
|
115
|
+
const branchMutationLogSvc = new BranchMutationLog();
|
|
116
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it
|
|
117
|
+
function branchMutationLogPath(root) {
|
|
118
|
+
return branchMutationLogSvc.branchMutationLogPath(root);
|
|
119
|
+
}
|
|
120
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it
|
|
121
|
+
function logBranchMutation(root, event) {
|
|
122
|
+
branchMutationLogSvc.logBranchMutation(root, event);
|
|
113
123
|
}
|
|
114
124
|
//# sourceMappingURL=branch-mutation-log.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-mutation-log.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/branch-mutation-log.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"branch-mutation-log.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/branch-mutation-log.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\n\nimport { WEBPIECES_TMP_DIR } from './constants';\nimport { toError } from './to-error';\n\n// The BRANCH-MUTATION log — an audit trail for every workflow verb that RENAMES or MOVES branches.\n// Records START / each phase boundary / END-with-outcome so the next agent (or a human) can\n// reconstruct what the tooling did to the branches. Writes to `.webpieces/hooks/branch-mutations.log`.\n// Lives in rules-config (the shared dep of pr-gate) so the pr-gate scripts can call it directly.\n\nconst HOOKS_DIR = 'hooks';\nconst LOG_FILE = 'branch-mutations.log';\nconst LOG_FILE_PREV = 'branch-mutations.1.log';\nconst MAX_LOG_BYTES = 512 * 1024; // 512 KB — rotate when exceeded (mirrors the other webpieces logs)\nconst MAX_DETAIL_LEN = 400;\n\n// The workflow verb whose branch mutation is being logged (the bin the AI/human invoked).\nexport type MutationVerb = 'wp-start-update' | 'wp-finish-update' | 'wp-start-upsert-pr' | 'wp-finish-upsert-pr';\n\n// A boundary within a verb's execution. START/END bracket the whole run; the middle phases mark each\n// irreversible git step so an interrupt leaves a breadcrumb at the last phase reached.\nexport type MutationPhase =\n | 'START' | 'BACKUP' | 'CHECKOUT_MAIN' | 'PULL' | 'SQUASH' | 'RENAME'\n | 'FINALIZE' | 'CONFLICT' | 'INTERRUPTED' | 'END';\n\n// Data-only record of one branch-mutation event (per CLAUDE.md: classes for data, explicit construction).\nexport class BranchMutationEvent {\n verb: MutationVerb;\n phase: MutationPhase;\n fromBranch: string = '';\n toBranch: string = '';\n oldMain: string = '';\n newMain: string = '';\n conflict: boolean = false;\n conflictFiles: string[] = [];\n outcome: string = '';\n artifacts: string[] = [];\n\n constructor(verb: MutationVerb, phase: MutationPhase) {\n this.verb = verb;\n this.phase = phase;\n }\n}\n\n/** Appends branch-mutation audit lines. `@provideSingleton` so it's injectable + drawn in the design. */\n@provideSingleton()\n@injectable()\nexport class BranchMutationLog {\n branchMutationLogPath(root: string): string {\n return path.join(root, WEBPIECES_TMP_DIR, HOOKS_DIR, LOG_FILE);\n }\n\n /**\n * Append one tab-separated line per branch-mutation event to\n * `.webpieces/hooks/branch-mutations.log`. Swallows all errors — logging must NEVER block or fail\n * the workflow it is observing.\n */\n logBranchMutation(root: string, event: BranchMutationEvent): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const timestamp = new Date().toISOString();\n const hooksDir = path.join(root, WEBPIECES_TMP_DIR, HOOKS_DIR);\n fs.mkdirSync(hooksDir, { recursive: true });\n\n const logPath = path.join(hooksDir, LOG_FILE);\n this.rotateLogFile(logPath, path.join(hooksDir, LOG_FILE_PREV));\n\n const line = [\n `[${timestamp}]`,\n event.verb,\n event.phase,\n this.oneLine(this.formatDetail(event)),\n ].join('\\t') + '\\n';\n fs.appendFileSync(logPath, line);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n }\n }\n\n // Render only the fields this event actually set, as `key=value` tokens — greppable on one line.\n private formatDetail(event: BranchMutationEvent): string {\n const parts: string[] = [];\n if (event.fromBranch !== '' || event.toBranch !== '') parts.push(`from=${event.fromBranch || '?'} to=${event.toBranch || '?'}`);\n if (event.oldMain !== '' || event.newMain !== '') parts.push(`oldMain=${event.oldMain || '?'} newMain=${event.newMain || '?'}`);\n if (event.conflict) parts.push('conflict=true');\n if (event.conflictFiles.length > 0) parts.push(`conflictFiles=${event.conflictFiles.length}(${event.conflictFiles.join(',')})`);\n if (event.outcome !== '') parts.push(`outcome=${event.outcome}`);\n for (const artifact of event.artifacts) parts.push(`artifact=${artifact}`);\n return parts.join(' ');\n }\n\n // Collapse newlines/tabs and cap length so one event is always exactly one log line.\n private oneLine(value: string): string {\n const flat = value.replace(/[\\t\\r\\n]+/g, ' ').trim();\n return flat.length <= MAX_DETAIL_LEN ? flat : flat.slice(0, MAX_DETAIL_LEN) + '…';\n }\n\n private rotateLogFile(logPath: string, prevPath: string): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const stat = fs.statSync(logPath);\n if (stat.size > MAX_LOG_BYTES) {\n if (fs.existsSync(prevPath)) fs.unlinkSync(prevPath);\n fs.renameSync(logPath, prevPath);\n }\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n }\n }\n}\n\n// Temporary migration delegators to BranchMutationLog — removed once consumers inject it.\nconst branchMutationLogSvc = new BranchMutationLog();\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it\nexport function branchMutationLogPath(root: string): string {\n return branchMutationLogSvc.branchMutationLogPath(root);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it\nexport function logBranchMutation(root: string, event: BranchMutationEvent): void {\n branchMutationLogSvc.logBranchMutation(root, event);\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;
|