@webpieces/dev-config 0.2.84 → 0.2.85

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.
@@ -0,0 +1,493 @@
1
+ "use strict";
2
+ /**
3
+ * Validate No Destructure Executor
4
+ *
5
+ * Validates that destructuring patterns are not used in TypeScript code.
6
+ * Uses LINE-BASED detection (not method-based) for git diff filtering.
7
+ *
8
+ * ============================================================================
9
+ * VIOLATIONS (BAD) - These patterns are flagged:
10
+ * ============================================================================
11
+ *
12
+ * - const { x, y } = obj — object destructuring in variable declarations
13
+ * - const [a, b] = fn() — array destructuring (except Promise.all)
14
+ * - for (const { email } of items) — object destructuring in for-of loops
15
+ * - for (const [a, b] of items) — array destructuring in for-of (except Object.entries)
16
+ * - const { page = 0 } = opts — destructuring with defaults
17
+ * - const { done: streamDone } = obj — destructuring with renaming
18
+ * - function foo({ x, y }: Type) — function parameter destructuring
19
+ *
20
+ * ============================================================================
21
+ * ALLOWED (skip — NOT violations)
22
+ * ============================================================================
23
+ *
24
+ * - const [a, b] = await Promise.all([...]) — Promise.all array destructuring
25
+ * - for (const [key, value] of Object.entries(obj)) — Object.entries in for-of
26
+ * - const { extracted, ...rest } = obj — rest operator separation
27
+ * - Lines with // webpieces-disable no-destructure -- [reason] (only when disableAllowed: true)
28
+ *
29
+ * ============================================================================
30
+ * MODES (LINE-BASED)
31
+ * ============================================================================
32
+ * - OFF: Skip validation entirely
33
+ * - MODIFIED_CODE: Flag destructuring on changed lines (lines in diff hunks)
34
+ * - MODIFIED_FILES: Flag ALL destructuring in files that were modified
35
+ *
36
+ * ============================================================================
37
+ * ESCAPE HATCH
38
+ * ============================================================================
39
+ * Add comment above the violation:
40
+ * // webpieces-disable no-destructure -- [your justification]
41
+ * const { x, y } = obj;
42
+ */
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.default = runExecutor;
45
+ const tslib_1 = require("tslib");
46
+ const child_process_1 = require("child_process");
47
+ const fs = tslib_1.__importStar(require("fs"));
48
+ const path = tslib_1.__importStar(require("path"));
49
+ const ts = tslib_1.__importStar(require("typescript"));
50
+ /**
51
+ * Get changed TypeScript files between base and head (or working tree if head not specified).
52
+ */
53
+ // webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths
54
+ function getChangedTypeScriptFiles(workspaceRoot, base, head) {
55
+ try {
56
+ const diffTarget = head ? `${base} ${head}` : base;
57
+ const output = (0, child_process_1.execSync)(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {
58
+ cwd: workspaceRoot,
59
+ encoding: 'utf-8',
60
+ });
61
+ const changedFiles = output
62
+ .trim()
63
+ .split('\n')
64
+ .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
65
+ if (!head) {
66
+ try {
67
+ const untrackedOutput = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {
68
+ cwd: workspaceRoot,
69
+ encoding: 'utf-8',
70
+ });
71
+ const untrackedFiles = untrackedOutput
72
+ .trim()
73
+ .split('\n')
74
+ .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));
75
+ const allFiles = new Set([...changedFiles, ...untrackedFiles]);
76
+ return Array.from(allFiles);
77
+ }
78
+ catch {
79
+ return changedFiles;
80
+ }
81
+ }
82
+ return changedFiles;
83
+ }
84
+ catch {
85
+ return [];
86
+ }
87
+ }
88
+ /**
89
+ * Get the diff content for a specific file.
90
+ */
91
+ function getFileDiff(workspaceRoot, file, base, head) {
92
+ try {
93
+ const diffTarget = head ? `${base} ${head}` : base;
94
+ const diff = (0, child_process_1.execSync)(`git diff ${diffTarget} -- "${file}"`, {
95
+ cwd: workspaceRoot,
96
+ encoding: 'utf-8',
97
+ });
98
+ if (!diff && !head) {
99
+ const fullPath = path.join(workspaceRoot, file);
100
+ if (fs.existsSync(fullPath)) {
101
+ const isUntracked = (0, child_process_1.execSync)(`git ls-files --others --exclude-standard "${file}"`, {
102
+ cwd: workspaceRoot,
103
+ encoding: 'utf-8',
104
+ }).trim();
105
+ if (isUntracked) {
106
+ const content = fs.readFileSync(fullPath, 'utf-8');
107
+ const lines = content.split('\n');
108
+ return lines.map((line) => `+${line}`).join('\n');
109
+ }
110
+ }
111
+ }
112
+ return diff;
113
+ }
114
+ catch {
115
+ return '';
116
+ }
117
+ }
118
+ /**
119
+ * Parse diff to extract changed line numbers (additions only - lines starting with +).
120
+ */
121
+ function getChangedLineNumbers(diffContent) {
122
+ const changedLines = new Set();
123
+ const lines = diffContent.split('\n');
124
+ let currentLine = 0;
125
+ for (const line of lines) {
126
+ const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
127
+ if (hunkMatch) {
128
+ currentLine = parseInt(hunkMatch[1], 10);
129
+ continue;
130
+ }
131
+ if (line.startsWith('+') && !line.startsWith('+++')) {
132
+ changedLines.add(currentLine);
133
+ currentLine++;
134
+ }
135
+ else if (line.startsWith('-') && !line.startsWith('---')) {
136
+ // Deletions don't increment line number
137
+ }
138
+ else {
139
+ currentLine++;
140
+ }
141
+ }
142
+ return changedLines;
143
+ }
144
+ /**
145
+ * Check if a line contains a webpieces-disable comment for no-destructure.
146
+ */
147
+ function hasDisableComment(lines, lineNumber) {
148
+ const startCheck = Math.max(0, lineNumber - 5);
149
+ for (let i = lineNumber - 2; i >= startCheck; i--) {
150
+ const line = lines[i]?.trim() ?? '';
151
+ if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {
152
+ break;
153
+ }
154
+ if (line.includes('webpieces-disable') && line.includes('no-destructure')) {
155
+ return true;
156
+ }
157
+ }
158
+ return false;
159
+ }
160
+ /**
161
+ * Check if an ArrayBindingPattern's initializer is `await Promise.all(...)`.
162
+ */
163
+ function isPromiseAllDestructure(node) {
164
+ const parent = node.parent;
165
+ if (!ts.isVariableDeclaration(parent))
166
+ return false;
167
+ const initializer = parent.initializer;
168
+ if (!initializer)
169
+ return false;
170
+ // Handle: const [a, b] = await Promise.all([...])
171
+ if (ts.isAwaitExpression(initializer)) {
172
+ const awaitedExpr = initializer.expression;
173
+ if (ts.isCallExpression(awaitedExpr)) {
174
+ const callExpr = awaitedExpr.expression;
175
+ // Promise.all(...)
176
+ if (ts.isPropertyAccessExpression(callExpr) && callExpr.name.text === 'all') {
177
+ const obj = callExpr.expression;
178
+ if (ts.isIdentifier(obj) && obj.text === 'Promise') {
179
+ return true;
180
+ }
181
+ }
182
+ }
183
+ }
184
+ return false;
185
+ }
186
+ /**
187
+ * Check if an ArrayBindingPattern in a for-of loop iterates over Object.entries(...).
188
+ */
189
+ function isObjectEntriesForOf(node) {
190
+ // Walk up: ArrayBindingPattern -> VariableDeclaration -> VariableDeclarationList -> ForOfStatement
191
+ const varDecl = node.parent;
192
+ if (!ts.isVariableDeclaration(varDecl))
193
+ return false;
194
+ const varDeclList = varDecl.parent;
195
+ if (!ts.isVariableDeclarationList(varDeclList))
196
+ return false;
197
+ const forOfStmt = varDeclList.parent;
198
+ if (!ts.isForOfStatement(forOfStmt))
199
+ return false;
200
+ // Check iterable expression ends with .entries()
201
+ const iterable = forOfStmt.expression;
202
+ if (ts.isCallExpression(iterable)) {
203
+ const callExpr = iterable.expression;
204
+ if (ts.isPropertyAccessExpression(callExpr) && callExpr.name.text === 'entries') {
205
+ return true;
206
+ }
207
+ }
208
+ return false;
209
+ }
210
+ /**
211
+ * Check if an ObjectBindingPattern contains a rest element (...rest).
212
+ */
213
+ function hasRestElement(node) {
214
+ for (const element of node.elements) {
215
+ if (element.dotDotDotToken) {
216
+ return true;
217
+ }
218
+ }
219
+ return false;
220
+ }
221
+ /**
222
+ * Find all destructuring patterns in a file using AST.
223
+ */
224
+ // webpieces-disable max-lines-new-methods -- AST traversal with multiple destructuring pattern checks and exception detection
225
+ function findDestructuringInFile(filePath, workspaceRoot, disableAllowed) {
226
+ const fullPath = path.join(workspaceRoot, filePath);
227
+ if (!fs.existsSync(fullPath))
228
+ return [];
229
+ const content = fs.readFileSync(fullPath, 'utf-8');
230
+ const fileLines = content.split('\n');
231
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
232
+ const violations = [];
233
+ // webpieces-disable max-lines-new-methods -- AST visitor needs to handle object/array binding patterns in declarations, for-of, and parameters
234
+ function visit(node) {
235
+ try {
236
+ // Check ObjectBindingPattern
237
+ if (ts.isObjectBindingPattern(node)) {
238
+ // Exception: rest operator separation
239
+ if (hasRestElement(node)) {
240
+ ts.forEachChild(node, visit);
241
+ return;
242
+ }
243
+ const context = getDestructureContext(node);
244
+ recordViolation(node, context, fileLines, sourceFile, violations, disableAllowed);
245
+ }
246
+ // Check ArrayBindingPattern
247
+ if (ts.isArrayBindingPattern(node)) {
248
+ // Exception: Promise.all destructure
249
+ if (isPromiseAllDestructure(node)) {
250
+ ts.forEachChild(node, visit);
251
+ return;
252
+ }
253
+ // Exception: Object.entries in for-of
254
+ if (isObjectEntriesForOf(node)) {
255
+ ts.forEachChild(node, visit);
256
+ return;
257
+ }
258
+ const context = getDestructureContext(node);
259
+ recordViolation(node, context, fileLines, sourceFile, violations, disableAllowed);
260
+ }
261
+ }
262
+ catch {
263
+ // Skip nodes that cause errors during analysis
264
+ }
265
+ ts.forEachChild(node, visit);
266
+ }
267
+ visit(sourceFile);
268
+ return violations;
269
+ }
270
+ function recordViolation(node, context, fileLines, sourceFile, violations, disableAllowed) {
271
+ const startPos = node.getStart(sourceFile);
272
+ if (startPos >= 0) {
273
+ const pos = sourceFile.getLineAndCharacterOfPosition(startPos);
274
+ const line = pos.line + 1;
275
+ const column = pos.character + 1;
276
+ const disabled = hasDisableComment(fileLines, line);
277
+ if (!disableAllowed && disabled) {
278
+ // When disableAllowed is false, ignore disable comments — still a violation
279
+ violations.push({ line, column, context, hasDisableComment: false });
280
+ }
281
+ else {
282
+ violations.push({ line, column, context, hasDisableComment: disabled });
283
+ }
284
+ }
285
+ }
286
+ /**
287
+ * Get a description of where the destructuring pattern appears.
288
+ */
289
+ function getDestructureContext(node) {
290
+ const parent = node.parent;
291
+ if (ts.isParameter(parent)) {
292
+ return 'function parameter destructuring';
293
+ }
294
+ if (ts.isVariableDeclaration(parent)) {
295
+ const grandparent = parent.parent;
296
+ if (grandparent && ts.isVariableDeclarationList(grandparent)) {
297
+ const forOfParent = grandparent.parent;
298
+ if (forOfParent && ts.isForOfStatement(forOfParent)) {
299
+ return ts.isObjectBindingPattern(node)
300
+ ? 'object destructuring in for-of loop'
301
+ : 'array destructuring in for-of loop';
302
+ }
303
+ }
304
+ return ts.isObjectBindingPattern(node)
305
+ ? 'object destructuring in variable declaration'
306
+ : 'array destructuring in variable declaration';
307
+ }
308
+ return ts.isObjectBindingPattern(node)
309
+ ? 'object destructuring'
310
+ : 'array destructuring';
311
+ }
312
+ /**
313
+ * MODIFIED_CODE mode: Flag violations on changed lines in diff hunks.
314
+ */
315
+ // webpieces-disable max-lines-new-methods -- File iteration with diff parsing and line filtering
316
+ function findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed) {
317
+ const violations = [];
318
+ for (const file of changedFiles) {
319
+ const diff = getFileDiff(workspaceRoot, file, base, head);
320
+ const changedLines = getChangedLineNumbers(diff);
321
+ if (changedLines.size === 0)
322
+ continue;
323
+ const allViolations = findDestructuringInFile(file, workspaceRoot, disableAllowed);
324
+ for (const v of allViolations) {
325
+ if (disableAllowed && v.hasDisableComment)
326
+ continue;
327
+ // LINE-BASED: Only include if the violation is on a changed line
328
+ if (!changedLines.has(v.line))
329
+ continue;
330
+ violations.push({
331
+ file,
332
+ line: v.line,
333
+ column: v.column,
334
+ context: v.context,
335
+ });
336
+ }
337
+ }
338
+ return violations;
339
+ }
340
+ /**
341
+ * MODIFIED_FILES mode: Flag ALL violations in files that were modified.
342
+ */
343
+ function findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed) {
344
+ const violations = [];
345
+ for (const file of changedFiles) {
346
+ const allViolations = findDestructuringInFile(file, workspaceRoot, disableAllowed);
347
+ for (const v of allViolations) {
348
+ if (disableAllowed && v.hasDisableComment)
349
+ continue;
350
+ violations.push({
351
+ file,
352
+ line: v.line,
353
+ column: v.column,
354
+ context: v.context,
355
+ });
356
+ }
357
+ }
358
+ return violations;
359
+ }
360
+ /**
361
+ * Auto-detect the base branch by finding the merge-base with origin/main.
362
+ */
363
+ function detectBase(workspaceRoot) {
364
+ try {
365
+ const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD origin/main', {
366
+ cwd: workspaceRoot,
367
+ encoding: 'utf-8',
368
+ stdio: ['pipe', 'pipe', 'pipe'],
369
+ }).trim();
370
+ if (mergeBase) {
371
+ return mergeBase;
372
+ }
373
+ }
374
+ catch {
375
+ try {
376
+ const mergeBase = (0, child_process_1.execSync)('git merge-base HEAD main', {
377
+ cwd: workspaceRoot,
378
+ encoding: 'utf-8',
379
+ stdio: ['pipe', 'pipe', 'pipe'],
380
+ }).trim();
381
+ if (mergeBase) {
382
+ return mergeBase;
383
+ }
384
+ }
385
+ catch {
386
+ // Ignore
387
+ }
388
+ }
389
+ return null;
390
+ }
391
+ /**
392
+ * Report violations to console.
393
+ */
394
+ // webpieces-disable max-lines-new-methods -- Console output with examples and escape hatch information
395
+ function reportViolations(violations, mode, disableAllowed) {
396
+ console.error('');
397
+ console.error('\u274c Destructuring patterns found! Use explicit property access instead.');
398
+ console.error('');
399
+ console.error('\ud83d\udcda Avoiding destructuring improves code traceability:');
400
+ console.error('');
401
+ console.error(' BAD: const { name, age } = user;');
402
+ console.error(' GOOD: const name = user.name;');
403
+ console.error(' const age = user.age;');
404
+ console.error('');
405
+ console.error(' BAD: function process({ x, y }: Point) { }');
406
+ console.error(' GOOD: function process(point: Point) { point.x; point.y; }');
407
+ console.error('');
408
+ for (const v of violations) {
409
+ console.error(` \u274c ${v.file}:${v.line}:${v.column}`);
410
+ console.error(` ${v.context}`);
411
+ }
412
+ console.error('');
413
+ console.error(' Allowed exceptions:');
414
+ console.error(' - const [a, b] = await Promise.all([...])');
415
+ console.error(' - for (const [key, value] of Object.entries(obj))');
416
+ console.error(' - const { extracted, ...rest } = obj (rest operator separation)');
417
+ console.error('');
418
+ if (disableAllowed) {
419
+ console.error(' Escape hatch (use sparingly):');
420
+ console.error(' // webpieces-disable no-destructure -- [your reason]');
421
+ }
422
+ else {
423
+ console.error(' Escape hatch: DISABLED (disableAllowed: false)');
424
+ console.error(' Disable comments are ignored. Fix the destructuring directly.');
425
+ }
426
+ console.error('');
427
+ console.error(` Current mode: ${mode}`);
428
+ console.error('');
429
+ }
430
+ /**
431
+ * Resolve mode considering ignoreModifiedUntilEpoch override.
432
+ * When active, downgrades to OFF. When expired, logs a warning.
433
+ */
434
+ function resolveNoDestructureMode(normalMode, epoch) {
435
+ if (epoch === undefined || normalMode === 'OFF') {
436
+ return normalMode;
437
+ }
438
+ const nowSeconds = Date.now() / 1000;
439
+ if (nowSeconds < epoch) {
440
+ const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];
441
+ console.log(`\n\u23ed\ufe0f Skipping no-destructure validation (ignoreModifiedUntilEpoch active, expires: ${expiresDate})`);
442
+ console.log('');
443
+ return 'OFF';
444
+ }
445
+ const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];
446
+ console.log(`\n\u26a0\ufe0f noDestructure.ignoreModifiedUntilEpoch (${epoch}) has expired (${expiresDate}). Remove it from nx.json. Using normal mode: ${normalMode}\n`);
447
+ return normalMode;
448
+ }
449
+ async function runExecutor(options, context) {
450
+ const workspaceRoot = context.root;
451
+ const mode = resolveNoDestructureMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);
452
+ const disableAllowed = options.disableAllowed ?? true;
453
+ if (mode === 'OFF') {
454
+ console.log('\n\u23ed\ufe0f Skipping no-destructure validation (mode: OFF)');
455
+ console.log('');
456
+ return { success: true };
457
+ }
458
+ console.log('\n\ud83d\udccf Validating No Destructuring\n');
459
+ console.log(` Mode: ${mode}`);
460
+ let base = process.env['NX_BASE'];
461
+ const head = process.env['NX_HEAD'];
462
+ if (!base) {
463
+ base = detectBase(workspaceRoot) ?? undefined;
464
+ if (!base) {
465
+ console.log('\n\u23ed\ufe0f Skipping no-destructure validation (could not detect base branch)');
466
+ console.log('');
467
+ return { success: true };
468
+ }
469
+ }
470
+ console.log(` Base: ${base}`);
471
+ console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);
472
+ console.log('');
473
+ const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);
474
+ if (changedFiles.length === 0) {
475
+ console.log('\u2705 No TypeScript files changed');
476
+ return { success: true };
477
+ }
478
+ console.log(`\ud83d\udcc2 Checking ${changedFiles.length} changed file(s)...`);
479
+ let violations = [];
480
+ if (mode === 'MODIFIED_CODE') {
481
+ violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);
482
+ }
483
+ else if (mode === 'MODIFIED_FILES') {
484
+ violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);
485
+ }
486
+ if (violations.length === 0) {
487
+ console.log('\u2705 No destructuring patterns found');
488
+ return { success: true };
489
+ }
490
+ reportViolations(violations, mode, disableAllowed);
491
+ return { success: false };
492
+ }
493
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-no-destructure/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Destructure Executor\n *\n * Validates that destructuring patterns are not used in TypeScript code.\n * Uses LINE-BASED detection (not method-based) for git diff filtering.\n *\n * ============================================================================\n * VIOLATIONS (BAD) - These patterns are flagged:\n * ============================================================================\n *\n * - const { x, y } = obj — object destructuring in variable declarations\n * - const [a, b] = fn() — array destructuring (except Promise.all)\n * - for (const { email } of items) — object destructuring in for-of loops\n * - for (const [a, b] of items) — array destructuring in for-of (except Object.entries)\n * - const { page = 0 } = opts — destructuring with defaults\n * - const { done: streamDone } = obj — destructuring with renaming\n * - function foo({ x, y }: Type) — function parameter destructuring\n *\n * ============================================================================\n * ALLOWED (skip — NOT violations)\n * ============================================================================\n *\n * - const [a, b] = await Promise.all([...]) — Promise.all array destructuring\n * - for (const [key, value] of Object.entries(obj)) — Object.entries in for-of\n * - const { extracted, ...rest } = obj — rest operator separation\n * - Lines with // webpieces-disable no-destructure -- [reason] (only when disableAllowed: true)\n *\n * ============================================================================\n * MODES (LINE-BASED)\n * ============================================================================\n * - OFF: Skip validation entirely\n * - MODIFIED_CODE: Flag destructuring on changed lines (lines in diff hunks)\n * - MODIFIED_FILES: Flag ALL destructuring in files that were modified\n *\n * ============================================================================\n * ESCAPE HATCH\n * ============================================================================\n * Add comment above the violation:\n * // webpieces-disable no-destructure -- [your justification]\n * const { x, y } = obj;\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\n\nexport type NoDestructureMode = 'OFF' | 'MODIFIED_CODE' | 'MODIFIED_FILES';\n\nexport interface ValidateNoDestructureOptions {\n mode?: NoDestructureMode;\n disableAllowed?: boolean;\n ignoreModifiedUntilEpoch?: number;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface DestructureViolation {\n file: string;\n line: number;\n column: number;\n context: string;\n}\n\n/**\n * Get changed TypeScript files between base and head (or working tree if head not specified).\n */\n// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths\nfunction getChangedTypeScriptFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only ${diffTarget} -- '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n\n if (!head) {\n try {\n const untrackedOutput = execSync(`git ls-files --others --exclude-standard '*.ts' '*.tsx'`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const untrackedFiles = untrackedOutput\n .trim()\n .split('\\n')\n .filter((f) => f && !f.includes('.spec.ts') && !f.includes('.test.ts'));\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Get the diff content for a specific file.\n */\nfunction getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\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 const lines = content.split('\\n');\n return lines.map((line) => `+${line}`).join('\\n');\n }\n }\n }\n\n return diff;\n } catch {\n return '';\n }\n}\n\n/**\n * Parse diff to extract changed line numbers (additions only - lines starting with +).\n */\nfunction 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 increment line number\n } else {\n currentLine++;\n }\n }\n\n return changedLines;\n}\n\n/**\n * Check if a line contains a webpieces-disable comment for no-destructure.\n */\nfunction hasDisableComment(lines: string[], lineNumber: number): boolean {\n const startCheck = Math.max(0, lineNumber - 5);\n for (let i = lineNumber - 2; i >= startCheck; i--) {\n const line = lines[i]?.trim() ?? '';\n if (line.startsWith('function ') || line.startsWith('class ') || line.endsWith('}')) {\n break;\n }\n if (line.includes('webpieces-disable') && line.includes('no-destructure')) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if an ArrayBindingPattern's initializer is `await Promise.all(...)`.\n */\nfunction isPromiseAllDestructure(node: ts.ArrayBindingPattern): boolean {\n const parent = node.parent;\n if (!ts.isVariableDeclaration(parent)) return false;\n const initializer = parent.initializer;\n if (!initializer) return false;\n\n // Handle: const [a, b] = await Promise.all([...])\n if (ts.isAwaitExpression(initializer)) {\n const awaitedExpr = initializer.expression;\n if (ts.isCallExpression(awaitedExpr)) {\n const callExpr = awaitedExpr.expression;\n // Promise.all(...)\n if (ts.isPropertyAccessExpression(callExpr) && callExpr.name.text === 'all') {\n const obj = callExpr.expression;\n if (ts.isIdentifier(obj) && obj.text === 'Promise') {\n return true;\n }\n }\n }\n }\n\n return false;\n}\n\n/**\n * Check if an ArrayBindingPattern in a for-of loop iterates over Object.entries(...).\n */\nfunction isObjectEntriesForOf(node: ts.ArrayBindingPattern): boolean {\n // Walk up: ArrayBindingPattern -> VariableDeclaration -> VariableDeclarationList -> ForOfStatement\n const varDecl = node.parent;\n if (!ts.isVariableDeclaration(varDecl)) return false;\n\n const varDeclList = varDecl.parent;\n if (!ts.isVariableDeclarationList(varDeclList)) return false;\n\n const forOfStmt = varDeclList.parent;\n if (!ts.isForOfStatement(forOfStmt)) return false;\n\n // Check iterable expression ends with .entries()\n const iterable = forOfStmt.expression;\n if (ts.isCallExpression(iterable)) {\n const callExpr = iterable.expression;\n if (ts.isPropertyAccessExpression(callExpr) && callExpr.name.text === 'entries') {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if an ObjectBindingPattern contains a rest element (...rest).\n */\nfunction hasRestElement(node: ts.ObjectBindingPattern): boolean {\n for (const element of node.elements) {\n if (element.dotDotDotToken) {\n return true;\n }\n }\n return false;\n}\n\ninterface DestructureInfo {\n line: number;\n column: number;\n context: string;\n hasDisableComment: boolean;\n}\n\n/**\n * Find all destructuring patterns in a file using AST.\n */\n// webpieces-disable max-lines-new-methods -- AST traversal with multiple destructuring pattern checks and exception detection\nfunction findDestructuringInFile(filePath: string, workspaceRoot: string, disableAllowed: boolean): DestructureInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const violations: DestructureInfo[] = [];\n\n // webpieces-disable max-lines-new-methods -- AST visitor needs to handle object/array binding patterns in declarations, for-of, and parameters\n function visit(node: ts.Node): void {\n try {\n // Check ObjectBindingPattern\n if (ts.isObjectBindingPattern(node)) {\n // Exception: rest operator separation\n if (hasRestElement(node)) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const context = getDestructureContext(node);\n recordViolation(node, context, fileLines, sourceFile, violations, disableAllowed);\n }\n\n // Check ArrayBindingPattern\n if (ts.isArrayBindingPattern(node)) {\n // Exception: Promise.all destructure\n if (isPromiseAllDestructure(node)) {\n ts.forEachChild(node, visit);\n return;\n }\n\n // Exception: Object.entries in for-of\n if (isObjectEntriesForOf(node)) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const context = getDestructureContext(node);\n recordViolation(node, context, fileLines, sourceFile, violations, disableAllowed);\n }\n } catch {\n // Skip nodes that cause errors during analysis\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return violations;\n}\n\nfunction recordViolation(\n node: ts.Node,\n context: string,\n fileLines: string[],\n sourceFile: ts.SourceFile,\n violations: DestructureInfo[],\n disableAllowed: boolean,\n): void {\n const startPos = node.getStart(sourceFile);\n if (startPos >= 0) {\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const column = pos.character + 1;\n const disabled = hasDisableComment(fileLines, line);\n\n if (!disableAllowed && disabled) {\n // When disableAllowed is false, ignore disable comments — still a violation\n violations.push({ line, column, context, hasDisableComment: false });\n } else {\n violations.push({ line, column, context, hasDisableComment: disabled });\n }\n }\n}\n\n/**\n * Get a description of where the destructuring pattern appears.\n */\nfunction getDestructureContext(node: ts.Node): string {\n const parent = node.parent;\n if (ts.isParameter(parent)) {\n return 'function parameter destructuring';\n }\n if (ts.isVariableDeclaration(parent)) {\n const grandparent = parent.parent;\n if (grandparent && ts.isVariableDeclarationList(grandparent)) {\n const forOfParent = grandparent.parent;\n if (forOfParent && ts.isForOfStatement(forOfParent)) {\n return ts.isObjectBindingPattern(node)\n ? 'object destructuring in for-of loop'\n : 'array destructuring in for-of loop';\n }\n }\n return ts.isObjectBindingPattern(node)\n ? 'object destructuring in variable declaration'\n : 'array destructuring in variable declaration';\n }\n return ts.isObjectBindingPattern(node)\n ? 'object destructuring'\n : 'array destructuring';\n}\n\n/**\n * MODIFIED_CODE mode: Flag violations on changed lines in diff hunks.\n */\n// webpieces-disable max-lines-new-methods -- File iteration with diff parsing and line filtering\nfunction findViolationsForModifiedCode(\n workspaceRoot: string,\n changedFiles: string[],\n base: string,\n head: string | undefined,\n disableAllowed: boolean\n): DestructureViolation[] {\n const violations: DestructureViolation[] = [];\n\n for (const file of changedFiles) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n\n if (changedLines.size === 0) continue;\n\n const allViolations = findDestructuringInFile(file, workspaceRoot, disableAllowed);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n // LINE-BASED: Only include if the violation is on a changed line\n if (!changedLines.has(v.line)) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * MODIFIED_FILES mode: Flag ALL violations in files that were modified.\n */\nfunction findViolationsForModifiedFiles(workspaceRoot: string, changedFiles: string[], disableAllowed: boolean): DestructureViolation[] {\n const violations: DestructureViolation[] = [];\n\n for (const file of changedFiles) {\n const allViolations = findDestructuringInFile(file, workspaceRoot, disableAllowed);\n\n for (const v of allViolations) {\n if (disableAllowed && v.hasDisableComment) continue;\n\n violations.push({\n file,\n line: v.line,\n column: v.column,\n context: v.context,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Auto-detect the base branch by finding the merge-base with origin/main.\n */\nfunction detectBase(workspaceRoot: string): string | null {\n try {\n const mergeBase = execSync('git merge-base HEAD origin/main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n try {\n const mergeBase = execSync('git merge-base HEAD main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n // Ignore\n }\n }\n return null;\n}\n\n/**\n * Report violations to console.\n */\n// webpieces-disable max-lines-new-methods -- Console output with examples and escape hatch information\nfunction reportViolations(violations: DestructureViolation[], mode: NoDestructureMode, disableAllowed: boolean): void {\n console.error('');\n console.error('\\u274c Destructuring patterns found! Use explicit property access instead.');\n console.error('');\n console.error('\\ud83d\\udcda Avoiding destructuring improves code traceability:');\n console.error('');\n console.error(' BAD: const { name, age } = user;');\n console.error(' GOOD: const name = user.name;');\n console.error(' const age = user.age;');\n console.error('');\n console.error(' BAD: function process({ x, y }: Point) { }');\n console.error(' GOOD: function process(point: Point) { point.x; point.y; }');\n console.error('');\n\n for (const v of violations) {\n console.error(` \\u274c ${v.file}:${v.line}:${v.column}`);\n console.error(` ${v.context}`);\n }\n console.error('');\n\n console.error(' Allowed exceptions:');\n console.error(' - const [a, b] = await Promise.all([...])');\n console.error(' - for (const [key, value] of Object.entries(obj))');\n console.error(' - const { extracted, ...rest } = obj (rest operator separation)');\n console.error('');\n\n if (disableAllowed) {\n console.error(' Escape hatch (use sparingly):');\n console.error(' // webpieces-disable no-destructure -- [your reason]');\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n console.error(' Disable comments are ignored. Fix the destructuring directly.');\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\n/**\n * Resolve mode considering ignoreModifiedUntilEpoch override.\n * When active, downgrades to OFF. When expired, logs a warning.\n */\nfunction resolveNoDestructureMode(normalMode: NoDestructureMode, epoch: number | undefined): NoDestructureMode {\n if (epoch === undefined || normalMode === 'OFF') {\n return normalMode;\n }\n const nowSeconds = Date.now() / 1000;\n if (nowSeconds < epoch) {\n const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];\n console.log(`\\n\\u23ed\\ufe0f Skipping no-destructure validation (ignoreModifiedUntilEpoch active, expires: ${expiresDate})`);\n console.log('');\n return 'OFF';\n }\n const expiresDate = new Date(epoch * 1000).toISOString().split('T')[0];\n console.log(`\\n\\u26a0\\ufe0f noDestructure.ignoreModifiedUntilEpoch (${epoch}) has expired (${expiresDate}). Remove it from nx.json. Using normal mode: ${normalMode}\\n`);\n return normalMode;\n}\n\nexport default async function runExecutor(\n options: ValidateNoDestructureOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const mode: NoDestructureMode = resolveNoDestructureMode(options.mode ?? 'OFF', options.ignoreModifiedUntilEpoch);\n const disableAllowed = options.disableAllowed ?? true;\n\n if (mode === 'OFF') {\n console.log('\\n\\u23ed\\ufe0f Skipping no-destructure validation (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n console.log('\\n\\ud83d\\udccf Validating No Destructuring\\n');\n console.log(` Mode: ${mode}`);\n\n let base = process.env['NX_BASE'];\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n base = detectBase(workspaceRoot) ?? undefined;\n\n if (!base) {\n console.log('\\n\\u23ed\\ufe0f Skipping no-destructure validation (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedTypeScriptFiles(workspaceRoot, base, head);\n\n if (changedFiles.length === 0) {\n console.log('\\u2705 No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`\\ud83d\\udcc2 Checking ${changedFiles.length} changed file(s)...`);\n\n let violations: DestructureViolation[] = [];\n\n if (mode === 'MODIFIED_CODE') {\n violations = findViolationsForModifiedCode(workspaceRoot, changedFiles, base, head, disableAllowed);\n } else if (mode === 'MODIFIED_FILES') {\n violations = findViolationsForModifiedFiles(workspaceRoot, changedFiles, disableAllowed);\n }\n\n if (violations.length === 0) {\n console.log('\\u2705 No destructuring patterns found');\n return { success: true };\n }\n\n reportViolations(violations, mode, disableAllowed);\n\n return { success: false };\n}\n"]}