@webpieces/code-rules 0.0.1 → 0.2.113

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.
Files changed (63) hide show
  1. package/package.json +4 -3
  2. package/src/cli.d.ts +1 -0
  3. package/src/cli.js +19 -0
  4. package/src/cli.js.map +1 -0
  5. package/src/diff-utils.d.ts +24 -0
  6. package/src/{diff-utils.ts → diff-utils.js} +30 -38
  7. package/src/diff-utils.js.map +1 -0
  8. package/src/from-shared-config.d.ts +28 -0
  9. package/src/from-shared-config.js +119 -0
  10. package/src/from-shared-config.js.map +1 -0
  11. package/src/index.js +33 -0
  12. package/src/index.js.map +1 -0
  13. package/src/validate-catch-error-pattern.d.ts +47 -0
  14. package/src/{validate-catch-error-pattern.ts → validate-catch-error-pattern.js} +74 -195
  15. package/src/validate-catch-error-pattern.js.map +1 -0
  16. package/src/validate-code.d.ts +98 -0
  17. package/src/{validate-code.ts → validate-code.js} +65 -259
  18. package/src/validate-code.js.map +1 -0
  19. package/src/validate-dtos.d.ts +41 -0
  20. package/src/{validate-dtos.ts → validate-dtos.js} +88 -215
  21. package/src/validate-dtos.js.map +1 -0
  22. package/src/validate-modified-files.d.ts +24 -0
  23. package/src/{validate-modified-files.ts → validate-modified-files.js} +46 -115
  24. package/src/validate-modified-files.js.map +1 -0
  25. package/src/validate-modified-methods.d.ts +30 -0
  26. package/src/{validate-modified-methods.ts → validate-modified-methods.js} +94 -196
  27. package/src/validate-modified-methods.js.map +1 -0
  28. package/src/validate-new-methods.d.ts +27 -0
  29. package/src/{validate-new-methods.ts → validate-new-methods.js} +63 -133
  30. package/src/validate-new-methods.js.map +1 -0
  31. package/src/validate-no-any-unknown.d.ts +41 -0
  32. package/src/{validate-no-any-unknown.ts → validate-no-any-unknown.js} +69 -146
  33. package/src/validate-no-any-unknown.js.map +1 -0
  34. package/src/validate-no-destructure.d.ts +51 -0
  35. package/src/{validate-no-destructure.ts → validate-no-destructure.js} +80 -166
  36. package/src/validate-no-destructure.js.map +1 -0
  37. package/src/validate-no-direct-api-resolver.d.ts +46 -0
  38. package/src/{validate-no-direct-api-resolver.ts → validate-no-direct-api-resolver.js} +112 -211
  39. package/src/validate-no-direct-api-resolver.js.map +1 -0
  40. package/src/validate-no-implicit-any.d.ts +36 -0
  41. package/src/{validate-no-implicit-any.ts → validate-no-implicit-any.js} +94 -141
  42. package/src/validate-no-implicit-any.js.map +1 -0
  43. package/src/validate-no-inline-types.d.ts +90 -0
  44. package/src/{validate-no-inline-types.ts → validate-no-inline-types.js} +93 -198
  45. package/src/validate-no-inline-types.js.map +1 -0
  46. package/src/validate-no-unmanaged-exceptions.d.ts +43 -0
  47. package/src/{validate-no-unmanaged-exceptions.ts → validate-no-unmanaged-exceptions.js} +71 -140
  48. package/src/validate-no-unmanaged-exceptions.js.map +1 -0
  49. package/src/validate-prisma-converters.d.ts +59 -0
  50. package/src/{validate-prisma-converters.ts → validate-prisma-converters.js} +120 -307
  51. package/src/validate-prisma-converters.js.map +1 -0
  52. package/src/validate-return-types.d.ts +28 -0
  53. package/src/{validate-return-types.ts → validate-return-types.js} +84 -168
  54. package/src/validate-return-types.js.map +1 -0
  55. package/LICENSE +0 -373
  56. package/jest.config.ts +0 -20
  57. package/project.json +0 -22
  58. package/src/cli.ts +0 -17
  59. package/src/from-shared-config.ts +0 -118
  60. package/tsconfig.json +0 -22
  61. package/tsconfig.lib.json +0 -10
  62. package/tsconfig.spec.json +0 -14
  63. /package/src/{index.ts → index.d.ts} +0 -0
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Validate No Direct API in Resolver Executor
3
4
  *
