@mr.dj2u/doctor 0.1.7 → 0.1.8
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/api-safety.d.ts +17 -0
- package/dist/checks/api-safety.d.ts.map +1 -0
- package/dist/checks/api-safety.js +282 -0
- package/dist/checks/api-safety.js.map +1 -0
- package/dist/checks/app-architecture.d.ts +3 -3
- package/dist/checks/app-architecture.d.ts.map +1 -1
- package/dist/checks/app-architecture.js +14 -11
- package/dist/checks/app-architecture.js.map +1 -1
- package/dist/checks/env-hygiene.d.ts +17 -0
- package/dist/checks/env-hygiene.d.ts.map +1 -1
- package/dist/checks/env-hygiene.js +376 -32
- package/dist/checks/env-hygiene.js.map +1 -1
- package/dist/checks/expo-config.d.ts.map +1 -1
- package/dist/checks/expo-config.js +4 -7
- package/dist/checks/expo-config.js.map +1 -1
- package/dist/checks/expo-doctor.d.ts.map +1 -1
- package/dist/checks/expo-doctor.js +6 -2
- package/dist/checks/expo-doctor.js.map +1 -1
- package/dist/checks/index.d.ts +4 -0
- package/dist/checks/index.d.ts.map +1 -1
- package/dist/checks/index.js +4 -0
- package/dist/checks/index.js.map +1 -1
- package/dist/checks/react-doctor.d.ts +28 -0
- package/dist/checks/react-doctor.d.ts.map +1 -0
- package/dist/checks/react-doctor.js +360 -0
- package/dist/checks/react-doctor.js.map +1 -0
- package/dist/checks/router-safety.d.ts +13 -0
- package/dist/checks/router-safety.d.ts.map +1 -0
- package/dist/checks/router-safety.js +360 -0
- package/dist/checks/router-safety.js.map +1 -0
- package/dist/checks/runtime-security.d.ts +17 -0
- package/dist/checks/runtime-security.d.ts.map +1 -0
- package/dist/checks/runtime-security.js +583 -0
- package/dist/checks/runtime-security.js.map +1 -0
- package/dist/checks/script-checks.d.ts +2 -0
- package/dist/checks/script-checks.d.ts.map +1 -1
- package/dist/checks/script-checks.js +33 -9
- package/dist/checks/script-checks.js.map +1 -1
- package/dist/cli-main.d.ts +1 -0
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/cli-main.js +28 -1
- package/dist/cli-main.js.map +1 -1
- package/dist/expo-router.d.ts +15 -0
- package/dist/expo-router.d.ts.map +1 -0
- package/dist/expo-router.js +76 -0
- package/dist/expo-router.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -15
- package/dist/index.js.map +1 -1
- package/dist/modes.d.ts +8 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +71 -0
- package/dist/modes.js.map +1 -0
- package/dist/reporter.d.ts +1 -1
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +73 -3
- package/dist/reporter.js.map +1 -1
- package/dist/scan-file.d.ts.map +1 -1
- package/dist/scan-file.js +9 -5
- package/dist/scan-file.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +11 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +124 -2
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { findExpoRouterApiRouteFiles, hasExpoRouterSignal, isExpoRouterApiRouteFile, } from '../expo-router.js';
|
|
3
|
+
import { findFiles, firstExistingPath, isToolingOrTestPath, pathExists, readOptionalText, readPackageJson, relative, SOURCE_EXTENSIONS, } from '../utils.js';
|
|
4
|
+
import { credentialSeverityForDetector, detectKnownCredentialShape, isCommentOnlyLine, isDynamicOrInterpolatedValue, isPlaceholderValue, looksLikeCredentialValue, } from './env-hygiene.js';
|
|
5
|
+
const MAX_FINDINGS = 25;
|
|
6
|
+
const IMPORT_FOLLOW_DEPTH = 2;
|
|
7
|
+
const SERVER_PACKAGES = new Set([
|
|
8
|
+
'prisma',
|
|
9
|
+
'@prisma/client',
|
|
10
|
+
'drizzle-orm',
|
|
11
|
+
'pg',
|
|
12
|
+
'postgres',
|
|
13
|
+
'mysql2',
|
|
14
|
+
'better-sqlite3',
|
|
15
|
+
'sqlite3',
|
|
16
|
+
'mongodb',
|
|
17
|
+
'mongoose',
|
|
18
|
+
'express',
|
|
19
|
+
'koa',
|
|
20
|
+
'fastify',
|
|
21
|
+
'hono',
|
|
22
|
+
'firebase-admin',
|
|
23
|
+
'jsonwebtoken',
|
|
24
|
+
'bcrypt',
|
|
25
|
+
'bcryptjs',
|
|
26
|
+
'argon2',
|
|
27
|
+
'nodemailer',
|
|
28
|
+
'ioredis',
|
|
29
|
+
'redis',
|
|
30
|
+
]);
|
|
31
|
+
const SERVER_NODE_BUILTINS = new Set([
|
|
32
|
+
'node:fs',
|
|
33
|
+
'node:child_process',
|
|
34
|
+
'node:http',
|
|
35
|
+
'node:https',
|
|
36
|
+
'node:net',
|
|
37
|
+
'node:cluster',
|
|
38
|
+
]);
|
|
39
|
+
const CLIENT_ENV_ALLOWLIST = new Set([
|
|
40
|
+
'NODE_ENV',
|
|
41
|
+
'EXPO_OS',
|
|
42
|
+
'JEST_WORKER_ID',
|
|
43
|
+
'VITEST',
|
|
44
|
+
'VITEST_POOL_ID',
|
|
45
|
+
]);
|
|
46
|
+
const TOOLING_CONFIG_BASENAME = /^(metro|babel|drizzle|tailwind|eslint|prettier|vitest|jest|webpack|app)\.config\.(js|cjs|mjs|ts)$/;
|
|
47
|
+
const EXPO_CONFIG_BASENAMES = new Set([
|
|
48
|
+
'app.json',
|
|
49
|
+
'app.config.js',
|
|
50
|
+
'app.config.ts',
|
|
51
|
+
'app.config.mjs',
|
|
52
|
+
'app.config.cjs',
|
|
53
|
+
]);
|
|
54
|
+
const METRO_CONFIG_BASENAMES = [
|
|
55
|
+
'metro.config.js',
|
|
56
|
+
'metro.config.cjs',
|
|
57
|
+
'metro.config.mjs',
|
|
58
|
+
'metro.config.ts',
|
|
59
|
+
];
|
|
60
|
+
const SERVER_PATH_SEGMENTS = new Set([
|
|
61
|
+
'server',
|
|
62
|
+
'servers',
|
|
63
|
+
'api-server',
|
|
64
|
+
'database',
|
|
65
|
+
'drizzle',
|
|
66
|
+
'db',
|
|
67
|
+
'scripts',
|
|
68
|
+
'middlewares',
|
|
69
|
+
'middleware',
|
|
70
|
+
]);
|
|
71
|
+
const CLIENT_BUNDLE_SEGMENTS = new Set(['components', 'features', 'screens', 'hooks', 'services']);
|
|
72
|
+
const SENSITIVE_EXTRA_KEY = /(apiKey|api_key|secret|token|password|serviceRole|service_role|privateKey|private_key|clientSecret|client_secret)/i;
|
|
73
|
+
const IMPORT_SPECIFIER_PATTERN = /(?:(?:^|[^\w.$])(?:import(?:\s+type)?(?:[\s\w{},*$]*from)?|export(?:\s+\*(?:\s+as\s+\w+)?|{[\s\w,]*})?\s+from)\s*|\brequire\s*\(\s*|\bimport\s*\(\s*)['"]([^'"]+)['"]/g;
|
|
74
|
+
const PROCESS_ENV_PATTERN = /process\.env(?:\.([A-Za-z_][A-Za-z0-9_]*)|\[\s*['"]([A-Za-z_][A-Za-z0-9_]*)['"]\s*\])/g;
|
|
75
|
+
const LOCALHOST_FETCH_PATTERN = /\b(?:fetch|axios)(?:\.(?:get|post|put|patch|delete))?\s*\(\s*['"`]https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|10\.0\.2\.2)(?::\d+)?/gi;
|
|
76
|
+
const USE_SERVER_PATTERN = /^['"]use server['"]\s*;?$/;
|
|
77
|
+
export async function checkRuntimeSecurity(projectPath) {
|
|
78
|
+
const packageJson = await readPackageJson(path.join(projectPath, 'package.json'));
|
|
79
|
+
if (!(await hasExpoAppSignal(projectPath, packageJson))) {
|
|
80
|
+
return {
|
|
81
|
+
name: 'runtime security',
|
|
82
|
+
status: 'skip',
|
|
83
|
+
message: 'No Expo app signals; runtime security scan skipped.',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const findings = [
|
|
87
|
+
...(await checkServerImports(projectPath, packageJson)),
|
|
88
|
+
...(await checkSSRSafety(projectPath, packageJson)),
|
|
89
|
+
...(await checkCredentialExposure(projectPath, packageJson)),
|
|
90
|
+
];
|
|
91
|
+
return toRuntimeSecurityResult(findings, true);
|
|
92
|
+
}
|
|
93
|
+
export async function scanFileRuntimeSecurity(projectPath, filePath) {
|
|
94
|
+
const packageJson = await readPackageJson(path.join(projectPath, 'package.json'));
|
|
95
|
+
const expo = await hasExpoAppSignal(projectPath, packageJson);
|
|
96
|
+
if (!expo) {
|
|
97
|
+
return {
|
|
98
|
+
name: 'runtime security',
|
|
99
|
+
status: 'skip',
|
|
100
|
+
message: 'No Expo app signals; runtime security scan skipped.',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const findings = await scanRuntimeSecurityFile(projectPath, filePath, packageJson ?? {});
|
|
104
|
+
const basename = path.basename(filePath);
|
|
105
|
+
if (METRO_CONFIG_BASENAMES.includes(basename)) {
|
|
106
|
+
findings.push(...(await checkSSRSafety(projectPath, packageJson)));
|
|
107
|
+
}
|
|
108
|
+
return toRuntimeSecurityResult(findings, true);
|
|
109
|
+
}
|
|
110
|
+
export async function checkServerImports(projectPath, packageJson) {
|
|
111
|
+
const pkg = packageJson ?? (await readPackageJson(path.join(projectPath, 'package.json'))) ?? {};
|
|
112
|
+
const sourceFiles = await findFiles(projectPath, (filePath) => SOURCE_EXTENSIONS.has(path.extname(filePath)));
|
|
113
|
+
const findings = [];
|
|
114
|
+
for (const filePath of sourceFiles) {
|
|
115
|
+
if (isIgnoredRuntimeFile(projectPath, filePath) || !isClientBundleRoot(projectPath, filePath)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
findings.push(...(await findServerImportFindings(projectPath, filePath, pkg)));
|
|
119
|
+
if (findings.length >= MAX_FINDINGS) {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return findings;
|
|
124
|
+
}
|
|
125
|
+
export async function checkSSRSafety(projectPath, packageJson) {
|
|
126
|
+
const pkg = packageJson ?? (await readPackageJson(path.join(projectPath, 'package.json'))) ?? {};
|
|
127
|
+
if (!(await projectUsesServerRuntime(projectPath, pkg))) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
const metroPath = await firstExistingPath(METRO_CONFIG_BASENAMES.map((basename) => path.join(projectPath, basename)));
|
|
131
|
+
if (!metroPath) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
const contents = (await readOptionalText(metroPath)) ?? '';
|
|
135
|
+
if (!contents.trim()) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const usesExpoDefault = /getDefaultConfig\s*\(/.test(contents) && /expo\/metro-config/.test(contents);
|
|
139
|
+
const overwritesConditions = /unstable_conditionNames\s*=/.test(contents) || /unstable_conditionsByPlatform\s*=/.test(contents);
|
|
140
|
+
const mentionsNodeCondition = /['"]node['"]/.test(contents);
|
|
141
|
+
if (usesExpoDefault && !overwritesConditions) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
if (overwritesConditions && mentionsNodeCondition) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
if (!usesExpoDefault || (overwritesConditions && !mentionsNodeCondition)) {
|
|
148
|
+
return [
|
|
149
|
+
{
|
|
150
|
+
file: relative(projectPath, metroPath),
|
|
151
|
+
line: lineNumberOf(contents, /unstable_conditionNames|getDefaultConfig|module\.exports/),
|
|
152
|
+
kind: 'metro-node-runtime',
|
|
153
|
+
severity: 'warn',
|
|
154
|
+
detector: 'metro-missing-node-condition',
|
|
155
|
+
identifier: 'node',
|
|
156
|
+
remediation: 'Keep expo/metro-config getDefaultConfig and include "node" in resolver.unstable_conditionNames (or conditionsByPlatform) so API routes and server modules resolve the Node runtime target.',
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
export async function checkCredentialExposure(projectPath, packageJson) {
|
|
163
|
+
const pkg = packageJson ?? (await readPackageJson(path.join(projectPath, 'package.json'))) ?? {};
|
|
164
|
+
const findings = [];
|
|
165
|
+
const configFiles = await findFiles(projectPath, (filePath) => EXPO_CONFIG_BASENAMES.has(path.basename(filePath)));
|
|
166
|
+
for (const filePath of configFiles) {
|
|
167
|
+
const contents = (await readOptionalText(filePath)) ?? '';
|
|
168
|
+
if (contents) {
|
|
169
|
+
findings.push(...findExpoConfigCredentialFindings(projectPath, filePath, contents));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const sourceFiles = await findFiles(projectPath, (filePath) => SOURCE_EXTENSIONS.has(path.extname(filePath)));
|
|
173
|
+
for (const filePath of sourceFiles) {
|
|
174
|
+
if (isIgnoredRuntimeFile(projectPath, filePath) || !isClientBundleRoot(projectPath, filePath)) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
findings.push(...(await findClientCredentialFindings(projectPath, filePath, pkg)));
|
|
178
|
+
if (findings.length >= MAX_FINDINGS) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return findings;
|
|
183
|
+
}
|
|
184
|
+
async function scanRuntimeSecurityFile(projectPath, filePath, packageJson) {
|
|
185
|
+
if (isIgnoredRuntimeFile(projectPath, filePath)) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
const findings = [];
|
|
189
|
+
const basename = path.basename(filePath);
|
|
190
|
+
const contents = (await readOptionalText(filePath)) ?? '';
|
|
191
|
+
if (EXPO_CONFIG_BASENAMES.has(basename) && contents) {
|
|
192
|
+
findings.push(...findExpoConfigCredentialFindings(projectPath, filePath, contents));
|
|
193
|
+
}
|
|
194
|
+
if (SOURCE_EXTENSIONS.has(path.extname(filePath))) {
|
|
195
|
+
findings.push(...(await findServerImportFindings(projectPath, filePath, packageJson)));
|
|
196
|
+
findings.push(...(await findClientCredentialFindings(projectPath, filePath, packageJson)));
|
|
197
|
+
}
|
|
198
|
+
return findings;
|
|
199
|
+
}
|
|
200
|
+
async function findServerImportFindings(projectPath, filePath, packageJson) {
|
|
201
|
+
const contents = (await readOptionalText(filePath)) ?? '';
|
|
202
|
+
if (!contents || (await isServerRuntimeFile(projectPath, filePath, packageJson, contents))) {
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
const findings = [];
|
|
206
|
+
const seen = new Set();
|
|
207
|
+
const queue = [
|
|
208
|
+
{ filePath, contents, depth: 0, originLine: 1 },
|
|
209
|
+
];
|
|
210
|
+
const visited = new Set([filePath]);
|
|
211
|
+
while (queue.length > 0) {
|
|
212
|
+
const current = queue.shift();
|
|
213
|
+
if (!current) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
for (const imported of readImportSpecifiers(current.contents)) {
|
|
217
|
+
const reportLine = current.depth === 0 ? imported.line : current.originLine;
|
|
218
|
+
const packageName = packageNameFromSpecifier(imported.specifier);
|
|
219
|
+
if (packageName && SERVER_PACKAGES.has(packageName)) {
|
|
220
|
+
const key = `${reportLine}:${packageName}`;
|
|
221
|
+
if (seen.has(key)) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
seen.add(key);
|
|
225
|
+
findings.push({
|
|
226
|
+
file: relative(projectPath, filePath),
|
|
227
|
+
line: reportLine,
|
|
228
|
+
kind: 'server-package-import',
|
|
229
|
+
severity: 'error',
|
|
230
|
+
detector: 'server-package-on-client',
|
|
231
|
+
identifier: packageName,
|
|
232
|
+
remediation: `Move ${packageName} usage behind an Expo Router API route, a *.server.* module, or a 'use server' file that the client does not import.`,
|
|
233
|
+
});
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (SERVER_NODE_BUILTINS.has(imported.specifier)) {
|
|
237
|
+
const key = `${reportLine}:${imported.specifier}`;
|
|
238
|
+
if (seen.has(key)) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
seen.add(key);
|
|
242
|
+
findings.push({
|
|
243
|
+
file: relative(projectPath, filePath),
|
|
244
|
+
line: reportLine,
|
|
245
|
+
kind: 'server-builtin-import',
|
|
246
|
+
severity: 'error',
|
|
247
|
+
detector: 'node-builtin-on-client',
|
|
248
|
+
identifier: imported.specifier,
|
|
249
|
+
remediation: `Keep ${imported.specifier} on the server. Use an API route or server module instead of importing it from client code.`,
|
|
250
|
+
});
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (current.depth >= IMPORT_FOLLOW_DEPTH) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
const resolved = await resolveRelativeImport(current.filePath, imported.specifier);
|
|
257
|
+
if (!resolved || visited.has(resolved)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
visited.add(resolved);
|
|
261
|
+
const resolvedContents = (await readOptionalText(resolved)) ?? '';
|
|
262
|
+
const resolvedIsServer = await isServerRuntimeFile(projectPath, resolved, packageJson, resolvedContents);
|
|
263
|
+
if (resolvedIsServer) {
|
|
264
|
+
const key = `${reportLine}:${imported.specifier}`;
|
|
265
|
+
if (seen.has(key)) {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
seen.add(key);
|
|
269
|
+
findings.push({
|
|
270
|
+
file: relative(projectPath, filePath),
|
|
271
|
+
line: reportLine,
|
|
272
|
+
kind: 'server-file-import',
|
|
273
|
+
severity: 'error',
|
|
274
|
+
detector: 'server-module-on-client',
|
|
275
|
+
identifier: imported.specifier,
|
|
276
|
+
remediation: 'Do not import server-only modules (*.server.*, +api routes, or "use server" files) from client components.',
|
|
277
|
+
});
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
queue.push({
|
|
281
|
+
filePath: resolved,
|
|
282
|
+
contents: resolvedContents,
|
|
283
|
+
depth: current.depth + 1,
|
|
284
|
+
originLine: reportLine,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return findings;
|
|
289
|
+
}
|
|
290
|
+
async function findClientCredentialFindings(projectPath, filePath, packageJson) {
|
|
291
|
+
const contents = (await readOptionalText(filePath)) ?? '';
|
|
292
|
+
if (!contents || (await isServerRuntimeFile(projectPath, filePath, packageJson, contents))) {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
const findings = [];
|
|
296
|
+
const searchable = stripCommentsPreservingLines(contents);
|
|
297
|
+
const lines = searchable.split(/\r?\n/);
|
|
298
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
299
|
+
if (isCommentOnlyLine(line)) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
PROCESS_ENV_PATTERN.lastIndex = 0;
|
|
303
|
+
for (const match of line.matchAll(PROCESS_ENV_PATTERN)) {
|
|
304
|
+
const identifier = match[1] ?? match[2];
|
|
305
|
+
if (!identifier || isAllowedClientEnvName(identifier)) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
findings.push({
|
|
309
|
+
file: relative(projectPath, filePath),
|
|
310
|
+
line: lineIndex + 1,
|
|
311
|
+
kind: 'client-private-env',
|
|
312
|
+
severity: 'error',
|
|
313
|
+
detector: 'client-process-env',
|
|
314
|
+
identifier,
|
|
315
|
+
remediation: 'Client bundles can only read EXPO_PUBLIC_* variables (plus NODE_ENV and EXPO_OS). Move private env access to an API route or server module.',
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
LOCALHOST_FETCH_PATTERN.lastIndex = 0;
|
|
319
|
+
if (LOCALHOST_FETCH_PATTERN.test(line)) {
|
|
320
|
+
findings.push({
|
|
321
|
+
file: relative(projectPath, filePath),
|
|
322
|
+
line: lineIndex + 1,
|
|
323
|
+
kind: 'localhost-fetch',
|
|
324
|
+
severity: 'warn',
|
|
325
|
+
detector: 'hardcoded-localhost-fetch',
|
|
326
|
+
identifier: 'localhost',
|
|
327
|
+
remediation: 'Replace hardcoded localhost/dev-server URLs with an EXPO_PUBLIC_* base URL so production builds do not call the local machine.',
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return findings;
|
|
332
|
+
}
|
|
333
|
+
function findExpoConfigCredentialFindings(projectPath, filePath, contents) {
|
|
334
|
+
const findings = [];
|
|
335
|
+
const lines = stripCommentsPreservingLines(contents).split(/\r?\n/);
|
|
336
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
337
|
+
if (isCommentOnlyLine(line)) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
for (const value of readQuotedValues(line)) {
|
|
341
|
+
if (isDynamicOrInterpolatedValue(value) ||
|
|
342
|
+
isPlaceholderValue(value) ||
|
|
343
|
+
looksLikeNonSecretConfigValue(value)) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
const detector = detectKnownCredentialShape(value);
|
|
347
|
+
if (detector) {
|
|
348
|
+
findings.push({
|
|
349
|
+
file: relative(projectPath, filePath),
|
|
350
|
+
line: lineIndex + 1,
|
|
351
|
+
kind: 'expo-config-hardcoded-credential',
|
|
352
|
+
severity: credentialSeverityForDetector(detector),
|
|
353
|
+
detector,
|
|
354
|
+
identifier: detector,
|
|
355
|
+
remediation: 'Do not hardcode credentials in Expo config. Read publishable values from EXPO_PUBLIC_* and keep secrets on the server.',
|
|
356
|
+
});
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const assignment = line.match(/['"]?([A-Za-z0-9_$.-]*(?:apiKey|api_key|secret|token|password|serviceRole|service_role|privateKey|private_key)[A-Za-z0-9_$.-]*)['"]?\s*[:=]\s*(['"`])([^'"`]+)\2/i);
|
|
361
|
+
if (!assignment?.[1] || !assignment[3] || /process\.env/.test(assignment[3])) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (isDynamicOrInterpolatedValue(assignment[3]) ||
|
|
365
|
+
isPlaceholderValue(assignment[3]) ||
|
|
366
|
+
looksLikeNonSecretConfigValue(assignment[3])) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (SENSITIVE_EXTRA_KEY.test(assignment[1]) && looksLikeCredentialValue(assignment[3])) {
|
|
370
|
+
findings.push({
|
|
371
|
+
file: relative(projectPath, filePath),
|
|
372
|
+
line: lineIndex + 1,
|
|
373
|
+
kind: 'expo-config-hardcoded-credential',
|
|
374
|
+
severity: 'error',
|
|
375
|
+
detector: 'expo-extra-literal',
|
|
376
|
+
identifier: assignment[1].slice(0, 80),
|
|
377
|
+
remediation: 'Move Expo extra credentials out of app config literals and into environment variables. Only EXPO_PUBLIC_* values may ship in the client extra config.',
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return findings;
|
|
382
|
+
}
|
|
383
|
+
async function isServerRuntimeFile(projectPath, filePath, packageJson, contents) {
|
|
384
|
+
const rel = relative(projectPath, filePath);
|
|
385
|
+
const basename = path.basename(filePath);
|
|
386
|
+
const extension = path.extname(filePath);
|
|
387
|
+
const stem = basename.slice(0, basename.length - extension.length);
|
|
388
|
+
if (EXPO_CONFIG_BASENAMES.has(basename) || METRO_CONFIG_BASENAMES.includes(basename)) {
|
|
389
|
+
return true;
|
|
390
|
+
}
|
|
391
|
+
if (/^(babel|eslint)\.config\.(js|cjs|mjs|ts)$/.test(basename)) {
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
const pathSegments = rel.split('/');
|
|
395
|
+
if (pathSegments.some((segment) => SERVER_PATH_SEGMENTS.has(segment))) {
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
if (/^(server|api-server)(\.|$)/i.test(stem)) {
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
if (TOOLING_CONFIG_BASENAME.test(basename) || extension === '.cjs') {
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
if (!rel.includes('/') && /\.(js|mjs|cjs)$/.test(basename) && !EXPO_CONFIG_BASENAMES.has(basename)) {
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
if (stem === '+html' || stem.endsWith('.server') || /\.server$/.test(stem)) {
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
if (isExpoRouterApiRouteFile(projectPath, filePath, packageJson)) {
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
const fileContents = contents ?? (await readOptionalText(filePath)) ?? '';
|
|
414
|
+
return hasUseServerDirective(fileContents);
|
|
415
|
+
}
|
|
416
|
+
function isIgnoredRuntimeFile(projectPath, filePath) {
|
|
417
|
+
return isToolingOrTestPath(projectPath, filePath);
|
|
418
|
+
}
|
|
419
|
+
function isClientBundleRoot(projectPath, filePath) {
|
|
420
|
+
const rel = relative(projectPath, filePath);
|
|
421
|
+
if (rel.startsWith('app/') || rel.startsWith('src/app/')) {
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
return rel.split('/').some((segment) => CLIENT_BUNDLE_SEGMENTS.has(segment));
|
|
425
|
+
}
|
|
426
|
+
function hasUseServerDirective(contents) {
|
|
427
|
+
for (const line of stripCommentsPreservingLines(contents).split(/\r?\n/)) {
|
|
428
|
+
const trimmed = line.trim();
|
|
429
|
+
if (!trimmed) {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
return USE_SERVER_PATTERN.test(trimmed);
|
|
433
|
+
}
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
function readImportSpecifiers(contents) {
|
|
437
|
+
const searchable = stripCommentsPreservingLines(contents);
|
|
438
|
+
const results = [];
|
|
439
|
+
IMPORT_SPECIFIER_PATTERN.lastIndex = 0;
|
|
440
|
+
for (const match of searchable.matchAll(IMPORT_SPECIFIER_PATTERN)) {
|
|
441
|
+
const specifier = match[1];
|
|
442
|
+
if (!specifier || match[0].includes('import type')) {
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
results.push({
|
|
446
|
+
specifier,
|
|
447
|
+
line: lineNumberAt(searchable, match.index ?? 0),
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
return results;
|
|
451
|
+
}
|
|
452
|
+
async function resolveRelativeImport(fromFile, specifier) {
|
|
453
|
+
if (!specifier.startsWith('.')) {
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
const base = path.resolve(path.dirname(fromFile), specifier);
|
|
457
|
+
const candidates = [
|
|
458
|
+
base,
|
|
459
|
+
`${base}.ts`,
|
|
460
|
+
`${base}.tsx`,
|
|
461
|
+
`${base}.js`,
|
|
462
|
+
`${base}.jsx`,
|
|
463
|
+
path.join(base, 'index.ts'),
|
|
464
|
+
path.join(base, 'index.tsx'),
|
|
465
|
+
path.join(base, 'index.js'),
|
|
466
|
+
path.join(base, 'index.jsx'),
|
|
467
|
+
];
|
|
468
|
+
for (const candidate of candidates) {
|
|
469
|
+
if (await pathExists(candidate)) {
|
|
470
|
+
return candidate;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
function packageNameFromSpecifier(specifier) {
|
|
476
|
+
if (specifier.startsWith('.') ||
|
|
477
|
+
specifier.startsWith('/') ||
|
|
478
|
+
specifier.startsWith('node:') ||
|
|
479
|
+
specifier.startsWith('#')) {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
if (specifier.startsWith('@')) {
|
|
483
|
+
const parts = specifier.split('/');
|
|
484
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : specifier;
|
|
485
|
+
}
|
|
486
|
+
return specifier.split('/')[0] ?? null;
|
|
487
|
+
}
|
|
488
|
+
async function hasExpoAppSignal(projectPath, packageJson) {
|
|
489
|
+
if (packageJson && (hasExpoRouterSignal(packageJson) || hasExpoDependency(packageJson))) {
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
const configPath = await firstExistingPath([...EXPO_CONFIG_BASENAMES].map((basename) => path.join(projectPath, basename)));
|
|
493
|
+
return configPath !== null;
|
|
494
|
+
}
|
|
495
|
+
function hasExpoDependency(packageJson) {
|
|
496
|
+
const deps = {
|
|
497
|
+
...packageJson.dependencies,
|
|
498
|
+
...packageJson.devDependencies,
|
|
499
|
+
};
|
|
500
|
+
return 'expo' in deps;
|
|
501
|
+
}
|
|
502
|
+
async function projectUsesServerRuntime(projectPath, packageJson) {
|
|
503
|
+
const apiRoutes = await findExpoRouterApiRouteFiles(projectPath, packageJson);
|
|
504
|
+
if (apiRoutes.length > 0) {
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
const appJsonPath = path.join(projectPath, 'app.json');
|
|
508
|
+
const appJson = await readOptionalText(appJsonPath);
|
|
509
|
+
if (appJson && /"output"\s*:\s*"server"/.test(appJson)) {
|
|
510
|
+
return true;
|
|
511
|
+
}
|
|
512
|
+
const sourceFiles = await findFiles(projectPath, (filePath) => SOURCE_EXTENSIONS.has(path.extname(filePath)));
|
|
513
|
+
for (const filePath of sourceFiles) {
|
|
514
|
+
const contents = await readOptionalText(filePath);
|
|
515
|
+
if (contents && hasUseServerDirective(contents)) {
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
function isAllowedClientEnvName(name) {
|
|
522
|
+
return name.startsWith('EXPO_PUBLIC_') || CLIENT_ENV_ALLOWLIST.has(name);
|
|
523
|
+
}
|
|
524
|
+
function looksLikeNonSecretConfigValue(value) {
|
|
525
|
+
const trimmed = value.trim();
|
|
526
|
+
if (trimmed.length < 8) {
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
if (/^https?:\/\//i.test(trimmed) && !/\/\/[^/\s]+:[^@\s]+@/.test(trimmed)) {
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
if (/^[a-z0-9-]+$/i.test(trimmed)) {
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
function readQuotedValues(line) {
|
|
538
|
+
const values = [];
|
|
539
|
+
for (const match of line.matchAll(/(['"`])([^'"`]+)\1/g)) {
|
|
540
|
+
if (match[2]) {
|
|
541
|
+
values.push(match[2]);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return values;
|
|
545
|
+
}
|
|
546
|
+
function stripCommentsPreservingLines(contents) {
|
|
547
|
+
const withoutBlock = contents.replace(/\/\*[\s\S]*?\*\//g, (block) => block.replace(/[^\n]/g, ' '));
|
|
548
|
+
return withoutBlock.replace(/(^|[^:])\/\/.*$/gm, '$1');
|
|
549
|
+
}
|
|
550
|
+
function lineNumberOf(contents, pattern) {
|
|
551
|
+
const match = contents.match(pattern);
|
|
552
|
+
if (!match || match.index === undefined) {
|
|
553
|
+
return 1;
|
|
554
|
+
}
|
|
555
|
+
return lineNumberAt(contents, match.index);
|
|
556
|
+
}
|
|
557
|
+
function lineNumberAt(contents, index) {
|
|
558
|
+
return contents.slice(0, index).split(/\r?\n/).length;
|
|
559
|
+
}
|
|
560
|
+
function toRuntimeSecurityResult(findings, expoProject) {
|
|
561
|
+
if (findings.length === 0) {
|
|
562
|
+
return {
|
|
563
|
+
name: 'runtime security',
|
|
564
|
+
status: expoProject ? 'pass' : 'skip',
|
|
565
|
+
message: expoProject
|
|
566
|
+
? 'No server-on-client imports, private client env access, or Expo config credential leaks found.'
|
|
567
|
+
: 'No Expo app signals; runtime security scan skipped.',
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
const hasError = findings.some((finding) => finding.severity === 'error');
|
|
571
|
+
return {
|
|
572
|
+
name: 'runtime security',
|
|
573
|
+
status: hasError ? 'error' : 'warn',
|
|
574
|
+
message: hasError
|
|
575
|
+
? 'Server-only code or private credentials may leak into the client bundle.'
|
|
576
|
+
: 'Runtime security warnings were found.',
|
|
577
|
+
details: {
|
|
578
|
+
findings: findings.slice(0, MAX_FINDINGS),
|
|
579
|
+
truncated: findings.length > MAX_FINDINGS,
|
|
580
|
+
},
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
//# sourceMappingURL=runtime-security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-security.js","sourceRoot":"","sources":["../../src/checks/runtime-security.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,EAC1B,iBAAiB,EACjB,4BAA4B,EAC5B,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,QAAQ;IACR,gBAAgB;IAChB,aAAa;IACb,IAAI;IACJ,UAAU;IACV,QAAQ;IACR,gBAAgB;IAChB,SAAS;IACT,SAAS;IACT,UAAU;IACV,SAAS;IACT,KAAK;IACL,SAAS;IACT,MAAM;IACN,gBAAgB;IAChB,cAAc;IACd,QAAQ;IACR,UAAU;IACV,QAAQ;IACR,YAAY;IACZ,SAAS;IACT,OAAO;CACR,CAAC,CAAC;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,SAAS;IACT,oBAAoB;IACpB,WAAW;IACX,YAAY;IACZ,UAAU;IACV,cAAc;CACf,CAAC,CAAC;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,UAAU;IACV,SAAS;IACT,gBAAgB;IAChB,QAAQ;IACR,gBAAgB;CACjB,CAAC,CAAC;AACH,MAAM,uBAAuB,GAC3B,mGAAmG,CAAC;AACtG,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,UAAU;IACV,eAAe;IACf,eAAe;IACf,gBAAgB;IAChB,gBAAgB;CACjB,CAAC,CAAC;AACH,MAAM,sBAAsB,GAAG;IAC7B,iBAAiB;IACjB,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;CAClB,CAAC;AACF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,QAAQ;IACR,SAAS;IACT,YAAY;IACZ,UAAU;IACV,SAAS;IACT,IAAI;IACJ,SAAS;IACT,aAAa;IACb,YAAY;CACb,CAAC,CAAC;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AACnG,MAAM,mBAAmB,GACvB,oHAAoH,CAAC;AACvH,MAAM,wBAAwB,GAC5B,wKAAwK,CAAC;AAC3K,MAAM,mBAAmB,GACvB,wFAAwF,CAAC;AAC3F,MAAM,uBAAuB,GAC3B,2IAA2I,CAAC;AAC9I,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AAqBvD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,WAAmB;IAC5D,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IAClF,IAAI,CAAC,CAAC,MAAM,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QACxD,OAAO;YACL,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,qDAAqD;SAC/D,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG;QACf,GAAG,CAAC,MAAM,kBAAkB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACvD,GAAG,CAAC,MAAM,cAAc,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACnD,GAAG,CAAC,MAAM,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;KAC7D,CAAC;IACF,OAAO,uBAAuB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAmB,EACnB,QAAgB;IAEhB,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC9D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,qDAAqD;SAC/D,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,sBAAsB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,cAAc,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,uBAAuB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,WAAgC;IAEhC,MAAM,GAAG,GAAG,WAAW,IAAI,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjG,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC5D,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAC9C,CAAC;IACF,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAE9C,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnC,IAAI,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC9F,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,wBAAwB,CAAC,WAAW,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/E,IAAI,QAAQ,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;YACpC,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,WAAgC;IAEhC,MAAM,GAAG,GAAG,WAAW,IAAI,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjG,IAAI,CAAC,CAAC,MAAM,wBAAwB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;QACxD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,iBAAiB,CACvC,sBAAsB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAC3E,CAAC;IACF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3D,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,eAAe,GAAG,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtG,MAAM,oBAAoB,GACxB,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,mCAAmC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrG,MAAM,qBAAqB,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE5D,IAAI,eAAe,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC7C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,oBAAoB,IAAI,qBAAqB,EAAE,CAAC;QAClD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC,eAAe,IAAI,CAAC,oBAAoB,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACzE,OAAO;YACL;gBACE,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC;gBACtC,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,0DAA0D,CAAC;gBACxF,IAAI,EAAE,oBAAoB;gBAC1B,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,8BAA8B;gBACxC,UAAU,EAAE,MAAM;gBAClB,WAAW,EACT,4LAA4L;aAC/L;SACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAmB,EACnB,WAAgC;IAEhC,MAAM,GAAG,GAAG,WAAW,IAAI,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjG,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAE9C,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC5D,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CACnD,CAAC;IACF,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,CAAC,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,GAAG,gCAAgC,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC5D,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAC9C,CAAC;IACF,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnC,IAAI,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC9F,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,4BAA4B,CAAC,WAAW,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,QAAQ,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;YACpC,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,uBAAuB,CACpC,WAAmB,EACnB,QAAgB,EAChB,WAAwB;IAExB,IAAI,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,CAAC,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAE1D,IAAI,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ,EAAE,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,GAAG,gCAAgC,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAClD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,wBAAwB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QACvF,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,4BAA4B,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAC7F,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,WAAmB,EACnB,QAAgB,EAChB,WAAwB;IAExB,MAAM,QAAQ,GAAG,CAAC,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1D,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC3F,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAqF;QAC9F,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;KAChD,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE5C,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,oBAAoB,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;YAC5E,MAAM,WAAW,GAAG,wBAAwB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACjE,IAAI,WAAW,IAAI,eAAe,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBACpD,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,WAAW,EAAE,CAAC;gBAC3C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClB,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;oBACrC,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,uBAAuB;oBAC7B,QAAQ,EAAE,OAAO;oBACjB,QAAQ,EAAE,0BAA0B;oBACpC,UAAU,EAAE,WAAW;oBACvB,WAAW,EAAE,QAAQ,WAAW,sHAAsH;iBACvJ,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjD,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;gBAClD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClB,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;oBACrC,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,uBAAuB;oBAC7B,QAAQ,EAAE,OAAO;oBACjB,QAAQ,EAAE,wBAAwB;oBAClC,UAAU,EAAE,QAAQ,CAAC,SAAS;oBAC9B,WAAW,EAAE,QAAQ,QAAQ,CAAC,SAAS,6FAA6F;iBACrI,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,IAAI,OAAO,CAAC,KAAK,IAAI,mBAAmB,EAAE,CAAC;gBACzC,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;YACnF,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACvC,SAAS;YACX,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAEtB,MAAM,gBAAgB,GAAG,CAAC,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YAClE,MAAM,gBAAgB,GAAG,MAAM,mBAAmB,CAChD,WAAW,EACX,QAAQ,EACR,WAAW,EACX,gBAAgB,CACjB,CAAC;YACF,IAAI,gBAAgB,EAAE,CAAC;gBACrB,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;gBAClD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClB,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;oBACrC,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,oBAAoB;oBAC1B,QAAQ,EAAE,OAAO;oBACjB,QAAQ,EAAE,yBAAyB;oBACnC,UAAU,EAAE,QAAQ,CAAC,SAAS;oBAC9B,WAAW,EACT,4GAA4G;iBAC/G,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,KAAK,CAAC,IAAI,CAAC;gBACT,QAAQ,EAAE,QAAQ;gBAClB,QAAQ,EAAE,gBAAgB;gBAC1B,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC;gBACxB,UAAU,EAAE,UAAU;aACvB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,4BAA4B,CACzC,WAAmB,EACnB,QAAgB,EAChB,WAAwB;IAExB,MAAM,QAAQ,GAAG,CAAC,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1D,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC3F,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,MAAM,UAAU,GAAG,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAExC,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAChD,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,mBAAmB,CAAC,SAAS,GAAG,CAAC,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACvD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;YACxC,IAAI,CAAC,UAAU,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;gBACtD,SAAS;YACX,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;gBACrC,IAAI,EAAE,SAAS,GAAG,CAAC;gBACnB,IAAI,EAAE,oBAAoB;gBAC1B,QAAQ,EAAE,OAAO;gBACjB,QAAQ,EAAE,oBAAoB;gBAC9B,UAAU;gBACV,WAAW,EACT,6IAA6I;aAChJ,CAAC,CAAC;QACL,CAAC;QAED,uBAAuB,CAAC,SAAS,GAAG,CAAC,CAAC;QACtC,IAAI,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;gBACrC,IAAI,EAAE,SAAS,GAAG,CAAC;gBACnB,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,2BAA2B;gBACrC,UAAU,EAAE,WAAW;gBACvB,WAAW,EACT,gIAAgI;aACnI,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,gCAAgC,CACvC,WAAmB,EACnB,QAAgB,EAChB,QAAgB;IAEhB,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,4BAA4B,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEpE,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAChD,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,IACE,4BAA4B,CAAC,KAAK,CAAC;gBACnC,kBAAkB,CAAC,KAAK,CAAC;gBACzB,6BAA6B,CAAC,KAAK,CAAC,EACpC,CAAC;gBACD,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;YACnD,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;oBACrC,IAAI,EAAE,SAAS,GAAG,CAAC;oBACnB,IAAI,EAAE,kCAAkC;oBACxC,QAAQ,EAAE,6BAA6B,CAAC,QAAQ,CAAC;oBACjD,QAAQ;oBACR,UAAU,EAAE,QAAQ;oBACpB,WAAW,EACT,wHAAwH;iBAC3H,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAC3B,mKAAmK,CACpK,CAAC;QACF,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,SAAS;QACX,CAAC;QACD,IACE,4BAA4B,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC3C,kBAAkB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACjC,6BAA6B,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAC5C,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACvF,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;gBACrC,IAAI,EAAE,SAAS,GAAG,CAAC;gBACnB,IAAI,EAAE,kCAAkC;gBACxC,QAAQ,EAAE,OAAO;gBACjB,QAAQ,EAAE,oBAAoB;gBAC9B,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;gBACtC,WAAW,EACT,uJAAuJ;aAC1J,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,WAAmB,EACnB,QAAgB,EAChB,WAAwB,EACxB,QAAiB;IAEjB,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAEnE,IAAI,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,sBAAsB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,2CAA2C,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACnE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,wBAAwB,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,IAAI,CAAC,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,OAAO,qBAAqB,CAAC,YAAY,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,oBAAoB,CAAC,WAAmB,EAAE,QAAgB;IACjE,OAAO,mBAAmB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,kBAAkB,CAAC,WAAmB,EAAE,QAAgB;IAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC5C,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,KAAK,MAAM,IAAI,IAAI,4BAA4B,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACzE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QACD,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,QAAgB;IAC5C,MAAM,UAAU,GAAG,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,OAAO,GAA+C,EAAE,CAAC;IAC/D,wBAAwB,CAAC,SAAS,GAAG,CAAC,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;QAClE,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACnD,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC;YACX,SAAS;YACT,IAAI,EAAE,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;SACjD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,QAAgB,EAAE,SAAiB;IACtE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG;QACjB,IAAI;QACJ,GAAG,IAAI,KAAK;QACZ,GAAG,IAAI,MAAM;QACb,GAAG,IAAI,KAAK;QACZ,GAAG,IAAI,MAAM;QACb,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;KAC7B,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAiB;IACjD,IACE,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QACzB,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QACzB,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC;QAC7B,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EACzB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACnE,CAAC;IACD,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACzC,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,WAAmB,EACnB,WAA+B;IAE/B,IAAI,WAAW,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QACxF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,iBAAiB,CACxC,CAAC,GAAG,qBAAqB,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAC/E,CAAC;IACF,OAAO,UAAU,KAAK,IAAI,CAAC;AAC7B,CAAC;AAED,SAAS,iBAAiB,CAAC,WAAwB;IACjD,MAAM,IAAI,GAAG;QACX,GAAG,WAAW,CAAC,YAAY;QAC3B,GAAG,WAAW,CAAC,eAAe;KAC/B,CAAC;IACF,OAAO,MAAM,IAAI,IAAI,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,WAAmB,EACnB,WAAwB;IAExB,MAAM,SAAS,GAAG,MAAM,2BAA2B,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC9E,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,OAAO,IAAI,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC5D,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAC9C,CAAC;IACF,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,QAAQ,IAAI,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,6BAA6B,CAAC,KAAa;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACzD,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,4BAA4B,CAAC,QAAgB;IACpD,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE,CACnE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAC7B,CAAC;IACF,OAAO,YAAY,CAAC,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB,EAAE,OAAe;IACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACxC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB,EAAE,KAAa;IACnD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AACxD,CAAC;AAED,SAAS,uBAAuB,CAC9B,QAAkC,EAClC,WAAoB;IAEpB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;YACrC,OAAO,EAAE,WAAW;gBAClB,CAAC,CAAC,gGAAgG;gBAClG,CAAC,CAAC,qDAAqD;SAC1D,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC1E,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;QACnC,OAAO,EAAE,QAAQ;YACf,CAAC,CAAC,0EAA0E;YAC5E,CAAC,CAAC,uCAAuC;QAC3C,OAAO,EAAE;YACP,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;YACzC,SAAS,EAAE,QAAQ,CAAC,MAAM,GAAG,YAAY;SAC1C;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -4,6 +4,8 @@ export declare function runScriptChecks(args: {
|
|
|
4
4
|
projectPath: string;
|
|
5
5
|
mode: DoctorMode;
|
|
6
6
|
fix: boolean;
|
|
7
|
+
runScripts: boolean;
|
|
7
8
|
timeoutMs: number;
|
|
9
|
+
reactDoctorRunner?: import('../types.js').ReactDoctorRunner;
|
|
8
10
|
}): Promise<DoctorCheckResult[]>;
|
|
9
11
|
//# sourceMappingURL=script-checks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"script-checks.d.ts","sourceRoot":"","sources":["../../src/checks/script-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"script-checks.d.ts","sourceRoot":"","sources":["../../src/checks/script-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAa9E,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,aAAa,EAAE,iBAAiB,CAAC;CAC7D,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA4B/B"}
|