@cr8rcho/alkahest 0.1.1

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 (130) hide show
  1. package/README.ko.md +208 -0
  2. package/README.md +208 -0
  3. package/dist/assets/dashboard.html +647 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +68 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/hook.d.ts +1 -0
  8. package/dist/commands/hook.js +64 -0
  9. package/dist/commands/hook.js.map +1 -0
  10. package/dist/commands/login.d.ts +11 -0
  11. package/dist/commands/login.js +27 -0
  12. package/dist/commands/login.js.map +1 -0
  13. package/dist/commands/mcp.d.ts +6 -0
  14. package/dist/commands/mcp.js +13 -0
  15. package/dist/commands/mcp.js.map +1 -0
  16. package/dist/commands/publish.d.ts +19 -0
  17. package/dist/commands/publish.js +27 -0
  18. package/dist/commands/publish.js.map +1 -0
  19. package/dist/commands/scan.d.ts +11 -0
  20. package/dist/commands/scan.js +29 -0
  21. package/dist/commands/scan.js.map +1 -0
  22. package/dist/commands/update.d.ts +15 -0
  23. package/dist/commands/update.js +41 -0
  24. package/dist/commands/update.js.map +1 -0
  25. package/dist/commands/view.d.ts +6 -0
  26. package/dist/commands/view.js +21 -0
  27. package/dist/commands/view.js.map +1 -0
  28. package/dist/core/adapters/angular.d.ts +2 -0
  29. package/dist/core/adapters/angular.js +305 -0
  30. package/dist/core/adapters/angular.js.map +1 -0
  31. package/dist/core/adapters/astro.d.ts +3 -0
  32. package/dist/core/adapters/astro.js +140 -0
  33. package/dist/core/adapters/astro.js.map +1 -0
  34. package/dist/core/adapters/compose.d.ts +2 -0
  35. package/dist/core/adapters/compose.js +195 -0
  36. package/dist/core/adapters/compose.js.map +1 -0
  37. package/dist/core/adapters/django.d.ts +2 -0
  38. package/dist/core/adapters/django.js +314 -0
  39. package/dist/core/adapters/django.js.map +1 -0
  40. package/dist/core/adapters/expo-router.d.ts +2 -0
  41. package/dist/core/adapters/expo-router.js +60 -0
  42. package/dist/core/adapters/expo-router.js.map +1 -0
  43. package/dist/core/adapters/flask.d.ts +2 -0
  44. package/dist/core/adapters/flask.js +249 -0
  45. package/dist/core/adapters/flask.js.map +1 -0
  46. package/dist/core/adapters/flutter.d.ts +2 -0
  47. package/dist/core/adapters/flutter.js +232 -0
  48. package/dist/core/adapters/flutter.js.map +1 -0
  49. package/dist/core/adapters/index.d.ts +19 -0
  50. package/dist/core/adapters/index.js +59 -0
  51. package/dist/core/adapters/index.js.map +1 -0
  52. package/dist/core/adapters/next-app.d.ts +2 -0
  53. package/dist/core/adapters/next-app.js +62 -0
  54. package/dist/core/adapters/next-app.js.map +1 -0
  55. package/dist/core/adapters/next-pages.d.ts +2 -0
  56. package/dist/core/adapters/next-pages.js +70 -0
  57. package/dist/core/adapters/next-pages.js.map +1 -0
  58. package/dist/core/adapters/nuxt.d.ts +2 -0
  59. package/dist/core/adapters/nuxt.js +59 -0
  60. package/dist/core/adapters/nuxt.js.map +1 -0
  61. package/dist/core/adapters/rails.d.ts +2 -0
  62. package/dist/core/adapters/rails.js +275 -0
  63. package/dist/core/adapters/rails.js.map +1 -0
  64. package/dist/core/adapters/react-jsx.d.ts +68 -0
  65. package/dist/core/adapters/react-jsx.js +355 -0
  66. package/dist/core/adapters/react-jsx.js.map +1 -0
  67. package/dist/core/adapters/react-navigation.d.ts +2 -0
  68. package/dist/core/adapters/react-navigation.js +153 -0
  69. package/dist/core/adapters/react-navigation.js.map +1 -0
  70. package/dist/core/adapters/react-router.d.ts +2 -0
  71. package/dist/core/adapters/react-router.js +249 -0
  72. package/dist/core/adapters/react-router.js.map +1 -0
  73. package/dist/core/adapters/remix.d.ts +2 -0
  74. package/dist/core/adapters/remix.js +109 -0
  75. package/dist/core/adapters/remix.js.map +1 -0
  76. package/dist/core/adapters/static-html.d.ts +2 -0
  77. package/dist/core/adapters/static-html.js +157 -0
  78. package/dist/core/adapters/static-html.js.map +1 -0
  79. package/dist/core/adapters/sveltekit.d.ts +2 -0
  80. package/dist/core/adapters/sveltekit.js +151 -0
  81. package/dist/core/adapters/sveltekit.js.map +1 -0
  82. package/dist/core/adapters/swiftui.d.ts +2 -0
  83. package/dist/core/adapters/swiftui.js +216 -0
  84. package/dist/core/adapters/swiftui.js.map +1 -0
  85. package/dist/core/adapters/types.d.ts +65 -0
  86. package/dist/core/adapters/types.js +2 -0
  87. package/dist/core/adapters/types.js.map +1 -0
  88. package/dist/core/adapters/uikit.d.ts +2 -0
  89. package/dist/core/adapters/uikit.js +178 -0
  90. package/dist/core/adapters/uikit.js.map +1 -0
  91. package/dist/core/adapters/vue-router.d.ts +2 -0
  92. package/dist/core/adapters/vue-router.js +224 -0
  93. package/dist/core/adapters/vue-router.js.map +1 -0
  94. package/dist/core/adapters/vue-sfc.d.ts +28 -0
  95. package/dist/core/adapters/vue-sfc.js +132 -0
  96. package/dist/core/adapters/vue-sfc.js.map +1 -0
  97. package/dist/core/credentials.d.ts +24 -0
  98. package/dist/core/credentials.js +30 -0
  99. package/dist/core/credentials.js.map +1 -0
  100. package/dist/core/dashboard.d.ts +9 -0
  101. package/dist/core/dashboard.js +20 -0
  102. package/dist/core/dashboard.js.map +1 -0
  103. package/dist/core/emit.d.ts +7 -0
  104. package/dist/core/emit.js +23 -0
  105. package/dist/core/emit.js.map +1 -0
  106. package/dist/core/hash.d.ts +2 -0
  107. package/dist/core/hash.js +6 -0
  108. package/dist/core/hash.js.map +1 -0
  109. package/dist/core/pipeline.d.ts +25 -0
  110. package/dist/core/pipeline.js +122 -0
  111. package/dist/core/pipeline.js.map +1 -0
  112. package/dist/core/publish.d.ts +31 -0
  113. package/dist/core/publish.js +87 -0
  114. package/dist/core/publish.js.map +1 -0
  115. package/dist/core/resolve.d.ts +42 -0
  116. package/dist/core/resolve.js +128 -0
  117. package/dist/core/resolve.js.map +1 -0
  118. package/dist/core/serve.d.ts +5 -0
  119. package/dist/core/serve.js +52 -0
  120. package/dist/core/serve.js.map +1 -0
  121. package/dist/core/types.d.ts +117 -0
  122. package/dist/core/types.js +9 -0
  123. package/dist/core/types.js.map +1 -0
  124. package/dist/core/version.d.ts +23 -0
  125. package/dist/core/version.js +102 -0
  126. package/dist/core/version.js.map +1 -0
  127. package/dist/mcp/server.d.ts +7 -0
  128. package/dist/mcp/server.js +224 -0
  129. package/dist/mcp/server.js.map +1 -0
  130. package/package.json +57 -0
