@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/src/diff-scope.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Shared git-diff + diff-scoping
|
|
4
|
-
* (nx-webpieces-rules). Centralized here in rules-config because it is the one package both
|
|
5
|
-
* those depend on, and it already shells out to git (see skip-rule.ts).
|
|
3
|
+
* Shared git-diff + diff-scoping service for ALL rule validators (code-rules) and nx executors
|
|
4
|
+
* (nx-webpieces-rules). Centralized here in rules-config because it is the one package both depend on.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - `getChangedFiles(..., { tsOnly: false })` reproduces validate-dtos' all-files diff.
|
|
11
|
-
* - `detectBase` replaces both the nested-try and the ref-loop spellings (identical behavior).
|
|
6
|
+
* `@provideSingleton` so it can be injected and appear in the rules-config DI design. Free-function
|
|
7
|
+
* delegators are kept temporarily so the many existing consumers stay green; they migrate to injecting
|
|
8
|
+
* {@link DiffScope} over follow-up PRs, then the delegators are removed.
|
|
12
9
|
*/
|
|
13
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.ChangedFilesOptions = exports.DiffRange = void 0;
|
|
11
|
+
exports.DiffScope = exports.ChangedFilesOptions = exports.DiffRange = void 0;
|
|
15
12
|
exports.detectBase = detectBase;
|
|
16
13
|
exports.resolveBase = resolveBase;
|
|
17
14
|
exports.getChangedFiles = getChangedFiles;
|
|
@@ -24,6 +21,8 @@ const tslib_1 = require("tslib");
|
|
|
24
21
|
const child_process_1 = require("child_process");
|
|
25
22
|
const fs = tslib_1.__importStar(require("fs"));
|
|
26
23
|
const path = tslib_1.__importStar(require("path"));
|
|
24
|
+
const core_context_1 = require("@webpieces/core-context");
|
|
25
|
+
const inversify_1 = require("inversify");
|
|
27
26
|
const to_error_1 = require("./to-error");
|
|
28
27
|
/** A git diff range: the base ref to compare against and an optional head (else the working tree). */
|
|
29
28
|
class DiffRange {
|
|
@@ -36,202 +35,216 @@ class ChangedFilesOptions {
|
|
|
36
35
|
tsOnly;
|
|
37
36
|
}
|
|
38
37
|
exports.ChangedFilesOptions = ChangedFilesOptions;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
function isTestFile(file) {
|
|
44
|
-
return file.includes('.spec.ts') || file.includes('.test.ts') || file.includes('__tests__/');
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Auto-detect the diff base: the merge-base of HEAD with origin/main, falling back to local main.
|
|
48
|
-
* Returns null when neither ref resolves (e.g. shallow clone with no main) — callers treat null as
|
|
49
|
-
* "no base detected" and typically skip.
|
|
50
|
-
*/
|
|
51
|
-
function detectBase(workspaceRoot) {
|
|
52
|
-
for (const ref of ['origin/main', 'main']) {
|
|
53
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
54
|
-
try {
|
|
55
|
-
const merged = (0, child_process_1.execSync)(`git merge-base HEAD ${ref}`, {
|
|
56
|
-
cwd: workspaceRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
-
}).trim();
|
|
58
|
-
if (merged)
|
|
59
|
-
return merged;
|
|
60
|
-
}
|
|
61
|
-
catch (err) {
|
|
62
|
-
const error = (0, to_error_1.toError)(err);
|
|
63
|
-
void error; // swallow — try the next ref
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Resolve the diff range a rule should compare against. Honors nx's NX_BASE / NX_HEAD (set by
|
|
70
|
-
* `nx affected --base=.. --head=..`); when NX_BASE is unset, auto-detects via detectBase. A returned
|
|
71
|
-
* `base` of undefined means "could not determine a base" (caller should skip).
|
|
72
|
-
*/
|
|
73
|
-
function resolveBase(workspaceRoot) {
|
|
74
|
-
const range = new DiffRange();
|
|
75
|
-
range.base = process.env['NX_BASE'];
|
|
76
|
-
range.head = process.env['NX_HEAD'];
|
|
77
|
-
if (!range.base) {
|
|
78
|
-
range.base = detectBase(workspaceRoot) ?? undefined;
|
|
79
|
-
}
|
|
80
|
-
return range;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Changed files between base and head (or base→working-tree when head is omitted). When head is
|
|
84
|
-
* omitted, untracked files are unioned in too (matching `nx affected`). `tsOnly` (default true)
|
|
85
|
-
* restricts to *.ts/*.tsx and drops test files; pass false for an all-files diff.
|
|
86
|
-
*
|
|
87
|
-
* Deletions are excluded (`--diff-filter=d`): every consumer reasons about a file's current
|
|
88
|
-
* content or location, and a path that no longer exists can't violate anything. This also fixes
|
|
89
|
-
* renames — without rename detection git reports a rename as delete+add, so filtering the delete
|
|
90
|
-
* side leaves only the file's NEW path in the list.
|
|
91
|
-
*/
|
|
92
|
-
// webpieces-disable max-lines-new-methods -- git command handling with untracked files needs several code paths
|
|
93
|
-
function getChangedFiles(workspaceRoot, base, head, opts) {
|
|
94
|
-
const tsOnly = opts?.tsOnly ?? true;
|
|
95
|
-
const glob = tsOnly ? " -- '*.ts' '*.tsx'" : '';
|
|
96
|
-
const keep = (f) => f.length > 0 && (!tsOnly || !isTestFile(f));
|
|
97
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
98
|
-
try {
|
|
99
|
-
const diffTarget = head ? `${base} ${head}` : base;
|
|
100
|
-
const output = (0, child_process_1.execSync)(`git diff --name-only --diff-filter=d ${diffTarget}${glob}`, {
|
|
101
|
-
cwd: workspaceRoot,
|
|
102
|
-
encoding: 'utf-8',
|
|
103
|
-
});
|
|
104
|
-
const changedFiles = output.trim().split('\n').filter(keep);
|
|
105
|
-
// Working-tree comparison (no head): also include untracked files, as nx affected does.
|
|
106
|
-
if (!head) {
|
|
38
|
+
let DiffScope = class DiffScope {
|
|
39
|
+
/** Auto-detect the diff base: merge-base of HEAD with origin/main, falling back to local main. */
|
|
40
|
+
detectBase(workspaceRoot) {
|
|
41
|
+
for (const ref of ['origin/main', 'main']) {
|
|
107
42
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
108
43
|
try {
|
|
109
|
-
const
|
|
110
|
-
cwd: workspaceRoot,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return Array.from(new Set([...changedFiles, ...untrackedFiles]));
|
|
44
|
+
const merged = (0, child_process_1.execSync)(`git merge-base HEAD ${ref}`, {
|
|
45
|
+
cwd: workspaceRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
46
|
+
}).trim();
|
|
47
|
+
if (merged)
|
|
48
|
+
return merged;
|
|
115
49
|
}
|
|
116
50
|
catch (err) {
|
|
117
51
|
const error = (0, to_error_1.toError)(err);
|
|
118
|
-
void error; // swallow —
|
|
119
|
-
return changedFiles;
|
|
52
|
+
void error; // swallow — try the next ref
|
|
120
53
|
}
|
|
121
54
|
}
|
|
122
|
-
return
|
|
55
|
+
return null;
|
|
123
56
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
57
|
+
/** Resolve the diff range a rule should compare against (honors nx's NX_BASE / NX_HEAD). */
|
|
58
|
+
resolveBase(workspaceRoot) {
|
|
59
|
+
const range = new DiffRange();
|
|
60
|
+
range.base = process.env['NX_BASE'];
|
|
61
|
+
range.head = process.env['NX_HEAD'];
|
|
62
|
+
if (!range.base) {
|
|
63
|
+
range.base = this.detectBase(workspaceRoot) ?? undefined;
|
|
64
|
+
}
|
|
65
|
+
return range;
|
|
128
66
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Changed files between base and head (or base→working-tree when head is omitted). Untracked files
|
|
69
|
+
* are unioned in for the working-tree case. `tsOnly` (default true) restricts to *.ts/*.tsx and
|
|
70
|
+
* drops test files. Deletions are excluded (`--diff-filter=d`).
|
|
71
|
+
*/
|
|
72
|
+
// webpieces-disable max-lines-new-methods -- git command handling with untracked files needs several code paths
|
|
73
|
+
getChangedFiles(workspaceRoot, base, head, opts) {
|
|
74
|
+
const tsOnly = opts?.tsOnly ?? true;
|
|
75
|
+
const glob = tsOnly ? " -- '*.ts' '*.tsx'" : '';
|
|
76
|
+
const keep = (f) => f.length > 0 && (!tsOnly || !this.isTestFile(f));
|
|
77
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
78
|
+
try {
|
|
79
|
+
const diffTarget = head ? `${base} ${head}` : base;
|
|
80
|
+
const output = (0, child_process_1.execSync)(`git diff --name-only --diff-filter=d ${diffTarget}${glob}`, {
|
|
81
|
+
cwd: workspaceRoot,
|
|
82
|
+
encoding: 'utf-8',
|
|
83
|
+
});
|
|
84
|
+
const changedFiles = output.trim().split('\n').filter(keep);
|
|
85
|
+
// Working-tree comparison (no head): also include untracked files, as nx affected does.
|
|
86
|
+
if (!head) {
|
|
87
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
88
|
+
try {
|
|
89
|
+
const untrackedOutput = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard${glob}`, {
|
|
90
|
+
cwd: workspaceRoot,
|
|
91
|
+
encoding: 'utf-8',
|
|
92
|
+
});
|
|
93
|
+
const untrackedFiles = untrackedOutput.trim().split('\n').filter(keep);
|
|
94
|
+
return Array.from(new Set([...changedFiles, ...untrackedFiles]));
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
const error = (0, to_error_1.toError)(err);
|
|
98
|
+
void error; // swallow — ls-files failure falls back to the tracked list
|
|
99
|
+
return changedFiles;
|
|
152
100
|
}
|
|
153
101
|
}
|
|
102
|
+
return changedFiles;
|
|
154
103
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
void error; // swallow — git diff failure returns no diff
|
|
160
|
-
return '';
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Parse a unified diff and return the set of added/changed line numbers (the `+` lines per hunk).
|
|
165
|
-
* This is the basis of NEW_AND_MODIFIED_CODE (line-level) scoping.
|
|
166
|
-
*/
|
|
167
|
-
function getChangedLineNumbers(diffContent) {
|
|
168
|
-
const changedLines = new Set();
|
|
169
|
-
const lines = diffContent.split('\n');
|
|
170
|
-
let currentLine = 0;
|
|
171
|
-
for (const line of lines) {
|
|
172
|
-
const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
173
|
-
if (hunkMatch) {
|
|
174
|
-
currentLine = parseInt(hunkMatch[1], 10);
|
|
175
|
-
continue;
|
|
104
|
+
catch (err) {
|
|
105
|
+
const error = (0, to_error_1.toError)(err);
|
|
106
|
+
void error; // swallow — git diff failure returns an empty list
|
|
107
|
+
return [];
|
|
176
108
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
109
|
+
}
|
|
110
|
+
/** Diff content for a single file (synthetic all-added diff for an untracked file with no head). */
|
|
111
|
+
getFileDiff(workspaceRoot, file, base, head) {
|
|
112
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
113
|
+
try {
|
|
114
|
+
const diffTarget = head ? `${base} ${head}` : base;
|
|
115
|
+
const diff = (0, child_process_1.execSync)(`git diff ${diffTarget} -- "${file}"`, {
|
|
116
|
+
cwd: workspaceRoot,
|
|
117
|
+
encoding: 'utf-8',
|
|
118
|
+
});
|
|
119
|
+
if (!diff && !head) {
|
|
120
|
+
const fullPath = path.join(workspaceRoot, file);
|
|
121
|
+
if (fs.existsSync(fullPath)) {
|
|
122
|
+
const isUntracked = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard "${file}"`, {
|
|
123
|
+
cwd: workspaceRoot,
|
|
124
|
+
encoding: 'utf-8',
|
|
125
|
+
}).trim();
|
|
126
|
+
if (isUntracked) {
|
|
127
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
128
|
+
return content.split('\n').map((l) => `+${l}`).join('\n');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return diff;
|
|
180
133
|
}
|
|
181
|
-
|
|
182
|
-
|
|
134
|
+
catch (err) {
|
|
135
|
+
const error = (0, to_error_1.toError)(err);
|
|
136
|
+
void error; // swallow — git diff failure returns no diff
|
|
137
|
+
return '';
|
|
183
138
|
}
|
|
184
|
-
|
|
185
|
-
|
|
139
|
+
}
|
|
140
|
+
/** Added/changed line numbers (the `+` lines per hunk) — basis of NEW_AND_MODIFIED_CODE scoping. */
|
|
141
|
+
getChangedLineNumbers(diffContent) {
|
|
142
|
+
const changedLines = new Set();
|
|
143
|
+
const lines = diffContent.split('\n');
|
|
144
|
+
let currentLine = 0;
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
147
|
+
if (hunkMatch) {
|
|
148
|
+
currentLine = parseInt(hunkMatch[1], 10);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
152
|
+
changedLines.add(currentLine);
|
|
153
|
+
currentLine++;
|
|
154
|
+
}
|
|
155
|
+
else if (line.startsWith('-') && !line.startsWith('---')) {
|
|
156
|
+
// Deletions don't advance the new-file line counter.
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
currentLine++;
|
|
160
|
+
}
|
|
186
161
|
}
|
|
162
|
+
return changedLines;
|
|
187
163
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {
|
|
209
|
-
newMethods.add(methodName);
|
|
164
|
+
/** Method names whose signature line is a `+` addition in the diff — the basis of "NEW" methods. */
|
|
165
|
+
findNewMethodSignaturesInDiff(diffContent) {
|
|
166
|
+
const newMethods = new Set();
|
|
167
|
+
const lines = diffContent.split('\n');
|
|
168
|
+
const patterns = [
|
|
169
|
+
/^\+\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
|
|
170
|
+
/^\+\s*(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\(/,
|
|
171
|
+
/^\+\s*(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?function/,
|
|
172
|
+
/^\+\s*(?:(?:public|private|protected)\s+)?(?:static\s+)?(?:async\s+)?(\w+)\s*\(/,
|
|
173
|
+
];
|
|
174
|
+
for (const line of lines) {
|
|
175
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
176
|
+
for (const pattern of patterns) {
|
|
177
|
+
const match = line.match(pattern);
|
|
178
|
+
if (match) {
|
|
179
|
+
const methodName = match[1];
|
|
180
|
+
if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {
|
|
181
|
+
newMethods.add(methodName);
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
210
184
|
}
|
|
211
|
-
break;
|
|
212
185
|
}
|
|
213
186
|
}
|
|
214
187
|
}
|
|
188
|
+
return newMethods;
|
|
215
189
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
for (let line = startLine; line <= endLine; line++) {
|
|
223
|
-
if (changedLines.has(line)) {
|
|
224
|
-
return true;
|
|
190
|
+
/** True if any line in [startLine, endLine] is in the changedLines set. */
|
|
191
|
+
hasChangesInRange(startLine, endLine, changedLines) {
|
|
192
|
+
for (let line = startLine; line <= endLine; line++) {
|
|
193
|
+
if (changedLines.has(line)) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
225
196
|
}
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
/** True if a node (method/function) is newly added or has any changed line in its range. */
|
|
200
|
+
isNewOrModified(name, startLine, endLine, changedLines, newMethodNames) {
|
|
201
|
+
if (newMethodNames.has(name))
|
|
202
|
+
return true;
|
|
203
|
+
return this.hasChangesInRange(startLine, endLine, changedLines);
|
|
204
|
+
}
|
|
205
|
+
// A file is "a test file" (excluded from diff-scoped rules) when it is a .spec/.test file or lives
|
|
206
|
+
// under a __tests__/ directory.
|
|
207
|
+
isTestFile(file) {
|
|
208
|
+
return file.includes('.spec.ts') || file.includes('.test.ts') || file.includes('__tests__/');
|
|
226
209
|
}
|
|
227
|
-
|
|
210
|
+
};
|
|
211
|
+
exports.DiffScope = DiffScope;
|
|
212
|
+
exports.DiffScope = DiffScope = tslib_1.__decorate([
|
|
213
|
+
(0, core_context_1.provideSingleton)(),
|
|
214
|
+
(0, inversify_1.injectable)()
|
|
215
|
+
], DiffScope);
|
|
216
|
+
// Temporary migration delegators to DiffScope — removed once consumers inject it.
|
|
217
|
+
const diffScopeSvc = new DiffScope();
|
|
218
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
219
|
+
function detectBase(workspaceRoot) {
|
|
220
|
+
return diffScopeSvc.detectBase(workspaceRoot);
|
|
228
221
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
222
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
223
|
+
function resolveBase(workspaceRoot) {
|
|
224
|
+
return diffScopeSvc.resolveBase(workspaceRoot);
|
|
225
|
+
}
|
|
226
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
227
|
+
function getChangedFiles(workspaceRoot, base, head, opts) {
|
|
228
|
+
return diffScopeSvc.getChangedFiles(workspaceRoot, base, head, opts);
|
|
229
|
+
}
|
|
230
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
231
|
+
function getFileDiff(workspaceRoot, file, base, head) {
|
|
232
|
+
return diffScopeSvc.getFileDiff(workspaceRoot, file, base, head);
|
|
233
|
+
}
|
|
234
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
235
|
+
function getChangedLineNumbers(diffContent) {
|
|
236
|
+
return diffScopeSvc.getChangedLineNumbers(diffContent);
|
|
237
|
+
}
|
|
238
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
239
|
+
function findNewMethodSignaturesInDiff(diffContent) {
|
|
240
|
+
return diffScopeSvc.findNewMethodSignaturesInDiff(diffContent);
|
|
241
|
+
}
|
|
242
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
243
|
+
function hasChangesInRange(startLine, endLine, changedLines) {
|
|
244
|
+
return diffScopeSvc.hasChangesInRange(startLine, endLine, changedLines);
|
|
245
|
+
}
|
|
246
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it
|
|
232
247
|
function isNewOrModified(name, startLine, endLine, changedLines, newMethodNames) {
|
|
233
|
-
|
|
234
|
-
return true;
|
|
235
|
-
return hasChangesInRange(startLine, endLine, changedLines);
|
|
248
|
+
return diffScopeSvc.isNewOrModified(name, startLine, endLine, changedLines, newMethodNames);
|
|
236
249
|
}
|
|
237
250
|
//# sourceMappingURL=diff-scope.js.map
|
package/src/diff-scope.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff-scope.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/diff-scope.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared git-diff + diff-scoping helpers for ALL rule validators (code-rules) and nx executors\n * (nx-webpieces-rules). Centralized here in rules-config because it is the one package both of\n * those depend on, and it already shells out to git (see skip-rule.ts).\n *\n * Before this module these functions were copy-pasted ~15× (one private copy per validator + the\n * validate-ts-in-src executor). They are now defined once; every consumer imports from\n * `@webpieces/rules-config`. The two historical variants are preserved as parameters:\n * - `getChangedFiles(..., { tsOnly: false })` reproduces validate-dtos' all-files diff.\n * - `detectBase` replaces both the nested-try and the ref-loop spellings (identical behavior).\n */\n\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport { toError } from './to-error';\n\n/** A git diff range: the base ref to compare against and an optional head (else the working tree). */\nexport class DiffRange {\n base?: string;\n head?: string;\n}\n\n/** Options for getChangedFiles. `tsOnly` (default true) restricts to *.ts/*.tsx and drops test files. */\nexport class ChangedFilesOptions {\n tsOnly?: boolean;\n}\n\n/**\n * A file is \"a test file\" (excluded from diff-scoped rules) when it is a .spec/.test file or lives\n * under a __tests__/ directory. Union of every per-validator filter so no consumer loses coverage.\n */\nfunction isTestFile(file: string): boolean {\n return file.includes('.spec.ts') || file.includes('.test.ts') || file.includes('__tests__/');\n}\n\n/**\n * Auto-detect the diff base: the merge-base of HEAD with origin/main, falling back to local main.\n * Returns null when neither ref resolves (e.g. shallow clone with no main) — callers treat null as\n * \"no base detected\" and typically skip.\n */\nexport function detectBase(workspaceRoot: string): string | null {\n for (const ref of ['origin/main', 'main']) {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const merged = execSync(`git merge-base HEAD ${ref}`, {\n cwd: workspaceRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (merged) return merged;\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — try the next ref\n }\n }\n return null;\n}\n\n/**\n * Resolve the diff range a rule should compare against. Honors nx's NX_BASE / NX_HEAD (set by\n * `nx affected --base=.. --head=..`); when NX_BASE is unset, auto-detects via detectBase. A returned\n * `base` of undefined means \"could not determine a base\" (caller should skip).\n */\nexport function resolveBase(workspaceRoot: string): DiffRange {\n const range = new DiffRange();\n range.base = process.env['NX_BASE'];\n range.head = process.env['NX_HEAD'];\n if (!range.base) {\n range.base = detectBase(workspaceRoot) ?? undefined;\n }\n return range;\n}\n\n/**\n * Changed files between base and head (or base→working-tree when head is omitted). When head is\n * omitted, untracked files are unioned in too (matching `nx affected`). `tsOnly` (default true)\n * restricts to *.ts/*.tsx and drops test files; pass false for an all-files diff.\n *\n * Deletions are excluded (`--diff-filter=d`): every consumer reasons about a file's current\n * content or location, and a path that no longer exists can't violate anything. This also fixes\n * renames — without rename detection git reports a rename as delete+add, so filtering the delete\n * side leaves only the file's NEW path in the list.\n */\n// webpieces-disable max-lines-new-methods -- git command handling with untracked files needs several code paths\nexport function getChangedFiles(\n workspaceRoot: string,\n base: string,\n head?: string,\n opts?: ChangedFilesOptions,\n): string[] {\n const tsOnly = opts?.tsOnly ?? true;\n const glob = tsOnly ? \" -- '*.ts' '*.tsx'\" : '';\n const keep = (f: string): boolean => f.length > 0 && (!tsOnly || !isTestFile(f));\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only --diff-filter=d ${diffTarget}${glob}`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output.trim().split('\\n').filter(keep);\n\n // Working-tree comparison (no head): also include untracked files, as nx affected does.\n if (!head) {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const untrackedOutput = execSync(`git ls-files --others --exclude-standard${glob}`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const untrackedFiles = untrackedOutput.trim().split('\\n').filter(keep);\n return Array.from(new Set([...changedFiles, ...untrackedFiles]));\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — ls-files failure falls back to the tracked list\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — git diff failure returns an empty list\n return [];\n }\n}\n\n/**\n * Diff content for a single file. When the file is untracked (and no head is given) a synthetic\n * all-added diff is produced so new files count as fully-changed.\n */\nexport function getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const diff = execSync(`git diff ${diffTarget} -- \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n\n if (!diff && !head) {\n const fullPath = path.join(workspaceRoot, file);\n if (fs.existsSync(fullPath)) {\n const isUntracked = execSync(`git ls-files --others --exclude-standard \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n }).trim();\n\n if (isUntracked) {\n const content = fs.readFileSync(fullPath, 'utf-8');\n return content.split('\\n').map((l: string) => `+${l}`).join('\\n');\n }\n }\n }\n\n return diff;\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — git diff failure returns no diff\n return '';\n }\n}\n\n/**\n * Parse a unified diff and return the set of added/changed line numbers (the `+` lines per hunk).\n * This is the basis of NEW_AND_MODIFIED_CODE (line-level) scoping.\n */\nexport function getChangedLineNumbers(diffContent: string): Set<number> {\n const changedLines = new Set<number>();\n const lines = diffContent.split('\\n');\n let currentLine = 0;\n\n for (const line of lines) {\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (line.startsWith('+') && !line.startsWith('+++')) {\n changedLines.add(currentLine);\n currentLine++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n // Deletions don't advance the new-file line counter.\n } else {\n currentLine++;\n }\n }\n\n return changedLines;\n}\n\n/**\n * Method names whose signature line is a `+` addition in the diff — the basis of \"NEW\" methods.\n */\nexport function findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n const newMethods = new Set<string>();\n const lines = diffContent.split('\\n');\n\n const patterns = [\n /^\\+\\s*(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?function/,\n /^\\+\\s*(?:(?:public|private|protected)\\s+)?(?:static\\s+)?(?:async\\s+)?(\\w+)\\s*\\(/,\n ];\n\n for (const line of lines) {\n if (line.startsWith('+') && !line.startsWith('+++')) {\n for (const pattern of patterns) {\n const match = line.match(pattern);\n if (match) {\n const methodName = match[1];\n if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {\n newMethods.add(methodName);\n }\n break;\n }\n }\n }\n }\n\n return newMethods;\n}\n\n/**\n * True if any line in [startLine, endLine] is in the changedLines set.\n */\nexport function hasChangesInRange(startLine: number, endLine: number, changedLines: Set<number>): boolean {\n for (let line = startLine; line <= endLine; line++) {\n if (changedLines.has(line)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * True if a node (method/function) is newly added or has any changed line in its range.\n */\nexport function isNewOrModified(\n name: string,\n startLine: number,\n endLine: number,\n changedLines: Set<number>,\n newMethodNames: Set<string>,\n): boolean {\n if (newMethodNames.has(name)) return true;\n return hasChangesInRange(startLine, endLine, changedLines);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"diff-scope.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/diff-scope.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared git-diff + diff-scoping service for ALL rule validators (code-rules) and nx executors\n * (nx-webpieces-rules). Centralized here in rules-config because it is the one package both depend on.\n *\n * `@provideSingleton` so it can be injected and appear in the rules-config DI design. Free-function\n * delegators are kept temporarily so the many existing consumers stay green; they migrate to injecting\n * {@link DiffScope} over follow-up PRs, then the delegators are removed.\n */\n\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\n\nimport { toError } from './to-error';\n\n/** A git diff range: the base ref to compare against and an optional head (else the working tree). */\nexport class DiffRange {\n base?: string;\n head?: string;\n}\n\n/** Options for getChangedFiles. `tsOnly` (default true) restricts to *.ts/*.tsx and drops test files. */\nexport class ChangedFilesOptions {\n tsOnly?: boolean;\n}\n\n@provideSingleton()\n@injectable()\nexport class DiffScope {\n /** Auto-detect the diff base: merge-base of HEAD with origin/main, falling back to local main. */\n detectBase(workspaceRoot: string): string | null {\n for (const ref of ['origin/main', 'main']) {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const merged = execSync(`git merge-base HEAD ${ref}`, {\n cwd: workspaceRoot, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (merged) return merged;\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — try the next ref\n }\n }\n return null;\n }\n\n /** Resolve the diff range a rule should compare against (honors nx's NX_BASE / NX_HEAD). */\n resolveBase(workspaceRoot: string): DiffRange {\n const range = new DiffRange();\n range.base = process.env['NX_BASE'];\n range.head = process.env['NX_HEAD'];\n if (!range.base) {\n range.base = this.detectBase(workspaceRoot) ?? undefined;\n }\n return range;\n }\n\n /**\n * Changed files between base and head (or base→working-tree when head is omitted). Untracked files\n * are unioned in for the working-tree case. `tsOnly` (default true) restricts to *.ts/*.tsx and\n * drops test files. Deletions are excluded (`--diff-filter=d`).\n */\n // webpieces-disable max-lines-new-methods -- git command handling with untracked files needs several code paths\n getChangedFiles(workspaceRoot: string, base: string, head?: string, opts?: ChangedFilesOptions): string[] {\n const tsOnly = opts?.tsOnly ?? true;\n const glob = tsOnly ? \" -- '*.ts' '*.tsx'\" : '';\n const keep = (f: string): boolean => f.length > 0 && (!tsOnly || !this.isTestFile(f));\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only --diff-filter=d ${diffTarget}${glob}`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output.trim().split('\\n').filter(keep);\n\n // Working-tree comparison (no head): also include untracked files, as nx affected does.\n if (!head) {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const untrackedOutput = execSync(`git ls-files --others --exclude-standard${glob}`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const untrackedFiles = untrackedOutput.trim().split('\\n').filter(keep);\n return Array.from(new Set([...changedFiles, ...untrackedFiles]));\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — ls-files failure falls back to the tracked list\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — git diff failure returns an empty list\n return [];\n }\n }\n\n /** Diff content for a single file (synthetic all-added diff for an untracked file with no head). */\n getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const diff = execSync(`git diff ${diffTarget} -- \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n\n if (!diff && !head) {\n const fullPath = path.join(workspaceRoot, file);\n if (fs.existsSync(fullPath)) {\n const isUntracked = execSync(`git ls-files --others --exclude-standard \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n }).trim();\n\n if (isUntracked) {\n const content = fs.readFileSync(fullPath, 'utf-8');\n return content.split('\\n').map((l: string) => `+${l}`).join('\\n');\n }\n }\n }\n\n return diff;\n } catch (err: unknown) {\n const error = toError(err);\n void error; // swallow — git diff failure returns no diff\n return '';\n }\n }\n\n /** Added/changed line numbers (the `+` lines per hunk) — basis of NEW_AND_MODIFIED_CODE scoping. */\n getChangedLineNumbers(diffContent: string): Set<number> {\n const changedLines = new Set<number>();\n const lines = diffContent.split('\\n');\n let currentLine = 0;\n\n for (const line of lines) {\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (line.startsWith('+') && !line.startsWith('+++')) {\n changedLines.add(currentLine);\n currentLine++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n // Deletions don't advance the new-file line counter.\n } else {\n currentLine++;\n }\n }\n\n return changedLines;\n }\n\n /** Method names whose signature line is a `+` addition in the diff — the basis of \"NEW\" methods. */\n findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n const newMethods = new Set<string>();\n const lines = diffContent.split('\\n');\n\n const patterns = [\n /^\\+\\s*(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/,\n /^\\+\\s*(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?function/,\n /^\\+\\s*(?:(?:public|private|protected)\\s+)?(?:static\\s+)?(?:async\\s+)?(\\w+)\\s*\\(/,\n ];\n\n for (const line of lines) {\n if (line.startsWith('+') && !line.startsWith('+++')) {\n for (const pattern of patterns) {\n const match = line.match(pattern);\n if (match) {\n const methodName = match[1];\n if (methodName && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(methodName)) {\n newMethods.add(methodName);\n }\n break;\n }\n }\n }\n }\n\n return newMethods;\n }\n\n /** True if any line in [startLine, endLine] is in the changedLines set. */\n hasChangesInRange(startLine: number, endLine: number, changedLines: Set<number>): boolean {\n for (let line = startLine; line <= endLine; line++) {\n if (changedLines.has(line)) {\n return true;\n }\n }\n return false;\n }\n\n /** True if a node (method/function) is newly added or has any changed line in its range. */\n isNewOrModified(\n name: string,\n startLine: number,\n endLine: number,\n changedLines: Set<number>,\n newMethodNames: Set<string>,\n ): boolean {\n if (newMethodNames.has(name)) return true;\n return this.hasChangesInRange(startLine, endLine, changedLines);\n }\n\n // A file is \"a test file\" (excluded from diff-scoped rules) when it is a .spec/.test file or lives\n // under a __tests__/ directory.\n private isTestFile(file: string): boolean {\n return file.includes('.spec.ts') || file.includes('.test.ts') || file.includes('__tests__/');\n }\n}\n\n// Temporary migration delegators to DiffScope — removed once consumers inject it.\nconst diffScopeSvc = new DiffScope();\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function detectBase(workspaceRoot: string): string | null {\n return diffScopeSvc.detectBase(workspaceRoot);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function resolveBase(workspaceRoot: string): DiffRange {\n return diffScopeSvc.resolveBase(workspaceRoot);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function getChangedFiles(workspaceRoot: string, base: string, head?: string, opts?: ChangedFilesOptions): string[] {\n return diffScopeSvc.getChangedFiles(workspaceRoot, base, head, opts);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n return diffScopeSvc.getFileDiff(workspaceRoot, file, base, head);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function getChangedLineNumbers(diffContent: string): Set<number> {\n return diffScopeSvc.getChangedLineNumbers(diffContent);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function findNewMethodSignaturesInDiff(diffContent: string): Set<string> {\n return diffScopeSvc.findNewMethodSignaturesInDiff(diffContent);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function hasChangesInRange(startLine: number, endLine: number, changedLines: Set<number>): boolean {\n return diffScopeSvc.hasChangesInRange(startLine, endLine, changedLines);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to DiffScope; removed once consumers inject it\nexport function isNewOrModified(\n name: string,\n startLine: number,\n endLine: number,\n changedLines: Set<number>,\n newMethodNames: Set<string>,\n): boolean {\n return diffScopeSvc.isNewOrModified(name, startLine, endLine, changedLines, newMethodNames);\n}\n"]}
|
package/src/index.d.ts
CHANGED
|
@@ -4,14 +4,14 @@ export { RuleFailError } from './rule-fail-error';
|
|
|
4
4
|
export { CliExitError } from './cli-exit-error';
|
|
5
5
|
export { runMain } from './run-main';
|
|
6
6
|
export { toError } from './to-error';
|
|
7
|
-
export { loadAndValidate, LoadedConfig } from './load-config';
|
|
8
|
-
export { findConfigFile, CONFIG_FILENAME } from './config-file';
|
|
7
|
+
export { loadAndValidate, LoadedConfig, ConfigLoader } from './load-config';
|
|
8
|
+
export { findConfigFile, CONFIG_FILENAME, ConfigFile } from './config-file';
|
|
9
9
|
export { RepoRootFinder, INSTRUCT_AI_DIR } from './repo-root';
|
|
10
10
|
export { RulesConfigDesign } from './rules-config-design';
|
|
11
11
|
export { ExcludePaths } from './exclude-hook-paths';
|
|
12
12
|
export { isPathExcluded } from './exclude-paths';
|
|
13
13
|
export { defaultRules, defaultRulesDir } from './default-rules';
|
|
14
|
-
export { loadTemplate, writeTemplateIfMissing, writeTemplate } from './load-template';
|
|
14
|
+
export { loadTemplate, writeTemplateIfMissing, writeTemplate, TemplateWriter } from './load-template';
|
|
15
15
|
export { validateWebpiecesConfig, validatePrGateSection, validateSectionPlacement, validateCommandsSection, validateExcludePaths, validateMatchRulesSection, allRuleNames } from './validate-config';
|
|
16
16
|
export { MatchRuleConfig, MatchRuleViolation, findMatchRuleViolations, isMatchRuleAllowedPath, compileMatchRulePatterns, renderMatchRuleMessage, DEFAULT_MATCH_RULES, } from './match-rules-config';
|
|
17
17
|
export type { ConfigSection } from './sections';
|
|
@@ -20,7 +20,7 @@ export { FieldDef } from './field-def';
|
|
|
20
20
|
export type { SchemaShape } from './field-def';
|
|
21
21
|
export { shouldSkipRule, getCurrentBranch } from './skip-rule';
|
|
22
22
|
export type { SkipRuleResult } from './skip-rule';
|
|
23
|
-
export { detectBase, resolveBase, getChangedFiles, getFileDiff, getChangedLineNumbers, findNewMethodSignaturesInDiff, hasChangesInRange, isNewOrModified, } from './diff-scope';
|
|
23
|
+
export { detectBase, resolveBase, getChangedFiles, getFileDiff, getChangedLineNumbers, findNewMethodSignaturesInDiff, hasChangesInRange, isNewOrModified, DiffScope, DiffRange, ChangedFilesOptions, } from './diff-scope';
|
|
24
24
|
export { AbstractRule } from './abstract-rule';
|
|
25
25
|
export { WEBPIECES_DISABLE, RULE_NAMES, hasDisable, WEBPIECES_TMP_DIR, MERGE_INFO_DIR, PR_REVIEW_DIR, MERGE_IN_PROGRESS_FILE, MERGE_EXPLANATION_FILE, } from './constants';
|
|
26
26
|
export { WebpiecesRulesConfig } from './WebpiecesRulesConfig';
|
package/src/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.
|
|
5
|
-
exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationEvent = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = exports.isRefreshInProgress = exports.isLockStale = exports.writeMainSyncLock = exports.readMainSyncLock = exports.writeMainSyncStatus = exports.readMainSyncStatus = exports.mainSyncLockPath = exports.mainSyncStatusPath = exports.DEFAULT_HANG_TIMEOUT_MINUTES = exports.MainSyncLock = exports.MainSyncStatus = exports.reviewJsonSchemaHint = exports.reviewJsonPath = exports.prDirFor = exports.loadReviewJson = exports.ReviewJson = exports.buildPrGateConfig = exports.defaultPrGateConfig = exports.defaultGates = exports.PrGateConfig = exports.GateDefinition = exports.VALIDATE_TS_MODES = exports.STRUCTURAL_MODES = exports.ON_OFF_MODES = exports.THROW_CAUSE_MODES = void 0;
|
|
3
|
+
exports.findNewMethodSignaturesInDiff = exports.getChangedLineNumbers = exports.getFileDiff = exports.getChangedFiles = exports.resolveBase = exports.detectBase = exports.getCurrentBranch = exports.shouldSkipRule = exports.FieldDef = exports.sectionForRule = exports.isHookGuard = exports.HOOK_GUARD_NAMES = exports.DEFAULT_MATCH_RULES = exports.renderMatchRuleMessage = exports.compileMatchRulePatterns = exports.isMatchRuleAllowedPath = exports.findMatchRuleViolations = exports.MatchRuleViolation = exports.MatchRuleConfig = exports.allRuleNames = exports.validateMatchRulesSection = exports.validateExcludePaths = exports.validateCommandsSection = exports.validateSectionPlacement = exports.validatePrGateSection = exports.validateWebpiecesConfig = exports.TemplateWriter = exports.writeTemplate = exports.writeTemplateIfMissing = exports.loadTemplate = exports.defaultRulesDir = exports.defaultRules = exports.isPathExcluded = exports.ExcludePaths = exports.RulesConfigDesign = exports.INSTRUCT_AI_DIR = exports.RepoRootFinder = exports.ConfigFile = exports.CONFIG_FILENAME = exports.findConfigFile = exports.ConfigLoader = exports.LoadedConfig = exports.loadAndValidate = exports.toError = exports.runMain = exports.CliExitError = exports.RuleFailError = exports.InformAiError = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
|
|
4
|
+
exports.RETURN_TYPE_MODES = exports.FILE_LIMIT_MODES = exports.METHOD_LIMIT_MODES = exports.BaseRuleConfig = exports.ValidateTsInSrcConfig = exports.NoJsFilesConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.FeatureBranchGuardConfig = exports.RedirectHowToMergeMainConfig = exports.PrMergeGuardConfig = exports.MergeInProgressGuardConfig = exports.PrCreationOrPushGuardConfig = exports.BranchCreationGuardConfig = exports.RoleTagConfig = exports.FrameworkTagConfig = exports.InjectAnnotationNotNeededForConcreteClassConfig = exports.NoFunctionOutsideClassConfig = exports.NoProcessExitOutsideMainConfig = exports.NoSymbolDiTokensConfig = exports.AngularNoDirectApiInResolverConfig = exports.ThrowCauseRequiredConfig = exports.CatchErrorPatternConfig = exports.NoUnmanagedExceptionsConfig = exports.NoDestructureConfig = exports.PrismaConverterConfig = exports.PrismaValidateDtosConfig = exports.NoImplicitAnyConfig = exports.NoAnyUnknownConfig = exports.NoInlineTypeLiteralsConfig = exports.RequireReturnTypeConfig = exports.MaxFileLinesConfig = exports.MaxMethodLinesConfig = exports.WebpiecesRulesConfig = exports.MERGE_EXPLANATION_FILE = exports.MERGE_IN_PROGRESS_FILE = exports.PR_REVIEW_DIR = exports.MERGE_INFO_DIR = exports.WEBPIECES_TMP_DIR = exports.hasDisable = exports.RULE_NAMES = exports.WEBPIECES_DISABLE = exports.AbstractRule = exports.ChangedFilesOptions = exports.DiffRange = exports.DiffScope = exports.isNewOrModified = exports.hasChangesInRange = void 0;
|
|
5
|
+
exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationEvent = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = exports.isRefreshInProgress = exports.isLockStale = exports.writeMainSyncLock = exports.readMainSyncLock = exports.writeMainSyncStatus = exports.readMainSyncStatus = exports.mainSyncLockPath = exports.mainSyncStatusPath = exports.DEFAULT_HANG_TIMEOUT_MINUTES = exports.MainSyncLock = exports.MainSyncStatus = exports.reviewJsonSchemaHint = exports.reviewJsonPath = exports.prDirFor = exports.loadReviewJson = exports.ReviewJson = exports.buildPrGateConfig = exports.defaultPrGateConfig = exports.defaultGates = exports.PrGateConfig = exports.GateDefinition = exports.VALIDATE_TS_MODES = exports.STRUCTURAL_MODES = exports.ON_OFF_MODES = exports.THROW_CAUSE_MODES = exports.DIRECT_API_RESOLVER_MODES = exports.PRISMA_CONVERTER_MODES = exports.PRISMA_DTOS_MODES = exports.PROJECT_MODES = exports.MODIFIED_CODE_MODES = exports.INLINE_TYPE_MODES = void 0;
|
|
6
6
|
var types_1 = require("./types");
|
|
7
7
|
Object.defineProperty(exports, "ResolvedConfig", { enumerable: true, get: function () { return types_1.ResolvedConfig; } });
|
|
8
8
|
Object.defineProperty(exports, "ResolvedRuleConfig", { enumerable: true, get: function () { return types_1.ResolvedRuleConfig; } });
|
|
@@ -19,9 +19,11 @@ Object.defineProperty(exports, "toError", { enumerable: true, get: function () {
|
|
|
19
19
|
var load_config_1 = require("./load-config");
|
|
20
20
|
Object.defineProperty(exports, "loadAndValidate", { enumerable: true, get: function () { return load_config_1.loadAndValidate; } });
|
|
21
21
|
Object.defineProperty(exports, "LoadedConfig", { enumerable: true, get: function () { return load_config_1.LoadedConfig; } });
|
|
22
|
+
Object.defineProperty(exports, "ConfigLoader", { enumerable: true, get: function () { return load_config_1.ConfigLoader; } });
|
|
22
23
|
var config_file_1 = require("./config-file");
|
|
23
24
|
Object.defineProperty(exports, "findConfigFile", { enumerable: true, get: function () { return config_file_1.findConfigFile; } });
|
|
24
25
|
Object.defineProperty(exports, "CONFIG_FILENAME", { enumerable: true, get: function () { return config_file_1.CONFIG_FILENAME; } });
|
|
26
|
+
Object.defineProperty(exports, "ConfigFile", { enumerable: true, get: function () { return config_file_1.ConfigFile; } });
|
|
25
27
|
var repo_root_1 = require("./repo-root");
|
|
26
28
|
Object.defineProperty(exports, "RepoRootFinder", { enumerable: true, get: function () { return repo_root_1.RepoRootFinder; } });
|
|
27
29
|
Object.defineProperty(exports, "INSTRUCT_AI_DIR", { enumerable: true, get: function () { return repo_root_1.INSTRUCT_AI_DIR; } });
|
|
@@ -38,6 +40,7 @@ var load_template_1 = require("./load-template");
|
|
|
38
40
|
Object.defineProperty(exports, "loadTemplate", { enumerable: true, get: function () { return load_template_1.loadTemplate; } });
|
|
39
41
|
Object.defineProperty(exports, "writeTemplateIfMissing", { enumerable: true, get: function () { return load_template_1.writeTemplateIfMissing; } });
|
|
40
42
|
Object.defineProperty(exports, "writeTemplate", { enumerable: true, get: function () { return load_template_1.writeTemplate; } });
|
|
43
|
+
Object.defineProperty(exports, "TemplateWriter", { enumerable: true, get: function () { return load_template_1.TemplateWriter; } });
|
|
41
44
|
var validate_config_1 = require("./validate-config");
|
|
42
45
|
Object.defineProperty(exports, "validateWebpiecesConfig", { enumerable: true, get: function () { return validate_config_1.validateWebpiecesConfig; } });
|
|
43
46
|
Object.defineProperty(exports, "validatePrGateSection", { enumerable: true, get: function () { return validate_config_1.validatePrGateSection; } });
|
|
@@ -72,6 +75,9 @@ Object.defineProperty(exports, "getChangedLineNumbers", { enumerable: true, get:
|
|
|
72
75
|
Object.defineProperty(exports, "findNewMethodSignaturesInDiff", { enumerable: true, get: function () { return diff_scope_1.findNewMethodSignaturesInDiff; } });
|
|
73
76
|
Object.defineProperty(exports, "hasChangesInRange", { enumerable: true, get: function () { return diff_scope_1.hasChangesInRange; } });
|
|
74
77
|
Object.defineProperty(exports, "isNewOrModified", { enumerable: true, get: function () { return diff_scope_1.isNewOrModified; } });
|
|
78
|
+
Object.defineProperty(exports, "DiffScope", { enumerable: true, get: function () { return diff_scope_1.DiffScope; } });
|
|
79
|
+
Object.defineProperty(exports, "DiffRange", { enumerable: true, get: function () { return diff_scope_1.DiffRange; } });
|
|
80
|
+
Object.defineProperty(exports, "ChangedFilesOptions", { enumerable: true, get: function () { return diff_scope_1.ChangedFilesOptions; } });
|
|
75
81
|
var abstract_rule_1 = require("./abstract-rule");
|
|
76
82
|
Object.defineProperty(exports, "AbstractRule", { enumerable: true, get: function () { return abstract_rule_1.AbstractRule; } });
|
|
77
83
|
var constants_1 = require("./constants");
|