@arch-atlas/core 0.1.0

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.
Files changed (41) hide show
  1. package/dist/analyzers/assets.d.ts +4 -0
  2. package/dist/analyzers/assets.d.ts.map +1 -0
  3. package/dist/analyzers/assets.js +45 -0
  4. package/dist/analyzers/assets.js.map +1 -0
  5. package/dist/analyzers/dead-code.d.ts +7 -0
  6. package/dist/analyzers/dead-code.d.ts.map +1 -0
  7. package/dist/analyzers/dead-code.js +202 -0
  8. package/dist/analyzers/dead-code.js.map +1 -0
  9. package/dist/analyzers/framework-routes.d.ts +16 -0
  10. package/dist/analyzers/framework-routes.d.ts.map +1 -0
  11. package/dist/analyzers/framework-routes.js +110 -0
  12. package/dist/analyzers/framework-routes.js.map +1 -0
  13. package/dist/analyzers/navigation.d.ts +4 -0
  14. package/dist/analyzers/navigation.d.ts.map +1 -0
  15. package/dist/analyzers/navigation.js +109 -0
  16. package/dist/analyzers/navigation.js.map +1 -0
  17. package/dist/discovery.d.ts +8 -0
  18. package/dist/discovery.d.ts.map +1 -0
  19. package/dist/discovery.js +240 -0
  20. package/dist/discovery.js.map +1 -0
  21. package/dist/graph.d.ts +5 -0
  22. package/dist/graph.d.ts.map +1 -0
  23. package/dist/graph.js +191 -0
  24. package/dist/graph.js.map +1 -0
  25. package/dist/index.d.ts +10 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +10 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/parser.d.ts +16 -0
  30. package/dist/parser.d.ts.map +1 -0
  31. package/dist/parser.js +291 -0
  32. package/dist/parser.js.map +1 -0
  33. package/dist/scanner.d.ts +40 -0
  34. package/dist/scanner.d.ts.map +1 -0
  35. package/dist/scanner.js +115 -0
  36. package/dist/scanner.js.map +1 -0
  37. package/dist/types.d.ts +159 -0
  38. package/dist/types.d.ts.map +1 -0
  39. package/dist/types.js +2 -0
  40. package/dist/types.js.map +1 -0
  41. package/package.json +32 -0