@@ -33,49 +34,23 @@
33
34
  * // webpieces-disable no-direct-api-resolver -- [your justification]
34
35
  * const myApi = inject(MyApi);
35
36
  */
36
-
37
- import { execSync } from 'child_process';
38
- import * as fs from 'fs';
39
- import * as path from 'path';
40
- import * as ts from 'typescript';
41
- import { getFileDiff, getChangedLineNumbers, findNewMethodSignaturesInDiff } from './diff-utils';
42
-
43
- export type NoDirectApiResolverMode = 'OFF' | 'MODIFIED_CODE' | 'NEW_AND_MODIFIED_METHODS' | 'MODIFIED_FILES';
44
-
45
- export interface ValidateNoDirectApiResolverOptions {
46
- mode?: NoDirectApiResolverMode;
47
- disableAllowed?: boolean;
48
- ignoreModifiedUntilEpoch?: number;
49
- enforcePaths?: string[];
50
- }
51
-
52
- export interface ExecutorResult {
53
- success: boolean;
54
- }
55
-
56
- interface Violation {
57
- file: string;
58
- line: number;
59
- column: number;
60
- context: string;
61
- }
62
-
63
- interface ViolationInfo {
64
- line: number;
65
- column: number;
66
- context: string;
67
- hasDisableComment: boolean;
68
- }
69
-
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.default = runValidator;
39
+ const tslib_1 = require("tslib");
40
+ const child_process_1 = require("child_process");
41
+ const fs = tslib_1.__importStar(require("fs"));
42
+ const path = tslib_1.__importStar(require("path"));
43
+ const ts = tslib_1.__importStar(require("typescript"));
44
+ const diff_utils_1 = require("./diff-utils");
70
45
  /**
71
46
  * Get changed TypeScript files between base and head (or working tree if head not specified).
72
47
  */
73
48
  // webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths
74
- function getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {
49
+ function getChangedTypeScriptFiles(workspaceRoot, base, head) {
75
50
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
76
51
  try {
77
52
  const diffTarget = head ? `${base} ${head}` : base;
78
- const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
53
+ const output = (0, child_process_1.execSync)(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
79
54
  cwd: workspaceRoot,
80
55
  encoding: 'utf-8',
81
56
  });
@@ -83,11 +58,10 @@ function getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: s
83
58
  .trim()
84
59
  .split('\n')
85
60
  .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
86
-
87
61
  if (!head) {
88
62
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
89
63
  try {
90
- const untrackedOutput = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
64
+ const untrackedOutput = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
91
65
  cwd: workspaceRoot,
92
66
  encoding: 'utf-8',
93
67
  });
@@ -97,23 +71,23 @@ function getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: s
97
71
  .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
98
72
  const allFiles = new Set([...changedFiles, ...untrackedFiles]);
99
73
  return Array.from(allFiles);
100
- } catch (err: unknown) {
74
+ }
75
+ catch (err) {
101
76
  //const error = toError(err);
102
77
  return changedFiles;
103
78
  }
104
79
  }
105
-
106
80
  return changedFiles;
107
- } catch (err: unknown) {
81
+ }
82
+ catch (err) {
108
83
  //const error = toError(err);
109
84
  return [];
110
85
  }
111
86
  }
112
-
113
87
  /**
114
88
  * Check if a line contains a webpieces-disable comment for no-direct-api-resolver.
115
89
  */
