@empline/preflight 1.1.58 → 1.1.59
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/accessibility/accessibility-validation.d.ts.map +1 -1
- package/dist/checks/accessibility/accessibility-validation.js +131 -14
- package/dist/checks/accessibility/accessibility-validation.js.map +1 -1
- package/dist/checks/accessibility/wcag-advanced-validation.d.ts +10 -0
- package/dist/checks/accessibility/wcag-advanced-validation.d.ts.map +1 -0
- package/dist/checks/accessibility/wcag-advanced-validation.js +622 -0
- package/dist/checks/accessibility/wcag-advanced-validation.js.map +1 -0
- package/dist/checks/database/query-performance-validation.d.ts +10 -0
- package/dist/checks/database/query-performance-validation.d.ts.map +1 -0
- package/dist/checks/database/query-performance-validation.js +544 -0
- package/dist/checks/database/query-performance-validation.js.map +1 -0
- package/dist/checks/react/react-patterns-validation.d.ts +10 -0
- package/dist/checks/react/react-patterns-validation.d.ts.map +1 -0
- package/dist/checks/react/react-patterns-validation.js +559 -0
- package/dist/checks/react/react-patterns-validation.js.map +1 -0
- package/dist/checks/security/security-headers-validation.d.ts +10 -0
- package/dist/checks/security/security-headers-validation.d.ts.map +1 -0
- package/dist/checks/security/security-headers-validation.js +594 -0
- package/dist/checks/security/security-headers-validation.js.map +1 -0
- package/dist/reporters/github-reporter.d.ts +35 -0
- package/dist/reporters/github-reporter.d.ts.map +1 -0
- package/dist/reporters/github-reporter.js +397 -0
- package/dist/reporters/github-reporter.js.map +1 -0
- package/dist/reporters/html-report.d.ts +12 -0
- package/dist/reporters/html-report.d.ts.map +1 -0
- package/dist/reporters/html-report.js +469 -0
- package/dist/reporters/html-report.js.map +1 -0
- package/dist/reporters/index.d.ts +8 -0
- package/dist/reporters/index.d.ts.map +1 -0
- package/dist/reporters/index.js +18 -0
- package/dist/reporters/index.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
|
|
38
|
+
exports.run = run;
|
|
39
|
+
/**
|
|
40
|
+
* React Patterns Validation Preflight (BLOCKING)
|
|
41
|
+
*
|
|
42
|
+
* Validates advanced React patterns and best practices:
|
|
43
|
+
*
|
|
44
|
+
* 1. Server Components:
|
|
45
|
+
* - Server components don't use client-only APIs
|
|
46
|
+
* - "use client" directive placement
|
|
47
|
+
* - Proper data fetching patterns
|
|
48
|
+
*
|
|
49
|
+
* 2. Suspense & Error Boundaries:
|
|
50
|
+
* - Async components wrapped in Suspense
|
|
51
|
+
* - Error boundaries for lazy-loaded components
|
|
52
|
+
* - Loading states for async operations
|
|
53
|
+
*
|
|
54
|
+
* 3. Hooks Best Practices:
|
|
55
|
+
* - useCallback/useMemo dependencies complete
|
|
56
|
+
* - useEffect cleanup for subscriptions
|
|
57
|
+
* - Custom hooks use "use" prefix
|
|
58
|
+
* - No hooks in conditionals/loops
|
|
59
|
+
*
|
|
60
|
+
* 4. State Management:
|
|
61
|
+
* - Context value stability
|
|
62
|
+
* - Avoid prop drilling anti-patterns
|
|
63
|
+
* - State updates during render
|
|
64
|
+
*
|
|
65
|
+
* 5. Performance Patterns:
|
|
66
|
+
* - Key prop stability in lists
|
|
67
|
+
* - Avoid inline object/function creation in JSX
|
|
68
|
+
* - Memoization where beneficial
|
|
69
|
+
*/
|
|
70
|
+
const fs = __importStar(require("node:fs"));
|
|
71
|
+
const path = __importStar(require("node:path"));
|
|
72
|
+
const glob_1 = require("glob");
|
|
73
|
+
const console_chars_1 = require("../../utils/console-chars");
|
|
74
|
+
exports.id = "react/react-patterns-validation";
|
|
75
|
+
exports.name = "React Patterns Validation";
|
|
76
|
+
exports.description = "Validates React patterns, hooks, Server Components, and performance best practices";
|
|
77
|
+
exports.category = "react";
|
|
78
|
+
exports.blocking = true;
|
|
79
|
+
exports.tags = ["react", "hooks", "server-components", "suspense", "performance"];
|
|
80
|
+
function getLineNumber(content, index) {
|
|
81
|
+
return content.substring(0, index).split("\n").length;
|
|
82
|
+
}
|
|
83
|
+
async function checkServerComponents() {
|
|
84
|
+
const issues = [];
|
|
85
|
+
const files = await (0, glob_1.glob)([
|
|
86
|
+
"app/**/*.tsx",
|
|
87
|
+
"app/**/*.ts",
|
|
88
|
+
], {
|
|
89
|
+
cwd: process.cwd(),
|
|
90
|
+
ignore: ["**/node_modules/**", "**/*.test.tsx", "**/*.spec.tsx"],
|
|
91
|
+
absolute: true,
|
|
92
|
+
});
|
|
93
|
+
// Client-only APIs that shouldn't be in server components
|
|
94
|
+
const clientOnlyPatterns = [
|
|
95
|
+
{ pattern: /\buseState\s*\(/, name: "useState" },
|
|
96
|
+
{ pattern: /\buseEffect\s*\(/, name: "useEffect" },
|
|
97
|
+
{ pattern: /\buseRef\s*\(/, name: "useRef" },
|
|
98
|
+
{ pattern: /\buseReducer\s*\(/, name: "useReducer" },
|
|
99
|
+
{ pattern: /\buseLayoutEffect\s*\(/, name: "useLayoutEffect" },
|
|
100
|
+
{ pattern: /\bwindow\b\./, name: "window" },
|
|
101
|
+
{ pattern: /\bdocument\b\./, name: "document" },
|
|
102
|
+
{ pattern: /\blocalStorage\b\./, name: "localStorage" },
|
|
103
|
+
{ pattern: /\bsessionStorage\b\./, name: "sessionStorage" },
|
|
104
|
+
{ pattern: /\baddEventListener\s*\(/, name: "addEventListener" },
|
|
105
|
+
];
|
|
106
|
+
for (const file of files) {
|
|
107
|
+
if (!fs.existsSync(file))
|
|
108
|
+
continue;
|
|
109
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
110
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
111
|
+
// Skip if it's a client component
|
|
112
|
+
const isClientComponent = /^["']use client["']/m.test(content);
|
|
113
|
+
if (isClientComponent)
|
|
114
|
+
continue;
|
|
115
|
+
// Skip files that are clearly server-side (API routes, server actions)
|
|
116
|
+
if (relativePath.includes("/api/") || content.includes("use server"))
|
|
117
|
+
continue;
|
|
118
|
+
// Check for client-only patterns
|
|
119
|
+
for (const { pattern, name } of clientOnlyPatterns) {
|
|
120
|
+
let match;
|
|
121
|
+
const regex = new RegExp(pattern.source, "g");
|
|
122
|
+
while ((match = regex.exec(content)) !== null) {
|
|
123
|
+
// Skip if it's in a comment
|
|
124
|
+
const lineStart = content.lastIndexOf("\n", match.index) + 1;
|
|
125
|
+
const line = content.substring(lineStart, match.index);
|
|
126
|
+
if (line.includes("//") || line.includes("/*"))
|
|
127
|
+
continue;
|
|
128
|
+
issues.push({
|
|
129
|
+
rule: "server-component-client-api",
|
|
130
|
+
message: `Server component uses client-only API: ${name}`,
|
|
131
|
+
file: relativePath,
|
|
132
|
+
line: getLineNumber(content, match.index),
|
|
133
|
+
severity: "error",
|
|
134
|
+
suggestion: `Add "use client" directive or move this code to a client component`,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return issues;
|
|
140
|
+
}
|
|
141
|
+
async function checkSuspenseAndBoundaries() {
|
|
142
|
+
const issues = [];
|
|
143
|
+
const files = await (0, glob_1.glob)([
|
|
144
|
+
"app/**/*.tsx",
|
|
145
|
+
"components/**/*.tsx",
|
|
146
|
+
"src/**/*.tsx",
|
|
147
|
+
], {
|
|
148
|
+
cwd: process.cwd(),
|
|
149
|
+
ignore: ["**/node_modules/**", "**/*.test.tsx", "**/*.spec.tsx"],
|
|
150
|
+
absolute: true,
|
|
151
|
+
});
|
|
152
|
+
for (const file of files) {
|
|
153
|
+
if (!fs.existsSync(file))
|
|
154
|
+
continue;
|
|
155
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
156
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
157
|
+
// Check for React.lazy without Suspense
|
|
158
|
+
const lazyRegex = /React\.lazy\s*\(|lazy\s*\(\s*\(\)/g;
|
|
159
|
+
if (lazyRegex.test(content)) {
|
|
160
|
+
const hasSuspense = /<Suspense/i.test(content);
|
|
161
|
+
if (!hasSuspense) {
|
|
162
|
+
issues.push({
|
|
163
|
+
rule: "lazy-needs-suspense",
|
|
164
|
+
message: "React.lazy used without Suspense boundary in file",
|
|
165
|
+
file: relativePath,
|
|
166
|
+
severity: "warning",
|
|
167
|
+
suggestion: "Wrap lazy-loaded components in <Suspense fallback={...}>",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Check for dynamic imports in Next.js without loading state
|
|
172
|
+
const dynamicRegex = /dynamic\s*\(\s*\(\)\s*=>\s*import/g;
|
|
173
|
+
let match;
|
|
174
|
+
while ((match = dynamicRegex.exec(content)) !== null) {
|
|
175
|
+
// Check for loading option
|
|
176
|
+
const surroundingCode = content.substring(match.index, match.index + 200);
|
|
177
|
+
const hasLoadingOption = /loading\s*:/.test(surroundingCode);
|
|
178
|
+
if (!hasLoadingOption) {
|
|
179
|
+
issues.push({
|
|
180
|
+
rule: "dynamic-loading-state",
|
|
181
|
+
message: "next/dynamic without loading option",
|
|
182
|
+
file: relativePath,
|
|
183
|
+
line: getLineNumber(content, match.index),
|
|
184
|
+
severity: "info",
|
|
185
|
+
suggestion: "Add loading: () => <Loading /> option for better UX",
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Check for async components without error handling
|
|
190
|
+
const asyncComponentRegex = /export\s+(?:default\s+)?async\s+function\s+(\w+)/g;
|
|
191
|
+
while ((match = asyncComponentRegex.exec(content)) !== null) {
|
|
192
|
+
const componentName = match[1];
|
|
193
|
+
// Check if there's an error.tsx in the same directory for pages
|
|
194
|
+
if (relativePath.includes("app/") && relativePath.includes("page.tsx")) {
|
|
195
|
+
const dir = path.dirname(file);
|
|
196
|
+
const errorFile = path.join(dir, "error.tsx");
|
|
197
|
+
if (!fs.existsSync(errorFile)) {
|
|
198
|
+
issues.push({
|
|
199
|
+
rule: "async-component-error-boundary",
|
|
200
|
+
message: `Async page component ${componentName} has no error.tsx in same directory`,
|
|
201
|
+
file: relativePath,
|
|
202
|
+
line: getLineNumber(content, match.index),
|
|
203
|
+
severity: "info",
|
|
204
|
+
suggestion: "Create error.tsx to handle component errors gracefully",
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return issues;
|
|
211
|
+
}
|
|
212
|
+
async function checkHooksPatterns() {
|
|
213
|
+
const issues = [];
|
|
214
|
+
const files = await (0, glob_1.glob)([
|
|
215
|
+
"app/**/*.tsx",
|
|
216
|
+
"components/**/*.tsx",
|
|
217
|
+
"src/**/*.tsx",
|
|
218
|
+
"hooks/**/*.ts",
|
|
219
|
+
"lib/**/*.ts",
|
|
220
|
+
], {
|
|
221
|
+
cwd: process.cwd(),
|
|
222
|
+
ignore: ["**/node_modules/**", "**/*.test.tsx", "**/*.spec.tsx"],
|
|
223
|
+
absolute: true,
|
|
224
|
+
});
|
|
225
|
+
for (const file of files) {
|
|
226
|
+
if (!fs.existsSync(file))
|
|
227
|
+
continue;
|
|
228
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
229
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
230
|
+
// Check for hooks in conditionals
|
|
231
|
+
const hookInConditionalRegex = /if\s*\([^)]*\)\s*\{[^}]*\b(use\w+)\s*\(/g;
|
|
232
|
+
let match;
|
|
233
|
+
while ((match = hookInConditionalRegex.exec(content)) !== null) {
|
|
234
|
+
issues.push({
|
|
235
|
+
rule: "hooks-no-conditional",
|
|
236
|
+
message: `Hook ${match[1]} called inside conditional`,
|
|
237
|
+
file: relativePath,
|
|
238
|
+
line: getLineNumber(content, match.index),
|
|
239
|
+
severity: "error",
|
|
240
|
+
suggestion: "Move hook call to top level of component",
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
// Check for hooks in loops
|
|
244
|
+
const hookInLoopRegex = /(?:for|while)\s*\([^)]*\)\s*\{[^}]*\b(use\w+)\s*\(/g;
|
|
245
|
+
while ((match = hookInLoopRegex.exec(content)) !== null) {
|
|
246
|
+
issues.push({
|
|
247
|
+
rule: "hooks-no-loop",
|
|
248
|
+
message: `Hook ${match[1]} called inside loop`,
|
|
249
|
+
file: relativePath,
|
|
250
|
+
line: getLineNumber(content, match.index),
|
|
251
|
+
severity: "error",
|
|
252
|
+
suggestion: "Hooks must be called at top level, not in loops",
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
// Check for useEffect without cleanup for subscriptions
|
|
256
|
+
const useEffectWithSubscription = /useEffect\s*\(\s*\(\)\s*=>\s*\{[^}]*(?:subscribe|addEventListener|setInterval|setTimeout)[^}]*\}/g;
|
|
257
|
+
while ((match = useEffectWithSubscription.exec(content)) !== null) {
|
|
258
|
+
const effectContent = match[0];
|
|
259
|
+
const hasCleanup = /return\s*\(\s*\)\s*=>/.test(effectContent) ||
|
|
260
|
+
/return\s+\(\s*\)\s*=>/.test(effectContent) ||
|
|
261
|
+
/return\s*function/.test(effectContent);
|
|
262
|
+
if (!hasCleanup) {
|
|
263
|
+
issues.push({
|
|
264
|
+
rule: "useeffect-cleanup",
|
|
265
|
+
message: "useEffect with subscription/timer missing cleanup",
|
|
266
|
+
file: relativePath,
|
|
267
|
+
line: getLineNumber(content, match.index),
|
|
268
|
+
severity: "warning",
|
|
269
|
+
suggestion: "Return cleanup function to unsubscribe/clear timer",
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Check for custom hooks not following naming convention
|
|
274
|
+
const customHookRegex = /export\s+(?:const|function)\s+(\w+)\s*(?:=|:|\()/g;
|
|
275
|
+
while ((match = customHookRegex.exec(content)) !== null) {
|
|
276
|
+
const funcName = match[1];
|
|
277
|
+
// If file is in hooks folder or function uses hooks but doesn't start with "use"
|
|
278
|
+
const isInHooksFolder = relativePath.includes("/hooks/") || relativePath.includes("\\hooks\\");
|
|
279
|
+
const usesHooks = /\buse(?:State|Effect|Ref|Callback|Memo|Context|Reducer)\s*\(/.test(content.substring(match.index, match.index + 500));
|
|
280
|
+
if ((isInHooksFolder || usesHooks) && !funcName.startsWith("use") && funcName !== "default") {
|
|
281
|
+
// Skip if it's clearly a component (returns JSX)
|
|
282
|
+
const functionBody = content.substring(match.index, match.index + 1000);
|
|
283
|
+
const isComponent = /<\w+|return\s*\(?\s*</.test(functionBody);
|
|
284
|
+
if (!isComponent && usesHooks) {
|
|
285
|
+
issues.push({
|
|
286
|
+
rule: "custom-hook-naming",
|
|
287
|
+
message: `Function "${funcName}" uses hooks but doesn't start with "use"`,
|
|
288
|
+
file: relativePath,
|
|
289
|
+
line: getLineNumber(content, match.index),
|
|
290
|
+
severity: "warning",
|
|
291
|
+
suggestion: `Rename to "use${funcName.charAt(0).toUpperCase() + funcName.slice(1)}"`,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Check for missing dependencies in useEffect/useCallback/useMemo
|
|
297
|
+
// This is a simplified check - full check requires AST parsing
|
|
298
|
+
const emptyDepsRegex = /(useEffect|useCallback|useMemo)\s*\([^,]+,\s*\[\s*\]\s*\)/g;
|
|
299
|
+
while ((match = emptyDepsRegex.exec(content)) !== null) {
|
|
300
|
+
const hookName = match[1];
|
|
301
|
+
const hookContent = match[0];
|
|
302
|
+
// Check if the callback uses variables that might need to be dependencies
|
|
303
|
+
const callbackMatch = hookContent.match(/\(\)\s*=>\s*\{([^}]+)\}/);
|
|
304
|
+
if (callbackMatch) {
|
|
305
|
+
const callback = callbackMatch[1];
|
|
306
|
+
// Look for common patterns that suggest missing dependencies
|
|
307
|
+
const usesExternalVars = /\b(props\.|state\.|count|value|data|user|id)\b/.test(callback);
|
|
308
|
+
if (usesExternalVars) {
|
|
309
|
+
issues.push({
|
|
310
|
+
rule: "hook-deps-check",
|
|
311
|
+
message: `${hookName} with empty deps array may have missing dependencies`,
|
|
312
|
+
file: relativePath,
|
|
313
|
+
line: getLineNumber(content, match.index),
|
|
314
|
+
severity: "info",
|
|
315
|
+
suggestion: "Review dependency array - variables used inside may need to be included",
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return issues;
|
|
322
|
+
}
|
|
323
|
+
async function checkContextPatterns() {
|
|
324
|
+
const issues = [];
|
|
325
|
+
const files = await (0, glob_1.glob)([
|
|
326
|
+
"app/**/*.tsx",
|
|
327
|
+
"components/**/*.tsx",
|
|
328
|
+
"contexts/**/*.tsx",
|
|
329
|
+
"providers/**/*.tsx",
|
|
330
|
+
"src/**/*.tsx",
|
|
331
|
+
], {
|
|
332
|
+
cwd: process.cwd(),
|
|
333
|
+
ignore: ["**/node_modules/**", "**/*.test.tsx", "**/*.spec.tsx"],
|
|
334
|
+
absolute: true,
|
|
335
|
+
});
|
|
336
|
+
for (const file of files) {
|
|
337
|
+
if (!fs.existsSync(file))
|
|
338
|
+
continue;
|
|
339
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
340
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
341
|
+
// Check for inline object creation in context value
|
|
342
|
+
const contextValueRegex = /<(\w+Context)\.Provider\s+value\s*=\s*\{\s*\{/g;
|
|
343
|
+
let match;
|
|
344
|
+
while ((match = contextValueRegex.exec(content)) !== null) {
|
|
345
|
+
// Check if it's using useMemo
|
|
346
|
+
const surroundingCode = content.substring(Math.max(0, match.index - 500), match.index);
|
|
347
|
+
const hasMemo = /useMemo\s*\([^)]*\)\s*$/.test(surroundingCode.trim());
|
|
348
|
+
if (!hasMemo) {
|
|
349
|
+
issues.push({
|
|
350
|
+
rule: "context-value-stability",
|
|
351
|
+
message: `${match[1]} value is created inline (new object each render)`,
|
|
352
|
+
file: relativePath,
|
|
353
|
+
line: getLineNumber(content, match.index),
|
|
354
|
+
severity: "warning",
|
|
355
|
+
suggestion: "Use useMemo to memoize context value object",
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return issues;
|
|
361
|
+
}
|
|
362
|
+
async function checkKeyPropPatterns() {
|
|
363
|
+
const issues = [];
|
|
364
|
+
const files = await (0, glob_1.glob)([
|
|
365
|
+
"app/**/*.tsx",
|
|
366
|
+
"components/**/*.tsx",
|
|
367
|
+
"src/**/*.tsx",
|
|
368
|
+
], {
|
|
369
|
+
cwd: process.cwd(),
|
|
370
|
+
ignore: ["**/node_modules/**", "**/*.test.tsx", "**/*.spec.tsx"],
|
|
371
|
+
absolute: true,
|
|
372
|
+
});
|
|
373
|
+
for (const file of files) {
|
|
374
|
+
if (!fs.existsSync(file))
|
|
375
|
+
continue;
|
|
376
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
377
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
378
|
+
// Check for index as key in maps
|
|
379
|
+
const indexAsKeyRegex = /\.map\s*\([^)]*,\s*(\w+)\s*\)[^{]*key\s*=\s*\{\s*\1\s*\}/g;
|
|
380
|
+
let match;
|
|
381
|
+
while ((match = indexAsKeyRegex.exec(content)) !== null) {
|
|
382
|
+
issues.push({
|
|
383
|
+
rule: "key-no-index",
|
|
384
|
+
message: "Using array index as key prop",
|
|
385
|
+
file: relativePath,
|
|
386
|
+
line: getLineNumber(content, match.index),
|
|
387
|
+
severity: "warning",
|
|
388
|
+
suggestion: "Use unique stable identifier instead of index for key",
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
// Alternative pattern: key={i} or key={index}
|
|
392
|
+
const indexKeyPatterns = /\.map\s*\(\s*\([^,)]*,\s*(i|index|idx)\s*\)[^}]*key\s*=\s*\{\s*\1\s*\}/g;
|
|
393
|
+
while ((match = indexKeyPatterns.exec(content)) !== null) {
|
|
394
|
+
issues.push({
|
|
395
|
+
rule: "key-no-index",
|
|
396
|
+
message: "Using array index as key prop",
|
|
397
|
+
file: relativePath,
|
|
398
|
+
line: getLineNumber(content, match.index),
|
|
399
|
+
severity: "warning",
|
|
400
|
+
suggestion: "Use unique stable identifier (e.g., item.id) for key",
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
// Check for Math.random() or Date.now() as key
|
|
404
|
+
const unstableKeyRegex = /key\s*=\s*\{\s*(?:Math\.random\s*\(\)|Date\.now\s*\(\)|crypto\.randomUUID\s*\(\))/g;
|
|
405
|
+
while ((match = unstableKeyRegex.exec(content)) !== null) {
|
|
406
|
+
issues.push({
|
|
407
|
+
rule: "key-no-random",
|
|
408
|
+
message: "Using random/timestamp as key causes remounts",
|
|
409
|
+
file: relativePath,
|
|
410
|
+
line: getLineNumber(content, match.index),
|
|
411
|
+
severity: "error",
|
|
412
|
+
suggestion: "Use stable unique identifier from data",
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return issues;
|
|
417
|
+
}
|
|
418
|
+
async function checkPerformancePatterns() {
|
|
419
|
+
const issues = [];
|
|
420
|
+
const files = await (0, glob_1.glob)([
|
|
421
|
+
"app/**/*.tsx",
|
|
422
|
+
"components/**/*.tsx",
|
|
423
|
+
"src/**/*.tsx",
|
|
424
|
+
], {
|
|
425
|
+
cwd: process.cwd(),
|
|
426
|
+
ignore: ["**/node_modules/**", "**/*.test.tsx", "**/*.spec.tsx"],
|
|
427
|
+
absolute: true,
|
|
428
|
+
});
|
|
429
|
+
for (const file of files) {
|
|
430
|
+
if (!fs.existsSync(file))
|
|
431
|
+
continue;
|
|
432
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
433
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
434
|
+
// Check for inline function in JSX props (common perf issue)
|
|
435
|
+
// Only flag if not onClick/onChange (event handlers are often fine inline)
|
|
436
|
+
const inlineFunctionRegex = /\b(?!onClick|onChange|onSubmit|onBlur|onFocus|onKeyDown|onKeyUp|onMouseEnter|onMouseLeave)(\w+)\s*=\s*\{\s*\(\s*\)\s*=>/g;
|
|
437
|
+
let match;
|
|
438
|
+
let inlineCount = 0;
|
|
439
|
+
while ((match = inlineFunctionRegex.exec(content)) !== null) {
|
|
440
|
+
inlineCount++;
|
|
441
|
+
}
|
|
442
|
+
if (inlineCount > 10) {
|
|
443
|
+
issues.push({
|
|
444
|
+
rule: "inline-function-props",
|
|
445
|
+
message: `${inlineCount} inline arrow functions in props (may cause re-renders)`,
|
|
446
|
+
file: relativePath,
|
|
447
|
+
severity: "info",
|
|
448
|
+
suggestion: "Consider useCallback for frequently re-rendered components",
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
// Check for inline object creation in props
|
|
452
|
+
const inlineObjectRegex = /\b(?!style|className)(\w+)\s*=\s*\{\s*\{\s*\w+\s*:/g;
|
|
453
|
+
let objectCount = 0;
|
|
454
|
+
while ((match = inlineObjectRegex.exec(content)) !== null) {
|
|
455
|
+
objectCount++;
|
|
456
|
+
}
|
|
457
|
+
if (objectCount > 10) {
|
|
458
|
+
issues.push({
|
|
459
|
+
rule: "inline-object-props",
|
|
460
|
+
message: `${objectCount} inline objects in props (may cause re-renders)`,
|
|
461
|
+
file: relativePath,
|
|
462
|
+
severity: "info",
|
|
463
|
+
suggestion: "Consider useMemo or extracting to constants",
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return issues;
|
|
468
|
+
}
|
|
469
|
+
async function run() {
|
|
470
|
+
const startTime = Date.now();
|
|
471
|
+
const allIssues = [];
|
|
472
|
+
// Run all React pattern checks
|
|
473
|
+
allIssues.push(...await checkServerComponents());
|
|
474
|
+
allIssues.push(...await checkSuspenseAndBoundaries());
|
|
475
|
+
allIssues.push(...await checkHooksPatterns());
|
|
476
|
+
allIssues.push(...await checkContextPatterns());
|
|
477
|
+
allIssues.push(...await checkKeyPropPatterns());
|
|
478
|
+
allIssues.push(...await checkPerformancePatterns());
|
|
479
|
+
// Convert to findings
|
|
480
|
+
const findings = allIssues.map(issue => ({
|
|
481
|
+
level: issue.severity,
|
|
482
|
+
message: issue.message,
|
|
483
|
+
file: issue.file,
|
|
484
|
+
startLine: issue.line,
|
|
485
|
+
ruleId: issue.rule,
|
|
486
|
+
suggestion: issue.suggestion,
|
|
487
|
+
}));
|
|
488
|
+
const errors = findings.filter(f => f.level === "error");
|
|
489
|
+
const warnings = findings.filter(f => f.level === "warning");
|
|
490
|
+
const infos = findings.filter(f => f.level === "info");
|
|
491
|
+
return {
|
|
492
|
+
passed: errors.length === 0,
|
|
493
|
+
findings,
|
|
494
|
+
duration: Date.now() - startTime,
|
|
495
|
+
metadata: {
|
|
496
|
+
errors: errors.length,
|
|
497
|
+
warnings: warnings.length,
|
|
498
|
+
infos: infos.length,
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
async function main() {
|
|
503
|
+
console.log(`\n${console_chars_1.emoji.components} REACT PATTERNS VALIDATION`);
|
|
504
|
+
console.log((0, console_chars_1.createDivider)(65, "heavy"));
|
|
505
|
+
const result = await run();
|
|
506
|
+
const { errors, warnings, infos } = result.metadata || {};
|
|
507
|
+
console.log(`\n${console_chars_1.emoji.search} Checking React patterns...`);
|
|
508
|
+
console.log(`\n${console_chars_1.emoji.chart} Summary:`);
|
|
509
|
+
console.log(` Errors: ${errors}`);
|
|
510
|
+
console.log(` Warnings: ${warnings}`);
|
|
511
|
+
console.log(` Info: ${infos}`);
|
|
512
|
+
if (result.passed && warnings === 0) {
|
|
513
|
+
console.log(`\n${console_chars_1.emoji.success} REACT PATTERNS VALIDATION PASSED`);
|
|
514
|
+
console.log(`\nAll React best practices are followed.`);
|
|
515
|
+
process.exit(0);
|
|
516
|
+
}
|
|
517
|
+
// Print findings by category
|
|
518
|
+
const errorFindings = result.findings.filter(f => f.level === "error");
|
|
519
|
+
if (errorFindings.length > 0) {
|
|
520
|
+
console.log(`\n${console_chars_1.emoji.error} Errors (blocking):`);
|
|
521
|
+
for (const finding of errorFindings) {
|
|
522
|
+
console.log(`\n ${finding.file}${finding.startLine ? `:${finding.startLine}` : ""}`);
|
|
523
|
+
console.log(` ${finding.message}`);
|
|
524
|
+
if (finding.suggestion) {
|
|
525
|
+
console.log(` ${console_chars_1.emoji.hint} ${finding.suggestion}`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
const warningFindings = result.findings.filter(f => f.level === "warning");
|
|
530
|
+
if (warningFindings.length > 0) {
|
|
531
|
+
console.log(`\n${console_chars_1.emoji.warning} Warnings:`);
|
|
532
|
+
for (const finding of warningFindings.slice(0, 10)) {
|
|
533
|
+
console.log(`\n ${finding.file}${finding.startLine ? `:${finding.startLine}` : ""}`);
|
|
534
|
+
console.log(` ${finding.message}`);
|
|
535
|
+
}
|
|
536
|
+
if (warningFindings.length > 10) {
|
|
537
|
+
console.log(`\n ... and ${warningFindings.length - 10} more warnings`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
console.log(`\n${console_chars_1.emoji.info} React Best Practices:`);
|
|
541
|
+
console.log(` - Server components must not use client APIs`);
|
|
542
|
+
console.log(` - Lazy-loaded components need Suspense`);
|
|
543
|
+
console.log(` - Hooks called at top level only`);
|
|
544
|
+
console.log(` - useEffect cleanup for subscriptions`);
|
|
545
|
+
console.log(` - Stable keys for list items`);
|
|
546
|
+
if (!result.passed) {
|
|
547
|
+
console.log(`\n${console_chars_1.emoji.error} REACT PATTERNS VALIDATION FAILED`);
|
|
548
|
+
process.exit(1);
|
|
549
|
+
}
|
|
550
|
+
console.log(`\n${console_chars_1.emoji.success} REACT PATTERNS VALIDATION PASSED`);
|
|
551
|
+
process.exit(0);
|
|
552
|
+
}
|
|
553
|
+
if (require.main === module) {
|
|
554
|
+
main().catch((err) => {
|
|
555
|
+
console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
|
|
556
|
+
process.exit(1);
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
//# sourceMappingURL=react-patterns-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-patterns-validation.js","sourceRoot":"","sources":["../../../src/checks/react/react-patterns-validation.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6eA,kBAoCC;AAhhBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,4CAA8B;AAC9B,gDAAkC;AAClC,+BAA4B;AAE5B,6DAAiE;AAEpD,QAAA,EAAE,GAAG,iCAAiC,CAAC;AACvC,QAAA,IAAI,GAAG,2BAA2B,CAAC;AACnC,QAAA,WAAW,GAAG,oFAAoF,CAAC;AACnG,QAAA,QAAQ,GAAG,OAAO,CAAC;AACnB,QAAA,QAAQ,GAAG,IAAI,CAAC;AAChB,QAAA,IAAI,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;AAWvF,SAAS,aAAa,CAAC,OAAe,EAAE,KAAa;IACnD,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACxD,CAAC;AAED,KAAK,UAAU,qBAAqB;IAClC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC;QACvB,cAAc;QACd,aAAa;KACd,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,oBAAoB,EAAE,eAAe,EAAE,eAAe,CAAC;QAChE,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,0DAA0D;IAC1D,MAAM,kBAAkB,GAAG;QACzB,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAE;QAChD,EAAE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,EAAE;QAClD,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC5C,EAAE,OAAO,EAAE,mBAAmB,EAAE,IAAI,EAAE,YAAY,EAAE;QACpD,EAAE,OAAO,EAAE,wBAAwB,EAAE,IAAI,EAAE,iBAAiB,EAAE;QAC9D,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3C,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,UAAU,EAAE;QAC/C,EAAE,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,EAAE;QACvD,EAAE,OAAO,EAAE,sBAAsB,EAAE,IAAI,EAAE,gBAAgB,EAAE;QAC3D,EAAE,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,kBAAkB,EAAE;KACjE,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAExD,kCAAkC;QAClC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/D,IAAI,iBAAiB;YAAE,SAAS;QAEhC,uEAAuE;QACvE,IAAI,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,SAAS;QAE/E,iCAAiC;QACjC,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,kBAAkB,EAAE,CAAC;YACnD,IAAI,KAAK,CAAC;YACV,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC9C,4BAA4B;gBAC5B,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC7D,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBACvD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAEzD,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,6BAA6B;oBACnC,OAAO,EAAE,0CAA0C,IAAI,EAAE;oBACzD,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;oBACzC,QAAQ,EAAE,OAAO;oBACjB,UAAU,EAAE,oEAAoE;iBACjF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,0BAA0B;IACvC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC;QACvB,cAAc;QACd,qBAAqB;QACrB,cAAc;KACf,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,oBAAoB,EAAE,eAAe,EAAE,eAAe,CAAC;QAChE,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAExD,wCAAwC;QACxC,MAAM,SAAS,GAAG,oCAAoC,CAAC;QACvD,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,qBAAqB;oBAC3B,OAAO,EAAE,mDAAmD;oBAC5D,IAAI,EAAE,YAAY;oBAClB,QAAQ,EAAE,SAAS;oBACnB,UAAU,EAAE,0DAA0D;iBACvE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,6DAA6D;QAC7D,MAAM,YAAY,GAAG,oCAAoC,CAAC;QAC1D,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACrD,2BAA2B;YAC3B,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;YAC1E,MAAM,gBAAgB,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAE7D,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,uBAAuB;oBAC7B,OAAO,EAAE,qCAAqC;oBAC9C,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;oBACzC,QAAQ,EAAE,MAAM;oBAChB,UAAU,EAAE,qDAAqD;iBAClE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,oDAAoD;QACpD,MAAM,mBAAmB,GAAG,mDAAmD,CAAC;QAChF,OAAO,CAAC,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAE/B,gEAAgE;YAChE,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACvE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;gBAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC9B,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,gCAAgC;wBACtC,OAAO,EAAE,wBAAwB,aAAa,qCAAqC;wBACnF,IAAI,EAAE,YAAY;wBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;wBACzC,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,wDAAwD;qBACrE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,kBAAkB;IAC/B,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC;QACvB,cAAc;QACd,qBAAqB;QACrB,cAAc;QACd,eAAe;QACf,aAAa;KACd,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,oBAAoB,EAAE,eAAe,EAAE,eAAe,CAAC;QAChE,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAExD,kCAAkC;QAClC,MAAM,sBAAsB,GAAG,0CAA0C,CAAC;QAC1E,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,sBAAsB;gBAC5B,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC,CAAC,4BAA4B;gBACrD,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;gBACzC,QAAQ,EAAE,OAAO;gBACjB,UAAU,EAAE,0CAA0C;aACvD,CAAC,CAAC;QACL,CAAC;QAED,2BAA2B;QAC3B,MAAM,eAAe,GAAG,qDAAqD,CAAC;QAC9E,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC,CAAC,qBAAqB;gBAC9C,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;gBACzC,QAAQ,EAAE,OAAO;gBACjB,UAAU,EAAE,iDAAiD;aAC9D,CAAC,CAAC;QACL,CAAC;QAED,wDAAwD;QACxD,MAAM,yBAAyB,GAAG,mGAAmG,CAAC;QACtI,OAAO,CAAC,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAClE,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,UAAU,GAAG,uBAAuB,CAAC,IAAI,CAAC,aAAa,CAAC;gBAC1C,uBAAuB,CAAC,IAAI,CAAC,aAAa,CAAC;gBAC3C,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAE5D,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,mBAAmB;oBACzB,OAAO,EAAE,mDAAmD;oBAC5D,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;oBACzC,QAAQ,EAAE,SAAS;oBACnB,UAAU,EAAE,oDAAoD;iBACjE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,MAAM,eAAe,GAAG,mDAAmD,CAAC;QAC5E,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,iFAAiF;YACjF,MAAM,eAAe,GAAG,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC/F,MAAM,SAAS,GAAG,8DAA8D,CAAC,IAAI,CACnF,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAClD,CAAC;YAEF,IAAI,CAAC,eAAe,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC5F,iDAAiD;gBACjD,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;gBACxE,MAAM,WAAW,GAAG,uBAAuB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAE/D,IAAI,CAAC,WAAW,IAAI,SAAS,EAAE,CAAC;oBAC9B,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,oBAAoB;wBAC1B,OAAO,EAAE,aAAa,QAAQ,2CAA2C;wBACzE,IAAI,EAAE,YAAY;wBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;wBACzC,QAAQ,EAAE,SAAS;wBACnB,UAAU,EAAE,iBAAiB,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG;qBACrF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,kEAAkE;QAClE,+DAA+D;QAC/D,MAAM,cAAc,GAAG,4DAA4D,CAAC;QACpF,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACvD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAE7B,0EAA0E;YAC1E,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACnE,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;gBAClC,6DAA6D;gBAC7D,MAAM,gBAAgB,GAAG,gDAAgD,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAEzF,IAAI,gBAAgB,EAAE,CAAC;oBACrB,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,iBAAiB;wBACvB,OAAO,EAAE,GAAG,QAAQ,sDAAsD;wBAC1E,IAAI,EAAE,YAAY;wBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;wBACzC,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,yEAAyE;qBACtF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,oBAAoB;IACjC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC;QACvB,cAAc;QACd,qBAAqB;QACrB,mBAAmB;QACnB,oBAAoB;QACpB,cAAc;KACf,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,oBAAoB,EAAE,eAAe,EAAE,eAAe,CAAC;QAChE,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAExD,oDAAoD;QACpD,MAAM,iBAAiB,GAAG,gDAAgD,CAAC;QAC3E,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1D,8BAA8B;YAC9B,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,CACvC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,EAC9B,KAAK,CAAC,KAAK,CACZ,CAAC;YACF,MAAM,OAAO,GAAG,yBAAyB,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC;YAEvE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,yBAAyB;oBAC/B,OAAO,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,mDAAmD;oBACvE,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;oBACzC,QAAQ,EAAE,SAAS;oBACnB,UAAU,EAAE,6CAA6C;iBAC1D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,oBAAoB;IACjC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC;QACvB,cAAc;QACd,qBAAqB;QACrB,cAAc;KACf,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,oBAAoB,EAAE,eAAe,EAAE,eAAe,CAAC;QAChE,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAExD,iCAAiC;QACjC,MAAM,eAAe,GAAG,2DAA2D,CAAC;QACpF,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,+BAA+B;gBACxC,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;gBACzC,QAAQ,EAAE,SAAS;gBACnB,UAAU,EAAE,uDAAuD;aACpE,CAAC,CAAC;QACL,CAAC;QAED,8CAA8C;QAC9C,MAAM,gBAAgB,GAAG,yEAAyE,CAAC;QACnG,OAAO,CAAC,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,+BAA+B;gBACxC,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;gBACzC,QAAQ,EAAE,SAAS;gBACnB,UAAU,EAAE,sDAAsD;aACnE,CAAC,CAAC;QACL,CAAC;QAED,+CAA+C;QAC/C,MAAM,gBAAgB,GAAG,oFAAoF,CAAC;QAC9G,OAAO,CAAC,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,+CAA+C;gBACxD,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;gBACzC,QAAQ,EAAE,OAAO;gBACjB,UAAU,EAAE,wCAAwC;aACrD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,wBAAwB;IACrC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC;QACvB,cAAc;QACd,qBAAqB;QACrB,cAAc;KACf,EAAE;QACD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,CAAC,oBAAoB,EAAE,eAAe,EAAE,eAAe,CAAC;QAChE,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAExD,6DAA6D;QAC7D,2EAA2E;QAC3E,MAAM,mBAAmB,GAAG,0HAA0H,CAAC;QACvJ,IAAI,KAAK,CAAC;QACV,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,OAAO,CAAC,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,WAAW,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,WAAW,GAAG,EAAE,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE,GAAG,WAAW,yDAAyD;gBAChF,IAAI,EAAE,YAAY;gBAClB,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,4DAA4D;aACzE,CAAC,CAAC;QACL,CAAC;QAED,4CAA4C;QAC5C,MAAM,iBAAiB,GAAG,qDAAqD,CAAC;QAChF,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,OAAO,CAAC,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1D,WAAW,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,WAAW,GAAG,EAAE,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,qBAAqB;gBAC3B,OAAO,EAAE,GAAG,WAAW,iDAAiD;gBACxE,IAAI,EAAE,YAAY;gBAClB,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,6CAA6C;aAC1D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAEM,KAAK,UAAU,GAAG;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAiB,EAAE,CAAC;IAEnC,+BAA+B;IAC/B,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,qBAAqB,EAAE,CAAC,CAAC;IACjD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,0BAA0B,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,kBAAkB,EAAE,CAAC,CAAC;IAC9C,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,oBAAoB,EAAE,CAAC,CAAC;IAChD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,oBAAoB,EAAE,CAAC,CAAC;IAChD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,wBAAwB,EAAE,CAAC,CAAC;IAEpD,sBAAsB;IACtB,MAAM,QAAQ,GAAuB,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3D,KAAK,EAAE,KAAK,CAAC,QAAQ;QACrB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,IAAI;QACrB,MAAM,EAAE,KAAK,CAAC,IAAI;QAClB,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC,CAAC,CAAC;IAEJ,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;IAEvD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC3B,QAAQ;QACR,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;QAChC,QAAQ,EAAE;YACR,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,QAAQ,CAAC,MAAM;YACzB,KAAK,EAAE,KAAK,CAAC,MAAM;SACpB;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,UAAU,4BAA4B,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAExC,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IAE1D,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,MAAM,6BAA6B,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,KAAK,WAAW,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,EAAE,CAAC,CAAC;IAEjC,IAAI,MAAM,CAAC,MAAM,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,6BAA6B;IAC7B,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACvE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,KAAK,qBAAqB,CAAC,CAAC;QACnD,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,QAAQ,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvF,OAAO,CAAC,GAAG,CAAC,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,QAAQ,qBAAK,CAAC,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAC3E,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,YAAY,CAAC,CAAC;QAC5C,KAAK,MAAM,OAAO,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC,QAAQ,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvF,OAAO,CAAC,GAAG,CAAC,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,eAAe,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,gBAAgB,eAAe,CAAC,MAAM,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,IAAI,wBAAwB,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAE/C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,KAAK,mCAAmC,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;IACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QAC1B,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;AACL,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { PreflightCheckResult } from "../../core/types";
|
|
3
|
+
export declare const id = "security/security-headers-validation";
|
|
4
|
+
export declare const name = "Security Headers Validation";
|
|
5
|
+
export declare const description = "Validates security headers, cookies, SRI, CORS, and OWASP best practices";
|
|
6
|
+
export declare const category = "security";
|
|
7
|
+
export declare const blocking = true;
|
|
8
|
+
export declare const tags: string[];
|
|
9
|
+
export declare function run(): Promise<PreflightCheckResult>;
|
|
10
|
+
//# sourceMappingURL=security-headers-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-headers-validation.d.ts","sourceRoot":"","sources":["../../../src/checks/security/security-headers-validation.ts"],"names":[],"mappings":";AAkCA,OAAO,EAAE,oBAAoB,EAAoB,MAAM,kBAAkB,CAAC;AAG1E,eAAO,MAAM,EAAE,yCAAyC,CAAC;AACzD,eAAO,MAAM,IAAI,gCAAgC,CAAC;AAClD,eAAO,MAAM,WAAW,6EAA6E,CAAC;AACtG,eAAO,MAAM,QAAQ,aAAa,CAAC;AACnC,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAA6D,CAAC;AAye/E,wBAAsB,GAAG,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAuCzD"}
|