@@ -0,0 +1,4 @@
1
+ import type { AssetInfo, AssetType, FileAnalysis } from '../types.js';
2
+ export declare function analyzeAssets(assetPaths: string[], files: FileAnalysis[]): AssetInfo[];
3
+ export declare function getAssetType(filePath: string): AssetType;
4
+ //# sourceMappingURL=assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/analyzers/assets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAYtE,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAmCtF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAGxD"}
@@ -0,0 +1,45 @@
1
+ import path from 'node:path';
2
+ const ASSET_EXTENSIONS = {
3
+ '.png': 'image', '.jpg': 'image', '.jpeg': 'image', '.gif': 'image', '.webp': 'image',
4
+ '.svg': 'svg',
5
+ '.ttf': 'font', '.otf': 'font', '.woff': 'font', '.woff2': 'font',
6
+ '.mp4': 'video', '.mov': 'video', '.webm': 'video',
7
+ '.mp3': 'audio', '.wav': 'audio', '.m4a': 'audio',
8
+ '.lottie': 'lottie',
9
+ };
10
+ export function analyzeAssets(assetPaths, files) {
11
+ const assetMap = new Map();
12
+ for (const assetPath of assetPaths) {
13
+ const ext = path.extname(assetPath).toLowerCase();
14
+ const type = ASSET_EXTENSIONS[ext] ?? (ext === '.json' && assetPath.includes('lottie') ? 'lottie' : 'other');
15
+ assetMap.set(assetPath, {
16
+ id: `asset:${assetPath}`,
17
+ path: assetPath,
18
+ type,
19
+ usedBy: [],
20
+ });
21
+ }
22
+ // Find asset references in imports
23
+ for (const file of files) {
24
+ for (const imp of file.imports) {
25
+ if (imp.resolvedPath && assetMap.has(imp.resolvedPath)) {
26
+ assetMap.get(imp.resolvedPath).usedBy.push(file.id);
27
+ }
28
+ // Check for asset path strings in source
29
+ const basename = path.basename(imp.source);
30
+ for (const [assetPath, asset] of assetMap) {
31
+ if (assetPath.includes(basename) || imp.source.includes(path.basename(assetPath, path.extname(assetPath)))) {
32
+ if (!asset.usedBy.includes(file.id)) {
33
+ asset.usedBy.push(file.id);
34
+ }
35
+ }
36
+ }
37
+ }
38
+ }
39
+ return [...assetMap.values()];
40
+ }
41
+ export function getAssetType(filePath) {
42
+ const ext = path.extname(filePath).toLowerCase();
43
+ return ASSET_EXTENSIONS[ext] ?? 'other';
44
+ }
45
+ //# sourceMappingURL=assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../src/analyzers/assets.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,gBAAgB,GAA8B;IAClD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACrF,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IACjE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IAClD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO;IACjD,SAAS,EAAE,QAAQ;CACpB,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,UAAoB,EAAE,KAAqB;IACvE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE9C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAE7G,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE;YACtB,EAAE,EAAE,SAAS,SAAS,EAAE;YACxB,IAAI,EAAE,SAAS;YACf,IAAI;YACJ,MAAM,EAAE,EAAE;SACX,CAAC,CAAC;IACL,CAAC;IAED,mCAAmC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;gBACvD,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACvD,CAAC;YAED,yCAAyC;YACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC3C,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC;gBAC1C,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC3G,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;wBACpC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { CircularDependency, DeadCodeItem, FileAnalysis, GraphEdge, GraphNode, PackageUsage, ProjectType, SearchIndexEntry } from '../types.js';
2
+ export declare function detectDeadCode(files: FileAnalysis[], entryPoints: string[], projectType?: ProjectType): DeadCodeItem[];
3
+ export declare function detectCircularDependencies(files: FileAnalysis[], edges: GraphEdge[]): CircularDependency[];
4
+ export declare function analyzePackages(files: FileAnalysis[]): PackageUsage[];
5
+ export declare function buildSearchIndex(nodes: GraphNode[], files: FileAnalysis[]): SearchIndexEntry[];
6
+ export declare function computeImportHeat(files: FileAnalysis[]): Map<string, number>;
7
+ //# sourceMappingURL=dead-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-code.d.ts","sourceRoot":"","sources":["../../src/analyzers/dead-code.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAIrB,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EAAE,EACrB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,CAAC,EAAE,WAAW,GACxB,YAAY,EAAE,CA0EhB;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,YAAY,EAAE,EACrB,KAAK,EAAE,SAAS,EAAE,GACjB,kBAAkB,EAAE,CAuDtB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CA4BrE;AAUD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CA0B9F;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAiB5E"}
@@ -0,0 +1,202 @@
1
+ import path from 'node:path';
2
+ import { toFileId } from '../parser.js';
3
+ import { isFrameworkRoute } from './framework-routes.js';
4
+ export function detectDeadCode(files, entryPoints, projectType) {
5
+ const importedBy = new Map();
6
+ const entryIds = new Set(entryPoints.map(toFileId));
7
+ const reachable = new Set();
8
+ // Framework routes are entry points even when never imported
9
+ for (const file of files) {
10
+ if (isFrameworkRoute(file.relativePath, projectType)) {
11
+ entryIds.add(file.id);
12
+ }
13
+ }
14
+ for (const file of files) {
15
+ if (!importedBy.has(file.id))
16
+ importedBy.set(file.id, new Set());
17
+ for (const imp of file.imports) {
18
+ if (imp.resolvedPath) {
19
+ const targetId = toFileId(imp.resolvedPath);
20
+ if (!importedBy.has(targetId))
21
+ importedBy.set(targetId, new Set());
22
+ importedBy.get(targetId).add(file.id);
23
+ }
24
+ }
25
+ }
26
+ const fileById = new Map(files.map((f) => [f.id, f]));
27
+ function dfs(startId) {
28
+ const stack = [startId];
29
+ while (stack.length > 0) {
30
+ const id = stack.pop();
31
+ if (reachable.has(id))
32
+ continue;
33
+ reachable.add(id);
34
+ const file = fileById.get(id);
35
+ if (!file)
36
+ continue;
37
+ for (const imp of file.imports) {
38
+ if (imp.resolvedPath) {
39
+ const targetId = toFileId(imp.resolvedPath);
40
+ if (!reachable.has(targetId))
41
+ stack.push(targetId);
42
+ }
43
+ }
44
+ }
45
+ }
46
+ for (const entry of entryIds)
47
+ dfs(entry);
48
+ const dead = [];
49
+ for (const file of files) {
50
+ const importers = importedBy.get(file.id);
51
+ const isFrameworkEntry = isFrameworkRoute(file.relativePath, projectType);
52
+ const isUnused = !importers?.size &&
53
+ !entryIds.has(file.id) &&
54
+ !reachable.has(file.id) &&
55
+ !isFrameworkEntry;
56
+ if (isUnused) {
57
+ let kind = 'file';
58
+ if (file.isScreen)
59
+ kind = 'screen';
60
+ else if (file.isHook)
61
+ kind = 'hook';
62
+ else if (file.isProvider)
63
+ kind = 'provider';
64
+ else if (file.components.length)
65
+ kind = 'component';
66
+ dead.push({
67
+ id: file.id,
68
+ path: file.relativePath,
69
+ kind,
70
+ reason: 'Never imported',
71
+ });
72
+ }
73
+ }
74
+ return dead;
75
+ }
76
+ export function detectCircularDependencies(files, edges) {
77
+ const cycles = [];
78
+ const adjacency = new Map();
79
+ for (const file of files) {
80
+ adjacency.set(file.id, []);
81
+ }
82
+ for (const edge of edges) {
83
+ if (edge.kind !== 'import')
84
+ continue;
85
+ adjacency.get(edge.source)?.push(edge.target);
86
+ }
87
+ const visited = new Set();
88
+ const stack = new Set();
89
+ const path = [];
90
+ function findCycles(node) {
91
+ if (stack.has(node)) {
92
+ const cycleStart = path.indexOf(node);
93
+ if (cycleStart >= 0) {
94
+ const cycle = path.slice(cycleStart).concat(node);
95
+ cycles.push({
96
+ cycle,
97
+ files: cycle.map((id) => id.replace('file:', '')),
98
+ });
99
+ }
100
+ return;
101
+ }
102
+ if (visited.has(node))
103
+ return;
104
+ visited.add(node);
105
+ stack.add(node);
106
+ path.push(node);
107
+ for (const target of adjacency.get(node) ?? []) {
108
+ findCycles(target);
109
+ }
110
+ path.pop();
111
+ stack.delete(node);
112
+ }
113
+ for (const file of files) {
114
+ if (!visited.has(file.id)) {
115
+ findCycles(file.id);
116
+ }
117
+ }
118
+ const seen = new Set();
119
+ return cycles.filter((c) => {
120
+ const key = [...c.cycle].sort().join('|');
121
+ if (seen.has(key))
122
+ return false;
123
+ seen.add(key);
124
+ return true;
125
+ });
126
+ }
127
+ export function analyzePackages(files) {
128
+ const packages = new Map();
129
+ for (const file of files) {
130
+ for (const imp of file.imports) {
131
+ if (!imp.isPackage)
132
+ continue;
133
+ const pkgName = getPackageName(imp.source);
134
+ if (!packages.has(pkgName)) {
135
+ packages.set(pkgName, {
136
+ name: pkgName,
137
+ files: [],
138
+ symbols: [],
139
+ consumers: [],
140
+ });
141
+ }
142
+ const pkg = packages.get(pkgName);
143
+ if (!pkg.files.includes(file.relativePath))
144
+ pkg.files.push(file.relativePath);
145
+ for (const spec of imp.specifiers) {
146
+ if (!pkg.symbols.includes(spec))
147
+ pkg.symbols.push(spec);
148
+ }
149
+ const consumer = file.components[0] ?? path.basename(file.path, path.extname(file.path));
150
+ if (!pkg.consumers.includes(consumer))
151
+ pkg.consumers.push(consumer);
152
+ }
153
+ }
154
+ return [...packages.values()].sort((a, b) => b.files.length - a.files.length);
155
+ }
156
+ function getPackageName(source) {
157
+ if (source.startsWith('@')) {
158
+ const parts = source.split('/');
159
+ return `${parts[0]}/${parts[1]}`;
160
+ }
161
+ return source.split('/')[0];
162
+ }
163
+ export function buildSearchIndex(nodes, files) {
164
+ const index = [];
165
+ for (const node of nodes) {
166
+ index.push({
167
+ id: node.id,
168
+ label: node.label,
169
+ kind: node.kind,
170
+ path: node.path,
171
+ keywords: [node.label, node.kind, node.path ?? '', node.layer ?? ''].filter(Boolean),
172
+ });
173
+ }
174
+ for (const file of files) {
175
+ for (const hook of file.hooks.filter((h) => h.isCustom)) {
176
+ index.push({
177
+ id: `${file.id}:hook:${hook.name}`,
178
+ label: hook.name,
179
+ kind: 'hook',
180
+ path: file.relativePath,
181
+ keywords: [hook.name, 'hook', file.relativePath],
182
+ });
183
+ }
184
+ }
185
+ return index;
186
+ }
187
+ export function computeImportHeat(files) {
188
+ const heat = new Map();
189
+ for (const file of files) {
190
+ heat.set(file.id, 0);
191
+ }
192
+ for (const file of files) {
193
+ for (const imp of file.imports) {
194
+ if (imp.resolvedPath) {
195
+ const targetId = toFileId(imp.resolvedPath);
196
+ heat.set(targetId, (heat.get(targetId) ?? 0) + 1);
197
+ }
198
+ }
199
+ }
200
+ return heat;
201
+ }
202
+ //# sourceMappingURL=dead-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-code.js","sourceRoot":"","sources":["../../src/analyzers/dead-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ProjectType } from '../types.js';
2
+ export declare function isNextJsPagesRoute(relativePath: string): boolean;
3
+ export declare function isNextJsAppRouterFile(relativePath: string): boolean;
4
+ export declare function isNextJsRootEntry(relativePath: string): boolean;
5
+ export declare function isExpoRouterRoute(relativePath: string): boolean;
6
+ export declare function isReactNavigationScreen(relativePath: string): boolean;
7
+ /**
8
+ * Files that frameworks load by convention — never imported directly.
9
+ */
10
+ export declare function isFrameworkRoute(relativePath: string, projectType?: ProjectType): boolean;
11
+ export declare function getFrameworkRouteReason(relativePath: string): string;
12
+ export declare function collectFrameworkRoutePaths(files: Array<{
13
+ path: string;
14
+ relativePath: string;
15
+ }>, projectType?: ProjectType): string[];
16
+ //# sourceMappingURL=framework-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-routes.d.ts","sourceRoot":"","sources":["../../src/analyzers/framework-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAqC/C,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAUhE;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAQnE;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAM/D;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAc/D;AAED,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAGrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAUzF;AAED,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMpE;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,EACpD,WAAW,CAAC,EAAE,WAAW,GACxB,MAAM,EAAE,CAIV"}
@@ -0,0 +1,110 @@
1
+ import path from 'node:path';
2
+ const SOURCE_EXTS = new Set(['.tsx', '.ts', '.jsx', '.js']);
3
+ /** Next.js App Router convention filenames */
4
+ const APP_ROUTER_SEGMENTS = new Set([
5
+ 'page',
6
+ 'layout',
7
+ 'route',
8
+ 'loading',
9
+ 'error',
10
+ 'template',
11
+ 'default',
12
+ 'not-found',
13
+ 'global-error',
14
+ 'opengraph-image',
15
+ 'icon',
16
+ 'apple-icon',
17
+ 'sitemap',
18
+ 'robots',
19
+ ]);
20
+ /** Expo Router route files */
21
+ const EXPO_ROUTER_PRIVATE = /^_/;
22
+ function normalizePath(relativePath) {
23
+ return relativePath.replace(/\\/g, '/');
24
+ }
25
+ function hasSegment(normalized, segment) {
26
+ return new RegExp(`(^|/)${segment}/`).test(normalized);
27
+ }
28
+ function fileSegmentName(normalized) {
29
+ return path.basename(normalized, path.extname(normalized));
30
+ }
31
+ export function isNextJsPagesRoute(relativePath) {
32
+ const normalized = normalizePath(relativePath);
33
+ if (!hasSegment(normalized, 'pages'))
34
+ return false;
35
+ const ext = path.extname(normalized);
36
+ if (!SOURCE_EXTS.has(ext))
37
+ return false;
38
+ // pages/api/hello.ts — API routes are framework entry points
39
+ // pages/_app.tsx, pages/_document.tsx — special entry files
40
+ return true;
41
+ }
42
+ export function isNextJsAppRouterFile(relativePath) {
43
+ const normalized = normalizePath(relativePath);
44
+ if (!hasSegment(normalized, 'app'))
45
+ return false;
46
+ const ext = path.extname(normalized);
47
+ if (!SOURCE_EXTS.has(ext))
48
+ return false;
49
+ return APP_ROUTER_SEGMENTS.has(fileSegmentName(normalized));
50
+ }
51
+ export function isNextJsRootEntry(relativePath) {
52
+ const base = path.basename(normalizePath(relativePath));
53
+ return [
54
+ 'middleware.ts', 'middleware.js',
55
+ 'instrumentation.ts', 'instrumentation.js',
56
+ ].includes(base);
57
+ }
58
+ export function isExpoRouterRoute(relativePath) {
59
+ const normalized = normalizePath(relativePath);
60
+ if (!hasSegment(normalized, 'app'))
61
+ return false;
62
+ const ext = path.extname(normalized);
63
+ if (!SOURCE_EXTS.has(ext))
64
+ return false;
65
+ const name = fileSegmentName(normalized);
66
+ // Route files and layouts; skip +not-found private groups handled by name
67
+ if (name === 'index' || name === '_layout')
68
+ return true;
69
+ if (EXPO_ROUTER_PRIVATE.test(name))
70
+ return name === '_layout';
71
+ // app/home.tsx, app/settings/profile.tsx
72
+ return !EXPO_ROUTER_PRIVATE.test(name);
73
+ }
74
+ export function isReactNavigationScreen(relativePath) {
75
+ const normalized = normalizePath(relativePath);
76
+ return /(^|\/)screens\//.test(normalized) || /Screen\.(tsx|ts|jsx|js)$/.test(normalized);
77
+ }
78
+ /**
79
+ * Files that frameworks load by convention — never imported directly.
80
+ */
81
+ export function isFrameworkRoute(relativePath, projectType) {
82
+ if (isNextJsPagesRoute(relativePath))
83
+ return true;
84
+ if (isNextJsAppRouterFile(relativePath))
85
+ return true;
86
+ if (isNextJsRootEntry(relativePath))
87
+ return true;
88
+ if (projectType === 'expo-router' || projectType === 'expo') {
89
+ if (isExpoRouterRoute(relativePath))
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ export function getFrameworkRouteReason(relativePath) {
95
+ if (isNextJsPagesRoute(relativePath))
96
+ return 'Next.js pages route';
97
+ if (isNextJsAppRouterFile(relativePath))
98
+ return 'Next.js app route';
99
+ if (isNextJsRootEntry(relativePath))
100
+ return 'Next.js framework entry';
101
+ if (isExpoRouterRoute(relativePath))
102
+ return 'Expo Router route';
103
+ return 'Framework route';
104
+ }
105
+ export function collectFrameworkRoutePaths(files, projectType) {
106
+ return files
107
+ .filter((f) => isFrameworkRoute(f.relativePath, projectType))
108
+ .map((f) => f.path);
109
+ }
110
+ //# sourceMappingURL=framework-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-routes.js","sourceRoot":"","sources":["../../src/analyzers/framework-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FileAnalysis, ProjectConfig, RouteInfo } from '../types.js';
2
+ export declare function analyzeNavigation(config: ProjectConfig, files: FileAnalysis[]): RouteInfo[];
3
+ export declare function buildNavigationTree(routes: RouteInfo[]): RouteInfo[];
4
+ //# sourceMappingURL=navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/analyzers/navigation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE1E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAK3F;AAkGD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAGpE"}
@@ -0,0 +1,109 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs';
3
+ export function analyzeNavigation(config, files) {
4
+ if (config.type === 'expo-router') {
5
+ return analyzeExpoRouter(config, files);
6
+ }
7
+ return analyzeReactNavigation(files);
8
+ }
9
+ function analyzeExpoRouter(config, files) {
10
+ const appDir = path.join(config.root, 'app');
11
+ if (!fs.existsSync(appDir))
12
+ return [];
13
+ const routes = [];
14
+ function walk(dir, routePath, parent) {
15
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
16
+ // Establish layout parent for this directory without re-walking
17
+ let layoutParent = parent;
18
+ for (const entry of entries) {
19
+ if (!entry.isFile())
20
+ continue;
21
+ const ext = path.extname(entry.name);
22
+ if (!['.tsx', '.ts', '.jsx', '.js'].includes(ext))
23
+ continue;
24
+ if (entry.name.replace(ext, '') !== '_layout')
25
+ continue;
26
+ const full = path.join(dir, entry.name);
27
+ const layoutRoute = {
28
+ id: `route:${full}`,
29
+ name: path.basename(dir) || 'root',
30
+ path: routePath || '/',
31
+ file: full,
32
+ type: 'expo-router',
33
+ children: [],
34
+ };
35
+ routes.push(layoutRoute);
36
+ layoutParent = layoutRoute;
37
+ break;
38
+ }
39
+ for (const entry of entries) {
40
+ if (entry.name.startsWith('_') && entry.name !== '_layout.tsx' && entry.name !== '_layout.ts')
41
+ continue;
42
+ if (entry.name.startsWith('.'))
43
+ continue;
44
+ const full = path.join(dir, entry.name);
45
+ if (entry.isDirectory()) {
46
+ const segment = entry.name.startsWith('(') ? '' : entry.name;
47
+ const newPath = segment ? `${routePath}/${segment}` : routePath;
48
+ walk(full, newPath, layoutParent);
49
+ }
50
+ else if (entry.isFile()) {
51
+ const ext = path.extname(entry.name);
52
+ if (!['.tsx', '.ts', '.jsx', '.js'].includes(ext))
53
+ continue;
54
+ const baseName = entry.name.replace(ext, '');
55
+ if (baseName === '_layout')
56
+ continue;
57
+ if (!baseName.startsWith('_')) {
58
+ const segment = baseName === 'index' ? '' : `/${baseName}`;
59
+ const route = {
60
+ id: `route:${full}`,
61
+ name: baseName === 'index' ? path.basename(dir) || 'index' : baseName,
62
+ path: `${routePath}${segment}` || '/',
63
+ file: full,
64
+ type: 'screen',
65
+ };
66
+ if (layoutParent?.children)
67
+ layoutParent.children.push(route);
68
+ else
69
+ routes.push(route);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ walk(appDir, '');
75
+ return routes;
76
+ }
77
+ function analyzeReactNavigation(files) {
78
+ const routes = [];
79
+ for (const file of files) {
80
+ if (!file.isNavigator && !file.isScreen)
81
+ continue;
82
+ const navType = detectNavigatorType(file);
83
+ routes.push({
84
+ id: `route:${file.path}`,
85
+ name: path.basename(file.path, path.extname(file.path)),
86
+ path: file.relativePath,
87
+ file: file.path,
88
+ type: navType,
89
+ });
90
+ }
91
+ return routes;
92
+ }
93
+ function detectNavigatorType(file) {
94
+ const name = path.basename(file.path);
95
+ if (/Stack/i.test(name))
96
+ return 'stack';
97
+ if (/Tab/i.test(name))
98
+ return 'tab';
99
+ if (/Drawer/i.test(name))
100
+ return 'drawer';
101
+ if (file.isScreen)
102
+ return 'screen';
103
+ return 'react-navigation';
104
+ }
105
+ export function buildNavigationTree(routes) {
106
+ const sorted = [...routes].sort((a, b) => a.path.localeCompare(b.path));
107
+ return sorted;
108
+ }
109
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/analyzers/navigation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { ProjectConfig } from './types.js';
2
+ declare const RN_EXTENSIONS: string[];
3
+ declare const IGNORE_DIRS: Set<string>;
4
+ export declare function discoverProject(root: string): ProjectConfig;
5
+ export declare function collectSourceFiles(root: string, workspaces?: string[]): string[];
6
+ export declare function collectAssets(root: string): string[];
7
+ export { RN_EXTENSIONS, IGNORE_DIRS };
8
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,YAAY,CAAC;AAG7D,QAAA,MAAM,aAAa,UAAiC,CAAC;AACrD,QAAA,MAAM,WAAW,aAqBf,CAAC;AAEH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAsB3D;AAuJD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAsBpF;AAgBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYpD;AAED,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC"}