@@ -0,0 +1,195 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join, relative, sep } from "node:path";
3
+ /**
4
+ * Jetpack Compose adapter (Android, Kotlin). Like react-navigation, screens are *registered*
5
+ * against string routes in a NavHost, not file-based — but Kotlin can't reuse the ts-morph
6
+ * parser, so this is a zero-dependency line/regex scan in the SwiftUI adapter's style.
7
+ *
8
+ * Model:
9
+ * - screen = a `composable("route") { Foo(...) }` destination in a NavHost. id = the route string.
10
+ * - the destination's first @Composable call (Foo()) tells us which composable renders it; we
11
+ * parse THAT function's body (across files) for nav/calls/features.
12
+ * - transition = navController.navigate("route") → target route (resolves against screen ids).
13
+ * - call = Retrofit/Ktor/`client.get("url")` / `URL("…")` string literals.
14
+ * - feature = Button / TextField / OutlinedTextField / Checkbox / Switch / LazyColumn / etc.
15
+ *
16
+ * Entry = the NavHost `startDestination = "route"`.
17
+ */
18
+ const COMPOSABLE_DEST = /\bcomposable\s*\(\s*(?:route\s*=\s*)?"([^"]+)"/;
19
+ const START_DEST = /\bstartDestination\s*=\s*"([^"]+)"/;
20
+ const NAVIGATE = /\bnavigate\s*\(\s*"([^"]+)"/;
21
+ // @Composable usually sits on its own line above `fun Name(` — match across whitespace/newlines, globally.
22
+ const COMPOSABLE_FN_G = /@Composable\s+(?:private\s+|internal\s+|public\s+)?fun\s+([A-Za-z_]\w*)\s*\(/g;
23
+ const SKIP_DIRS = /^(build|\.gradle|\.idea)$/i;
24
+ export const composeAdapter = {
25
+ id: "compose",
26
+ router: "compose-nav",
27
+ detect(projectRoot) {
28
+ let found = false;
29
+ walkKotlin(projectRoot, (file) => {
30
+ if (found)
31
+ return;
32
+ const src = safeRead(file).slice(0, 4000);
33
+ if (/\bandroidx\.compose\b/.test(src) || /\bandroidx\.navigation\.compose\b/.test(src))
34
+ found = true;
35
+ });
36
+ return found;
37
+ },
38
+ discover(projectRoot) {
39
+ // Pass 1: index every @Composable fn name → its source file (for route→composable resolution).
40
+ const fnFile = new Map();
41
+ const sources = new Map();
42
+ walkKotlin(projectRoot, (file) => {
43
+ const src = safeRead(file);
44
+ sources.set(file, src);
45
+ // @Composable and `fun` are usually on separate lines — scan the whole source, not line-by-line.
46
+ for (const m of src.matchAll(COMPOSABLE_FN_G)) {
47
+ if (!fnFile.has(m[1]))
48
+ fnFile.set(m[1], file);
49
+ }
50
+ });
51
+ // Pass 2: find NavHost composable("route") { Composable() } destinations.
52
+ const files = [];
53
+ const seen = new Set();
54
+ let startDest = null;
55
+ for (const [file, src] of sources) {
56
+ const lines = src.split("\n");
57
+ for (let i = 0; i < lines.length; i++) {
58
+ if (!startDest) {
59
+ const sd = lines[i].match(START_DEST);
60
+ if (sd)
61
+ startDest = sd[1];
62
+ }
63
+ const dest = lines[i].match(COMPOSABLE_DEST);
64
+ if (!dest)
65
+ continue;
66
+ const route = dest[1];
67
+ if (seen.has(route))
68
+ continue;
69
+ seen.add(route);
70
+ // The composable rendered by this destination → its defining file (fall back to the NavHost file).
71
+ const target = firstComposableCall(lines, i);
72
+ const declFile = (target && fnFile.get(target)) || file;
73
+ files.push({
74
+ absPath: declFile,
75
+ relPath: relative(projectRoot, declFile).split(sep).join("/"),
76
+ id: route,
77
+ route,
78
+ title: titleFromRoute(route, target),
79
+ });
80
+ }
81
+ }
82
+ if (startDest) {
83
+ const e = files.find((f) => f.id === startDest);
84
+ if (e)
85
+ e.isEntry = true;
86
+ }
87
+ files.sort((a, b) => a.id.localeCompare(b.id));
88
+ return files;
89
+ },
90
+ parse(file) {
91
+ return parseKotlin(safeRead(file.absPath));
92
+ },
93
+ };
94
+ // ---------- discovery helpers ----------
95
+ function walkKotlin(dir, onFile) {
96
+ let entries;
97
+ try {
98
+ entries = readdirSync(dir, { withFileTypes: true, encoding: "utf8" });
99
+ }
100
+ catch {
101
+ return;
102
+ }
103
+ for (const entry of entries) {
104
+ if (entry.name.startsWith(".") || entry.name === "node_modules")
105
+ continue;
106
+ const full = join(dir, entry.name);
107
+ if (entry.isDirectory()) {
108
+ if (SKIP_DIRS.test(entry.name))
109
+ continue;
110
+ walkKotlin(full, onFile);
111
+ }
112
+ else if (entry.name.endsWith(".kt")) {
113
+ onFile(full);
114
+ }
115
+ }
116
+ }
117
+ function safeRead(file) {
118
+ try {
119
+ return readFileSync(file, "utf8");
120
+ }
121
+ catch {
122
+ return "";
123
+ }
124
+ }
125
+ /** The first PascalCase composable call inside a `composable(...) { ... }` block (same or next few lines). */
126
+ function firstComposableCall(lines, i) {
127
+ for (let j = i; j < Math.min(i + 4, lines.length); j++) {
128
+ // skip the composable( … ) registration call itself; look for an invoked Composable, e.g. HomeScreen(
129
+ const after = j === i ? lines[j].replace(COMPOSABLE_DEST, "") : lines[j];
130
+ const m = after.match(/\b([A-Z]\w*)\s*\(/);
131
+ if (m)
132
+ return m[1];
133
+ }
134
+ return null;
135
+ }
136
+ /** Route string → Title; falls back to the composable name. `home` → Home, `detail/{id}` → Detail. */
137
+ function titleFromRoute(route, composable) {
138
+ const seg = route.split("/").filter((s) => s && !s.startsWith("{"))[0];
139
+ const base = seg || composable || route;
140
+ return base
141
+ .replace(/Screen$/, "")
142
+ .replace(/[-_]/g, " ")
143
+ .replace(/\b\w/g, (c) => c.toUpperCase());
144
+ }
145
+ // ---------- parsing (line heuristics) ----------
146
+ const FEATURE_RULES = [
147
+ { re: /\b(?:Button|OutlinedButton|TextButton|IconButton|FloatingActionButton|ElevatedButton|FilledTonalButton)\s*\(/, kind: "button", label: () => "Button" },
148
+ { re: /\b(?:TextField|OutlinedTextField|BasicTextField)\s*\(/, kind: "input", label: () => "Input" },
149
+ { re: /\b(?:Checkbox|Switch|RadioButton|Slider)\s*\(/, kind: "input", label: () => "Input" },
150
+ { re: /\b(?:LazyColumn|LazyRow|LazyVerticalGrid|LazyHorizontalGrid)\s*\(/, kind: "list", label: () => "List" },
151
+ ];
152
+ const URL_STRING = /\b(?:URL|HttpUrl)\s*\(\s*"([^"]+)"|"(https?:\/\/[^"]+)"/;
153
+ const HTTP_CLIENT = /\bclient\.(get|post|put|delete|patch)\s*(?:<[^>]*>)?\s*\(\s*"([^"]+)"|\b(?:Retrofit|OkHttpClient|HttpClient)\s*\(/;
154
+ function parseKotlin(src) {
155
+ const lines = src.split("\n");
156
+ const navs = [];
157
+ const calls = [];
158
+ const features = [];
159
+ const components = new Set();
160
+ for (let i = 0; i < lines.length; i++) {
161
+ const line = lines[i];
162
+ const lineNo = i + 1;
163
+ // --- transition: navController.navigate("route") ---
164
+ const nav = line.match(NAVIGATE);
165
+ if (nav)
166
+ navs.push({ target: nav[1], raw: snippet(line), trigger: "navigate()", line: lineNo });
167
+ // --- call: URL literal / typed HTTP client ---
168
+ const urlM = line.match(URL_STRING);
169
+ if (urlM) {
170
+ calls.push({ url: urlM[1] ?? urlM[2] ?? null, raw: snippet(line), trigger: "URL", line: lineNo });
171
+ }
172
+ else {
173
+ const httpM = line.match(HTTP_CLIENT);
174
+ if (httpM)
175
+ calls.push({ url: httpM[2] ?? null, method: httpM[1]?.toUpperCase(), raw: snippet(line), trigger: "http", line: lineNo });
176
+ }
177
+ // --- feature: Compose UI controls (one per line) ---
178
+ for (const rule of FEATURE_RULES) {
179
+ const m = line.match(rule.re);
180
+ if (m) {
181
+ features.push({ kind: rule.kind, label: rule.label(m), detail: m[0].trim().slice(0, 40), line: lineNo });
182
+ break;
183
+ }
184
+ }
185
+ // --- components: invoked PascalCase composables that look like screens (XxxScreen) ---
186
+ for (const m of line.matchAll(/\b([A-Z]\w*Screen)\s*\(/g))
187
+ components.add(m[1]);
188
+ }
189
+ return { navs, calls, features, components: [...components].sort(), contains: [] };
190
+ }
191
+ function snippet(text) {
192
+ const flat = text.replace(/\s+/g, " ").trim();
193
+ return flat.length > 80 ? flat.slice(0, 77) + "..." : flat;
194
+ }
195
+ //# sourceMappingURL=compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../src/core/adapters/compose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { FrameworkAdapter } from "./types.js";
2
+ export declare const djangoAdapter: FrameworkAdapter;
@@ -0,0 +1,314 @@
1
+ import { readdirSync, readFileSync, existsSync } from "node:fs";
2
+ import { join, relative, sep } from "node:path";
3
+ // Cross-file maps, rebuilt each discover() and read by parse().
4
+ let urlNameToRoute = new Map();
5
+ let routeToInfo = new Map();
6
+ export const djangoAdapter = {
7
+ id: "django",
8
+ router: "django-urls",
9
+ detect(projectRoot) {
10
+ if (existsSync(join(projectRoot, "manage.py")))
11
+ return true;
12
+ let found = false;
13
+ walkPy(projectRoot, (file) => {
14
+ if (found)
15
+ return;
16
+ if (file.endsWith("urls.py") && /\burlpatterns\s*=/.test(safeRead(file)))
17
+ found = true;
18
+ });
19
+ return found;
20
+ },
21
+ discover(projectRoot) {
22
+ urlNameToRoute = new Map();
23
+ routeToInfo = new Map();
24
+ // Pass A: read every urls.py — its pattern entries and the modules it include()s.
25
+ const urlFiles = new Map();
26
+ walkPy(projectRoot, (file) => {
27
+ if (file.endsWith("urls.py"))
28
+ urlFiles.set(modulePath(projectRoot, file), parseUrlsFile(safeRead(file), file));
29
+ });
30
+ // include('blog.urls') references a dotted module; match it to a urlFiles key by dotted suffix.
31
+ const resolveInclude = (mod) => {
32
+ if (urlFiles.has(mod))
33
+ return mod;
34
+ const suffix = mod.replace(/\./g, "/");
35
+ for (const key of urlFiles.keys())
36
+ if (key.replace(/\./g, "/").endsWith(suffix))
37
+ return key;
38
+ return null;
39
+ };
40
+ // Roots = urls.py modules not pulled in by another's include().
41
+ const included = new Set();
42
+ for (const mod of urlFiles.values())
43
+ for (const inc of mod.includes) {
44
+ const k = resolveInclude(inc.module);
45
+ if (k)
46
+ included.add(k);
47
+ }
48
+ const roots = [...urlFiles.entries()].filter(([m]) => !included.has(m));
49
+ const files = [];
50
+ const usedRelPaths = new Set();
51
+ const emit = (info) => {
52
+ if (routeToInfo.has(info.route))
53
+ return; // first declaration wins
54
+ routeToInfo.set(info.route, info);
55
+ if (info.name)
56
+ urlNameToRoute.set(info.name, info.route);
57
+ // Prefer the template as the screen's file (1:1 with the route). Many routes share one
58
+ // views.py, so relPath must stay unique — it's the pipeline's per-screen key — disambiguate
59
+ // a collision with the route.
60
+ const repr = info.templateFile ?? info.viewFile ?? join(projectRoot, "urls.py");
61
+ let relPath = relative(projectRoot, repr).split(sep).join("/");
62
+ if (usedRelPaths.has(relPath))
63
+ relPath = `${relPath}#${info.route}`;
64
+ usedRelPaths.add(relPath);
65
+ files.push({
66
+ absPath: repr,
67
+ relPath,
68
+ id: info.route,
69
+ route: info.route,
70
+ title: titleFromRoute(info.route, info.name),
71
+ isEntry: info.route === "/",
72
+ });
73
+ };
74
+ const expand = (moduleName, prefix, seen) => {
75
+ if (seen.has(moduleName))
76
+ return; // guard against cyclic includes
77
+ seen.add(moduleName);
78
+ const mod = urlFiles.get(moduleName);
79
+ if (!mod)
80
+ return;
81
+ for (const p of mod.patterns) {
82
+ const route = joinRoute(prefix, p.path);
83
+ const view = p.view ? resolveView(projectRoot, mod.file, p.view) : null;
84
+ emit({
85
+ route,
86
+ name: p.name,
87
+ viewFile: view?.file ?? null,
88
+ viewFn: view?.fn ?? null,
89
+ templateFile: p.templateName
90
+ ? resolveTemplate(projectRoot, p.templateName)
91
+ : view
92
+ ? resolveTemplate(projectRoot, templateOfView(view.file, view.fn))
93
+ : null,
94
+ });
95
+ }
96
+ for (const inc of mod.includes) {
97
+ const k = resolveInclude(inc.module);
98
+ if (k)
99
+ expand(k, joinRoute(prefix, inc.path), seen);
100
+ }
101
+ };
102
+ for (const [moduleName] of roots)
103
+ expand(moduleName, "", new Set());
104
+ files.sort((a, b) => a.route.localeCompare(b.route));
105
+ return files;
106
+ },
107
+ parse(file) {
108
+ const info = routeToInfo.get(file.id);
109
+ const viewSrc = info?.viewFile && info.viewFn ? viewBody(safeRead(info.viewFile), info.viewFn) : "";
110
+ const templateSrc = info?.templateFile ? safeRead(info.templateFile) : "";
111
+ return parseDjango(viewSrc, templateSrc);
112
+ },
113
+ };
114
+ const PATH_CALL = /\b(?:path|re_path|url)\s*\(\s*r?["']([^"']*)["']\s*,\s*([\s\S]*?)\)\s*,?/g;
115
+ const NAME_KW = /name\s*=\s*["']([^"']+)["']/;
116
+ const TEMPLATE_NAME_KW = /template_name\s*=\s*["']([^"']+)["']/;
117
+ const INCLUDE_CALL = /include\s*\(\s*["']([^"']+)["']/;
118
+ function parseUrlsFile(src, file) {
119
+ const patterns = [];
120
+ const includes = [];
121
+ for (const m of src.matchAll(PATH_CALL)) {
122
+ const routePath = m[1];
123
+ const rest = m[2];
124
+ const inc = rest.match(INCLUDE_CALL);
125
+ if (inc) {
126
+ includes.push({ path: routePath, module: inc[1] });
127
+ continue;
128
+ }
129
+ const name = rest.match(NAME_KW)?.[1] ?? null;
130
+ const templateName = rest.match(TEMPLATE_NAME_KW)?.[1] ?? null;
131
+ // View ref = the first token of `rest` before a comma: `views.home`, `home`, `HomeView.as_view()`.
132
+ const viewToken = rest.split(",")[0].trim().replace(/\.as_view\s*\([^)]*\)\s*$/, "");
133
+ const view = /^[A-Za-z_][\w.]*$/.test(viewToken) ? viewToken : null;
134
+ patterns.push({ path: routePath, view, name, templateName });
135
+ }
136
+ return { file, patterns, includes };
137
+ }
138
+ // ---------- view → template + data calls ----------
139
+ /** Resolve a urls.py view ref ("views.home" / "home") to (file, fn). Searches *.py for `def fn(`. */
140
+ function resolveView(projectRoot, urlsFile, ref) {
141
+ const fn = ref.includes(".") ? ref.slice(ref.lastIndexOf(".") + 1) : ref;
142
+ // Class-based views are PascalCase; we still record the fn but template resolution will fall back.
143
+ const defRe = new RegExp(`\\b(?:def|class)\\s+${fn}\\b`);
144
+ // Prefer a views.py next to the urls.py, else any .py under the project.
145
+ const sibling = join(urlsFile.slice(0, urlsFile.lastIndexOf(sep)), "views.py");
146
+ if (existsSync(sibling) && defRe.test(safeRead(sibling)))
147
+ return { file: sibling, fn };
148
+ let hit = null;
149
+ walkPy(projectRoot, (file) => {
150
+ if (hit || !file.endsWith(".py"))
151
+ return;
152
+ if (defRe.test(safeRead(file)))
153
+ hit = { file, fn };
154
+ });
155
+ return hit;
156
+ }
157
+ /** The template a view renders: `render(request, 'x.html')` / `return render(..., "x.html")`. */
158
+ function templateOfView(file, fn) {
159
+ const body = viewBody(safeRead(file), fn);
160
+ const m = body.match(/render\s*\(\s*request\s*,\s*["']([^"']+)["']/) ?? body.match(/render\s*\(\s*[^,]+,\s*["']([^"']+\.html)["']/);
161
+ return m ? m[1] : null;
162
+ }
163
+ /** Resolve a template name ("blog/list.html") to a file under any `templates/` dir. */
164
+ function resolveTemplate(projectRoot, name) {
165
+ if (!name)
166
+ return null;
167
+ let hit = null;
168
+ walkAll(projectRoot, (file) => {
169
+ if (hit)
170
+ return;
171
+ const norm = file.split(sep).join("/");
172
+ if (norm.endsWith("/templates/" + name) || norm.endsWith("/" + name)) {
173
+ if (norm.includes("/templates/"))
174
+ hit = file;
175
+ else if (!hit)
176
+ hit = file; // weaker match
177
+ }
178
+ });
179
+ return hit;
180
+ }
181
+ /** Body of `def fn(` / `class fn(` up to the next top-level def/class (indentation 0). */
182
+ function viewBody(src, fn) {
183
+ const lines = src.split("\n");
184
+ const start = lines.findIndex((l) => new RegExp(`^\\s*(?:def|class)\\s+${fn}\\b`).test(l));
185
+ if (start < 0)
186
+ return "";
187
+ const out = [lines[start]];
188
+ for (let i = start + 1; i < lines.length; i++) {
189
+ if (/^\S/.test(lines[i]) && /^(?:def|class|@)\b/.test(lines[i]))
190
+ break; // next top-level decl
191
+ out.push(lines[i]);
192
+ }
193
+ return out.join("\n");
194
+ }
195
+ // ---------- signal extraction (view body + template) ----------
196
+ const URL_TAG = /\{%\s*url\s+["']([^"']+)["']/;
197
+ const HREF = /<a\b[^>]*?\shref=["']([^"'#{]+)["']/i;
198
+ const REDIRECT = /\bredirect\s*\(\s*["']([^"']+)["']/;
199
+ const HTTP_CALL = /\brequests\.(get|post|put|delete|patch)\s*\(\s*["']([^"']+)["']/;
200
+ const ORM_CALL = /\b([A-Z]\w*)\.objects\.(all|filter|get|create|count|exclude)\b/;
201
+ const FORM_ACTION = /<form\b[^>]*?\saction=["']([^"']+)["']/i;
202
+ const FEATURE_RULES = [
203
+ { re: /<button\b[^>]*>([^<]*)/i, kind: "button", label: (m) => m[1].trim() || "Button" },
204
+ { re: /<(?:input|textarea|select)\b[^>]*\bplaceholder=["']([^"']*)["']/i, kind: "input", label: (m) => m[1] || "Input" },
205
+ { re: /<(?:input|textarea|select)\b/i, kind: "input", label: () => "Input" },
206
+ { re: /<form\b/i, kind: "form", label: () => "Form" },
207
+ ];
208
+ function parseDjango(viewSrc, templateSrc) {
209
+ const navs = [];
210
+ const calls = [];
211
+ const features = [];
212
+ // --- view body: redirects + data calls ---
213
+ viewSrc.split(/\r?\n/).forEach((rawLine, i) => {
214
+ const line = rawLine.trim();
215
+ const red = line.match(REDIRECT);
216
+ if (red)
217
+ navs.push({ target: resolveTarget(red[1]), raw: snippet(line), trigger: "redirect()", line: i + 1 });
218
+ const httpM = line.match(HTTP_CALL);
219
+ if (httpM)
220
+ calls.push({ url: httpM[2], method: httpM[1].toUpperCase(), raw: snippet(line), trigger: "requests", line: i + 1 });
221
+ const orm = line.match(ORM_CALL);
222
+ if (orm)
223
+ calls.push({ url: `${orm[1]}.${orm[2]}`, raw: snippet(line), trigger: "orm", line: i + 1 });
224
+ });
225
+ // --- template: {% url %} + <a href> nav, <form action> calls, features ---
226
+ templateSrc.split(/\r?\n/).forEach((rawLine, i) => {
227
+ const line = rawLine.trim();
228
+ const urlTag = line.match(URL_TAG);
229
+ if (urlTag)
230
+ navs.push({ target: urlNameToRoute.get(urlTag[1]) ?? null, raw: snippet(line), trigger: "{% url %}", line: i + 1 });
231
+ else {
232
+ const href = line.match(HREF);
233
+ if (href)
234
+ navs.push({ target: resolveTarget(href[1]), raw: snippet(line), trigger: "<a href>", line: i + 1 });
235
+ }
236
+ const action = line.match(FORM_ACTION);
237
+ if (action)
238
+ calls.push({ url: action[1], method: "POST", raw: snippet(line), trigger: "<form action>", line: i + 1 });
239
+ for (const rule of FEATURE_RULES) {
240
+ const m = line.match(rule.re);
241
+ if (m) {
242
+ features.push({ kind: rule.kind, label: rule.label(m), detail: m[0].trim().slice(0, 40), line: i + 1 });
243
+ break;
244
+ }
245
+ }
246
+ });
247
+ return { navs, calls, features, components: [], contains: [] };
248
+ }
249
+ /** A redirect/href target: a URL name (resolve via the map) or a literal path. */
250
+ function resolveTarget(raw) {
251
+ if (raw.startsWith("/"))
252
+ return normalize(raw);
253
+ return urlNameToRoute.get(raw) ?? null;
254
+ }
255
+ // ---------- helpers ----------
256
+ function joinRoute(prefix, path) {
257
+ const combined = (prefix + path).replace(/\/{2,}/g, "/");
258
+ let r = combined.startsWith("/") ? combined : "/" + combined;
259
+ if (r.length > 1)
260
+ r = r.replace(/\/+$/, "/"); // keep a single trailing slash (Django convention)
261
+ return r === "" ? "/" : r;
262
+ }
263
+ function normalize(path) {
264
+ let r = path.startsWith("/") ? path : "/" + path;
265
+ r = r.replace(/\/{2,}/g, "/");
266
+ return r;
267
+ }
268
+ function titleFromRoute(route, name) {
269
+ if (route === "/")
270
+ return "Home";
271
+ const base = name ?? route.split("/").filter((s) => s && !s.startsWith("<")).pop() ?? route;
272
+ return base.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
273
+ }
274
+ /** Dotted module ("blog.urls") → resolved urls.py file key (project-relative module path). */
275
+ function modulePath(projectRoot, file) {
276
+ return relative(projectRoot, file).replace(/\.py$/, "").split(sep).join(".");
277
+ }
278
+ function walkPy(dir, onFile) {
279
+ walkExt(dir, [".py"], onFile);
280
+ }
281
+ function walkAll(dir, onFile) {
282
+ walkExt(dir, [".html", ".py"], onFile);
283
+ }
284
+ function walkExt(dir, exts, onFile) {
285
+ let entries;
286
+ try {
287
+ entries = readdirSync(dir, { withFileTypes: true });
288
+ }
289
+ catch {
290
+ return;
291
+ }
292
+ for (const entry of entries) {
293
+ if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "__pycache__")
294
+ continue;
295
+ const full = join(dir, entry.name);
296
+ if (entry.isDirectory())
297
+ walkExt(full, exts, onFile);
298
+ else if (exts.some((e) => entry.name.endsWith(e)))
299
+ onFile(full);
300
+ }
301
+ }
302
+ function safeRead(file) {
303
+ try {
304
+ return readFileSync(file, "utf8");
305
+ }
306
+ catch {
307
+ return "";
308
+ }
309
+ }
310
+ function snippet(text) {
311
+ const flat = text.replace(/\s+/g, " ").trim();
312
+ return flat.length > 80 ? flat.slice(0, 77) + "..." : flat;
313
+ }
314
+ //# sourceMappingURL=django.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"django.js","sourceRoot":"","sources":["../../../src/core/adapters/django.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { FrameworkAdapter } from "./types.js";
2
+ export declare const expoRouterAdapter: FrameworkAdapter;
@@ -0,0 +1,60 @@
1
+ import { statSync, existsSync } from "node:fs";
2
+ import { join, relative, sep } from "node:path";
3
+ import { sourceFileFor, walk, parseReactScreen, titleFromRoute, hasDependency } from "./react-jsx.js";
4
+ /**
5
+ * Expo Router adapter (React Native, file-based). Like Next's app-router but every route
6
+ * file is a screen: `app/**​/*.{tsx,jsx,ts,js}` → route, excluding layouts (`_layout`) and
7
+ * Expo's special `+`-prefixed files (`+html`, `+not-found`, `+native-intent`).
8
+ * Screen id = route; route groups `(x)` are stripped; `index` collapses to its dir.
9
+ * JSX signal extraction (incl. <Link href>, router.push, navigation.navigate) is shared.
10
+ */
11
+ const ROUTE_RE = /\.(tsx|jsx|ts|js)$/;
12
+ function appDirOf(projectRoot) {
13
+ return ([join(projectRoot, "app"), join(projectRoot, "src", "app")].find((d) => existsSync(d) && statSync(d).isDirectory()) ?? null);
14
+ }
15
+ export const expoRouterAdapter = {
16
+ id: "react-native",
17
+ router: "expo-router",
18
+ detect(projectRoot) {
19
+ return hasDependency(projectRoot, "expo-router") && appDirOf(projectRoot) !== null;
20
+ },
21
+ discover(projectRoot) {
22
+ const appDir = appDirOf(projectRoot);
23
+ if (!appDir)
24
+ return [];
25
+ const files = [];
26
+ walk(appDir, (file) => {
27
+ if (!ROUTE_RE.test(file))
28
+ return;
29
+ const base = file.slice(file.lastIndexOf(sep) + 1).replace(ROUTE_RE, "");
30
+ if (base === "_layout" || base.startsWith("+"))
31
+ return; // layouts & Expo special files
32
+ const route = routeFromAppFile(appDir, file);
33
+ files.push({
34
+ absPath: file,
35
+ relPath: relative(projectRoot, file).split(sep).join("/"),
36
+ id: route,
37
+ route,
38
+ title: titleFromRoute(route),
39
+ isEntry: route === "/", // app/index → "/"
40
+ });
41
+ });
42
+ files.sort((a, b) => a.route.localeCompare(b.route));
43
+ return files;
44
+ },
45
+ parse(file) {
46
+ return parseReactScreen(sourceFileFor(file.absPath));
47
+ },
48
+ };
49
+ /** Expo route file → route. Strips route groups `(x)`, collapses `index`, keeps dynamic `[slug]`/`[...all]`. */
50
+ function routeFromAppFile(appDir, file) {
51
+ const segs = relative(appDir, file)
52
+ .replace(ROUTE_RE, "")
53
+ .split(sep)
54
+ .filter((s) => !(s.startsWith("(") && s.endsWith(")")));
55
+ if (segs[segs.length - 1] === "index")
56
+ segs.pop();
57
+ const route = "/" + segs.join("/");
58
+ return route.length > 1 ? route.replace(/\/+$/, "") : "/";
59
+ }
60
+ //# sourceMappingURL=expo-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expo-router.js","sourceRoot":"","sources":["../../../src/core/adapters/expo-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { FrameworkAdapter } from "./types.js";
2
+ export declare const flaskAdapter: FrameworkAdapter;