@empline/preflight 1.1.10 → 1.1.11

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,319 @@
1
+ #!/usr/bin/env tsx
2
+ "use strict";
3
+ /**
4
+ * Turbopack Prisma Computed Property Preflight (BLOCKING)
5
+ *
6
+ * Detects computed property names in Prisma `where` clauses that can get
7
+ * mangled by Turbopack during build, resulting in "column not found" errors.
8
+ *
9
+ * Problem Pattern:
10
+ * const field = resolveCatalogIdField(productType);
11
+ * await prisma.coreListings.findMany({
12
+ * where: {
13
+ * [field]: catalogId, // Turbopack mangles `field` -> "_field" -> undefined
14
+ * }
15
+ * });
16
+ *
17
+ * Safe Pattern:
18
+ * // Use explicit property names with switch statement
19
+ * let catalogWhere = {};
20
+ * switch (productType) {
21
+ * case ProductType.SPORTS_CARD:
22
+ * catalogWhere = { sportsCardCatalogId: catalogId };
23
+ * break;
24
+ * }
25
+ * await prisma.coreListings.findMany({
26
+ * where: { ...baseWhere, ...catalogWhere }
27
+ * });
28
+ *
29
+ * Why this matters:
30
+ * - Turbopack's minification can mangle computed property key variable names
31
+ * - Results in Prisma runtime error: "column '(not available)' does not exist"
32
+ * - Breaks production builds silently - works in dev but fails in prod
33
+ *
34
+ * Usage:
35
+ * pnpm preflight turbopack/prisma-computed-property
36
+ * pnpm preflight turbopack/prisma-computed-property --verbose
37
+ */
38
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
39
+ if (k2 === undefined) k2 = k;
40
+ var desc = Object.getOwnPropertyDescriptor(m, k);
41
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
42
+ desc = { enumerable: true, get: function() { return m[k]; } };
43
+ }
44
+ Object.defineProperty(o, k2, desc);
45
+ }) : (function(o, m, k, k2) {
46
+ if (k2 === undefined) k2 = k;
47
+ o[k2] = m[k];
48
+ }));
49
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
50
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
51
+ }) : function(o, v) {
52
+ o["default"] = v;
53
+ });
54
+ var __importStar = (this && this.__importStar) || (function () {
55
+ var ownKeys = function(o) {
56
+ ownKeys = Object.getOwnPropertyNames || function (o) {
57
+ var ar = [];
58
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
59
+ return ar;
60
+ };
61
+ return ownKeys(o);
62
+ };
63
+ return function (mod) {
64
+ if (mod && mod.__esModule) return mod;
65
+ var result = {};
66
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
67
+ __setModuleDefault(result, mod);
68
+ return result;
69
+ };
70
+ })();
71
+ Object.defineProperty(exports, "__esModule", { value: true });
72
+ exports.requires = exports.tags = exports.description = exports.blocking = exports.category = exports.name = exports.id = void 0;
73
+ exports.run = run;
74
+ const fs = __importStar(require("fs"));
75
+ const glob_1 = require("glob");
76
+ const console_chars_1 = require("../../utils/console-chars");
77
+ // Check metadata
78
+ exports.id = "turbopack/prisma-computed-property";
79
+ exports.name = "Turbopack Prisma Computed Property Safety";
80
+ exports.category = "turbopack";
81
+ exports.blocking = true; // This causes runtime production errors
82
+ exports.description = "Detects computed property names in Prisma where clauses that may cause Turbopack mangling";
83
+ exports.tags = ["turbopack", "prisma", "runtime", "production"];
84
+ exports.requires = [];
85
+ const EXCLUDED_PATTERNS = [
86
+ "**/node_modules/**",
87
+ "**/dist/**",
88
+ "**/.next/**",
89
+ "**/coverage/**",
90
+ "**/test-results/**",
91
+ "**/*.test.ts",
92
+ "**/*.spec.ts",
93
+ "**/*.test.tsx",
94
+ "**/*.spec.tsx",
95
+ "**/preflight-manager/src/checks/**", // Exclude preflight source files (contain examples)
96
+ ];
97
+ /**
98
+ * Detects computed property names used in Prisma where clauses
99
+ */
100
+ function checkFile(filePath, content) {
101
+ const issues = [];
102
+ const lines = content.split("\n");
103
+ // Skip files that don't use Prisma
104
+ if (!content.includes("prisma.") && !content.includes("@prisma/client")) {
105
+ return issues;
106
+ }
107
+ // Pattern 1: Detect computed property name in object literal [variable]
108
+ // Look for patterns like: { [x]: value } or { [variable]: value }
109
+ // Especially when near Prisma method calls
110
+ const computedPropPattern = /\[\s*(\w+)\s*\]\s*:/g;
111
+ let match;
112
+ while ((match = computedPropPattern.exec(content)) !== null) {
113
+ const variableName = match[1];
114
+ const matchIndex = match.index;
115
+ // Skip if it's a literal (number, string, or common iteration vars)
116
+ if (/^[0-9]+$/.test(variableName))
117
+ continue;
118
+ if (["i", "j", "k", "idx", "index", "key"].includes(variableName))
119
+ continue;
120
+ // Skip common safe variable names (user-provided data, not column names)
121
+ // 'field' is typically used in helper functions with hardcoded string literal arguments
122
+ if (["template", "templateName", "fieldName", "field"].includes(variableName))
123
+ continue;
124
+ // Check context - is this near a Prisma call?
125
+ const contextStart = Math.max(0, matchIndex - 200);
126
+ const contextEnd = Math.min(content.length, matchIndex + 200);
127
+ const context = content.substring(contextStart, contextEnd);
128
+ // Look for Prisma method patterns in context
129
+ const prismaPatterns = [
130
+ /prisma\.\w+\.(findFirst|findMany|findUnique|create|update|updateMany|delete|deleteMany|upsert|count|aggregate)/,
131
+ /\.(where|select|include|orderBy)\s*:/,
132
+ /await\s+prisma\./,
133
+ ];
134
+ // Skip if this is in a data block (create/update data, not column names)
135
+ if (/\.data\s*[:=]/.test(context) || /data:\s*\{/.test(context)) {
136
+ // Check if we're specifically in a data block vs where block
137
+ const beforeMatch = content.substring(Math.max(0, matchIndex - 100), matchIndex);
138
+ if (!beforeMatch.includes("where:") && !beforeMatch.includes("where =")) {
139
+ continue;
140
+ }
141
+ }
142
+ // Skip if this looks like a JSON field update (fieldMappings, config, etc.)
143
+ if (/fieldMappings|exportSettings|config\s*[:=]/.test(context)) {
144
+ continue;
145
+ }
146
+ const isPrismaContext = prismaPatterns.some((p) => p.test(context));
147
+ if (!isPrismaContext)
148
+ continue;
149
+ // Find line number
150
+ let lineNumber = 1;
151
+ let charCount = 0;
152
+ for (let i = 0; i < lines.length; i++) {
153
+ charCount += lines[i].length + 1;
154
+ if (charCount > matchIndex) {
155
+ lineNumber = i + 1;
156
+ break;
157
+ }
158
+ }
159
+ issues.push({
160
+ file: filePath,
161
+ line: lineNumber,
162
+ severity: "error",
163
+ message: `Computed property [${variableName}] in Prisma query may be mangled by Turbopack`,
164
+ suggestion: `Use explicit property names instead: switch(type) { case X: where = { explicitField: value }; }`,
165
+ snippet: lines[lineNumber - 1]?.trim().substring(0, 100),
166
+ pattern: `[${variableName}]`,
167
+ });
168
+ }
169
+ // Pattern 2: Detect dynamic key assignment before where clause
170
+ // e.g., const key = getField(); later used in where: { [key]: value }
171
+ const dynamicKeyPattern = /const\s+(\w+(?:Field|Key|Name|Id))\s*=\s*(?:\w+\(|.*resolve)/gi;
172
+ while ((match = dynamicKeyPattern.exec(content)) !== null) {
173
+ const keyVariable = match[1];
174
+ // Check if this variable is used in a computed property later
175
+ const usagePattern = new RegExp(`\\[\\s*${keyVariable}\\s*\\]\\s*:`, "g");
176
+ if (usagePattern.test(content)) {
177
+ let lineNumber = 1;
178
+ let charCount = 0;
179
+ for (let i = 0; i < lines.length; i++) {
180
+ charCount += lines[i].length + 1;
181
+ if (charCount > match.index) {
182
+ lineNumber = i + 1;
183
+ break;
184
+ }
185
+ }
186
+ // Avoid duplicates - only add if not already reported
187
+ const alreadyReported = issues.some((issue) => issue.file === filePath && Math.abs(issue.line - lineNumber) < 5);
188
+ if (!alreadyReported) {
189
+ issues.push({
190
+ file: filePath,
191
+ line: lineNumber,
192
+ severity: "warning",
193
+ message: `Variable '${keyVariable}' may be used as computed property key in Prisma query`,
194
+ suggestion: `Consider using explicit property names with a switch statement instead of dynamic key resolution`,
195
+ snippet: lines[lineNumber - 1]?.trim().substring(0, 100),
196
+ pattern: keyVariable,
197
+ });
198
+ }
199
+ }
200
+ }
201
+ return issues;
202
+ }
203
+ async function run() {
204
+ const args = process.argv.slice(2);
205
+ const verbose = args.includes("--verbose") || args.includes("-v");
206
+ const jsonOutput = args.includes("--json");
207
+ if (!jsonOutput) {
208
+ console.log(`\n${console_chars_1.emoji.palette} Turbopack Prisma Computed Property Preflight`);
209
+ console.log((0, console_chars_1.createDivider)(80, "heavy"));
210
+ console.log(` Detecting computed property names in Prisma queries that may cause`);
211
+ console.log(` "column '(not available)' does not exist" errors in production.`);
212
+ console.log("");
213
+ }
214
+ const startTime = Date.now();
215
+ const allIssues = [];
216
+ // Find all TypeScript files
217
+ const files = await (0, glob_1.glob)("**/*.{ts,tsx}", {
218
+ cwd: process.cwd(),
219
+ absolute: true,
220
+ ignore: EXCLUDED_PATTERNS,
221
+ });
222
+ let filesScanned = 0;
223
+ for (const file of files) {
224
+ try {
225
+ const content = fs.readFileSync(file, "utf-8");
226
+ filesScanned++;
227
+ const issues = checkFile(file, content);
228
+ allIssues.push(...issues);
229
+ }
230
+ catch (error) {
231
+ if (verbose) {
232
+ console.error(`${console_chars_1.emoji.warning} Error reading ${file}: ${error.message}`);
233
+ }
234
+ }
235
+ }
236
+ const duration = Date.now() - startTime;
237
+ const errors = allIssues.filter((i) => i.severity === "error");
238
+ const warnings = allIssues.filter((i) => i.severity === "warning");
239
+ // JSON output mode
240
+ if (jsonOutput) {
241
+ console.log(JSON.stringify(allIssues, null, 2));
242
+ process.exit(errors.length > 0 ? 1 : 0);
243
+ }
244
+ // Report results
245
+ console.log(`\n${console_chars_1.emoji.chart} Scan Summary:`);
246
+ console.log(` Files scanned: ${filesScanned}`);
247
+ console.log(` Duration: ${duration}ms`);
248
+ if (allIssues.length === 0) {
249
+ console.log(`\n${console_chars_1.emoji.success} No computed property patterns detected in Prisma queries`);
250
+ console.log(` All Prisma queries use explicit property names.`);
251
+ process.exit(0);
252
+ }
253
+ console.log(`\n${console_chars_1.emoji.clipboard} Issues Found:`);
254
+ console.log(` ${console_chars_1.emoji.error} Errors: ${errors.length}`);
255
+ console.log(` ${console_chars_1.emoji.warning} Warnings: ${warnings.length}`);
256
+ if (errors.length > 0) {
257
+ console.log(`\n${console_chars_1.emoji.error} ERRORS (will cause production runtime errors):`);
258
+ console.log((0, console_chars_1.createDivider)(60, "light"));
259
+ for (const issue of errors.slice(0, verbose ? 20 : 10)) {
260
+ const relativePath = issue.file.replace(process.cwd(), "").replace(/^[\\/]/, "");
261
+ console.log(` ${relativePath}:${issue.line}`);
262
+ console.log(` ${issue.message}`);
263
+ console.log(` ${console_chars_1.emoji.hint} ${issue.suggestion}`);
264
+ if (issue.snippet) {
265
+ console.log(` ${console_chars_1.emoji.memo} ${issue.snippet}`);
266
+ }
267
+ console.log("");
268
+ }
269
+ if (errors.length > (verbose ? 20 : 10)) {
270
+ console.log(` ... and ${errors.length - (verbose ? 20 : 10)} more`);
271
+ }
272
+ }
273
+ if (verbose && warnings.length > 0) {
274
+ console.log(`\n${console_chars_1.emoji.warning} WARNINGS:`);
275
+ console.log((0, console_chars_1.createDivider)(60, "light"));
276
+ for (const issue of warnings.slice(0, 10)) {
277
+ const relativePath = issue.file.replace(process.cwd(), "").replace(/^[\\/]/, "");
278
+ console.log(` ${relativePath}:${issue.line}`);
279
+ console.log(` ${issue.message}`);
280
+ console.log(` ${console_chars_1.emoji.hint} ${issue.suggestion}`);
281
+ console.log("");
282
+ }
283
+ }
284
+ // Print fix guidance
285
+ console.log(`\n${console_chars_1.emoji.docs} How to fix:`);
286
+ console.log(` Replace computed property names with explicit switch statements:`);
287
+ console.log("");
288
+ console.log(` // BEFORE (risky):`);
289
+ console.log(` const catalogIdField = resolveCatalogIdField(productType);`);
290
+ console.log(` await prisma.coreListings.findMany({`);
291
+ console.log(` where: { [catalogIdField]: catalogId }`);
292
+ console.log(` });`);
293
+ console.log("");
294
+ console.log(` // AFTER (safe):`);
295
+ console.log(` let catalogWhere: Record<string, string> = {};`);
296
+ console.log(` switch (productType) {`);
297
+ console.log(` case ProductType.SPORTS_CARD:`);
298
+ console.log(` catalogWhere = { sportsCardCatalogId: catalogId };`);
299
+ console.log(` break;`);
300
+ console.log(` case ProductType.TCG_CARD:`);
301
+ console.log(` catalogWhere = { tcgCardCatalogId: catalogId };`);
302
+ console.log(` break;`);
303
+ console.log(` }`);
304
+ console.log(` await prisma.coreListings.findMany({`);
305
+ console.log(` where: { ...baseWhere, ...catalogWhere }`);
306
+ console.log(` });`);
307
+ // Exit code
308
+ if (errors.length > 0) {
309
+ console.log(`\n${console_chars_1.emoji.error} ${errors.length} error(s) found - blocking.`);
310
+ process.exit(1);
311
+ }
312
+ console.log(`\n${console_chars_1.emoji.success} Preflight complete`);
313
+ process.exit(0);
314
+ }
315
+ // Allow direct execution
316
+ if (require.main === module) {
317
+ run().catch(console.error);
318
+ }
319
+ //# sourceMappingURL=prisma-computed-property.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-computed-property.js","sourceRoot":"","sources":["../../../src/checks/turbopack/prisma-computed-property.ts"],"names":[],"mappings":"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"}
@@ -6,10 +6,14 @@
6
6
  * These are patterns that apply to all pages, not just integrations.
7
7
  *
8
8
  * Checks:
9
- * - Buttons disabled during loading states (async action buttons only)
10
- * - Extracted async handlers (not inline)
11
- * - Network error handling (fetch calls must have catch)
12
- * - Multi-step wizard reset functionality
9
+ * 1. Pagination consolidation - must use UnifiedPagination, not BottomPagination/DataTablePagination
10
+ * 2. Hardcoded colors - must use design tokens (var(--color-*))
11
+ * 3. Responsive breakpoints - must have tablet breakpoints (sm, md), not just xs→lg jumps
12
+ * 4. Metric component consolidation - must use StatCard/CompactStatCard
13
+ * 5. Accessibility - buttons and interactive elements must have ARIA labels
14
+ * 6. Error handling - fetch calls must have catch, forms must have error states
15
+ * 7. Loading states - async operations must disable buttons and show loading indicators
16
+ * 8. Micro-interactions - save confirmations, button feedback
13
17
  *
14
18
  * Usage:
15
19
  * pnpm preflight:ui-consistency
@@ -36,9 +40,50 @@ declare class UIConsistencyPreflight {
36
40
  private readFile;
37
41
  private shouldExclude;
38
42
  /**
39
- * Validate UI consistency across relevant files
43
+ * Check 1: Pagination Component Consolidation
44
+ * Ensures deprecated pagination components are not used
40
45
  */
41
- private validateUIConsistency;
46
+ private validatePaginationConsolidation;
47
+ /**
48
+ * Check 2: Hardcoded Colors
49
+ * Ensures design tokens are used instead of hardcoded color values
50
+ */
51
+ private validateDesignTokens;
52
+ /**
53
+ * Check 3: Responsive Breakpoints
54
+ * Ensures proper tablet breakpoints exist (not just xs→lg jumps)
55
+ */
56
+ private validateResponsiveBreakpoints;
57
+ /**
58
+ * Check 4: Accessibility - ARIA Labels
59
+ * Ensures interactive elements have proper ARIA attributes
60
+ */
61
+ private validateAccessibility;
62
+ /**
63
+ * Check 5: Error Handling
64
+ * Ensures proper error handling for async operations
65
+ */
66
+ private validateErrorHandling;
67
+ /**
68
+ * Check 6: Loading States
69
+ * Ensures async operations have proper loading indicators
70
+ */
71
+ private validateLoadingStates;
72
+ /**
73
+ * Check 7: Wizard Reset Functionality
74
+ * Ensures multi-step wizards have reset capability
75
+ */
76
+ private validateWizardReset;
77
+ /**
78
+ * Check 8: Password Fields
79
+ * Ensures secret fields use password type
80
+ */
81
+ private validatePasswordFields;
82
+ /**
83
+ * Check 9: Metric Component Consolidation
84
+ * Ensures deprecated metric components are not used
85
+ */
86
+ private validateMetricConsolidation;
42
87
  /**
43
88
  * Run all checks
44
89
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ui-consistency-validation.d.ts","sourceRoot":"","sources":["../../../src/checks/ui/ui-consistency-validation.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AAYH,eAAO,MAAM,EAAE,iCAAiC,CAAC;AACjD,eAAO,MAAM,IAAI,8BAA8B,CAAC;AAChD,eAAO,MAAM,WAAW,4EAA4E,CAAC;AACrG,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,IAAI,UAAiE,CAAC;AAEnF,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAmBD,cAAM,sBAAsB;IAC1B,OAAO,CAAC,OAAO,CAAU;gBAEb,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO;IAI/C,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyF7B;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;IAapE,OAAO,CAAC,YAAY;CA0CrB;AAkBD,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"ui-consistency-validation.d.ts","sourceRoot":"","sources":["../../../src/checks/ui/ui-consistency-validation.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;GAmBG;AAYH,eAAO,MAAM,EAAE,iCAAiC,CAAC;AACjD,eAAO,MAAM,IAAI,8BAA8B,CAAC;AAChD,eAAO,MAAM,WAAW,4EAA4E,CAAC;AACrG,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,IAAI,UAA8G,CAAC;AAEhI,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA4DD,cAAM,sBAAsB;IAC1B,OAAO,CAAC,OAAO,CAAU;gBAEb,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO;IAI/C,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,OAAO,CAAC,+BAA+B;IAoDvC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAiE5B;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAoDrC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAkE7B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAwD7B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAwD7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAwC3B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA+C9B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA2CnC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;IAuBpE,OAAO,CAAC,YAAY;CA0CrB;AAkBD,OAAO,EAAE,sBAAsB,EAAE,CAAC"}