116
- function hasDisableComment(lines: string[], lineNumber: number): boolean {
90
+ function hasDisableComment(lines, lineNumber) {
117
91
  const startCheck = Math.max(0, lineNumber - 5);
118
92
  for (let i = lineNumber - 2; i >= startCheck; i--) {
119
93
  const line = lines[i]?.trim() ?? '';
@@ -126,60 +100,56 @@ function hasDisableComment(lines: string[], lineNumber: number): boolean {
126
100
  }
127
101
  return false;
128
102
  }
129
-
130
103
  /**
131
104
  * Auto-detect the base branch by finding the merge-base with origin/main.
132
105
  */
133
- function detectBase(workspaceRoot: string): string | null {
106
+ function detectBase(workspaceRoot) {
134
107
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
135
108
  try {
136
- const mergeBase = execSync('git merge-base HEAD origin/main', {
109
+ const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD origin/main', {
137
110
  cwd: workspaceRoot,
138
111
  encoding: 'utf-8',
139
112
  stdio: ['pipe', 'pipe', 'pipe'],
140
113
  }).trim();
141
-
142
114
  if (mergeBase) {
143
115
  return mergeBase;
144
116
  }
145
- } catch (err: unknown) {
117
+ }
118
+ catch (err) {
146
119
  //const error = toError(err);
147
120
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
148
121
  try {
149
- const mergeBase = execSync('git merge-base HEAD main', {
122
+ const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD main', {
150
123
  cwd: workspaceRoot,
151
124
  encoding: 'utf-8',
152
125
  stdio: ['pipe', 'pipe', 'pipe'],
153
126
  }).trim();
154
-
155
127
  if (mergeBase) {
156
128
  return mergeBase;
157
129
  }
158
- } catch (err2: unknown) {
130
+ }
131
+ catch (err2) {
159
132
  //const error2 = toError(err2);
160
133
  // Ignore
161
134
  }
162
135
  }
163
136
  return null;
164
137
  }
165
-
166
138
  /**
167
139
  * Find inject(XxxApi) calls in *.routes.ts files.
168
140
  * Flags any CallExpression where callee is `inject` and the first argument is an identifier ending with `Api`.
169
141
  */
170
- function findDirectApiInjections(filePath: string, workspaceRoot: string, disableAllowed: boolean): ViolationInfo[] {
171
- if (!filePath.endsWith('.routes.ts')) return [];
172
-
142
+ function findDirectApiInjections(filePath, workspaceRoot, disableAllowed) {
143
+ if (!filePath.endsWith('.routes.ts'))
144
+ return [];
173
145
  const fullPath = path.join(workspaceRoot, filePath);
174
- if (!fs.existsSync(fullPath)) return [];
175
-
146
+ if (!fs.existsSync(fullPath))
147
+ return [];
176
148
  const content = fs.readFileSync(fullPath, 'utf-8');
177
149
  const fileLines = content.split('\n');
178
150
  const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
179
-
180
- const violations: ViolationInfo[] = [];
181
-
182
- function visit(node: ts.Node): void {
151
+ const violations = [];
152
+ function visit(node) {
183
153
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
184
154
  try {
185
155
  if (ts.isCallExpression(node)) {
@@ -193,45 +163,41 @@ function findDirectApiInjections(filePath: string, workspaceRoot: string, disabl
193
163
  const line = pos.line + 1;
194
164
  const column = pos.character + 1;
195
165
  const disabled = hasDisableComment(fileLines, line);
196
-
197
166
  if (!disableAllowed && disabled) {
198
167
  violations.push({ line, column, context: `inject(${firstArg.text}) in route resolver`, hasDisableComment: false });
199
- } else {
168
+ }
169
+ else {
200
170
  violations.push({ line, column, context: `inject(${firstArg.text}) in route resolver`, hasDisableComment: disabled });
201
171
  }
202
172
  }
203
173
  }
204
174
  }
205
175
  }
206
- } catch (err: unknown) {
176
+ }
177
+ catch (err) {
207
178
  //const error = toError(err);
208
179
  // Skip nodes that cause errors during analysis
209
180
  }
210
-
211
181
  ts.forEachChild(node, visit);
212
182
  }
213
-
214
183
  visit(sourceFile);
215
184
  return violations;
216
185
  }
217
-
218
186
  /**
219
187
  * Find this.<field>.snapshot.data access patterns in *.component.ts files.
220
188
  * Flags PropertyAccessExpression chains: this.<anything>.snapshot.data
221
189
  */
222
- function findSnapshotDataAccess(filePath: string, workspaceRoot: string, disableAllowed: boolean): ViolationInfo[] {
223
- if (!filePath.endsWith('.component.ts')) return [];
224
-
190
+ function findSnapshotDataAccess(filePath, workspaceRoot, disableAllowed) {
191
+ if (!filePath.endsWith('.component.ts'))
192
+ return [];
225
193
  const fullPath = path.join(workspaceRoot, filePath);
226
- if (!fs.existsSync(fullPath)) return [];
227
-
194
+ if (!fs.existsSync(fullPath))
195
+ return [];
228
196
  const content = fs.readFileSync(fullPath, 'utf-8');
229
197
  const fileLines = content.split('\n');
230
198
  const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
231
-
232
- const violations: ViolationInfo[] = [];
233
-
234
- function visit(node: ts.Node): void {
199
+ const violations = [];
200
+ function visit(node) {
235
201
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
236
202
  try {
237
203
  // Looking for: this.<field>.snapshot.data
@@ -250,10 +216,10 @@ function findSnapshotDataAccess(filePath: string, workspaceRoot: string, disable
250
216
  const line = pos.line + 1;
251
217
  const column = pos.character + 1;
252
218
  const disabled = hasDisableComment(fileLines, line);
253
-
254
219
  if (!disableAllowed && disabled) {
255
220
  violations.push({ line, column, context: `this.${fieldName}.snapshot.data in component`, hasDisableComment: false });
256
- } else {
221
+ }
222
+ else {
257
223
  violations.push({ line, column, context: `this.${fieldName}.snapshot.data in component`, hasDisableComment: disabled });
258
224
  }
259
225
  }
@@ -261,53 +227,42 @@ function findSnapshotDataAccess(filePath: string, workspaceRoot: string, disable
261
227
  }
262
228
  }
263
229
  }
264
- } catch (err: unknown) {
230
+ }
231
+ catch (err) {
265
232
  //const error = toError(err);
266
233
  // Skip nodes that cause errors during analysis
267
234
  }
268
-
269
235
  ts.forEachChild(node, visit);
270
236
  }
271
-
272
237
  visit(sourceFile);
273
238
  return violations;
274
239
  }
275
-
276
240
  /**
277
241
  * Find all violations in a file (both inject(Api) and snapshot.data patterns).
278
242
  */
279
- function findViolationsInFile(filePath: string, workspaceRoot: string, disableAllowed: boolean): ViolationInfo[] {
243
+ function findViolationsInFile(filePath, workspaceRoot, disableAllowed) {
280
244
  const apiViolations = findDirectApiInjections(filePath, workspaceRoot, disableAllowed);
281
245
  const snapshotViolations = findSnapshotDataAccess(filePath, workspaceRoot, disableAllowed);
282
246
  return [...apiViolations, ...snapshotViolations];
283
247
  }
284
-
285
248
  /**
286
249
  * MODIFIED_CODE mode: Flag violations on changed lines in diff hunks.
287
250
  */
288
251
  // webpieces-disable max-lines-new-methods -- File iteration with diff parsing and line filtering
289
- function findViolationsForModifiedCode(
290
- workspaceRoot: string,
291
- changedFiles: string[],
292
- base: string,
293
- head: string | undefined,
294
- disableAllowed: boolean
295
- ): Violation[] {
296
- const violations: Violation[] = [];
297
-
252
+ function findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed) {
253
+ const violations = [];
298
254
  for (const file of changedFiles) {
299
- const diff = getFileDiff(workspaceRoot, file, base, head);
300
- const changedLines = getChangedLineNumbers(diff);
301
-
302
- if (changedLines.size === 0) continue;
303
-
255
+ const diff = (0, diff_utils_1.getFileDiff)(workspaceRoot, file, base, head);
256
+ const changedLines = (0, diff_utils_1.getChangedLineNumbers)(diff);
257
+ if (changedLines.size === 0)
258
+ continue;
304
259
  const allViolations = findViolationsInFile(file, workspaceRoot, disableAllowed);
305
-
306
260
  for (const v of allViolations) {
307
- if (disableAllowed && v.hasDisableComment) continue;
261
+ if (disableAllowed && v.hasDisableComment)
262
+ continue;
308
263
  // LINE-BASED: Only include if the violation is on a changed line
309
- if (!changedLines.has(v.line)) continue;
310
-
264
+ if (!changedLines.has(v.line))
265
+ continue;
311
266
  violations.push({
312
267
  file,
313
268
  line: v.line,
@@ -316,22 +271,18 @@ function findViolationsForModifiedCode(
316
271
  });
317
272
  }
318
273
  }
319
-
320
274
  return violations;
321
275
  }
322
-
323
276
  /**
324
277
  * MODIFIED_FILES mode: Flag ALL violations in files that were modified.
325
278
  */
326
- function findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean): Violation[] {
327
- const violations: Violation[] = [];
328
-
279
+ function findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed) {
280
+ const violations = [];
329
281
  for (const file of changedFiles) {
330
282
  const allViolations = findViolationsInFile(file, workspaceRoot, disableAllowed);
331
-
332
283
  for (const v of allViolations) {
333
- if (disableAllowed && v.hasDisableComment) continue;
334
-
284
+ if (disableAllowed && v.hasDisableComment)
285
+ continue;
335
286
  violations.push({
336
287
  file,
337
288
  line: v.line,
@@ -340,31 +291,21 @@ function findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: str
340
291
  });
341
292
  }
342
293
  }
343
-
344
294
  return violations;
345
295
  }
346
-
347
- interface RangeInfo {
348
- name: string;
349
- startLine: number;
350
- endLine: number;
351
- }
352
-
353
296
  /**
354
297
  * Find route object ranges in *.routes.ts files.
355
298
  * A route object is an ObjectLiteralExpression that contains (directly or in descendants)
356
299
  * a `resolve` property. Returns the line range of each such top-level route object.
357
300
  */
358
- function findRouteObjectRanges(filePath: string, workspaceRoot: string): RangeInfo[] {
301
+ function findRouteObjectRanges(filePath, workspaceRoot) {
359
302
  const fullPath = path.join(workspaceRoot, filePath);
360
- if (!fs.existsSync(fullPath)) return [];
361
-
303
+ if (!fs.existsSync(fullPath))
304
+ return [];
362
305
  const content = fs.readFileSync(fullPath, 'utf-8');
363
306
  const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
364
-
365
- const ranges: RangeInfo[] = [];
366
-
367
- function hasResolveProperty(node: ts.Node): boolean {
307
+ const ranges = [];
308
+ function hasResolveProperty(node) {
368
309
  if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === 'resolve') {
369
310
  return true;
370
311
  }
@@ -376,8 +317,7 @@ function findRouteObjectRanges(filePath: string, workspaceRoot: string): RangeIn
376
317
  });
377
318
  return found;
378
319
  }
379
-
380
- function visitTopLevel(node: ts.Node): void {
320
+ function visitTopLevel(node) {
381
321
  if (ts.isObjectLiteralExpression(node) && hasResolveProperty(node)) {
382
322
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
383
323
  const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
@@ -390,42 +330,39 @@ function findRouteObjectRanges(filePath: string, workspaceRoot: string): RangeIn
390
330
  }
391
331
  ts.forEachChild(node, visitTopLevel);
392
332
  }
393
-
394
333
  visitTopLevel(sourceFile);
395
334
  return ranges;
396
335
  }
397
-
398
336
  /**
399
337
  * Find method/function ranges in *.component.ts files.
400
338
  * Returns ranges for class methods, function declarations, and arrow functions in variable declarations.
401
339
  */
402
- function findMethodRanges(filePath: string, workspaceRoot: string): RangeInfo[] {
340
+ function findMethodRanges(filePath, workspaceRoot) {
403
341
  const fullPath = path.join(workspaceRoot, filePath);
404
- if (!fs.existsSync(fullPath)) return [];
405
-
342
+ if (!fs.existsSync(fullPath))
343
+ return [];
406
344
  const content = fs.readFileSync(fullPath, 'utf-8');
407
345
  const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
408
-
409
- const ranges: RangeInfo[] = [];
410
-
411
- function visit(node: ts.Node): void {
412
- let methodName: string | undefined;
413
- let startLine: number | undefined;
414
- let endLine: number | undefined;
415
-
346
+ const ranges = [];
347
+ function visit(node) {
348
+ let methodName;
349
+ let startLine;
350
+ let endLine;
416
351
  if (ts.isMethodDeclaration(node) && node.name) {
417
352
  methodName = node.name.getText(sourceFile);
418
353
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
419
354
  const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
420
355
  startLine = start.line + 1;
421
356
  endLine = end.line + 1;
422
- } else if (ts.isFunctionDeclaration(node) && node.name) {
357
+ }
358
+ else if (ts.isFunctionDeclaration(node) && node.name) {
423
359
  methodName = node.name.getText(sourceFile);
424
360
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
425
361
  const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
426
362
  startLine = start.line + 1;
427
363
  endLine = end.line + 1;
428
- } else if (ts.isArrowFunction(node)) {
364
+ }
365
+ else if (ts.isArrowFunction(node)) {
429
366
  if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
430
367
  methodName = node.parent.name.getText(sourceFile);
431
368
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
@@ -434,44 +371,31 @@ function findMethodRanges(filePath: string, workspaceRoot: string): RangeInfo[]
434
371
  endLine = end.line + 1;
435
372
  }
436
373
  }
437
-
438
374
  if (methodName && startLine !== undefined && endLine !== undefined) {
439
375
  ranges.push({ name: methodName, startLine, endLine });
440
376
  }
441
-
442
377
  ts.forEachChild(node, visit);
443
378
  }
444
-
445
379
  visit(sourceFile);
446
380
  return ranges;
447
381
  }
448
-
449
382
  /**
450
383
  * NEW_AND_MODIFIED_METHODS mode: Flag violations in new/modified method/route scopes.
451
384
  * - For *.routes.ts: If any line in a route object is changed, flag all inject(XxxApi) violations in that route
452
385
  * - For *.component.ts: If a method is new/modified, flag all snapshot.data violations in that method
453
386
  */
454
387
  // webpieces-disable max-lines-new-methods -- Method-scoped validation with route objects and component methods
455
- function findViolationsForModifiedMethods(
456
- workspaceRoot: string,
457
- changedFiles: string[],
458
- base: string,
459
- head: string | undefined,
460
- disableAllowed: boolean
461
- ): Violation[] {
462
- const violations: Violation[] = [];
463
-
388
+ function findViolationsForModifiedMethods(workspaceRoot, changedFiles, base, head, disableAllowed) {
389
+ const violations = [];
464
390
  for (const file of changedFiles) {
465
- const diff = getFileDiff(workspaceRoot, file, base, head);
466
- const changedLines = getChangedLineNumbers(diff);
467
- const newMethodNames = findNewMethodSignaturesInDiff(diff);
468
-
469
- if (changedLines.size === 0 && newMethodNames.size === 0) continue;
470
-
391
+ const diff = (0, diff_utils_1.getFileDiff)(workspaceRoot, file, base, head);
392
+ const changedLines = (0, diff_utils_1.getChangedLineNumbers)(diff);
393
+ const newMethodNames = (0, diff_utils_1.findNewMethodSignaturesInDiff)(diff);
394
+ if (changedLines.size === 0 && newMethodNames.size === 0)
395
+ continue;
471
396
  if (file.endsWith('.routes.ts')) {
472
397
  const routeRanges = findRouteObjectRanges(file, workspaceRoot);
473
398
  const allViolations = findDirectApiInjections(file, workspaceRoot, disableAllowed);
474
-
475
399
  for (const range of routeRanges) {
476
400
  let rangeHasChanges = false;
477
401
  for (let line = range.startLine; line <= range.endLine; line++) {
@@ -480,10 +404,11 @@ function findViolationsForModifiedMethods(
480
404
  break;
481
405
  }
482
406
  }
483
- if (!rangeHasChanges) continue;
484
-
407
+ if (!rangeHasChanges)
408
+ continue;
485
409
  for (const v of allViolations) {
486
- if (disableAllowed && v.hasDisableComment) continue;
410
+ if (disableAllowed && v.hasDisableComment)
411
+ continue;
487
412
  if (v.line >= range.startLine && v.line <= range.endLine) {
488
413
  violations.push({
489
414
  file,
@@ -494,10 +419,10 @@ function findViolationsForModifiedMethods(
494
419
  }
495
420
  }
496
421
  }
497
- } else if (file.endsWith('.component.ts')) {
422
+ }
423
+ else if (file.endsWith('.component.ts')) {
498
424
  const methodRanges = findMethodRanges(file, workspaceRoot);
499
425
  const allViolations = findSnapshotDataAccess(file, workspaceRoot, disableAllowed);
500
-
501
426
  for (const range of methodRanges) {
502
427
  const isNewMethod = newMethodNames.has(range.name);
503
428
  let rangeHasChanges = false;
@@ -509,10 +434,11 @@ function findViolationsForModifiedMethods(
509
434
  }
510
435
  }
511
436
  }
512
- if (!isNewMethod && !rangeHasChanges) continue;
513
-
437
+ if (!isNewMethod && !rangeHasChanges)
438
+ continue;
514
439
  for (const v of allViolations) {
515
- if (disableAllowed && v.hasDisableComment) continue;
440
+ if (disableAllowed && v.hasDisableComment)
441
+ continue;
516
442
  if (v.line >= range.startLine && v.line <= range.endLine) {
517
443
  violations.push({
518
444
  file,
@@ -525,15 +451,13 @@ function findViolationsForModifiedMethods(
525
451
  }
526
452
  }
527
453
  }
528
-
529
454
  return violations;
530
455
  }
531
-
532
456
  /**
533
457
  * Report violations to console.
534
458
  */
535
459
  // webpieces-disable max-lines-new-methods -- Console output with examples and escape hatch information
536
- function reportViolations(violations: Violation[], mode: NoDirectApiResolverMode, disableAllowed: boolean): void {
460
+ function reportViolations(violations, mode, disableAllowed) {
537
461
  console.error('');
538
462
  console.error('\u274c Direct API usage in resolvers or snapshot.data in components found!');
539
463
  console.error('');
@@ -553,17 +477,16 @@ function reportViolations(violations: Violation[], mode: NoDirectApiResolverMode
553
477
  console.error(' GOOD (in *.component.ts):');
554
478
  console.error(' this.myService.data$.subscribe(data => ...)');
555
479
  console.error('');
556
-
557
480
  for (const v of violations) {
558
481
  console.error(` \u274c ${v.file}:${v.line}:${v.column}`);
559
482
  console.error(` ${v.context}`);
560
483
  }
561
484
  console.error('');
562
-
563
485
  if (disableAllowed) {
564
486
  console.error(' Escape hatch (use sparingly):');
565
487
  console.error(' // webpieces-disable no-direct-api-resolver -- [your reason]');
566
- } else {
488
+ }
489
+ else {
567
490
  console.error(' Escape hatch: DISABLED (disableAllowed: false)');
568
491
  console.error(' Disable comments are ignored. Fix the pattern directly.');
569
492
  }
@@ -571,12 +494,11 @@ function reportViolations(violations: Violation[], mode: NoDirectApiResolverMode
571
494
  console.error(` Current mode: ${mode}`);
572
495
  console.error('');
573
496
  }
574
-
575
497
  /**
576
498
  * Resolve mode considering ignoreModifiedUntilEpoch override.
577
499
  * When active, downgrades to OFF. When expired, logs a warning.
578
500
  */
579
- function resolveMode(normalMode: NoDirectApiResolverMode, epoch: number | undefined): NoDirectApiResolverMode {
501
+ function resolveMode(normalMode, epoch) {
580
502
  if (epoch === undefined || normalMode === 'OFF') {
581
503
  return normalMode;
582
504
  }
@@ -589,88 +511,67 @@ function resolveMode(normalMode: NoDirectApiResolverMode, epoch: number | undefi
589
511
  }
590
512
  return normalMode;
591
513
  }
592
-
593
514
  /**
594
515
  * Filter changed files to only those under enforcePaths (if configured).
595
516
  */
596
- function filterByEnforcePaths(changedFiles: string[], enforcePaths: string[] | undefined): string[] {
517
+ function filterByEnforcePaths(changedFiles, enforcePaths) {
597
518
  if (!enforcePaths || enforcePaths.length === 0) {
598
519
  return changedFiles;
599
520
  }
600
- return changedFiles.filter((file) =>
601
- enforcePaths.some((prefix) => file.startsWith(prefix))
602
- );
521
+ return changedFiles.filter((file) => enforcePaths.some((prefix) => file.startsWith(prefix)));
603
522
  }
604
-
605
523
  /**
606
524
  * Filter to only relevant Angular files (*.routes.ts and *.component.ts).
607
525
  */
608
- function filterRelevantFiles(changedFiles: string[]): string[] {
609
- return changedFiles.filter((file) =>
610
- file.endsWith('.routes.ts') || file.endsWith('.component.ts')
611
- );
526
+ function filterRelevantFiles(changedFiles) {
527
+ return changedFiles.filter((file) => file.endsWith('.routes.ts') || file.endsWith('.component.ts'));
612
528
  }
613
-
614
- export default async function runValidator(
615
- options: ValidateNoDirectApiResolverOptions,
616
- workspaceRoot: string
617
- ): Promise<ExecutorResult> {
618
- const mode: NoDirectApiResolverMode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
529
+ async function runValidator(options, workspaceRoot) {
530
+ const mode = resolveMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
619
531
  const disableAllowed = options.disableAllowed ?? true;
620
-
621
532
  if (mode === 'OFF') {
622
533
  console.log('\n\u23ed\ufe0f Skipping no-direct-api-resolver validation (mode: OFF)');
623
534
  console.log('');
624
535
  return { success: true };
625
536
  }
626
-
627
537
  console.log('\n\ud83d\udccf Validating No Direct API in Resolver\n');
628
538
  console.log(` Mode: ${mode}`);
629
-
630
539
  let base = process.env['NX_BASE'];
631
540
  const head = process.env['NX_HEAD'];
632
-
633
541
  if (!base) {
634
542
  base = detectBase(workspaceRoot) ?? undefined;
635
-
636
543
  if (!base) {
637
544
  console.log('\n\u23ed\ufe0f Skipping no-direct-api-resolver validation (could not detect base branch)');
638
545
  console.log('');
639
546
  return { success: true };
640
547
  }
641
548
  }
642
-
643
549
  console.log(` Base: ${base}`);
644
550
  console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
645
551
  console.log('');
646
-
647
552
  const allChangedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
648
553
  const scopedFiles = filterByEnforcePaths(allChangedFiles, options.enforcePaths);
649
554
  const changedFiles = filterRelevantFiles(scopedFiles);
650
-
651
555
  if (changedFiles.length === 0) {
652
556
  console.log('\u2705 No relevant Angular files changed (*.routes.ts, *.component.ts)');
653
557
  return { success: true };
654
558
  }
655
-
656
559
  console.log(`\ud83d\udcc2 Checking ${changedFiles.length} changed file(s)...`);
657
-
658
- let violations: Violation[] = [];
659
-
560
+ let violations = [];
660
561
  if (mode === 'MODIFIED_CODE') {
661
562
  violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);
662
- } else if (mode === 'NEW_AND_MODIFIED_METHODS') {
563
+ }
564
+ else if (mode === 'NEW_AND_MODIFIED_METHODS') {
663
565
  violations = findViolationsForModifiedMethods(workspaceRoot, changedFiles, base, head, disableAllowed);
664
- } else if (mode === 'MODIFIED_FILES') {
566
+ }
567
+ else if (mode === 'MODIFIED_FILES') {
665
568
  violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);
666
569
  }
667
-
668
570
  if (violations.length === 0) {
669
571
  console.log('\u2705 No direct API resolver patterns found');
670
572
  return { success: true };
671
573
  }
672
-
673
574
  reportViolations(violations, mode, disableAllowed);
674
-
675
575
  return { success: false };
676
576
  }
577
+ //# sourceMappingURL=validate-no-direct-api-resolver.js.map