@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,360 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { appRelativePath, findExpoRouterAppDirs, isExpoRouterApiRouteSourceFile, isExpoRouterLayoutFile, isExpoRouterSpecialFile, isRootLayoutPath, isRouteGroupDirName, isTestLikeFile, routeGroupSegments, } from '../expo-router.js';
|
|
3
|
+
import { findFiles, pathExists, readOptionalText, relative, SOURCE_EXTENSIONS, stripJsComments, } from '../utils.js';
|
|
4
|
+
const MAX_FINDINGS = 50;
|
|
5
|
+
const CONVENTIONAL_GROUPS = new Set(['auth', 'tabs', 'drawer', 'modal']);
|
|
6
|
+
const MAX_GROUP_DEPTH = 2;
|
|
7
|
+
const MIXED_CONCERN_LINE_THRESHOLD = 180;
|
|
8
|
+
const API_THIN_WRAPPER_LINE_THRESHOLD = 150;
|
|
9
|
+
const API_NOT_THIN_LINE_THRESHOLD = 250;
|
|
10
|
+
const ROOT_LAYOUT_HEAVY_LINES = 300;
|
|
11
|
+
const ROOT_LAYOUT_MIXED_LINES = 180;
|
|
12
|
+
const AUTH_SIGNAL_RE = /\b(useAuth|useAuthStore|useAuthUiStore|getSession|getSupabaseSession|getUser|isLoggedIn|isAuthenticated|Redirect|Stack\.Protected|Protected)\b/;
|
|
13
|
+
const IMPORT_FROM_RE = /\bfrom\s+['"]([^'"]+)['"]/g;
|
|
14
|
+
const DATA_LAYER_IMPORT_RE = /\b(from|require\()\s*['"][^'"]*(supabase|drizzle|postgres)/;
|
|
15
|
+
const QUERY_RE = /\b(useQuery|useMutation)\b/;
|
|
16
|
+
const NAVIGATOR_RE = /\b(Stack|Tabs|Drawer|Slot)\b/;
|
|
17
|
+
const INLINE_DB_RE = /\b(from\s+['"]drizzle-orm['"]|supabase\.from\s*\(|sql\s*`)/;
|
|
18
|
+
const DYNAMIC_ROUTER_CONCAT_RE = /\brouter\.(push|replace|navigate)\s*\(\s*(['"])\/\2\s*\+/;
|
|
19
|
+
const DYNAMIC_HREF_CONCAT_RE = /\bhref=\{\s*(['"])\/\1\s*\+/;
|
|
20
|
+
const DYNAMIC_ROUTER_TEMPLATE_RE = /\brouter\.(push|replace|navigate)\s*\(\s*`[^`]*\$\{/;
|
|
21
|
+
const DYNAMIC_HREF_TEMPLATE_RE = /\bhref=\{\s*`[^`]*\$\{/;
|
|
22
|
+
const ROUTER_PATH_JOIN_RE = /\brouter\.(push|replace|navigate)\s*\(\s*path\.join\b/;
|
|
23
|
+
export async function checkRouterSafety(projectPath) {
|
|
24
|
+
const appDirs = await findExpoRouterAppDirs(projectPath);
|
|
25
|
+
if (appDirs.length === 0) {
|
|
26
|
+
return {
|
|
27
|
+
name: 'router safety',
|
|
28
|
+
status: 'skip',
|
|
29
|
+
message: 'No Expo Router app directory found.',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const findings = [...(await checkRouteGroups(projectPath)), ...(await checkLayouts(projectPath))];
|
|
33
|
+
const routeFiles = await collectRouteSourceFiles(projectPath, appDirs);
|
|
34
|
+
for (const filePath of routeFiles) {
|
|
35
|
+
if (findings.length >= MAX_FINDINGS) {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
const contents = (await readOptionalText(filePath)) ?? '';
|
|
39
|
+
findings.push(...checkNavigationPatterns(projectPath, filePath, contents));
|
|
40
|
+
findings.push(...checkMixedConcerns(projectPath, filePath, contents));
|
|
41
|
+
}
|
|
42
|
+
return toRouterResult(findings);
|
|
43
|
+
}
|
|
44
|
+
export async function scanFileRouterSafety(projectPath, filePath) {
|
|
45
|
+
const appDirs = await findExpoRouterAppDirs(projectPath);
|
|
46
|
+
if (appDirs.length === 0) {
|
|
47
|
+
return {
|
|
48
|
+
name: 'router safety',
|
|
49
|
+
status: 'skip',
|
|
50
|
+
message: 'No Expo Router app directory found.',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const shortPath = relative(projectPath, filePath);
|
|
54
|
+
const inAppRoot = shortPath.startsWith('app/') || shortPath.startsWith('src/app/');
|
|
55
|
+
if (!inAppRoot || !SOURCE_EXTENSIONS.has(path.extname(filePath))) {
|
|
56
|
+
return {
|
|
57
|
+
name: 'router safety',
|
|
58
|
+
status: 'skip',
|
|
59
|
+
message: 'File is not an Expo Router route file.',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const contents = (await readOptionalText(filePath)) ?? '';
|
|
63
|
+
const findings = [
|
|
64
|
+
...checkNavigationPatterns(projectPath, filePath, contents),
|
|
65
|
+
...checkMixedConcerns(projectPath, filePath, contents),
|
|
66
|
+
];
|
|
67
|
+
if (isRootLayoutPath(shortPath)) {
|
|
68
|
+
findings.push(...findOverloadedRootLayout(projectPath, filePath, contents));
|
|
69
|
+
}
|
|
70
|
+
const appDir = appDirs.find((dir) => filePath.startsWith(dir));
|
|
71
|
+
if (appDir) {
|
|
72
|
+
const appRel = appRelativePath(appDir, filePath);
|
|
73
|
+
const parentGroup = parentGroupPath(appRel);
|
|
74
|
+
if (parentGroup) {
|
|
75
|
+
const groupFindings = await checkRouteGroups(projectPath);
|
|
76
|
+
findings.push(...groupFindings.filter((finding) => finding.file.endsWith(parentGroup) || finding.file.includes(`${parentGroup}/`)));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return toRouterResult(findings, true);
|
|
80
|
+
}
|
|
81
|
+
export async function checkRouteGroups(projectPath) {
|
|
82
|
+
const appDirs = await findExpoRouterAppDirs(projectPath);
|
|
83
|
+
const findings = [];
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
for (const appDir of appDirs) {
|
|
86
|
+
const files = await collectRouteSourceFiles(projectPath, [appDir]);
|
|
87
|
+
const groups = collectGroupInfo(appDir, files);
|
|
88
|
+
const appDirKey = relative(projectPath, appDir);
|
|
89
|
+
for (const group of groups.values()) {
|
|
90
|
+
const key = `${appDirKey}:${group.relPath}:${group.hasLayout}:${group.depth}`;
|
|
91
|
+
if (seen.has(key)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
seen.add(key);
|
|
95
|
+
if (group.depth > MAX_GROUP_DEPTH) {
|
|
96
|
+
findings.push({
|
|
97
|
+
file: relative(projectPath, path.join(appDir, group.relPath)),
|
|
98
|
+
kind: 'nested-groups',
|
|
99
|
+
message: `${relative(projectPath, path.join(appDir, group.relPath))}: nested route groups are ${group.depth} deep; flatten groups beyond ${MAX_GROUP_DEPTH} levels.`,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (!group.hasLayout) {
|
|
103
|
+
const conventional = CONVENTIONAL_GROUPS.has(group.name);
|
|
104
|
+
findings.push({
|
|
105
|
+
file: relative(projectPath, path.join(appDir, group.relPath)),
|
|
106
|
+
kind: conventional ? 'missing-conventional-layout' : 'group-without-layout',
|
|
107
|
+
message: conventional
|
|
108
|
+
? `${relative(projectPath, path.join(appDir, group.relPath))}: (${group.name}) group has no _layout file.`
|
|
109
|
+
: `${relative(projectPath, path.join(appDir, group.relPath))}: route group has no _layout file; confirm the group has a purpose.`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return findings;
|
|
115
|
+
}
|
|
116
|
+
export async function checkLayouts(projectPath) {
|
|
117
|
+
const appDirs = await findExpoRouterAppDirs(projectPath);
|
|
118
|
+
const findings = [];
|
|
119
|
+
for (const appDir of appDirs) {
|
|
120
|
+
const files = await collectRouteSourceFiles(projectPath, [appDir]);
|
|
121
|
+
const rootLayoutFiles = files.filter((filePath) => isRootLayoutPath(relative(projectPath, filePath)));
|
|
122
|
+
for (const layoutPath of rootLayoutFiles) {
|
|
123
|
+
const contents = (await readOptionalText(layoutPath)) ?? '';
|
|
124
|
+
findings.push(...findOverloadedRootLayout(projectPath, layoutPath, contents));
|
|
125
|
+
}
|
|
126
|
+
const hasAuthShapedRoutes = files.some((filePath) => isAuthShapedRoute(appRelativePath(appDir, filePath)));
|
|
127
|
+
if (hasAuthShapedRoutes) {
|
|
128
|
+
const layoutContents = [];
|
|
129
|
+
for (const filePath of files) {
|
|
130
|
+
const appRel = appRelativePath(appDir, filePath);
|
|
131
|
+
if (isExpoRouterLayoutFile(filePath) &&
|
|
132
|
+
(isRootLayoutPath(relative(projectPath, filePath)) || isAuthGroupPath(appRel))) {
|
|
133
|
+
layoutContents.push(...(await collectLayoutAuthSources(projectPath, filePath)));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const scanned = layoutContents.join('\n');
|
|
137
|
+
if (!AUTH_SIGNAL_RE.test(scanned)) {
|
|
138
|
+
findings.push({
|
|
139
|
+
file: relative(projectPath, appDir),
|
|
140
|
+
kind: 'missing-auth-layout',
|
|
141
|
+
message: `${relative(projectPath, appDir)}: auth-shaped routes exist without an auth-aware layout (session check, Redirect, or Protected).`,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return findings;
|
|
147
|
+
}
|
|
148
|
+
export function checkNavigationPatterns(projectPath, filePath, contents) {
|
|
149
|
+
if (isTestLikeFile(filePath) || path.basename(filePath).includes('+api')) {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
const scanned = stripJsComments(contents);
|
|
153
|
+
const shortPath = relative(projectPath, filePath);
|
|
154
|
+
const findings = [];
|
|
155
|
+
if (DYNAMIC_ROUTER_CONCAT_RE.test(scanned) ||
|
|
156
|
+
DYNAMIC_HREF_CONCAT_RE.test(scanned) ||
|
|
157
|
+
DYNAMIC_ROUTER_TEMPLATE_RE.test(scanned) ||
|
|
158
|
+
DYNAMIC_HREF_TEMPLATE_RE.test(scanned) ||
|
|
159
|
+
ROUTER_PATH_JOIN_RE.test(scanned)) {
|
|
160
|
+
findings.push({
|
|
161
|
+
file: shortPath,
|
|
162
|
+
kind: 'dynamic-navigation',
|
|
163
|
+
message: `${shortPath}: builds a route path by concatenation or interpolation; use a typed pathname object instead of string assembly.`,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return findings;
|
|
167
|
+
}
|
|
168
|
+
export function checkMixedConcerns(projectPath, filePath, contents) {
|
|
169
|
+
if (isTestLikeFile(filePath)) {
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
const shortPath = relative(projectPath, filePath);
|
|
173
|
+
const scanned = stripJsComments(contents);
|
|
174
|
+
const lineCount = contents.split(/\r?\n/).length;
|
|
175
|
+
const findings = [];
|
|
176
|
+
if (isExpoRouterApiRouteSourceFile(filePath)) {
|
|
177
|
+
const hasInlineDb = INLINE_DB_RE.test(scanned);
|
|
178
|
+
if (lineCount > API_NOT_THIN_LINE_THRESHOLD ||
|
|
179
|
+
(lineCount > API_THIN_WRAPPER_LINE_THRESHOLD && hasInlineDb)) {
|
|
180
|
+
findings.push({
|
|
181
|
+
file: shortPath,
|
|
182
|
+
kind: 'api-business-logic',
|
|
183
|
+
message: `${shortPath}: ${lineCount} lines; keep API routes as thin wrappers around services instead of inlining business logic.`,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return findings;
|
|
187
|
+
}
|
|
188
|
+
if (isExpoRouterSpecialFile(filePath) || isExpoRouterLayoutFile(filePath)) {
|
|
189
|
+
return findings;
|
|
190
|
+
}
|
|
191
|
+
const hasAuth = AUTH_SIGNAL_RE.test(scanned);
|
|
192
|
+
const hasData = DATA_LAYER_IMPORT_RE.test(scanned) || QUERY_RE.test(scanned);
|
|
193
|
+
const helperCount = countHelperFunctions(scanned);
|
|
194
|
+
const concernCount = [hasAuth, hasData, helperCount >= 3].filter(Boolean).length;
|
|
195
|
+
if (lineCount > MIXED_CONCERN_LINE_THRESHOLD && concernCount >= 2) {
|
|
196
|
+
findings.push({
|
|
197
|
+
file: shortPath,
|
|
198
|
+
kind: 'mixed-concerns',
|
|
199
|
+
message: `${shortPath}: mixes auth, data, and helper logic in a ${lineCount}-line route file; split into features/services.`,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return findings;
|
|
203
|
+
}
|
|
204
|
+
function findOverloadedRootLayout(projectPath, filePath, contents) {
|
|
205
|
+
const shortPath = relative(projectPath, filePath);
|
|
206
|
+
const scanned = stripJsComments(contents);
|
|
207
|
+
const lineCount = contents.split(/\r?\n/).length;
|
|
208
|
+
const hasData = DATA_LAYER_IMPORT_RE.test(scanned) || QUERY_RE.test(scanned);
|
|
209
|
+
const hasNavigator = NAVIGATOR_RE.test(scanned);
|
|
210
|
+
if (lineCount > ROOT_LAYOUT_HEAVY_LINES ||
|
|
211
|
+
(lineCount > ROOT_LAYOUT_MIXED_LINES && hasData && hasNavigator)) {
|
|
212
|
+
return [
|
|
213
|
+
{
|
|
214
|
+
file: shortPath,
|
|
215
|
+
kind: 'overloaded-root-layout',
|
|
216
|
+
message: `${shortPath}: ${lineCount} lines; split providers, data loading, and navigation out of the root layout.`,
|
|
217
|
+
},
|
|
218
|
+
];
|
|
219
|
+
}
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
function toRouterResult(findings, fileScan = false) {
|
|
223
|
+
if (findings.length > 0) {
|
|
224
|
+
return {
|
|
225
|
+
name: 'router safety',
|
|
226
|
+
status: 'warn',
|
|
227
|
+
message: fileScan
|
|
228
|
+
? 'File has Expo Router safety warnings.'
|
|
229
|
+
: 'Expo Router groups, layouts, or navigation have safety warnings.',
|
|
230
|
+
details: {
|
|
231
|
+
findings: findings.slice(0, MAX_FINDINGS),
|
|
232
|
+
truncated: findings.length > MAX_FINDINGS,
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
name: 'router safety',
|
|
238
|
+
status: 'pass',
|
|
239
|
+
message: fileScan
|
|
240
|
+
? 'File passed the router safety scan.'
|
|
241
|
+
: 'Route groups, layouts, and navigation passed the safety scan.',
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async function collectRouteSourceFiles(projectPath, appDirs) {
|
|
245
|
+
const files = [];
|
|
246
|
+
for (const appDir of appDirs) {
|
|
247
|
+
if (!(await pathExists(appDir))) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
files.push(...(await findFiles(appDir, (filePath) => {
|
|
251
|
+
return SOURCE_EXTENSIONS.has(path.extname(filePath)) && !isTestLikeFile(filePath);
|
|
252
|
+
})));
|
|
253
|
+
}
|
|
254
|
+
return files;
|
|
255
|
+
}
|
|
256
|
+
function collectGroupInfo(appDir, files) {
|
|
257
|
+
const groups = new Map();
|
|
258
|
+
for (const filePath of files) {
|
|
259
|
+
const appRel = appRelativePath(appDir, filePath);
|
|
260
|
+
const segments = appRel.split('/');
|
|
261
|
+
const prefixes = [];
|
|
262
|
+
for (const segment of segments.slice(0, -1)) {
|
|
263
|
+
prefixes.push(segment);
|
|
264
|
+
if (!isRouteGroupDirName(segment)) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const relPath = prefixes.join('/');
|
|
268
|
+
const existing = groups.get(relPath) ?? {
|
|
269
|
+
relPath,
|
|
270
|
+
name: segment.slice(1, -1),
|
|
271
|
+
depth: routeGroupSegments(relPath).length,
|
|
272
|
+
hasLayout: false,
|
|
273
|
+
};
|
|
274
|
+
if (isLayoutInGroup(appRel, relPath)) {
|
|
275
|
+
existing.hasLayout = true;
|
|
276
|
+
}
|
|
277
|
+
groups.set(relPath, existing);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return groups;
|
|
281
|
+
}
|
|
282
|
+
function isLayoutInGroup(appRel, groupRel) {
|
|
283
|
+
const expectedPrefix = `${groupRel}/`;
|
|
284
|
+
if (!appRel.startsWith(expectedPrefix)) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
const rest = appRel.slice(expectedPrefix.length);
|
|
288
|
+
return isExpoRouterLayoutFile(rest) && !rest.includes('/');
|
|
289
|
+
}
|
|
290
|
+
function parentGroupPath(appRel) {
|
|
291
|
+
const dir = appRel.split('/').slice(0, -1);
|
|
292
|
+
for (let index = dir.length - 1; index >= 0; index -= 1) {
|
|
293
|
+
const segment = dir[index];
|
|
294
|
+
if (segment && isRouteGroupDirName(segment)) {
|
|
295
|
+
return dir.slice(0, index + 1).join('/');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
function isAuthShapedRoute(appRel) {
|
|
301
|
+
return isAuthGroupPath(appRel) || /(^|\/)(sign-in|sign-up|login)\.(tsx|ts|jsx|js)$/.test(appRel);
|
|
302
|
+
}
|
|
303
|
+
function isAuthGroupPath(appRel) {
|
|
304
|
+
return /(^|\/)\(auth\)(\/|$)/.test(appRel) || /(^|\/)auth(\/|$)/.test(appRel);
|
|
305
|
+
}
|
|
306
|
+
async function collectLayoutAuthSources(projectPath, layoutPath) {
|
|
307
|
+
const contents = (await readOptionalText(layoutPath)) ?? '';
|
|
308
|
+
const sources = [contents];
|
|
309
|
+
if (contents.split(/\r?\n/).length > 80) {
|
|
310
|
+
return sources;
|
|
311
|
+
}
|
|
312
|
+
for (const match of contents.matchAll(IMPORT_FROM_RE)) {
|
|
313
|
+
const spec = match[1];
|
|
314
|
+
if (!spec) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const resolved = await resolveLayoutImport(projectPath, layoutPath, spec);
|
|
318
|
+
if (!resolved) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const imported = await readOptionalText(resolved);
|
|
322
|
+
if (imported) {
|
|
323
|
+
sources.push(imported);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return sources;
|
|
327
|
+
}
|
|
328
|
+
async function resolveLayoutImport(projectPath, fromFile, spec) {
|
|
329
|
+
let base;
|
|
330
|
+
if (spec.startsWith('@/') || spec.startsWith('~/')) {
|
|
331
|
+
base = path.join(projectPath, 'src', spec.slice(2));
|
|
332
|
+
}
|
|
333
|
+
else if (spec.startsWith('.')) {
|
|
334
|
+
base = path.resolve(path.dirname(fromFile), spec);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
const candidates = [
|
|
340
|
+
base,
|
|
341
|
+
`${base}.tsx`,
|
|
342
|
+
`${base}.ts`,
|
|
343
|
+
`${base}.jsx`,
|
|
344
|
+
`${base}.js`,
|
|
345
|
+
path.join(base, 'index.tsx'),
|
|
346
|
+
path.join(base, 'index.ts'),
|
|
347
|
+
];
|
|
348
|
+
for (const candidate of candidates) {
|
|
349
|
+
if (await pathExists(candidate)) {
|
|
350
|
+
return candidate;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
function countHelperFunctions(contents) {
|
|
356
|
+
const functionMatches = contents.match(/\bfunction\s+[A-Za-z_][\w]*/g) ?? [];
|
|
357
|
+
const arrowMatches = contents.match(/\bconst\s+[A-Za-z_][\w]*\s*=\s*(async\s*)?\(/g) ?? [];
|
|
358
|
+
return functionMatches.length + arrowMatches.length;
|
|
359
|
+
}
|
|
360
|
+
//# sourceMappingURL=router-safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-safety.js","sourceRoot":"","sources":["../../src/checks/router-safety.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DoctorCheckResult, PackageJson } from '../types.js';
|
|
2
|
+
export type RuntimeSecurityFindingKind = 'server-package-import' | 'server-file-import' | 'server-builtin-import' | 'metro-node-runtime' | 'expo-config-hardcoded-credential' | 'client-private-env' | 'localhost-fetch';
|
|
3
|
+
export interface RuntimeSecurityFinding {
|
|
4
|
+
file: string;
|
|
5
|
+
line: number;
|
|
6
|
+
kind: RuntimeSecurityFindingKind;
|
|
7
|
+
severity: 'error' | 'warn';
|
|
8
|
+
detector: string;
|
|
9
|
+
remediation: string;
|
|
10
|
+
identifier?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function checkRuntimeSecurity(projectPath: string): Promise<DoctorCheckResult>;
|
|
13
|
+
export declare function scanFileRuntimeSecurity(projectPath: string, filePath: string): Promise<DoctorCheckResult>;
|
|
14
|
+
export declare function checkServerImports(projectPath: string, packageJson?: PackageJson | null): Promise<RuntimeSecurityFinding[]>;
|
|
15
|
+
export declare function checkSSRSafety(projectPath: string, packageJson?: PackageJson | null): Promise<RuntimeSecurityFinding[]>;
|
|
16
|
+
export declare function checkCredentialExposure(projectPath: string, packageJson?: PackageJson | null): Promise<RuntimeSecurityFinding[]>;
|
|
17
|
+
//# sourceMappingURL=runtime-security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-security.d.ts","sourceRoot":"","sources":["../../src/checks/runtime-security.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkGlE,MAAM,MAAM,0BAA0B,GAClC,uBAAuB,GACvB,oBAAoB,GACpB,uBAAuB,GACvB,oBAAoB,GACpB,kCAAkC,GAClC,oBAAoB,GACpB,iBAAiB,CAAC;AAEtB,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,0BAA0B,CAAC;IACjC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgB1F;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,iBAAiB,CAAC,CAiB5B;AAED,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,GAC/B,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAkBnC;AAED,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,GAC/B,OAAO,CAAC,sBAAsB,EAAE,CAAC,CA+CnC;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,GAC/B,OAAO,CAAC,sBAAsB,EAAE,CAAC,CA4BnC"}
|