@empline/preflight 1.1.33 → 1.1.35
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/dist/checks/auth/client-only-protected-pages.d.ts +14 -0
- package/dist/checks/auth/client-only-protected-pages.d.ts.map +1 -0
- package/dist/checks/auth/client-only-protected-pages.js +182 -0
- package/dist/checks/auth/client-only-protected-pages.js.map +1 -0
- package/dist/checks/auth/empty-data-instead-of-redirect.d.ts +14 -0
- package/dist/checks/auth/empty-data-instead-of-redirect.d.ts.map +1 -0
- package/dist/checks/auth/empty-data-instead-of-redirect.js +200 -0
- package/dist/checks/auth/empty-data-instead-of-redirect.js.map +1 -0
- package/dist/checks/auth/store-id-fallback.d.ts +14 -0
- package/dist/checks/auth/store-id-fallback.d.ts.map +1 -0
- package/dist/checks/auth/store-id-fallback.js +217 -0
- package/dist/checks/auth/store-id-fallback.js.map +1 -0
- package/dist/checks/auth/store-page-auth-guard.d.ts +14 -0
- package/dist/checks/auth/store-page-auth-guard.d.ts.map +1 -0
- package/dist/checks/auth/store-page-auth-guard.js +255 -0
- package/dist/checks/auth/store-page-auth-guard.js.map +1 -0
- package/dist/checks/data-integrity/api-route-reference-validation.d.ts +14 -0
- package/dist/checks/data-integrity/api-route-reference-validation.d.ts.map +1 -0
- package/dist/checks/data-integrity/api-route-reference-validation.js +219 -0
- package/dist/checks/data-integrity/api-route-reference-validation.js.map +1 -0
- package/dist/checks/system/active-preflight-migration-tracker.d.ts +13 -0
- package/dist/checks/system/active-preflight-migration-tracker.d.ts.map +1 -0
- package/dist/checks/system/active-preflight-migration-tracker.js +244 -0
- package/dist/checks/system/active-preflight-migration-tracker.js.map +1 -0
- package/dist/checks/ui/filter-option-coverage.d.ts +14 -0
- package/dist/checks/ui/filter-option-coverage.d.ts.map +1 -0
- package/dist/checks/ui/filter-option-coverage.js +286 -0
- package/dist/checks/ui/filter-option-coverage.js.map +1 -0
- package/dist/checks/ui/query-param-state-sync.d.ts +14 -0
- package/dist/checks/ui/query-param-state-sync.d.ts.map +1 -0
- package/dist/checks/ui/query-param-state-sync.js +251 -0
- package/dist/checks/ui/query-param-state-sync.js.map +1 -0
- package/dist/checks/ui/unimplemented-action-handler.d.ts +14 -0
- package/dist/checks/ui/unimplemented-action-handler.d.ts.map +1 -0
- package/dist/checks/ui/unimplemented-action-handler.js +230 -0
- package/dist/checks/ui/unimplemented-action-handler.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
|
|
8
|
+
exports.run = run;
|
|
9
|
+
/**
|
|
10
|
+
* Filter Option Coverage Preflight
|
|
11
|
+
*
|
|
12
|
+
* Detects when filter options don't cover all possible values. This causes
|
|
13
|
+
* UX issues where users can't filter to see certain items.
|
|
14
|
+
*
|
|
15
|
+
* Example problems this catches:
|
|
16
|
+
* - Status filter options are [ACTIVE, PENDING, SOLD] but API returns INACTIVE/REMOVED items
|
|
17
|
+
* - Category filter missing options that exist in the data
|
|
18
|
+
* - StatusCounts show items in statuses that aren't filterable
|
|
19
|
+
*
|
|
20
|
+
* Pattern detection:
|
|
21
|
+
* 1. Find filter option definitions (STATUS_OPTIONS, CATEGORY_OPTIONS, etc.)
|
|
22
|
+
* 2. Find where those options are used in UI filters
|
|
23
|
+
* 3. Find where status/category counts are displayed
|
|
24
|
+
* 4. Check for mismatches where counts show values not in filter options
|
|
25
|
+
*/
|
|
26
|
+
const fs_1 = __importDefault(require("fs"));
|
|
27
|
+
const path_1 = __importDefault(require("path"));
|
|
28
|
+
const glob_1 = require("glob");
|
|
29
|
+
const console_chars_1 = require("../../utils/console-chars");
|
|
30
|
+
// METADATA
|
|
31
|
+
exports.id = "ui/filter-option-coverage";
|
|
32
|
+
exports.name = "Filter Option Coverage";
|
|
33
|
+
exports.description = "Detects filter options that don't cover all possible values";
|
|
34
|
+
exports.category = "ui";
|
|
35
|
+
exports.blocking = false; // Warning - may be intentional
|
|
36
|
+
exports.tags = ["ui", "filters", "options", "enum", "consistency"];
|
|
37
|
+
exports.requires = ["trading-card-system"];
|
|
38
|
+
/**
|
|
39
|
+
* Patterns to find option/enum definitions
|
|
40
|
+
*/
|
|
41
|
+
const OPTION_DEFINITION_PATTERNS = [
|
|
42
|
+
// const STATUS_OPTIONS = [{ value: "ACTIVE" }, ...]
|
|
43
|
+
/const\s+([A-Z_]+_OPTIONS)\s*(?::\s*[^=]+)?\s*=\s*\[([^\]]+)\]/gs,
|
|
44
|
+
// export const LISTING_STATUS_OPTIONS = [...]
|
|
45
|
+
/export\s+const\s+([A-Z_]+_OPTIONS)\s*(?::\s*[^=]+)?\s*=\s*\[([^\]]+)\]/gs,
|
|
46
|
+
// const statusOptions = [...]
|
|
47
|
+
/const\s+(\w+Options)\s*(?::\s*[^=]+)?\s*=\s*\[([^\]]+)\]/gs,
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* Patterns to find count field access (statusCounts.ACTIVE, etc.)
|
|
51
|
+
*/
|
|
52
|
+
const COUNT_USAGE_PATTERNS = [
|
|
53
|
+
// statusCounts.ACTIVE, statusCounts["PENDING"]
|
|
54
|
+
/(\w+Counts?)\.([A-Z_]+)/g,
|
|
55
|
+
// counts.status.ACTIVE
|
|
56
|
+
/counts\.(\w+)\.([A-Z_]+)/g,
|
|
57
|
+
// Object.entries(statusCounts)
|
|
58
|
+
/Object\.(?:entries|keys)\s*\(\s*(\w+Counts?)\s*\)/g,
|
|
59
|
+
];
|
|
60
|
+
/**
|
|
61
|
+
* Extract values from option array string
|
|
62
|
+
*/
|
|
63
|
+
function extractOptionValues(arrayContent) {
|
|
64
|
+
const values = [];
|
|
65
|
+
// Match value: "X" or value: 'X' patterns
|
|
66
|
+
const valuePattern = /value:\s*["'`]([^"'`]+)["'`]/g;
|
|
67
|
+
let match;
|
|
68
|
+
while ((match = valuePattern.exec(arrayContent)) !== null) {
|
|
69
|
+
values.push(match[1]);
|
|
70
|
+
}
|
|
71
|
+
// Also match simple string arrays ["ACTIVE", "PENDING"]
|
|
72
|
+
if (values.length === 0) {
|
|
73
|
+
const simplePattern = /["'`]([A-Z][A-Z_]+)["'`]/g;
|
|
74
|
+
while ((match = simplePattern.exec(arrayContent)) !== null) {
|
|
75
|
+
values.push(match[1]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return values;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Find all enum values from Prisma schema or TypeScript enums
|
|
82
|
+
*/
|
|
83
|
+
async function findEnumValues(enumName) {
|
|
84
|
+
const values = [];
|
|
85
|
+
// Check Prisma schema
|
|
86
|
+
const schemaPath = path_1.default.join(process.cwd(), "prisma/schema.prisma");
|
|
87
|
+
if (fs_1.default.existsSync(schemaPath)) {
|
|
88
|
+
const schema = fs_1.default.readFileSync(schemaPath, "utf-8");
|
|
89
|
+
const enumPattern = new RegExp(`enum\\s+${enumName}\\s*\\{([^}]+)\\}`, "s");
|
|
90
|
+
const match = schema.match(enumPattern);
|
|
91
|
+
if (match) {
|
|
92
|
+
const enumBody = match[1];
|
|
93
|
+
const valuePattern = /^\s*([A-Z_]+)/gm;
|
|
94
|
+
let valueMatch;
|
|
95
|
+
while ((valueMatch = valuePattern.exec(enumBody)) !== null) {
|
|
96
|
+
values.push(valueMatch[1]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Check TypeScript enums in constants
|
|
101
|
+
const enumFiles = await (0, glob_1.glob)("lib/constants/**/*.ts", { cwd: process.cwd() });
|
|
102
|
+
for (const enumFile of enumFiles) {
|
|
103
|
+
const content = fs_1.default.readFileSync(path_1.default.join(process.cwd(), enumFile), "utf-8");
|
|
104
|
+
const tsEnumPattern = new RegExp(`enum\\s+${enumName}\\s*\\{([^}]+)\\}`, "s");
|
|
105
|
+
const match = content.match(tsEnumPattern);
|
|
106
|
+
if (match) {
|
|
107
|
+
const enumBody = match[1];
|
|
108
|
+
const valuePattern = /^\s*([A-Z_]+)\s*(?:=|,|$)/gm;
|
|
109
|
+
let valueMatch;
|
|
110
|
+
while ((valueMatch = valuePattern.exec(enumBody)) !== null) {
|
|
111
|
+
values.push(valueMatch[1]);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return values;
|
|
116
|
+
}
|
|
117
|
+
async function run() {
|
|
118
|
+
console.log(`\n${console_chars_1.emoji.search} FILTER OPTION COVERAGE CHECK`);
|
|
119
|
+
console.log((0, console_chars_1.createDivider)(65, "heavy"));
|
|
120
|
+
const issues = [];
|
|
121
|
+
const optionDefinitions = [];
|
|
122
|
+
const countUsages = [];
|
|
123
|
+
// Step 1: Find option definitions
|
|
124
|
+
console.log(`\n${console_chars_1.emoji.file} Scanning for filter option definitions...`);
|
|
125
|
+
const constantFiles = await (0, glob_1.glob)([
|
|
126
|
+
"lib/constants/**/*.ts",
|
|
127
|
+
"lib/enums.ts",
|
|
128
|
+
"constants/**/*.ts",
|
|
129
|
+
], {
|
|
130
|
+
cwd: process.cwd(),
|
|
131
|
+
ignore: ["**/*.d.ts"],
|
|
132
|
+
});
|
|
133
|
+
for (const constFile of constantFiles) {
|
|
134
|
+
const filePath = path_1.default.join(process.cwd(), constFile);
|
|
135
|
+
if (!fs_1.default.existsSync(filePath))
|
|
136
|
+
continue;
|
|
137
|
+
const content = fs_1.default.readFileSync(filePath, "utf-8");
|
|
138
|
+
for (const pattern of OPTION_DEFINITION_PATTERNS) {
|
|
139
|
+
pattern.lastIndex = 0;
|
|
140
|
+
let match;
|
|
141
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
142
|
+
const optionName = match[1];
|
|
143
|
+
const arrayContent = match[2];
|
|
144
|
+
const values = extractOptionValues(arrayContent);
|
|
145
|
+
const lineNum = content.substring(0, match.index).split("\n").length;
|
|
146
|
+
if (values.length > 0) {
|
|
147
|
+
optionDefinitions.push({
|
|
148
|
+
file: constFile,
|
|
149
|
+
line: lineNum,
|
|
150
|
+
name: optionName,
|
|
151
|
+
values,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
console.log(` Found ${optionDefinitions.length} option definitions`);
|
|
158
|
+
// Step 2: Find where counts are used
|
|
159
|
+
console.log(`\n${console_chars_1.emoji.search} Scanning for count usages...`);
|
|
160
|
+
const uiFiles = await (0, glob_1.glob)([
|
|
161
|
+
"app/**/*Client.tsx",
|
|
162
|
+
"components/**/*.tsx",
|
|
163
|
+
], {
|
|
164
|
+
cwd: process.cwd(),
|
|
165
|
+
ignore: ["**/*.d.ts"],
|
|
166
|
+
});
|
|
167
|
+
for (const uiFile of uiFiles) {
|
|
168
|
+
const filePath = path_1.default.join(process.cwd(), uiFile);
|
|
169
|
+
if (!fs_1.default.existsSync(filePath))
|
|
170
|
+
continue;
|
|
171
|
+
const content = fs_1.default.readFileSync(filePath, "utf-8");
|
|
172
|
+
// Find statusCounts.X patterns
|
|
173
|
+
const countPattern = /(\w+Counts?)\.([A-Z_]+)/g;
|
|
174
|
+
const countFields = [];
|
|
175
|
+
let countMatch;
|
|
176
|
+
while ((countMatch = countPattern.exec(content)) !== null) {
|
|
177
|
+
const countVar = countMatch[1];
|
|
178
|
+
const fieldName = countMatch[2];
|
|
179
|
+
// Skip if it's a common method/property
|
|
180
|
+
if (["length", "toString", "valueOf"].includes(fieldName))
|
|
181
|
+
continue;
|
|
182
|
+
countFields.push(fieldName);
|
|
183
|
+
}
|
|
184
|
+
if (countFields.length > 0) {
|
|
185
|
+
const lineNum = content.indexOf("Counts") !== -1
|
|
186
|
+
? content.substring(0, content.indexOf("Counts")).split("\n").length
|
|
187
|
+
: 1;
|
|
188
|
+
countUsages.push({
|
|
189
|
+
file: uiFile,
|
|
190
|
+
line: lineNum,
|
|
191
|
+
countFields: [...new Set(countFields)],
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
console.log(` Found ${countUsages.length} files with count usages`);
|
|
196
|
+
// Step 3: Compare options to counts
|
|
197
|
+
console.log(`\n${console_chars_1.emoji.check} Comparing filter options to count fields...`);
|
|
198
|
+
// Map option names to their corresponding enum type
|
|
199
|
+
const optionToEnumMap = {
|
|
200
|
+
LISTING_STATUS_OPTIONS: "ListingStatus",
|
|
201
|
+
ORDER_STATUS_OPTIONS: "OrderStatus",
|
|
202
|
+
STATUS_OPTIONS: "Status",
|
|
203
|
+
PAYMENT_STATUS_OPTIONS: "PaymentStatus",
|
|
204
|
+
CATEGORY_OPTIONS: "Category",
|
|
205
|
+
};
|
|
206
|
+
for (const optionDef of optionDefinitions) {
|
|
207
|
+
// Get the expected enum values
|
|
208
|
+
const enumName = optionToEnumMap[optionDef.name];
|
|
209
|
+
const enumValues = enumName ? await findEnumValues(enumName) : [];
|
|
210
|
+
// Find counts that reference more values than the options have
|
|
211
|
+
for (const countUsage of countUsages) {
|
|
212
|
+
// Check if option name suggests it's for this type
|
|
213
|
+
const optionPrefix = optionDef.name.replace(/_OPTIONS$/, "").toLowerCase();
|
|
214
|
+
// Look for count fields that aren't in the options
|
|
215
|
+
const countFieldsForType = countUsage.countFields.filter((field) => {
|
|
216
|
+
// This is a heuristic - count fields often match option values
|
|
217
|
+
return enumValues.includes(field) || optionDef.values.includes(field);
|
|
218
|
+
});
|
|
219
|
+
const missingFromOptions = countFieldsForType.filter((field) => !optionDef.values.includes(field));
|
|
220
|
+
if (missingFromOptions.length > 0) {
|
|
221
|
+
issues.push({
|
|
222
|
+
file: countUsage.file,
|
|
223
|
+
line: countUsage.line,
|
|
224
|
+
optionName: optionDef.name,
|
|
225
|
+
missingValues: missingFromOptions,
|
|
226
|
+
description: `Counts display ${missingFromOptions.join(", ")} but filter options (${optionDef.name}) don't include them`,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Also check against enum values from Prisma
|
|
231
|
+
if (enumValues.length > 0) {
|
|
232
|
+
const missingFromOptions = enumValues.filter((enumVal) => !optionDef.values.includes(enumVal));
|
|
233
|
+
if (missingFromOptions.length > 0) {
|
|
234
|
+
issues.push({
|
|
235
|
+
file: optionDef.file,
|
|
236
|
+
line: optionDef.line,
|
|
237
|
+
optionName: optionDef.name,
|
|
238
|
+
missingValues: missingFromOptions,
|
|
239
|
+
description: `Filter options missing enum values: ${missingFromOptions.join(", ")}`,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Deduplicate
|
|
245
|
+
const uniqueIssues = issues.filter((issue, index, self) => index === self.findIndex((i) => i.optionName === issue.optionName &&
|
|
246
|
+
JSON.stringify(i.missingValues.sort()) === JSON.stringify(issue.missingValues.sort())));
|
|
247
|
+
// Summary
|
|
248
|
+
console.log(`\n${console_chars_1.emoji.chart} Summary:`);
|
|
249
|
+
console.log(` Option definitions: ${optionDefinitions.length}`);
|
|
250
|
+
console.log(` Count usage files: ${countUsages.length}`);
|
|
251
|
+
console.log(` Coverage issues: ${uniqueIssues.length}`);
|
|
252
|
+
if (uniqueIssues.length === 0) {
|
|
253
|
+
console.log(`\n${console_chars_1.emoji.success} FILTER OPTION COVERAGE CHECK PASSED`);
|
|
254
|
+
console.log(`\nAll filter options cover the available values.`);
|
|
255
|
+
return { success: true, errors: 0, warnings: 0 };
|
|
256
|
+
}
|
|
257
|
+
console.log(`\n${console_chars_1.emoji.warning} Filter option coverage issues:`);
|
|
258
|
+
for (const issue of uniqueIssues) {
|
|
259
|
+
console.log(`\n ${issue.optionName}:`);
|
|
260
|
+
console.log(` ${issue.description}`);
|
|
261
|
+
console.log(` Missing: ${issue.missingValues.join(", ")}`);
|
|
262
|
+
console.log(` Defined in: ${issue.file}:${issue.line}`);
|
|
263
|
+
}
|
|
264
|
+
console.log(`\n${console_chars_1.emoji.info} To fix filter coverage:`);
|
|
265
|
+
console.log(` 1. Add missing values to the options array`);
|
|
266
|
+
console.log(` 2. Or intentionally exclude with a comment: // Excluded: REMOVED (internal only)`);
|
|
267
|
+
console.log(` 3. Example:`);
|
|
268
|
+
console.log(` export const LISTING_STATUS_OPTIONS = [`);
|
|
269
|
+
console.log(` { value: "ACTIVE", label: "Active" },`);
|
|
270
|
+
console.log(` { value: "INACTIVE", label: "Inactive" }, // Add missing`);
|
|
271
|
+
console.log(` ];`);
|
|
272
|
+
console.log(`\n${console_chars_1.emoji.warning} FILTER OPTION COVERAGE CHECK COMPLETED WITH WARNINGS`);
|
|
273
|
+
return { success: true, errors: 0, warnings: uniqueIssues.length };
|
|
274
|
+
}
|
|
275
|
+
// Allow direct execution
|
|
276
|
+
if (require.main === module) {
|
|
277
|
+
run()
|
|
278
|
+
.then((result) => {
|
|
279
|
+
process.exit(result.success ? 0 : 1);
|
|
280
|
+
})
|
|
281
|
+
.catch((err) => {
|
|
282
|
+
console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=filter-option-coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-option-coverage.js","sourceRoot":"","sources":["../../../src/checks/ui/filter-option-coverage.ts"],"names":[],"mappings":";;;;;;;AA+IA,kBAoMC;AAlVD;;;;;;;;;;;;;;;;GAgBG;AACH,4CAAoB;AACpB,gDAAwB;AACxB,+BAA4B;AAE5B,6DAAiE;AAEjE,WAAW;AACE,QAAA,EAAE,GAAG,2BAA2B,CAAC;AACjC,QAAA,IAAI,GAAG,wBAAwB,CAAC;AAChC,QAAA,WAAW,GAAG,6DAA6D,CAAC;AAC5E,QAAA,QAAQ,GAAG,IAAI,CAAC;AAChB,QAAA,QAAQ,GAAG,KAAK,CAAC,CAAC,+BAA+B;AACjD,QAAA,IAAI,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AAC3D,QAAA,QAAQ,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAuBhD;;GAEG;AACH,MAAM,0BAA0B,GAAG;IACjC,oDAAoD;IACpD,iEAAiE;IACjE,8CAA8C;IAC9C,0EAA0E;IAC1E,8BAA8B;IAC9B,4DAA4D;CAC7D,CAAC;AAEF;;GAEG;AACH,MAAM,oBAAoB,GAAG;IAC3B,+CAA+C;IAC/C,0BAA0B;IAC1B,uBAAuB;IACvB,2BAA2B;IAC3B,+BAA+B;IAC/B,oDAAoD;CACrD,CAAC;AAEF;;GAEG;AACH,SAAS,mBAAmB,CAAC,YAAoB;IAC/C,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,0CAA0C;IAC1C,MAAM,YAAY,GAAG,+BAA+B,CAAC;IACrD,IAAI,KAAK,CAAC;IACV,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,wDAAwD;IACxD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,aAAa,GAAG,2BAA2B,CAAC;QAClD,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,cAAc,CAAC,QAAgB;IAC5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,sBAAsB;IACtB,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,sBAAsB,CAAC,CAAC;IACpE,IAAI,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,WAAW,QAAQ,mBAAmB,EAAE,GAAG,CAAC,CAAC;QAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,YAAY,GAAG,iBAAiB,CAAC;YACvC,IAAI,UAAU,CAAC;YACf,OAAO,CAAC,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC3D,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,sCAAsC;IACtC,MAAM,SAAS,GAAG,MAAM,IAAA,WAAI,EAAC,uBAAuB,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC9E,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QAC7E,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,WAAW,QAAQ,mBAAmB,EAAE,GAAG,CAAC,CAAC;QAC9E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC3C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,YAAY,GAAG,6BAA6B,CAAC;YACnD,IAAI,UAAU,CAAC;YACf,OAAO,CAAC,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC3D,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAEM,KAAK,UAAU,GAAG;IACvB,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,MAAM,+BAA+B,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAExC,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,iBAAiB,GAAuB,EAAE,CAAC;IACjD,MAAM,WAAW,GAAiB,EAAE,CAAC;IAErC,kCAAkC;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,IAAI,4CAA4C,CAAC,CAAC;IAEzE,MAAM,aAAa,GAAG,MAAM,IAAA,WAAI,EAAC;QAC/B,uBAAuB;QACvB,cAAc;QACd,mBAAmB;KACpB,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,WAAW,CAAC;KACtB,CAAC,CAAC;IAEH,KAAK,MAAM,SAAS,IAAI,aAAa,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEvC,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAEnD,KAAK,MAAM,OAAO,IAAI,0BAA0B,EAAE,CAAC;YACjD,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;YACtB,IAAI,KAAK,CAAC;YACV,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAChD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC9B,MAAM,MAAM,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;gBACjD,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;gBAErE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,iBAAiB,CAAC,IAAI,CAAC;wBACrB,IAAI,EAAE,SAAS;wBACf,IAAI,EAAE,OAAO;wBACb,IAAI,EAAE,UAAU;wBAChB,MAAM;qBACP,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,YAAY,iBAAiB,CAAC,MAAM,qBAAqB,CAAC,CAAC;IAEvE,qCAAqC;IACrC,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,MAAM,+BAA+B,CAAC,CAAC;IAE9D,MAAM,OAAO,GAAG,MAAM,IAAA,WAAI,EAAC;QACzB,oBAAoB;QACpB,qBAAqB;KACtB,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,WAAW,CAAC;KACtB,CAAC,CAAC;IAEH,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEvC,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAEnD,+BAA+B;QAC/B,MAAM,YAAY,GAAG,0BAA0B,CAAC;QAChD,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,IAAI,UAAU,CAAC;QAEf,OAAO,CAAC,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1D,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAEhC,wCAAwC;YACxC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAAE,SAAS;YAEpE,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC9B,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAC9C,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;gBACpE,CAAC,CAAC,CAAC,CAAC;YAEN,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;aACvC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,YAAY,WAAW,CAAC,MAAM,0BAA0B,CAAC,CAAC;IAEtE,oCAAoC;IACpC,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,KAAK,8CAA8C,CAAC,CAAC;IAE5E,oDAAoD;IACpD,MAAM,eAAe,GAA2B;QAC9C,sBAAsB,EAAE,eAAe;QACvC,oBAAoB,EAAE,aAAa;QACnC,cAAc,EAAE,QAAQ;QACxB,sBAAsB,EAAE,eAAe;QACvC,gBAAgB,EAAE,UAAU;KAC7B,CAAC;IAEF,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;QAC1C,+BAA+B;QAC/B,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAElE,+DAA+D;QAC/D,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,mDAAmD;YACnD,MAAM,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YAE3E,mDAAmD;YACnD,MAAM,kBAAkB,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACjE,+DAA+D;gBAC/D,OAAO,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACxE,CAAC,CAAC,CAAC;YAEH,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,MAAM,CAClD,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC7C,CAAC;YAEF,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,UAAU,CAAC,IAAI;oBACrB,IAAI,EAAE,UAAU,CAAC,IAAI;oBACrB,UAAU,EAAE,SAAS,CAAC,IAAI;oBAC1B,aAAa,EAAE,kBAAkB;oBACjC,WAAW,EAAE,kBAAkB,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,SAAS,CAAC,IAAI,sBAAsB;iBACzH,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,6CAA6C;QAC7C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,CAC1C,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CACjD,CAAC;YAEF,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,SAAS,CAAC,IAAI;oBACpB,IAAI,EAAE,SAAS,CAAC,IAAI;oBACpB,UAAU,EAAE,SAAS,CAAC,IAAI;oBAC1B,aAAa,EAAE,kBAAkB;oBACjC,WAAW,EAAE,uCAAuC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;iBACpF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,cAAc;IACd,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CACxD,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAC7B,CAAC,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU;QACjC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CACtF,CACF,CAAC;IAEF,UAAU;IACV,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,KAAK,WAAW,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,0BAA0B,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,yBAAyB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,uBAAuB,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IAE1D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,sCAAsC,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;QAChE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;IACjE,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,IAAI,0BAA0B,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,qFAAqF,CAAC,CAAC;IACnG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAExB,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,uDAAuD,CAAC,CAAC;IACvF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC;AACrE,CAAC;AAED,yBAAyB;AACzB,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,GAAG,EAAE;SACF,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACpB,OAAO,CAAC,KAAK,CAAC,GAAG,qBAAK,CAAC,KAAK,oBAAoB,EAAE,GAAG,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export declare const id = "ui/query-param-state-sync";
|
|
3
|
+
export declare const name = "Query Param State Sync";
|
|
4
|
+
export declare const description = "Detects URL params that aren't synced with component state";
|
|
5
|
+
export declare const category = "ui";
|
|
6
|
+
export declare const blocking = false;
|
|
7
|
+
export declare const tags: string[];
|
|
8
|
+
export declare const requires: string[];
|
|
9
|
+
export declare function run(): Promise<{
|
|
10
|
+
success: boolean;
|
|
11
|
+
errors: number;
|
|
12
|
+
warnings: number;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=query-param-state-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-param-state-sync.d.ts","sourceRoot":"","sources":["../../../src/checks/ui/query-param-state-sync.ts"],"names":[],"mappings":";AAwBA,eAAO,MAAM,EAAE,8BAA8B,CAAC;AAC9C,eAAO,MAAM,IAAI,2BAA2B,CAAC;AAC7C,eAAO,MAAM,WAAW,+DAA+D,CAAC;AACxF,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,IAAI,UAAyD,CAAC;AAC3E,eAAO,MAAM,QAAQ,UAA0B,CAAC;AA6EhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA4K3F"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
|
|
8
|
+
exports.run = run;
|
|
9
|
+
/**
|
|
10
|
+
* Query Param State Sync Preflight
|
|
11
|
+
*
|
|
12
|
+
* Detects when URL query parameters aren't properly synced with component state.
|
|
13
|
+
* This causes confusing UX where URL params have no effect on the page.
|
|
14
|
+
*
|
|
15
|
+
* Example problems this catches:
|
|
16
|
+
* - /orders?status=pending but filterStatus state doesn't read from URL
|
|
17
|
+
* - URL has ?page=2 but page state starts at 1
|
|
18
|
+
* - Link passes ?category=shoes but category filter ignores URL param
|
|
19
|
+
*
|
|
20
|
+
* Pattern detection:
|
|
21
|
+
* 1. Find URL params used in links/navigation
|
|
22
|
+
* 2. Find state variables that match those param names
|
|
23
|
+
* 3. Check if state is initialized from URL params
|
|
24
|
+
*/
|
|
25
|
+
const fs_1 = __importDefault(require("fs"));
|
|
26
|
+
const path_1 = __importDefault(require("path"));
|
|
27
|
+
const glob_1 = require("glob");
|
|
28
|
+
const console_chars_1 = require("../../utils/console-chars");
|
|
29
|
+
// METADATA
|
|
30
|
+
exports.id = "ui/query-param-state-sync";
|
|
31
|
+
exports.name = "Query Param State Sync";
|
|
32
|
+
exports.description = "Detects URL params that aren't synced with component state";
|
|
33
|
+
exports.category = "ui";
|
|
34
|
+
exports.blocking = false; // Warning - not always a bug
|
|
35
|
+
exports.tags = ["ui", "url", "params", "state", "sync", "navigation"];
|
|
36
|
+
exports.requires = ["trading-card-system"];
|
|
37
|
+
/**
|
|
38
|
+
* Common filter/pagination param names
|
|
39
|
+
*/
|
|
40
|
+
const COMMON_PARAMS = [
|
|
41
|
+
"status",
|
|
42
|
+
"page",
|
|
43
|
+
"limit",
|
|
44
|
+
"sort",
|
|
45
|
+
"order",
|
|
46
|
+
"filter",
|
|
47
|
+
"category",
|
|
48
|
+
"type",
|
|
49
|
+
"search",
|
|
50
|
+
"q",
|
|
51
|
+
"tab",
|
|
52
|
+
"view",
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* State variable patterns to match params
|
|
56
|
+
*/
|
|
57
|
+
const STATE_TO_PARAM_MAP = {
|
|
58
|
+
status: ["filterStatus", "selectedStatus", "status", "statusFilter"],
|
|
59
|
+
page: ["page", "currentPage", "pageNumber"],
|
|
60
|
+
limit: ["limit", "pageSize", "perPage", "itemsPerPage"],
|
|
61
|
+
sort: ["sort", "sortBy", "sortField", "orderBy"],
|
|
62
|
+
order: ["order", "sortOrder", "sortDirection"],
|
|
63
|
+
category: ["category", "selectedCategory", "categoryFilter"],
|
|
64
|
+
tab: ["tab", "activeTab", "selectedTab", "tabValue"],
|
|
65
|
+
search: ["search", "searchQuery", "query", "searchTerm"],
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Patterns to find URL param usage
|
|
69
|
+
*/
|
|
70
|
+
const URL_PARAM_PATTERNS = [
|
|
71
|
+
// Link href with query param: href={`/orders?status=${status}`}
|
|
72
|
+
/href\s*=\s*[{`]["'`][^`"']*\?([a-zA-Z]+)=/g,
|
|
73
|
+
// searchParams.get("status")
|
|
74
|
+
/searchParams\.get\s*\(\s*["'`]([a-zA-Z]+)["'`]\)/g,
|
|
75
|
+
// useSearchParams() and params.get("status")
|
|
76
|
+
/params\.get\s*\(\s*["'`]([a-zA-Z]+)["'`]\)/g,
|
|
77
|
+
// router.push with query params
|
|
78
|
+
/router\.push\s*\([^)]*\?([a-zA-Z]+)=/g,
|
|
79
|
+
// URLSearchParams set/append
|
|
80
|
+
/\.(?:set|append)\s*\(\s*["'`]([a-zA-Z]+)["'`]/g,
|
|
81
|
+
];
|
|
82
|
+
/**
|
|
83
|
+
* Patterns to find state initialization from URL
|
|
84
|
+
*/
|
|
85
|
+
const STATE_FROM_URL_PATTERNS = [
|
|
86
|
+
// useState(searchParams.get("status"))
|
|
87
|
+
/useState\s*\(\s*(?:searchParams|params)\.get\s*\(\s*["'`]([a-zA-Z]+)["'`]\)/g,
|
|
88
|
+
// const status = searchParams.get("status")
|
|
89
|
+
/const\s+([a-zA-Z]+)\s*=\s*(?:searchParams|params)\.get/g,
|
|
90
|
+
// Initial state from searchParams
|
|
91
|
+
/(?:initial|default)[A-Z]\w*\s*=\s*(?:searchParams|params)\.get\s*\(\s*["'`]([a-zA-Z]+)["'`]\)/g,
|
|
92
|
+
];
|
|
93
|
+
async function run() {
|
|
94
|
+
console.log(`\n${console_chars_1.emoji.search} QUERY PARAM STATE SYNC CHECK`);
|
|
95
|
+
console.log((0, console_chars_1.createDivider)(65, "heavy"));
|
|
96
|
+
const issues = [];
|
|
97
|
+
const paramUsages = [];
|
|
98
|
+
const stateInitFromUrl = new Map(); // file -> params
|
|
99
|
+
// Scan client components
|
|
100
|
+
console.log(`\n${console_chars_1.emoji.file} Scanning client components...`);
|
|
101
|
+
const clientFiles = await (0, glob_1.glob)([
|
|
102
|
+
"app/**/*Client.tsx",
|
|
103
|
+
"app/**/*Client.ts",
|
|
104
|
+
"app/**/page.tsx",
|
|
105
|
+
"components/**/*.tsx",
|
|
106
|
+
], {
|
|
107
|
+
cwd: process.cwd(),
|
|
108
|
+
ignore: ["**/*.d.ts", "**/node_modules/**", "app/api/**"],
|
|
109
|
+
});
|
|
110
|
+
if (clientFiles.length === 0) {
|
|
111
|
+
console.log(`\n${console_chars_1.emoji.warning} No client files found - skipping check`);
|
|
112
|
+
return { success: true, errors: 0, warnings: 1 };
|
|
113
|
+
}
|
|
114
|
+
for (const clientFile of clientFiles) {
|
|
115
|
+
const filePath = path_1.default.join(process.cwd(), clientFile);
|
|
116
|
+
if (!fs_1.default.existsSync(filePath))
|
|
117
|
+
continue;
|
|
118
|
+
const content = fs_1.default.readFileSync(filePath, "utf-8");
|
|
119
|
+
const lines = content.split("\n");
|
|
120
|
+
// Find URL params being used in links/navigation
|
|
121
|
+
for (const pattern of URL_PARAM_PATTERNS) {
|
|
122
|
+
pattern.lastIndex = 0;
|
|
123
|
+
let match;
|
|
124
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
125
|
+
const paramName = match[1].toLowerCase();
|
|
126
|
+
const lineNum = content.substring(0, match.index).split("\n").length;
|
|
127
|
+
if (COMMON_PARAMS.includes(paramName)) {
|
|
128
|
+
paramUsages.push({
|
|
129
|
+
file: clientFile,
|
|
130
|
+
line: lineNum,
|
|
131
|
+
paramName,
|
|
132
|
+
context: "link",
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Find state initialized from URL params
|
|
138
|
+
const fileParamsFromUrl = new Set();
|
|
139
|
+
for (const pattern of STATE_FROM_URL_PATTERNS) {
|
|
140
|
+
pattern.lastIndex = 0;
|
|
141
|
+
let match;
|
|
142
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
143
|
+
const paramName = match[1].toLowerCase();
|
|
144
|
+
fileParamsFromUrl.add(paramName);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
stateInitFromUrl.set(clientFile, fileParamsFromUrl);
|
|
148
|
+
// Find useState calls that match param names but DON'T read from URL
|
|
149
|
+
const useStatePattern = /useState\s*(?:<[^>]+>)?\s*\(\s*([^)]+)\)/g;
|
|
150
|
+
let stateMatch;
|
|
151
|
+
while ((stateMatch = useStatePattern.exec(content)) !== null) {
|
|
152
|
+
const initialValue = stateMatch[1].trim();
|
|
153
|
+
const lineNum = content.substring(0, stateMatch.index).split("\n").length;
|
|
154
|
+
const lineContent = lines[lineNum - 1] || "";
|
|
155
|
+
// Extract state variable name from line
|
|
156
|
+
const varMatch = lineContent.match(/const\s+\[(\w+)/);
|
|
157
|
+
if (!varMatch)
|
|
158
|
+
continue;
|
|
159
|
+
const stateName = varMatch[1].toLowerCase();
|
|
160
|
+
// Check if this state name matches any common param
|
|
161
|
+
for (const [param, stateNames] of Object.entries(STATE_TO_PARAM_MAP)) {
|
|
162
|
+
if (stateNames.map((s) => s.toLowerCase()).includes(stateName)) {
|
|
163
|
+
// Check if initialized from URL
|
|
164
|
+
const isFromUrl = /searchParams|params\.get|useSearchParams/.test(initialValue);
|
|
165
|
+
if (!isFromUrl && !fileParamsFromUrl.has(param)) {
|
|
166
|
+
// Check if this file uses URL for this param elsewhere
|
|
167
|
+
const usesParamInUrl = content.includes(`?${param}=`) ||
|
|
168
|
+
content.includes(`searchParams.get("${param}")`);
|
|
169
|
+
if (usesParamInUrl) {
|
|
170
|
+
paramUsages.push({
|
|
171
|
+
file: clientFile,
|
|
172
|
+
line: lineNum,
|
|
173
|
+
paramName: param,
|
|
174
|
+
context: "state",
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Analyze: Find params used in URLs but state not initialized from URL
|
|
183
|
+
for (const usage of paramUsages) {
|
|
184
|
+
if (usage.context === "link") {
|
|
185
|
+
const fileParamsFromUrl = stateInitFromUrl.get(usage.file) || new Set();
|
|
186
|
+
// Check if there's corresponding state that reads from URL
|
|
187
|
+
if (!fileParamsFromUrl.has(usage.paramName)) {
|
|
188
|
+
// Check if the file has state for this param at all
|
|
189
|
+
const content = fs_1.default.readFileSync(path_1.default.join(process.cwd(), usage.file), "utf-8");
|
|
190
|
+
const possibleStateNames = STATE_TO_PARAM_MAP[usage.paramName] || [usage.paramName];
|
|
191
|
+
const hasState = possibleStateNames.some((name) => new RegExp(`\\[${name}[,\\s]`, "i").test(content));
|
|
192
|
+
if (hasState) {
|
|
193
|
+
issues.push({
|
|
194
|
+
file: usage.file,
|
|
195
|
+
line: usage.line,
|
|
196
|
+
paramName: usage.paramName,
|
|
197
|
+
description: `URL param "${usage.paramName}" used in links but state isn't initialized from URL`,
|
|
198
|
+
severity: "warning",
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else if (usage.context === "state") {
|
|
204
|
+
issues.push({
|
|
205
|
+
file: usage.file,
|
|
206
|
+
line: usage.line,
|
|
207
|
+
paramName: usage.paramName,
|
|
208
|
+
description: `State matches URL param "${usage.paramName}" but isn't synced with URL`,
|
|
209
|
+
severity: "warning",
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Deduplicate
|
|
214
|
+
const uniqueIssues = issues.filter((issue, index, self) => index === self.findIndex((i) => i.file === issue.file && i.paramName === issue.paramName));
|
|
215
|
+
// Summary
|
|
216
|
+
console.log(`\n${console_chars_1.emoji.chart} Summary:`);
|
|
217
|
+
console.log(` Files scanned: ${clientFiles.length}`);
|
|
218
|
+
console.log(` URL param usages found: ${paramUsages.length}`);
|
|
219
|
+
console.log(` Sync issues: ${uniqueIssues.length}`);
|
|
220
|
+
if (uniqueIssues.length === 0) {
|
|
221
|
+
console.log(`\n${console_chars_1.emoji.success} QUERY PARAM STATE SYNC CHECK PASSED`);
|
|
222
|
+
console.log(`\nAll URL params are properly synced with component state.`);
|
|
223
|
+
return { success: true, errors: 0, warnings: 0 };
|
|
224
|
+
}
|
|
225
|
+
console.log(`\n${console_chars_1.emoji.warning} URL param sync issues found:`);
|
|
226
|
+
for (const issue of uniqueIssues) {
|
|
227
|
+
console.log(`\n ${issue.file}:${issue.line}`);
|
|
228
|
+
console.log(` ${issue.description}`);
|
|
229
|
+
}
|
|
230
|
+
console.log(`\n${console_chars_1.emoji.info} To fix URL param sync:`);
|
|
231
|
+
console.log(` 1. Read initial state from searchParams: useState(searchParams.get("status"))`);
|
|
232
|
+
console.log(` 2. Or use useSearchParams() hook to keep state in URL`);
|
|
233
|
+
console.log(` 3. Sync state changes back to URL with router.push()`);
|
|
234
|
+
console.log(` 4. Example:`);
|
|
235
|
+
console.log(` const searchParams = useSearchParams();`);
|
|
236
|
+
console.log(` const [status, setStatus] = useState(searchParams.get("status") || "all");`);
|
|
237
|
+
console.log(`\n${console_chars_1.emoji.warning} QUERY PARAM STATE SYNC CHECK COMPLETED WITH WARNINGS`);
|
|
238
|
+
return { success: true, errors: 0, warnings: uniqueIssues.length };
|
|
239
|
+
}
|
|
240
|
+
// Allow direct execution
|
|
241
|
+
if (require.main === module) {
|
|
242
|
+
run()
|
|
243
|
+
.then((result) => {
|
|
244
|
+
process.exit(result.success ? 0 : 1);
|
|
245
|
+
})
|
|
246
|
+
.catch((err) => {
|
|
247
|
+
console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=query-param-state-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-param-state-sync.js","sourceRoot":"","sources":["../../../src/checks/ui/query-param-state-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export declare const id = "ui/unimplemented-action-handler";
|
|
3
|
+
export declare const name = "Unimplemented Action Handler";
|
|
4
|
+
export declare const description = "Detects UI actions that have no implementation in handlers";
|
|
5
|
+
export declare const category = "ui";
|
|
6
|
+
export declare const blocking = true;
|
|
7
|
+
export declare const tags: string[];
|
|
8
|
+
export declare const requires: string[];
|
|
9
|
+
export declare function run(): Promise<{
|
|
10
|
+
success: boolean;
|
|
11
|
+
errors: number;
|
|
12
|
+
warnings: number;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=unimplemented-action-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unimplemented-action-handler.d.ts","sourceRoot":"","sources":["../../../src/checks/ui/unimplemented-action-handler.ts"],"names":[],"mappings":";AAwBA,eAAO,MAAM,EAAE,oCAAoC,CAAC;AACpD,eAAO,MAAM,IAAI,iCAAiC,CAAC;AACnD,eAAO,MAAM,WAAW,+DAA+D,CAAC;AACxF,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAAqE,CAAC;AACvF,eAAO,MAAM,QAAQ,UAA0B,CAAC;AA8EhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAiK3F"}
|