@akanjs/cli 3.1.0-rc.1 → 3.1.0-rc.3
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/.build-stamp +1 -1
- package/{CodeAgent-kyprmy06.js → CodeAgent-ctk4fh2b.js} +2 -2
- package/{CodeTui-21mtze3j.js → CodeTui-mrxtrdzw.js} +1 -1
- package/TunnelShare-rj74jd6x.js +13 -0
- package/{agent.command-f3gsc1gd.js → agent.command-ncre6kwz.js} +5 -5
- package/akanCode.js +2 -2
- package/{application.command-5s780vnz.js → application.command-54mawreg.js} +52 -41
- package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-8573zr2w.js} +16 -30
- package/buildBatch.proc.js +22 -13
- package/{cloud.command-yj6xb2a7.js → cloud.command-nyemv0m3.js} +57 -65
- package/cloud.script-ht6yb203.js +23 -0
- package/{code.command-3wkn4ja5.js → code.command-spsrzg63.js} +6 -6
- package/{context.command-9jjn3gcw.js → context.command-768zv7z4.js} +16 -13
- package/context.runner-tf1b53qq.js +24 -0
- package/{guideline.command-dtczrqpf.js → guideline.command-4ycwc51q.js} +2 -2
- package/guidelines/conventions/conventions.instruction.md +28 -15
- package/guidelines/cssRule/cssRule.instruction.md +12 -6
- package/guidelines/mcpRule/mcpRule.instruction.md +27 -11
- package/guidelines/runtimeRule/runtimeRule.instruction.md +24 -15
- package/guidelines/transportRule/transportRule.instruction.md +28 -5
- package/incrementalBuilder.proc.js +9 -6
- package/{index-2etcv0sc.js → index-00seamy5.js} +1 -1
- package/{index-jx4bzvwg.js → index-1a7nhq56.js} +92 -52
- package/{index-e0cvze1s.js → index-1nyxvz8j.js} +4 -4
- package/index-2z3kykvd.js +248 -0
- package/{index-rtct7d43.js → index-3675mvjw.js} +1 -1
- package/{index-56d2g8ms.js → index-3ddt3qjg.js} +1 -1
- package/{index-6jjtnhkw.js → index-3x7yeecy.js} +51 -9
- package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
- package/index-8935h3n1.js +33 -0
- package/{index-v29746vb.js → index-8eqkxwsx.js} +3 -3
- package/{index-c2yrsxdh.js → index-91rt5bye.js} +96 -320
- package/{index-55mynnqs.js → index-bv210r6t.js} +459 -210
- package/{index-c76k723e.js → index-c4h5b5nq.js} +2 -2
- package/{index-qt22xstj.js → index-c9zjb3tw.js} +5 -3
- package/{index-c1x0be5j.js → index-dmsvd2rv.js} +2 -2
- package/index-ec080x99.js +1124 -0
- package/{index-ctanya41.js → index-fjqvd5mx.js} +4 -4
- package/{index-aprt7pkz.js → index-fvn6f5wx.js} +229 -1327
- package/{index-rc5rwyps.js → index-jj7yapwq.js} +71 -60
- package/index-kmamh5bv.js +241 -0
- package/{index-fm46xrf1.js → index-q5abh0jq.js} +3 -3
- package/{index-1w2qaee2.js → index-qf8g88j9.js} +361 -291
- package/{index-gnyf1fqy.js → index-qvghfv6v.js} +2 -2
- package/{index-ae5pwhgs.js → index-r5d6rq19.js} +10 -8
- package/{index-2mx692qq.js → index-vhfjzda3.js} +2 -2
- package/{index-8r4d7cmt.js → index-w9b71b6y.js} +4 -4
- package/{index-8ggztp8k.js → index-wanhh011.js} +42 -177
- package/{index-05g3jayg.js → index-wdze51wz.js} +1 -1
- package/index-wjqbc7sf.js +668 -0
- package/{index-rwq3ekqc.js → index-xf40a295.js} +7 -7
- package/{index-krq7btbt.js → index-xm5tmpv0.js} +3 -3
- package/index.js +22 -22
- package/{library.command-gaga5bmq.js → library.command-88ahgych.js} +3 -3
- package/{localRegistry.command-vsreyy42.js → localRegistry.command-ykea1m7b.js} +12 -9
- package/{module.command-7vpf6db4.js → module.command-zky4b7m9.js} +5 -5
- package/{package.command-twmvvf69.js → package.command-vh8pcedh.js} +3 -3
- package/package.json +2 -2
- package/{page.command-5asq7fdf.js → page.command-fyqeqxc3.js} +3 -3
- package/{pipeline.command-d0v38572.js → pipeline.command-r5t30py6.js} +220 -219
- package/{primitive.command-dyrs2fm8.js → primitive.command-a0516zfk.js} +6 -6
- package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-7djd4z50.js} +1 -1
- package/{quality.command-6emsqpbg.js → quality.command-k7jcnfn0.js} +2 -2
- package/{repair.command-8t6aegv5.js → repair.command-85zg2an3.js} +5 -5
- package/{scalar.command-bnggy1x7.js → scalar.command-g5vmqwca.js} +4 -4
- package/{subspace.command-md2teygq.js → subspace.command-mp4evgsj.js} +421 -362
- package/{tunnel.command-jx3tdm2d.js → tunnel.command-kbnr99sj.js} +7 -4
- package/{workflow.command-jx0wag5r.js → workflow.command-9y9p1n8y.js} +10 -10
- package/{workspace.command-yxd7rr7g.js → workspace.command-jmec2kjg.js} +33 -30
- package/TunnelShare-q4jq08qg.js +0 -9
- package/cloud.script-h6pvcpa2.js +0 -20
- package/context.runner-atcrzz5b.js +0 -21
- package/index-6w0rbr9d.js +0 -68
- package/index-pgj2rt78.js +0 -404
|
@@ -3,13 +3,27 @@ import {
|
|
|
3
3
|
SOURCE_EXTS,
|
|
4
4
|
WatchRootResolver
|
|
5
5
|
} from "./index-k9rrten6.js";
|
|
6
|
+
import {
|
|
7
|
+
bundleDefine,
|
|
8
|
+
CsrEntryFiles,
|
|
9
|
+
loaderFor,
|
|
10
|
+
BarrelAnalyzer,
|
|
11
|
+
createBarrelImportsPlugin,
|
|
12
|
+
createTsconfigPackageResolver,
|
|
13
|
+
rewriteBarrelImports,
|
|
14
|
+
toClientReferencePath,
|
|
15
|
+
scanUseClientExports,
|
|
16
|
+
CsrDevPaths,
|
|
17
|
+
PagesEntrySourceGenerator,
|
|
18
|
+
PagesBundleBuilder
|
|
19
|
+
} from "./index-ec080x99.js";
|
|
6
20
|
import {
|
|
7
21
|
FileSys2
|
|
8
22
|
} from "./index-52w0fvh8.js";
|
|
9
23
|
import {
|
|
10
24
|
AsyncDefaultExportDetector,
|
|
11
25
|
resolveSsrPageEntriesForApp
|
|
12
|
-
} from "./index-
|
|
26
|
+
} from "./index-bv210r6t.js";
|
|
13
27
|
|
|
14
28
|
// pkgs/@akanjs/devkit/artifact/routeSeedIndex.ts
|
|
15
29
|
import path from "path";
|
|
@@ -80,525 +94,12 @@ function serializeArtifactPath(artifactPath, artifactDir) {
|
|
|
80
94
|
|
|
81
95
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntryDiscovery.ts
|
|
82
96
|
import fs from "fs";
|
|
83
|
-
import path4 from "path";
|
|
84
|
-
|
|
85
|
-
// pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
|
|
86
97
|
import path2 from "path";
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// pkgs/@akanjs/devkit/transforms/moduleSyntax.ts
|
|
90
|
-
var loaderFor = (absPath) => {
|
|
91
|
-
if (absPath.endsWith(".tsx"))
|
|
92
|
-
return "tsx";
|
|
93
|
-
if (absPath.endsWith(".jsx"))
|
|
94
|
-
return "jsx";
|
|
95
|
-
if (absPath.endsWith(".ts"))
|
|
96
|
-
return "ts";
|
|
97
|
-
return "js";
|
|
98
|
-
};
|
|
99
|
-
var parseNamedList = (listBody) => {
|
|
100
|
-
const out = [];
|
|
101
|
-
for (const raw of listBody.split(",")) {
|
|
102
|
-
let rest = raw.trim();
|
|
103
|
-
if (!rest)
|
|
104
|
-
continue;
|
|
105
|
-
let isType = false;
|
|
106
|
-
if (rest.startsWith("type ")) {
|
|
107
|
-
isType = true;
|
|
108
|
-
rest = rest.slice(5).trim();
|
|
109
|
-
}
|
|
110
|
-
const asMatch = /^(\w+)\s+as\s+(\w+)$/.exec(rest);
|
|
111
|
-
if (asMatch) {
|
|
112
|
-
out.push({ imported: asMatch[1] ?? "", local: asMatch[2] ?? "", isType });
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
if (/^\w+$/.test(rest))
|
|
116
|
-
out.push({ imported: rest, local: rest, isType });
|
|
117
|
-
}
|
|
118
|
-
return out;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
|
|
122
|
-
var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
|
|
123
|
-
var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
|
|
124
|
-
var CANDIDATE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
125
|
-
|
|
126
|
-
class BarrelAnalyzer {
|
|
127
|
-
#logger = new Logger("BarrelAnalyzer");
|
|
128
|
-
#opts;
|
|
129
|
-
#cache = new Map;
|
|
130
|
-
#tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
131
|
-
#tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
|
|
132
|
-
constructor(opts) {
|
|
133
|
-
this.#opts = opts;
|
|
134
|
-
}
|
|
135
|
-
analyze(pkgName) {
|
|
136
|
-
const cached = this.#cache.get(pkgName);
|
|
137
|
-
if (cached)
|
|
138
|
-
return cached;
|
|
139
|
-
const promise = this.#analyzeSafe(pkgName);
|
|
140
|
-
this.#cache.set(pkgName, promise);
|
|
141
|
-
return promise;
|
|
142
|
-
}
|
|
143
|
-
async#analyzeSafe(pkgName) {
|
|
144
|
-
try {
|
|
145
|
-
const pkg = await this.#opts.resolvePackage(pkgName);
|
|
146
|
-
if (!pkg)
|
|
147
|
-
return null;
|
|
148
|
-
const map = new Map;
|
|
149
|
-
await this.#walk(pkg.entryFile, pkg, map, new Set);
|
|
150
|
-
return map;
|
|
151
|
-
} catch (err) {
|
|
152
|
-
this.#logger.error(`analyze failed for ${pkgName}: ${err.message}`);
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
async#walk(absFile, pkg, map, visited) {
|
|
157
|
-
if (visited.has(absFile))
|
|
158
|
-
return;
|
|
159
|
-
visited.add(absFile);
|
|
160
|
-
const file = Bun.file(absFile);
|
|
161
|
-
if (!await file.exists())
|
|
162
|
-
return;
|
|
163
|
-
const source = await file.text();
|
|
164
|
-
const currentSubpath = this.#subpathFor(pkg, absFile);
|
|
165
|
-
if (!currentSubpath)
|
|
166
|
-
return;
|
|
167
|
-
const authoritative = this.#scanExports(source, absFile);
|
|
168
|
-
authoritative.delete("default");
|
|
169
|
-
const attributed = new Set;
|
|
170
|
-
const attribute = (listBody, subpath) => {
|
|
171
|
-
for (const item of parseNamedList(listBody)) {
|
|
172
|
-
if (item.isType || item.imported === "default" || !authoritative.has(item.local))
|
|
173
|
-
continue;
|
|
174
|
-
attributed.add(item.local);
|
|
175
|
-
if (!map.has(item.local))
|
|
176
|
-
map.set(item.local, { subpath, originalName: item.imported });
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
const starSpecs = [];
|
|
180
|
-
for (const m of source.matchAll(REEXPORT_RE)) {
|
|
181
|
-
const star = m[1];
|
|
182
|
-
const nsAs = m[2];
|
|
183
|
-
const namedList = m[3];
|
|
184
|
-
const spec = m[5] ?? "";
|
|
185
|
-
if (!isRelative(spec))
|
|
186
|
-
continue;
|
|
187
|
-
if (star) {
|
|
188
|
-
if (nsAs)
|
|
189
|
-
authoritative.delete(nsAs);
|
|
190
|
-
else
|
|
191
|
-
starSpecs.push(spec);
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
if (namedList !== undefined) {
|
|
195
|
-
const targetAbs = await this.#resolveRel(absFile, spec);
|
|
196
|
-
if (!targetAbs)
|
|
197
|
-
continue;
|
|
198
|
-
const targetSubpath = this.#subpathFor(pkg, targetAbs);
|
|
199
|
-
if (targetSubpath)
|
|
200
|
-
attribute(namedList, targetSubpath);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
LOCAL_NAMED_RE.lastIndex = 0;
|
|
204
|
-
let n = LOCAL_NAMED_RE.exec(source);
|
|
205
|
-
while (n !== null) {
|
|
206
|
-
const body = n[1] ?? "";
|
|
207
|
-
n = LOCAL_NAMED_RE.exec(source);
|
|
208
|
-
attribute(body, currentSubpath);
|
|
209
|
-
}
|
|
210
|
-
for (const name of authoritative) {
|
|
211
|
-
if (attributed.has(name))
|
|
212
|
-
continue;
|
|
213
|
-
if (map.has(name))
|
|
214
|
-
continue;
|
|
215
|
-
map.set(name, { subpath: currentSubpath, originalName: name });
|
|
216
|
-
}
|
|
217
|
-
for (const spec of starSpecs) {
|
|
218
|
-
const targetAbs = await this.#resolveRel(absFile, spec);
|
|
219
|
-
if (targetAbs)
|
|
220
|
-
await this.#walk(targetAbs, pkg, map, visited);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
#scanExports(source, absFile) {
|
|
224
|
-
try {
|
|
225
|
-
const transpiler = [".tsx", ".jsx"].includes(path2.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
|
|
226
|
-
const { exports } = transpiler.scan(source);
|
|
227
|
-
return new Set(exports);
|
|
228
|
-
} catch (err) {
|
|
229
|
-
this.#logger.error(`scan failed: ${err.message}`);
|
|
230
|
-
return new Set;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
#subpathFor(pkg, absFile) {
|
|
234
|
-
const rel = path2.relative(pkg.pkgDir, absFile);
|
|
235
|
-
if (!rel || rel.startsWith("..") || path2.isAbsolute(rel))
|
|
236
|
-
return null;
|
|
237
|
-
if (pkg.preserveFilePath)
|
|
238
|
-
return `${pkg.pkgName}/${rel.split(path2.sep).join("/")}`;
|
|
239
|
-
const ext = CANDIDATE_EXTS.find((candidate) => rel.endsWith(candidate));
|
|
240
|
-
const parts = (ext ? rel.slice(0, -ext.length) : rel).split(path2.sep);
|
|
241
|
-
if (parts[parts.length - 1] === "index")
|
|
242
|
-
parts.pop();
|
|
243
|
-
const tail = parts.join("/");
|
|
244
|
-
return tail === "" ? pkg.pkgName : `${pkg.pkgName}/${tail}`;
|
|
245
|
-
}
|
|
246
|
-
async#resolveRel(fromFile, relSpec) {
|
|
247
|
-
if (this.#opts.resolveRelative)
|
|
248
|
-
return this.#opts.resolveRelative(fromFile, relSpec);
|
|
249
|
-
return defaultResolveRelative(fromFile, relSpec);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
var isRelative = (spec) => {
|
|
253
|
-
return spec.startsWith("./") || spec.startsWith("../") || spec === "." || spec === "..";
|
|
254
|
-
};
|
|
255
|
-
var defaultResolveRelative = async (fromFile, relSpec) => {
|
|
256
|
-
const baseDir = path2.dirname(fromFile);
|
|
257
|
-
const joined = path2.resolve(baseDir, relSpec);
|
|
258
|
-
if (path2.extname(joined)) {
|
|
259
|
-
if (await Bun.file(joined).exists())
|
|
260
|
-
return joined;
|
|
261
|
-
return null;
|
|
262
|
-
}
|
|
263
|
-
for (const ext of CANDIDATE_EXTS) {
|
|
264
|
-
const cand = joined + ext;
|
|
265
|
-
if (await Bun.file(cand).exists())
|
|
266
|
-
return cand;
|
|
267
|
-
}
|
|
268
|
-
for (const ext of CANDIDATE_EXTS) {
|
|
269
|
-
const cand = path2.join(joined, `index${ext}`);
|
|
270
|
-
if (await Bun.file(cand).exists())
|
|
271
|
-
return cand;
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
// pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
|
|
277
|
-
import path3 from "path";
|
|
278
|
-
import ts from "typescript";
|
|
279
|
-
var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
|
|
280
|
-
const akanConfig = await app.getConfig();
|
|
281
|
-
const barrels = [...new Set(akanConfig.barrelImports)].filter(Boolean);
|
|
282
|
-
const analyzer = new BarrelAnalyzer({
|
|
283
|
-
resolvePackage: await createTsconfigPackageResolver(app)
|
|
284
|
-
});
|
|
285
|
-
return {
|
|
286
|
-
name: "barrel-imports",
|
|
287
|
-
setup(build) {
|
|
288
|
-
build.onLoad({
|
|
289
|
-
filter: /^(?:(?!.*[\\/]node_modules[\\/]).*|.*[\\/]node_modules[\\/]akanjs[\\/].*)\.(tsx|ts|jsx|js)(\?v=\d+)?$/
|
|
290
|
-
}, async (args) => {
|
|
291
|
-
const realPath = args.path.replace(/\?v=\d+$/, "");
|
|
292
|
-
const loader = loaderFor(realPath);
|
|
293
|
-
let source = await Bun.file(realPath).text();
|
|
294
|
-
if (skipPath(realPath))
|
|
295
|
-
return { contents: source, loader };
|
|
296
|
-
if (!MACRO_ATTR_RE.test(source) && barrels.length > 0) {
|
|
297
|
-
const rewritten = await rewriteBarrelImports(source, barrels, analyzer);
|
|
298
|
-
if (rewritten !== null)
|
|
299
|
-
source = rewritten;
|
|
300
|
-
}
|
|
301
|
-
if (pipeAfter) {
|
|
302
|
-
const piped = await pipeAfter(source, { path: realPath });
|
|
303
|
-
if (piped !== null)
|
|
304
|
-
source = piped;
|
|
305
|
-
}
|
|
306
|
-
return { contents: source, loader };
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
};
|
|
311
|
-
var createTsconfigPackageResolver = async (app) => {
|
|
312
|
-
const tsconfig = await app.getTsConfig();
|
|
313
|
-
const tsconfigPaths = tsconfig.compilerOptions.paths ?? {};
|
|
314
|
-
const wildcardEntries = Object.entries(tsconfigPaths).filter(([k]) => k.endsWith("/*")).map(([k, v]) => ({ prefix: k.slice(0, -1), replacements: v })).sort((a, b) => b.prefix.length - a.prefix.length);
|
|
315
|
-
return async (pkgName) => {
|
|
316
|
-
const exact = tsconfigPaths[pkgName];
|
|
317
|
-
if (exact && exact.length > 0) {
|
|
318
|
-
const raw = exact[0];
|
|
319
|
-
if (!raw)
|
|
320
|
-
return null;
|
|
321
|
-
const entryFile = path3.resolve(app.workspace.workspaceRoot, raw);
|
|
322
|
-
if (!await Bun.file(entryFile).exists())
|
|
323
|
-
return null;
|
|
324
|
-
const parsed = path3.parse(entryFile);
|
|
325
|
-
const lastSlash = pkgName.lastIndexOf("/");
|
|
326
|
-
if (parsed.name !== "index" && lastSlash > 0 && pkgName.slice(lastSlash + 1) === parsed.name)
|
|
327
|
-
return { pkgName: pkgName.slice(0, lastSlash), entryFile, pkgDir: parsed.dir };
|
|
328
|
-
return { pkgName, entryFile, pkgDir: path3.dirname(entryFile) };
|
|
329
|
-
}
|
|
330
|
-
for (const { prefix, replacements } of wildcardEntries) {
|
|
331
|
-
if (!pkgName.startsWith(prefix))
|
|
332
|
-
continue;
|
|
333
|
-
const suffix = pkgName.slice(prefix.length);
|
|
334
|
-
for (const repl of replacements) {
|
|
335
|
-
if (!repl)
|
|
336
|
-
continue;
|
|
337
|
-
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
338
|
-
const candidate = path3.resolve(app.workspace.workspaceRoot, replPath + suffix);
|
|
339
|
-
for (const ext of CANDIDATE_EXTS2) {
|
|
340
|
-
const file = `${candidate}${ext}`;
|
|
341
|
-
if (await Bun.file(file).exists()) {
|
|
342
|
-
const lastSlash = pkgName.lastIndexOf("/");
|
|
343
|
-
const parentSpec = lastSlash > 0 ? pkgName.slice(0, lastSlash) : pkgName;
|
|
344
|
-
return { pkgName: parentSpec, entryFile: file, pkgDir: path3.dirname(file) };
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
for (const ext of CANDIDATE_EXTS2) {
|
|
348
|
-
const file = path3.join(candidate, `index${ext}`);
|
|
349
|
-
if (await Bun.file(file).exists())
|
|
350
|
-
return { pkgName, entryFile: file, pkgDir: candidate };
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
|
|
356
|
-
if (exported)
|
|
357
|
-
return exported;
|
|
358
|
-
const pkgJsonPath = path3.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
|
|
359
|
-
if (!await Bun.file(pkgJsonPath).exists())
|
|
360
|
-
return null;
|
|
361
|
-
try {
|
|
362
|
-
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
363
|
-
const rel = pkgJson.module ?? pkgJson.main ?? "index.js";
|
|
364
|
-
const entryFile = path3.resolve(path3.dirname(pkgJsonPath), rel);
|
|
365
|
-
if (!await Bun.file(entryFile).exists())
|
|
366
|
-
return null;
|
|
367
|
-
return { pkgName, entryFile, pkgDir: path3.dirname(pkgJsonPath) };
|
|
368
|
-
} catch {
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
};
|
|
373
|
-
var CANDIDATE_EXTS2 = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
98
|
+
var USE_CLIENT_RE = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
374
99
|
var NODE_MODULES_RE = /[\\/]node_modules[\\/]/;
|
|
375
100
|
var AKANJS_NODE_MODULE_RE = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
376
|
-
var defaultSkipPath = (absPath) => NODE_MODULES_RE.test(absPath) && !AKANJS_NODE_MODULE_RE.test(absPath);
|
|
377
|
-
var resolveNodePackageExport = async (workspaceRoot, specifier) => {
|
|
378
|
-
const packageName = getPackageName(specifier);
|
|
379
|
-
if (!packageName)
|
|
380
|
-
return null;
|
|
381
|
-
const pkgJsonPath = path3.join(workspaceRoot, "node_modules", packageName, "package.json");
|
|
382
|
-
if (!await Bun.file(pkgJsonPath).exists())
|
|
383
|
-
return null;
|
|
384
|
-
try {
|
|
385
|
-
const pkgDir = path3.dirname(pkgJsonPath);
|
|
386
|
-
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
387
|
-
const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
|
|
388
|
-
const exported = resolvePackageExport(pkgJson.exports, subpath);
|
|
389
|
-
const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
|
|
390
|
-
if (!rel?.startsWith("."))
|
|
391
|
-
return null;
|
|
392
|
-
const entryFile = await resolveFileCandidate(path3.resolve(pkgDir, rel));
|
|
393
|
-
if (!entryFile)
|
|
394
|
-
return null;
|
|
395
|
-
return { pkgName: specifier, entryFile, pkgDir: path3.dirname(entryFile), preserveFilePath: true };
|
|
396
|
-
} catch {
|
|
397
|
-
return null;
|
|
398
|
-
}
|
|
399
|
-
};
|
|
400
|
-
var resolveExportValue = (value) => {
|
|
401
|
-
if (!value)
|
|
402
|
-
return null;
|
|
403
|
-
if (typeof value === "string")
|
|
404
|
-
return value;
|
|
405
|
-
if (Array.isArray(value)) {
|
|
406
|
-
for (const item of value) {
|
|
407
|
-
const resolved = resolveExportValue(item);
|
|
408
|
-
if (resolved)
|
|
409
|
-
return resolved;
|
|
410
|
-
}
|
|
411
|
-
return null;
|
|
412
|
-
}
|
|
413
|
-
for (const condition of ["source", "import", "default", "types"]) {
|
|
414
|
-
const resolved = resolveExportValue(value[condition]);
|
|
415
|
-
if (resolved)
|
|
416
|
-
return resolved;
|
|
417
|
-
}
|
|
418
|
-
return null;
|
|
419
|
-
};
|
|
420
|
-
var resolvePackageExport = (exportsMap, subpath) => {
|
|
421
|
-
if (!exportsMap)
|
|
422
|
-
return null;
|
|
423
|
-
const exact = resolveExportValue(exportsMap[subpath]);
|
|
424
|
-
if (exact)
|
|
425
|
-
return exact;
|
|
426
|
-
for (const [key, value] of Object.entries(exportsMap)) {
|
|
427
|
-
const starIdx = key.indexOf("*");
|
|
428
|
-
if (starIdx === -1)
|
|
429
|
-
continue;
|
|
430
|
-
const prefix = key.slice(0, starIdx);
|
|
431
|
-
const suffix = key.slice(starIdx + 1);
|
|
432
|
-
if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix))
|
|
433
|
-
continue;
|
|
434
|
-
const wildcard = subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
435
|
-
const resolved = resolveExportValue(value);
|
|
436
|
-
if (resolved)
|
|
437
|
-
return resolved.replace("*", wildcard);
|
|
438
|
-
}
|
|
439
|
-
return null;
|
|
440
|
-
};
|
|
441
|
-
var getPackageName = (specifier) => {
|
|
442
|
-
const parts = specifier.split("/");
|
|
443
|
-
if (!parts[0])
|
|
444
|
-
return null;
|
|
445
|
-
if (specifier.startsWith("@"))
|
|
446
|
-
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
|
|
447
|
-
return parts[0];
|
|
448
|
-
};
|
|
449
|
-
var resolveFileCandidate = async (candidate) => {
|
|
450
|
-
if (await Bun.file(candidate).exists())
|
|
451
|
-
return candidate;
|
|
452
|
-
if (path3.extname(candidate))
|
|
453
|
-
return null;
|
|
454
|
-
for (const ext of CANDIDATE_EXTS2) {
|
|
455
|
-
const file = `${candidate}${ext}`;
|
|
456
|
-
if (await Bun.file(file).exists())
|
|
457
|
-
return file;
|
|
458
|
-
}
|
|
459
|
-
for (const ext of CANDIDATE_EXTS2) {
|
|
460
|
-
const file = path3.join(candidate, `index${ext}`);
|
|
461
|
-
if (await Bun.file(file).exists())
|
|
462
|
-
return file;
|
|
463
|
-
}
|
|
464
|
-
return null;
|
|
465
|
-
};
|
|
466
|
-
var MACRO_ATTR_RE = /with\s*\{\s*type\s*:\s*["']macro["']\s*\}/;
|
|
467
|
-
var rewriteBarrelImports = async (source, barrels, analyzer) => {
|
|
468
|
-
if (!barrels.some((barrel) => source.includes(barrel)))
|
|
469
|
-
return null;
|
|
470
|
-
const statements = findImportStatements(source);
|
|
471
|
-
if (statements.length === 0)
|
|
472
|
-
return null;
|
|
473
|
-
let changed = false;
|
|
474
|
-
let out = source;
|
|
475
|
-
for (let i = statements.length - 1;i >= 0; i--) {
|
|
476
|
-
const stmt = statements[i];
|
|
477
|
-
if (!stmt)
|
|
478
|
-
continue;
|
|
479
|
-
if (!barrels.includes(stmt.specifier))
|
|
480
|
-
continue;
|
|
481
|
-
const map = await analyzer.analyze(stmt.specifier);
|
|
482
|
-
if (!map || map.size === 0)
|
|
483
|
-
continue;
|
|
484
|
-
const replacement = rewriteSingleStatement(stmt, map);
|
|
485
|
-
if (replacement === null)
|
|
486
|
-
continue;
|
|
487
|
-
out = out.slice(0, stmt.start) + replacement + out.slice(stmt.end);
|
|
488
|
-
changed = true;
|
|
489
|
-
}
|
|
490
|
-
return changed ? out : null;
|
|
491
|
-
};
|
|
492
|
-
var findImportStatements = (source) => {
|
|
493
|
-
const statements = [];
|
|
494
|
-
const sourceFile = ts.createSourceFile("barrel-imports.tsx", source, ts.ScriptTarget.Latest, false, ts.ScriptKind.TSX);
|
|
495
|
-
for (const statement of sourceFile.statements) {
|
|
496
|
-
if (!ts.isImportDeclaration(statement))
|
|
497
|
-
continue;
|
|
498
|
-
if (!ts.isStringLiteral(statement.moduleSpecifier))
|
|
499
|
-
continue;
|
|
500
|
-
const importClause = statement.importClause;
|
|
501
|
-
if (!importClause)
|
|
502
|
-
continue;
|
|
503
|
-
statements.push({
|
|
504
|
-
start: statement.getStart(sourceFile),
|
|
505
|
-
end: statement.end,
|
|
506
|
-
clause: source.slice(importClause.getStart(sourceFile), importClause.end).trim(),
|
|
507
|
-
specifier: statement.moduleSpecifier.text
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
return statements;
|
|
511
|
-
};
|
|
512
|
-
var parseImportClause = (clause) => {
|
|
513
|
-
let rest = clause.trim();
|
|
514
|
-
let typeOnly = false;
|
|
515
|
-
if (rest.startsWith("type ")) {
|
|
516
|
-
typeOnly = true;
|
|
517
|
-
rest = rest.slice(5).trim();
|
|
518
|
-
}
|
|
519
|
-
const parsed = { typeOnly };
|
|
520
|
-
const commaMatch = /^(\w+)\s*,\s*(.+)$/.exec(rest);
|
|
521
|
-
if (commaMatch) {
|
|
522
|
-
parsed.defaultImport = commaMatch[1];
|
|
523
|
-
rest = commaMatch[2] ?? "";
|
|
524
|
-
} else if (/^\w+$/.test(rest)) {
|
|
525
|
-
parsed.defaultImport = rest;
|
|
526
|
-
return parsed;
|
|
527
|
-
}
|
|
528
|
-
if (rest.startsWith("*")) {
|
|
529
|
-
const ns = /^\*\s+as\s+(\w+)$/.exec(rest);
|
|
530
|
-
if (!ns)
|
|
531
|
-
return null;
|
|
532
|
-
parsed.namespaceImport = ns[1];
|
|
533
|
-
return parsed;
|
|
534
|
-
}
|
|
535
|
-
if (rest.startsWith("{")) {
|
|
536
|
-
const close = rest.indexOf("}");
|
|
537
|
-
if (close === -1)
|
|
538
|
-
return null;
|
|
539
|
-
parsed.named = parseNamedList(rest.slice(1, close));
|
|
540
|
-
}
|
|
541
|
-
return parsed;
|
|
542
|
-
};
|
|
543
|
-
var rewriteSingleStatement = (stmt, map) => {
|
|
544
|
-
const clause = parseImportClause(stmt.clause);
|
|
545
|
-
if (!clause)
|
|
546
|
-
return null;
|
|
547
|
-
if (clause.namespaceImport)
|
|
548
|
-
return null;
|
|
549
|
-
if (clause.typeOnly && !clause.defaultImport)
|
|
550
|
-
return null;
|
|
551
|
-
if (!clause.named?.length)
|
|
552
|
-
return null;
|
|
553
|
-
const remaining = [];
|
|
554
|
-
const rewrites = new Map;
|
|
555
|
-
for (const item of clause.named) {
|
|
556
|
-
if (item.isType) {
|
|
557
|
-
remaining.push(item);
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
const target = map.get(item.imported);
|
|
561
|
-
if (!target) {
|
|
562
|
-
remaining.push(item);
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
const list = rewrites.get(target.subpath) ?? [];
|
|
566
|
-
list.push({ imported: target.originalName, local: item.local, isType: false });
|
|
567
|
-
rewrites.set(target.subpath, list);
|
|
568
|
-
}
|
|
569
|
-
if (rewrites.size === 0)
|
|
570
|
-
return null;
|
|
571
|
-
const lines = [];
|
|
572
|
-
if (shouldPreserveBarrelSideEffects(stmt.specifier))
|
|
573
|
-
lines.push(`import "${stmt.specifier}";`);
|
|
574
|
-
if (clause.defaultImport || remaining.length > 0) {
|
|
575
|
-
const parts = [];
|
|
576
|
-
if (clause.defaultImport)
|
|
577
|
-
parts.push(clause.defaultImport);
|
|
578
|
-
if (remaining.length > 0)
|
|
579
|
-
parts.push(`{ ${remaining.map(serializeNamedItem).join(", ")} }`);
|
|
580
|
-
lines.push(`import ${parts.join(", ")} from "${stmt.specifier}";`);
|
|
581
|
-
}
|
|
582
|
-
for (const [subpath, items] of rewrites) {
|
|
583
|
-
lines.push(`import { ${items.map(serializeNamedItem).join(", ")} } from "${subpath}";`);
|
|
584
|
-
}
|
|
585
|
-
return lines.join(`
|
|
586
|
-
`);
|
|
587
|
-
};
|
|
588
|
-
var shouldPreserveBarrelSideEffects = (specifier) => /^@(apps|libs)\/[^/]+\/client$/.test(specifier);
|
|
589
|
-
var serializeNamedItem = (item) => {
|
|
590
|
-
const prefix = item.isType ? "type " : "";
|
|
591
|
-
if (item.imported === item.local)
|
|
592
|
-
return `${prefix}${item.imported}`;
|
|
593
|
-
return `${prefix}${item.imported} as ${item.local}`;
|
|
594
|
-
};
|
|
595
|
-
|
|
596
|
-
// pkgs/@akanjs/devkit/frontendBuild/clientEntryDiscovery.ts
|
|
597
|
-
var USE_CLIENT_RE = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
598
|
-
var NODE_MODULES_RE2 = /[\\/]node_modules[\\/]/;
|
|
599
|
-
var AKANJS_NODE_MODULE_RE2 = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
600
101
|
var NON_SOURCE_EXT_RE = /\.(css|scss|sass|less|json|svg|png|jpe?g|webp|gif|avif|ico|woff2?|ttf|otf|mp3|mp4|wav)$/i;
|
|
601
|
-
var shouldSkipNodeModule = (absPath) =>
|
|
102
|
+
var shouldSkipNodeModule = (absPath) => NODE_MODULES_RE.test(absPath) && !AKANJS_NODE_MODULE_RE.test(absPath);
|
|
602
103
|
|
|
603
104
|
class GraphClientEntryDiscovery {
|
|
604
105
|
#akanConfig;
|
|
@@ -634,7 +135,7 @@ class GraphClientEntryDiscovery {
|
|
|
634
135
|
return;
|
|
635
136
|
let moved = false;
|
|
636
137
|
for (const file of files) {
|
|
637
|
-
const absPath =
|
|
138
|
+
const absPath = path2.resolve(file);
|
|
638
139
|
const exists = fs.existsSync(absPath);
|
|
639
140
|
if (exists !== this.#readFiles.has(absPath))
|
|
640
141
|
moved = true;
|
|
@@ -665,11 +166,11 @@ class GraphClientEntryDiscovery {
|
|
|
665
166
|
return entry.promise;
|
|
666
167
|
}
|
|
667
168
|
async#fileExists(p) {
|
|
668
|
-
const absPath =
|
|
169
|
+
const absPath = path2.resolve(p);
|
|
669
170
|
return await this.#lookup(this.#fileExistsCache, absPath, () => Bun.file(absPath).exists(), (exists) => exists);
|
|
670
171
|
}
|
|
671
172
|
#facts(file) {
|
|
672
|
-
const absPath =
|
|
173
|
+
const absPath = path2.resolve(file);
|
|
673
174
|
let cached = this.#factsCache.get(absPath);
|
|
674
175
|
if (!cached) {
|
|
675
176
|
cached = (async () => {
|
|
@@ -702,7 +203,7 @@ class GraphClientEntryDiscovery {
|
|
|
702
203
|
}
|
|
703
204
|
}
|
|
704
205
|
async#resolveFileCandidate(absPathNoExt) {
|
|
705
|
-
const cacheKey =
|
|
206
|
+
const cacheKey = path2.resolve(absPathNoExt);
|
|
706
207
|
return await this.#lookup(this.#resolvedFileCache, cacheKey, async () => {
|
|
707
208
|
if (await this.#fileExists(cacheKey))
|
|
708
209
|
return cacheKey;
|
|
@@ -712,7 +213,7 @@ class GraphClientEntryDiscovery {
|
|
|
712
213
|
return f;
|
|
713
214
|
}
|
|
714
215
|
for (const ext of SOURCE_EXTS) {
|
|
715
|
-
const f =
|
|
216
|
+
const f = path2.join(cacheKey, `index${ext}`);
|
|
716
217
|
if (await this.#fileExists(f))
|
|
717
218
|
return f;
|
|
718
219
|
}
|
|
@@ -723,7 +224,7 @@ class GraphClientEntryDiscovery {
|
|
|
723
224
|
const cacheKey = `${importerDir}\x00${spec}`;
|
|
724
225
|
return await this.#lookup(this.#resolvedSpecifierCache, cacheKey, async () => {
|
|
725
226
|
if (spec.startsWith(".") || spec.startsWith("/")) {
|
|
726
|
-
const abs = spec.startsWith("/") ? spec :
|
|
227
|
+
const abs = spec.startsWith("/") ? spec : path2.resolve(importerDir, spec);
|
|
727
228
|
return await this.#resolveFileCandidate(abs);
|
|
728
229
|
}
|
|
729
230
|
const pkg = await this.#resolvePackage(spec);
|
|
@@ -732,7 +233,7 @@ class GraphClientEntryDiscovery {
|
|
|
732
233
|
}
|
|
733
234
|
async#discoverFromFile(file, walk) {
|
|
734
235
|
const epoch = this.#epoch;
|
|
735
|
-
const absPath =
|
|
236
|
+
const absPath = path2.resolve(file);
|
|
736
237
|
const cached = this.#reachableEntriesCache.get(absPath);
|
|
737
238
|
if (cached)
|
|
738
239
|
return new Set(cached);
|
|
@@ -764,7 +265,7 @@ class GraphClientEntryDiscovery {
|
|
|
764
265
|
entries.add(absPath);
|
|
765
266
|
return this.#finishDiscovery(absPath, walk, entries, epoch);
|
|
766
267
|
}
|
|
767
|
-
const importerDir =
|
|
268
|
+
const importerDir = path2.dirname(absPath);
|
|
768
269
|
for (const imp of facts.imports) {
|
|
769
270
|
const spec = imp.path;
|
|
770
271
|
if (!spec)
|
|
@@ -792,66 +293,12 @@ class GraphClientEntryDiscovery {
|
|
|
792
293
|
|
|
793
294
|
// pkgs/@akanjs/devkit/frontendBuild/routeClientBuilder.ts
|
|
794
295
|
import { mkdir } from "fs/promises";
|
|
795
|
-
import
|
|
296
|
+
import path4 from "path";
|
|
796
297
|
import { SSR_DEV_CHUNK, SSR_DEV_ID_PREFIX } from "akanjs/server/hmr/csrDevManifest";
|
|
797
298
|
|
|
798
|
-
// pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
|
|
799
|
-
import path5 from "path";
|
|
800
|
-
import ts2 from "typescript";
|
|
801
|
-
var USE_CLIENT_RE2 = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
802
|
-
var IMPLICIT_ROOT_LAYOUT_RE = /[/\\]\.akan[/\\]generated[/\\](?:implicit-root-layout|root-layouts[/\\].*__root_layout)\.(tsx|ts|jsx|js)$/;
|
|
803
|
-
var STAR_REEXPORT_HINT_RE = /\bexport\s*\*\s*from\b/;
|
|
804
|
-
var hasUseClientDirective = (source) => USE_CLIENT_RE2.test(source);
|
|
805
|
-
function toClientReferencePath(absPath, workspaceRoot) {
|
|
806
|
-
return path5.relative(path5.resolve(workspaceRoot), path5.resolve(absPath)).split(path5.sep).join("/");
|
|
807
|
-
}
|
|
808
|
-
var starReexportSpecifiers = (source, filePath) => ts2.createSourceFile(filePath, source, ts2.ScriptTarget.Latest).statements.filter((statement) => ts2.isExportDeclaration(statement) && !statement.exportClause && !statement.isTypeOnly && !!statement.moduleSpecifier && ts2.isStringLiteral(statement.moduleSpecifier)).map((statement) => statement.moduleSpecifier.text);
|
|
809
|
-
var scanUseClientExports = (source, filePath, workspaceRoot) => {
|
|
810
|
-
const stars = USE_CLIENT_RE2.test(source) && STAR_REEXPORT_HINT_RE.test(source) ? starReexportSpecifiers(source, filePath) : [];
|
|
811
|
-
if (stars.length) {
|
|
812
|
-
const file = workspaceRoot ? toClientReferencePath(filePath, workspaceRoot) : filePath;
|
|
813
|
-
const listed = stars.slice(0, 3).map((specifier) => `\`export * from ${JSON.stringify(specifier)}\``);
|
|
814
|
-
const written = stars.length > 3 ? `${listed.join(", ")} (and ${stars.length - 3} more)` : listed.join(", ");
|
|
815
|
-
throw new Error(`${file} is a "use client" module, so it cannot ${written}: the server sees only the names a client module ` + `declares, and a star re-export declares none. Re-export them by name \u2014 \`export { \u2026 } from ${JSON.stringify(stars[0])}\`.`);
|
|
816
|
-
}
|
|
817
|
-
return new Bun.Transpiler({ loader: loaderFor(filePath) }).scan(source).exports;
|
|
818
|
-
};
|
|
819
|
-
function transformUseClient(source, args) {
|
|
820
|
-
if (!USE_CLIENT_RE2.test(source))
|
|
821
|
-
return null;
|
|
822
|
-
if (IMPLICIT_ROOT_LAYOUT_RE.test(args.path))
|
|
823
|
-
return null;
|
|
824
|
-
const exports = scanUseClientExports(source, args.path, args.workspaceRoot);
|
|
825
|
-
if (exports.length === 0)
|
|
826
|
-
return null;
|
|
827
|
-
args.onClientModule?.(args.path, exports);
|
|
828
|
-
const referencePath = args.workspaceRoot ? toClientReferencePath(args.path, args.workspaceRoot) : args.path;
|
|
829
|
-
const filePathLit = JSON.stringify(referencePath);
|
|
830
|
-
const lines = [`import { registerClientReference } from "react-server-dom-webpack/server.node";`];
|
|
831
|
-
for (const name of exports) {
|
|
832
|
-
const nameLit = JSON.stringify(name);
|
|
833
|
-
const errMsg = JSON.stringify(`Attempted to call '${name}' from '${referencePath}' on the server, but it is a client-only export.`);
|
|
834
|
-
const proxy = `() => { throw new Error(${errMsg}); }`;
|
|
835
|
-
const binding = name === "default" ? `export default registerClientReference(${proxy}, ${filePathLit}, ${nameLit});` : `export const ${name} = registerClientReference(${proxy}, ${filePathLit}, ${nameLit});`;
|
|
836
|
-
lines.push(binding);
|
|
837
|
-
}
|
|
838
|
-
return lines.join(`
|
|
839
|
-
`);
|
|
840
|
-
}
|
|
841
|
-
|
|
842
299
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntriesBundler.ts
|
|
843
300
|
import fs2 from "fs";
|
|
844
|
-
import
|
|
845
|
-
|
|
846
|
-
// pkgs/@akanjs/devkit/frontendBuild/bundleDefine.ts
|
|
847
|
-
var bundleDefine = (app, command, renderEnv) => {
|
|
848
|
-
const nodeEnv = command === "build" ? "production" : "development";
|
|
849
|
-
return {
|
|
850
|
-
"process.env.NODE_ENV": JSON.stringify(nodeEnv),
|
|
851
|
-
"process.env.AKAN_PUBLIC_RENDER_ENV": JSON.stringify(renderEnv),
|
|
852
|
-
...Object.fromEntries(Object.entries(app.getPublicEnv()).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, value]) => [`process.env.${key}`, JSON.stringify(value)]))
|
|
853
|
-
};
|
|
854
|
-
};
|
|
301
|
+
import path3 from "path";
|
|
855
302
|
|
|
856
303
|
// pkgs/@akanjs/devkit/frontendBuild/clientBuildTypes.ts
|
|
857
304
|
var CLIENT_BUNDLE_NAMING = {
|
|
@@ -933,23 +380,23 @@ class ClientEntriesBundler {
|
|
|
933
380
|
};
|
|
934
381
|
}
|
|
935
382
|
async#createOpaqueEntryAliases() {
|
|
936
|
-
const aliasDir =
|
|
383
|
+
const aliasDir = path3.join(this.#app.cwdPath, ".akan", "generated", "client-entry-alias", this.#outputSubdir);
|
|
937
384
|
fs2.mkdirSync(aliasDir, { recursive: true });
|
|
938
385
|
const originalByAlias = new Map;
|
|
939
386
|
const aliasedEntries = await Promise.all(this.#entries.map(async (entry) => {
|
|
940
|
-
const absEntry =
|
|
387
|
+
const absEntry = path3.resolve(entry);
|
|
941
388
|
const hash = Bun.hash(`${this.#app.name}
|
|
942
389
|
${this.#outputSubdir}
|
|
943
390
|
${absEntry}`).toString(36);
|
|
944
|
-
const aliasPath =
|
|
391
|
+
const aliasPath = path3.join(aliasDir, `${hash}.tsx`);
|
|
945
392
|
await Bun.write(aliasPath, this.#createOpaqueEntryAliasSource(absEntry, await this.#scanEntryExportNames(absEntry)));
|
|
946
|
-
originalByAlias.set(
|
|
393
|
+
originalByAlias.set(path3.resolve(aliasPath), absEntry);
|
|
947
394
|
return aliasPath;
|
|
948
395
|
}));
|
|
949
396
|
return { entries: aliasedEntries, originalByAlias, aliasDir };
|
|
950
397
|
}
|
|
951
398
|
#createOpaqueEntryAliasSource(absEntry, exportNames) {
|
|
952
|
-
const entryLit = JSON.stringify(
|
|
399
|
+
const entryLit = JSON.stringify(path3.resolve(absEntry));
|
|
953
400
|
if (exportNames.length === 0)
|
|
954
401
|
return `export * from ${entryLit};
|
|
955
402
|
`;
|
|
@@ -1018,16 +465,16 @@ ${absEntry}`).toString(36);
|
|
|
1018
465
|
return rewritten;
|
|
1019
466
|
}
|
|
1020
467
|
#toServeUrl(absOutPath) {
|
|
1021
|
-
const rel =
|
|
468
|
+
const rel = path3.relative(this.#outdir, absOutPath).split(path3.sep).join("/");
|
|
1022
469
|
return `${this.#servePrefix}/${rel}`;
|
|
1023
470
|
}
|
|
1024
471
|
#absFromOutdir(p) {
|
|
1025
|
-
return
|
|
472
|
+
return path3.isAbsolute(p) ? p : path3.resolve(this.#outdir, p);
|
|
1026
473
|
}
|
|
1027
474
|
#absFromEntryPoint(p) {
|
|
1028
|
-
if (
|
|
1029
|
-
return
|
|
1030
|
-
const candidates = [
|
|
475
|
+
if (path3.isAbsolute(p))
|
|
476
|
+
return path3.resolve(p);
|
|
477
|
+
const candidates = [path3.resolve(process.cwd(), p), path3.resolve(this.#app.cwdPath, p)];
|
|
1031
478
|
return candidates.find((candidate) => fs2.existsSync(candidate)) ?? candidates[0];
|
|
1032
479
|
}
|
|
1033
480
|
#collectChunkUrls(absOutPath, visited = new Set) {
|
|
@@ -1103,118 +550,6 @@ ${absEntry}`).toString(36);
|
|
|
1103
550
|
}
|
|
1104
551
|
}
|
|
1105
552
|
|
|
1106
|
-
// pkgs/@akanjs/devkit/frontendBuild/csrDevPaths.ts
|
|
1107
|
-
import fs3 from "fs";
|
|
1108
|
-
import path7 from "path";
|
|
1109
|
-
|
|
1110
|
-
class CsrDevPaths {
|
|
1111
|
-
static modulePrefix = "akan-module:";
|
|
1112
|
-
static stubPrefix = "stub:";
|
|
1113
|
-
static emptyStubPrefix = "stub:empty:";
|
|
1114
|
-
static vendorPrefix = "vendor:";
|
|
1115
|
-
root;
|
|
1116
|
-
constructor(workspaceRoot) {
|
|
1117
|
-
this.root = CsrDevPaths.realpath(workspaceRoot);
|
|
1118
|
-
}
|
|
1119
|
-
idOf(file) {
|
|
1120
|
-
const real = CsrDevPaths.realpath(file);
|
|
1121
|
-
const relative = path7.relative(this.root, real);
|
|
1122
|
-
const id = relative.startsWith("..") || path7.isAbsolute(relative) ? real : relative;
|
|
1123
|
-
return id.split(path7.sep).join("/");
|
|
1124
|
-
}
|
|
1125
|
-
fileOf(id) {
|
|
1126
|
-
return path7.isAbsolute(id) ? id : path7.join(this.root, id);
|
|
1127
|
-
}
|
|
1128
|
-
static isStub(target) {
|
|
1129
|
-
return target.startsWith(CsrDevPaths.stubPrefix);
|
|
1130
|
-
}
|
|
1131
|
-
static isVendorFile(file) {
|
|
1132
|
-
return file.includes(`${path7.sep}node_modules${path7.sep}`);
|
|
1133
|
-
}
|
|
1134
|
-
static isScript(file) {
|
|
1135
|
-
return /\.[cm]?[jt]sx?$/.test(file);
|
|
1136
|
-
}
|
|
1137
|
-
static mtimeOf(file) {
|
|
1138
|
-
return fs3.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? -1;
|
|
1139
|
-
}
|
|
1140
|
-
static async hashOf(file) {
|
|
1141
|
-
const source = Bun.file(file);
|
|
1142
|
-
return await source.exists() ? Bun.hash(await source.arrayBuffer()).toString(36) : "";
|
|
1143
|
-
}
|
|
1144
|
-
static realpath(file) {
|
|
1145
|
-
return fs3.existsSync(file) ? fs3.realpathSync.native(file) : path7.resolve(file);
|
|
1146
|
-
}
|
|
1147
|
-
static isNamed(file) {
|
|
1148
|
-
try {
|
|
1149
|
-
return fs3.realpathSync.native(file) === file;
|
|
1150
|
-
} catch {
|
|
1151
|
-
return false;
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
static #extensions = {
|
|
1155
|
-
import: [".tsx", ".jsx", ".mts", ".ts", ".mjs", ".js", ".cts", ".cjs"],
|
|
1156
|
-
require: [".tsx", ".ts", ".jsx", ".cts", ".cjs", ".js", ".mjs", ".mts"]
|
|
1157
|
-
};
|
|
1158
|
-
static resolveOnDisk(base, kind = "import") {
|
|
1159
|
-
return CsrDevPaths.#asFile(base, kind) ?? CsrDevPaths.#asFolder(base, kind);
|
|
1160
|
-
}
|
|
1161
|
-
static resolveRelative(dir, specifier, kind = "import") {
|
|
1162
|
-
const base = path7.resolve(dir, specifier);
|
|
1163
|
-
const folder = /(^|[\\/])\.\.?$|[\\/]$/.test(specifier);
|
|
1164
|
-
return folder ? CsrDevPaths.#asFolder(base, kind) : CsrDevPaths.resolveOnDisk(base, kind);
|
|
1165
|
-
}
|
|
1166
|
-
static #asFile(base, kind) {
|
|
1167
|
-
const isFile = (candidate) => fs3.statSync(candidate, { throwIfNoEntry: false })?.isFile() ?? false;
|
|
1168
|
-
return [base, ...CsrDevPaths.#extensions[kind].map((extension) => `${base}${extension}`)].find(isFile) ?? null;
|
|
1169
|
-
}
|
|
1170
|
-
static #asFolder(dir, kind) {
|
|
1171
|
-
const entry = CsrDevPaths.#packageEntryOf(dir, kind);
|
|
1172
|
-
const named = entry ? CsrDevPaths.#asFile(path7.join(dir, entry), kind) ?? CsrDevPaths.#indexOf(path7.join(dir, entry), kind) : null;
|
|
1173
|
-
return named ?? CsrDevPaths.#indexOf(dir, kind);
|
|
1174
|
-
}
|
|
1175
|
-
static #indexOf(dir, kind) {
|
|
1176
|
-
return CsrDevPaths.#asFile(path7.join(dir, "index"), kind);
|
|
1177
|
-
}
|
|
1178
|
-
static #packageEntryOf(dir, kind) {
|
|
1179
|
-
try {
|
|
1180
|
-
const pkg = JSON.parse(fs3.readFileSync(path7.join(dir, "package.json"), "utf8"));
|
|
1181
|
-
const fields = kind === "require" ? [pkg.browser, pkg.main] : [pkg.browser, pkg.module, pkg.main];
|
|
1182
|
-
const entry = fields.find((field) => typeof field === "string");
|
|
1183
|
-
return typeof entry === "string" ? entry : null;
|
|
1184
|
-
} catch {
|
|
1185
|
-
return null;
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
static installedSince(specifier, from, since) {
|
|
1189
|
-
const [first = "", second = ""] = specifier.split("/");
|
|
1190
|
-
const name = first.startsWith("@") ? `${first}/${second}` : first;
|
|
1191
|
-
if (!name || name.startsWith("."))
|
|
1192
|
-
return false;
|
|
1193
|
-
for (let dir = path7.resolve(from);; dir = path7.dirname(dir)) {
|
|
1194
|
-
const pkgDir = path7.join(dir, "node_modules", name);
|
|
1195
|
-
if (fs3.existsSync(path7.join(pkgDir, "package.json")))
|
|
1196
|
-
return (fs3.statSync(pkgDir, { throwIfNoEntry: false })?.ctimeMs ?? 0) > since;
|
|
1197
|
-
if (path7.dirname(dir) === dir)
|
|
1198
|
-
return false;
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
static tryResolve(specifier, from) {
|
|
1202
|
-
try {
|
|
1203
|
-
return Bun.resolveSync(specifier, from);
|
|
1204
|
-
} catch {
|
|
1205
|
-
return null;
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
static lineCount(text) {
|
|
1209
|
-
let count = 0;
|
|
1210
|
-
for (let index = text.indexOf(`
|
|
1211
|
-
`);index !== -1; index = text.indexOf(`
|
|
1212
|
-
`, index + 1))
|
|
1213
|
-
count += 1;
|
|
1214
|
-
return count;
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
553
|
// pkgs/@akanjs/devkit/frontendBuild/vendorSpecifiers.ts
|
|
1219
554
|
var VENDOR_SPECIFIERS = [
|
|
1220
555
|
"react",
|
|
@@ -1292,13 +627,13 @@ class RouteClientBuilder {
|
|
|
1292
627
|
ssrModuleMap[row.id][row.name] = { id: ssrOutput, chunks: [ssrOutput, ssrOutput], name: row.name, async: true };
|
|
1293
628
|
}
|
|
1294
629
|
for (const entry of bootstrapEntries.buildEntries) {
|
|
1295
|
-
const buildEntry =
|
|
1296
|
-
const originalEntry =
|
|
630
|
+
const buildEntry = path4.resolve(entry);
|
|
631
|
+
const originalEntry = path4.resolve(bootstrapEntries.originalByBuildEntry.get(buildEntry) ?? buildEntry);
|
|
1297
632
|
if (!acceptedEntries.has(originalEntry))
|
|
1298
633
|
continue;
|
|
1299
634
|
const deps = new Set([originalEntry]);
|
|
1300
635
|
for (const dep of referenceBundle.entryDepsByAbsPath.get(buildEntry) ?? [])
|
|
1301
|
-
deps.add(
|
|
636
|
+
deps.add(path4.resolve(dep));
|
|
1302
637
|
const sortedDeps = [...deps].sort();
|
|
1303
638
|
clientDepsByEntry[originalEntry] = sortedDeps;
|
|
1304
639
|
if (routeEntries.has(originalEntry))
|
|
@@ -1363,25 +698,25 @@ class RouteClientBuilder {
|
|
|
1363
698
|
}).bundle();
|
|
1364
699
|
}
|
|
1365
700
|
async#createBootstrapEntries(entries) {
|
|
1366
|
-
if (!await Bun.file(
|
|
701
|
+
if (!await Bun.file(path4.join(this.#app.cwdPath, "lib", "st.ts")).exists()) {
|
|
1367
702
|
return { buildEntries: entries, originalByBuildEntry: new Map };
|
|
1368
703
|
}
|
|
1369
|
-
const outdir =
|
|
704
|
+
const outdir = path4.join(this.#app.cwdPath, ".akan", "generated", "client-entry-bootstrap");
|
|
1370
705
|
await mkdir(outdir, { recursive: true });
|
|
1371
706
|
const originalByBuildEntry = new Map;
|
|
1372
707
|
const buildEntries = await Promise.all(entries.map(async (entry) => {
|
|
1373
|
-
const absEntry =
|
|
708
|
+
const absEntry = path4.resolve(entry);
|
|
1374
709
|
const hash = Bun.hash(`${this.#app.name}
|
|
1375
710
|
${absEntry}`).toString(36);
|
|
1376
|
-
const base =
|
|
1377
|
-
const wrapperEntry =
|
|
711
|
+
const base = path4.basename(absEntry).replace(/[^A-Za-z0-9._-]/g, "_");
|
|
712
|
+
const wrapperEntry = path4.join(outdir, `${base}-${hash}.tsx`);
|
|
1378
713
|
const exportNames = await this.#scanExportNames(absEntry);
|
|
1379
714
|
await Bun.write(wrapperEntry, RouteClientBuilder.createStoreBootstrapEntrySource({
|
|
1380
715
|
appName: this.#app.name,
|
|
1381
716
|
originalEntry: absEntry,
|
|
1382
717
|
exportNames
|
|
1383
718
|
}));
|
|
1384
|
-
originalByBuildEntry.set(
|
|
719
|
+
originalByBuildEntry.set(path4.resolve(wrapperEntry), absEntry);
|
|
1385
720
|
return wrapperEntry;
|
|
1386
721
|
}));
|
|
1387
722
|
return { buildEntries, originalByBuildEntry };
|
|
@@ -1455,11 +790,11 @@ ${declared.map(({ name }) => `export default ${name};`).join(`
|
|
|
1455
790
|
try {
|
|
1456
791
|
return Bun.resolveSync("akanjs/server", import.meta.dir);
|
|
1457
792
|
} catch {
|
|
1458
|
-
return
|
|
793
|
+
return path4.resolve(import.meta.dir, "../../../server/index.ts");
|
|
1459
794
|
}
|
|
1460
795
|
}
|
|
1461
796
|
static createStoreBootstrapEntrySource(args) {
|
|
1462
|
-
const originalEntry = JSON.stringify(
|
|
797
|
+
const originalEntry = JSON.stringify(path4.resolve(args.originalEntry));
|
|
1463
798
|
const namedExports = args.exportNames.filter((name) => name !== "default");
|
|
1464
799
|
const lines = [
|
|
1465
800
|
`import ${JSON.stringify(`@apps/${args.appName}/client`)};`,
|
|
@@ -1486,8 +821,8 @@ ${declared.map(({ name }) => `export default ${name};`).join(`
|
|
|
1486
821
|
|
|
1487
822
|
// pkgs/@akanjs/devkit/frontendBuild/autoImportSync.ts
|
|
1488
823
|
import { readdir, readFile, stat } from "fs/promises";
|
|
1489
|
-
import
|
|
1490
|
-
import
|
|
824
|
+
import path5 from "path";
|
|
825
|
+
import ts from "typescript";
|
|
1491
826
|
var TEST_FILE_RE = /\.(test|spec)\.(ts|tsx)$/;
|
|
1492
827
|
var AKAN_BASE = {
|
|
1493
828
|
names: ["Int", "Float", "ID", "Any", "Upload", "enumOf", "dayjs"],
|
|
@@ -1624,7 +959,7 @@ class AutoImportSync {
|
|
|
1624
959
|
#workspaceRoot;
|
|
1625
960
|
#domainCache = new Map;
|
|
1626
961
|
constructor({ workspaceRoot }) {
|
|
1627
|
-
this.#workspaceRoot =
|
|
962
|
+
this.#workspaceRoot = path5.resolve(workspaceRoot);
|
|
1628
963
|
}
|
|
1629
964
|
async syncForBatch(files) {
|
|
1630
965
|
const changedFiles = [];
|
|
@@ -1636,7 +971,7 @@ class AutoImportSync {
|
|
|
1636
971
|
this.#domainCache.delete(pkgRoot);
|
|
1637
972
|
}
|
|
1638
973
|
for (const file of files) {
|
|
1639
|
-
const abs =
|
|
974
|
+
const abs = path5.resolve(file);
|
|
1640
975
|
if (seen.has(abs))
|
|
1641
976
|
continue;
|
|
1642
977
|
seen.add(abs);
|
|
@@ -1654,13 +989,13 @@ class AutoImportSync {
|
|
|
1654
989
|
return { changedFiles, errors };
|
|
1655
990
|
}
|
|
1656
991
|
#contextFor(abs) {
|
|
1657
|
-
const rel =
|
|
1658
|
-
if (rel.startsWith("..") ||
|
|
992
|
+
const rel = path5.relative(this.#workspaceRoot, abs);
|
|
993
|
+
if (rel.startsWith("..") || path5.isAbsolute(rel))
|
|
1659
994
|
return null;
|
|
1660
|
-
const base =
|
|
995
|
+
const base = path5.basename(abs);
|
|
1661
996
|
if (TEST_FILE_RE.test(base) || base === "index.ts" || base === "index.tsx" || base.endsWith(".d.ts"))
|
|
1662
997
|
return null;
|
|
1663
|
-
const parts = rel.split(
|
|
998
|
+
const parts = rel.split(path5.sep).filter(Boolean);
|
|
1664
999
|
const [scope, project, facet] = parts;
|
|
1665
1000
|
if (scope !== "apps" && scope !== "libs" || !project || !facet)
|
|
1666
1001
|
return null;
|
|
@@ -1702,8 +1037,8 @@ class AutoImportSync {
|
|
|
1702
1037
|
};
|
|
1703
1038
|
}
|
|
1704
1039
|
async#domainResolver(abs, ctx, kinds) {
|
|
1705
|
-
const index = await this.#domainIndex(
|
|
1706
|
-
const fileDir =
|
|
1040
|
+
const index = await this.#domainIndex(path5.join(this.#workspaceRoot, ctx.scope, ctx.project));
|
|
1041
|
+
const fileDir = path5.dirname(abs);
|
|
1707
1042
|
return (symbol) => {
|
|
1708
1043
|
if (!PASCAL_CASE_RE.test(symbol) || DOMAIN_DENYLIST.has(symbol))
|
|
1709
1044
|
return null;
|
|
@@ -1714,12 +1049,12 @@ class AutoImportSync {
|
|
|
1714
1049
|
};
|
|
1715
1050
|
}
|
|
1716
1051
|
async#libBarrelResolver(abs, ctx) {
|
|
1717
|
-
const fileDir =
|
|
1718
|
-
const libDir =
|
|
1052
|
+
const fileDir = path5.dirname(abs);
|
|
1053
|
+
const libDir = path5.join(this.#workspaceRoot, ctx.scope, ctx.project, "lib");
|
|
1719
1054
|
const available = new Map;
|
|
1720
1055
|
for (const [symbol, { barrel, kind }] of Object.entries(LIB_BARRELS)) {
|
|
1721
|
-
if (await fileExists(
|
|
1722
|
-
available.set(symbol, { specifier: relativeSpecifier(fileDir,
|
|
1056
|
+
if (await fileExists(path5.join(libDir, `${barrel}.ts`)))
|
|
1057
|
+
available.set(symbol, { specifier: relativeSpecifier(fileDir, path5.join(libDir, barrel)), kind });
|
|
1723
1058
|
}
|
|
1724
1059
|
return (symbol) => available.get(symbol) ?? null;
|
|
1725
1060
|
}
|
|
@@ -1727,20 +1062,20 @@ class AutoImportSync {
|
|
|
1727
1062
|
const cached = this.#domainCache.get(pkgRoot);
|
|
1728
1063
|
if (cached)
|
|
1729
1064
|
return cached;
|
|
1730
|
-
const index = await buildDomainIndex(
|
|
1065
|
+
const index = await buildDomainIndex(path5.join(pkgRoot, "lib"));
|
|
1731
1066
|
this.#domainCache.set(pkgRoot, index);
|
|
1732
1067
|
return index;
|
|
1733
1068
|
}
|
|
1734
1069
|
#domainPkgRootOf(file) {
|
|
1735
|
-
const rel =
|
|
1736
|
-
if (rel.startsWith("..") ||
|
|
1070
|
+
const rel = path5.relative(this.#workspaceRoot, path5.resolve(file));
|
|
1071
|
+
if (rel.startsWith("..") || path5.isAbsolute(rel))
|
|
1737
1072
|
return null;
|
|
1738
|
-
const [scope, project, facet] = rel.split(
|
|
1073
|
+
const [scope, project, facet] = rel.split(path5.sep).filter(Boolean);
|
|
1739
1074
|
if (scope !== "apps" && scope !== "libs" || !project || facet !== "lib")
|
|
1740
1075
|
return null;
|
|
1741
|
-
if (!domainKindOf(
|
|
1076
|
+
if (!domainKindOf(path5.basename(file)))
|
|
1742
1077
|
return null;
|
|
1743
|
-
return
|
|
1078
|
+
return path5.join(this.#workspaceRoot, scope, project);
|
|
1744
1079
|
}
|
|
1745
1080
|
}
|
|
1746
1081
|
var roleFor = (facet, base) => {
|
|
@@ -1781,7 +1116,7 @@ var targetFor = (symbol, ctx) => {
|
|
|
1781
1116
|
return null;
|
|
1782
1117
|
};
|
|
1783
1118
|
var transformSource = (source, fileName, ctx, resolveExtra) => {
|
|
1784
|
-
const sf =
|
|
1119
|
+
const sf = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, scriptKindFor(fileName));
|
|
1785
1120
|
const bound = collectBoundNames(sf);
|
|
1786
1121
|
const used = collectUsedReferences(sf);
|
|
1787
1122
|
const bareGlobals = collectBareGlobalReferences(sf);
|
|
@@ -1803,7 +1138,7 @@ var transformSource = (source, fileName, ctx, resolveExtra) => {
|
|
|
1803
1138
|
}
|
|
1804
1139
|
if (namedBySpecifier.size === 0 && namespaceImports.length === 0)
|
|
1805
1140
|
return null;
|
|
1806
|
-
const importDecls = sf.statements.filter(
|
|
1141
|
+
const importDecls = sf.statements.filter(ts.isImportDeclaration);
|
|
1807
1142
|
const anchor = importDecls.at(-1) ?? null;
|
|
1808
1143
|
const namedImportsBySpecifier = collectExistingNamedImports(importDecls);
|
|
1809
1144
|
const edits = [];
|
|
@@ -1859,61 +1194,61 @@ ${newStatements.join(`
|
|
|
1859
1194
|
var collectBoundNames = (sf) => {
|
|
1860
1195
|
const names = new Set;
|
|
1861
1196
|
const visit = (node) => {
|
|
1862
|
-
if (
|
|
1197
|
+
if (ts.isImportClause(node)) {
|
|
1863
1198
|
if (node.name)
|
|
1864
1199
|
names.add(node.name.text);
|
|
1865
1200
|
const bindings = node.namedBindings;
|
|
1866
|
-
if (bindings &&
|
|
1201
|
+
if (bindings && ts.isNamespaceImport(bindings))
|
|
1867
1202
|
names.add(bindings.name.text);
|
|
1868
|
-
if (bindings &&
|
|
1203
|
+
if (bindings && ts.isNamedImports(bindings))
|
|
1869
1204
|
for (const el of bindings.elements)
|
|
1870
1205
|
names.add(el.name.text);
|
|
1871
1206
|
}
|
|
1872
|
-
if ((
|
|
1207
|
+
if ((ts.isVariableDeclaration(node) || ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node) || ts.isParameter(node) || ts.isBindingElement(node) || ts.isEnumDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node)) && node.name && ts.isIdentifier(node.name))
|
|
1873
1208
|
names.add(node.name.text);
|
|
1874
|
-
|
|
1209
|
+
ts.forEachChild(node, visit);
|
|
1875
1210
|
};
|
|
1876
|
-
|
|
1211
|
+
ts.forEachChild(sf, visit);
|
|
1877
1212
|
return names;
|
|
1878
1213
|
};
|
|
1879
1214
|
var collectUsedReferences = (sf) => {
|
|
1880
1215
|
const used = new Set;
|
|
1881
1216
|
const visit = (node) => {
|
|
1882
|
-
if (
|
|
1217
|
+
if (ts.isIdentifier(node) && isReferencePosition(node))
|
|
1883
1218
|
used.add(node.text);
|
|
1884
|
-
|
|
1219
|
+
ts.forEachChild(node, visit);
|
|
1885
1220
|
};
|
|
1886
|
-
|
|
1221
|
+
ts.forEachChild(sf, visit);
|
|
1887
1222
|
return used;
|
|
1888
1223
|
};
|
|
1889
1224
|
var collectBareGlobalReferences = (sf) => {
|
|
1890
1225
|
const bare = new Set;
|
|
1891
1226
|
const visit = (node) => {
|
|
1892
|
-
if (
|
|
1227
|
+
if (ts.isIdentifier(node) && GLOBAL_NAMES.has(node.text) && isReferencePosition(node)) {
|
|
1893
1228
|
const parent = node.parent;
|
|
1894
|
-
if (!(parent &&
|
|
1229
|
+
if (!(parent && ts.isPropertyAccessExpression(parent) && parent.expression === node))
|
|
1895
1230
|
bare.add(node.text);
|
|
1896
1231
|
}
|
|
1897
|
-
|
|
1232
|
+
ts.forEachChild(node, visit);
|
|
1898
1233
|
};
|
|
1899
|
-
|
|
1234
|
+
ts.forEachChild(sf, visit);
|
|
1900
1235
|
return bare;
|
|
1901
1236
|
};
|
|
1902
1237
|
var isReferencePosition = (node) => {
|
|
1903
1238
|
const parent = node.parent;
|
|
1904
1239
|
if (!parent)
|
|
1905
1240
|
return true;
|
|
1906
|
-
if (
|
|
1241
|
+
if (ts.isPropertyAccessExpression(parent) && parent.name === node)
|
|
1907
1242
|
return false;
|
|
1908
|
-
if (
|
|
1243
|
+
if (ts.isQualifiedName(parent) && parent.right === node)
|
|
1909
1244
|
return false;
|
|
1910
|
-
if (
|
|
1245
|
+
if (ts.isPropertyAssignment(parent) && parent.name === node)
|
|
1911
1246
|
return false;
|
|
1912
|
-
if (
|
|
1247
|
+
if (ts.isPropertySignature(parent) && parent.name === node)
|
|
1913
1248
|
return false;
|
|
1914
|
-
if (
|
|
1249
|
+
if (ts.isBindingElement(parent) && parent.propertyName === node)
|
|
1915
1250
|
return false;
|
|
1916
|
-
if (
|
|
1251
|
+
if (ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent))
|
|
1917
1252
|
return false;
|
|
1918
1253
|
return true;
|
|
1919
1254
|
};
|
|
@@ -1922,9 +1257,9 @@ var collectExistingNamedImports = (importDecls) => {
|
|
|
1922
1257
|
for (const decl of importDecls) {
|
|
1923
1258
|
const clause = decl.importClause;
|
|
1924
1259
|
const bindings = clause?.namedBindings;
|
|
1925
|
-
if (!clause || !bindings || !
|
|
1260
|
+
if (!clause || !bindings || !ts.isNamedImports(bindings))
|
|
1926
1261
|
continue;
|
|
1927
|
-
if (!
|
|
1262
|
+
if (!ts.isStringLiteral(decl.moduleSpecifier))
|
|
1928
1263
|
continue;
|
|
1929
1264
|
const specifier = decl.moduleSpecifier.text;
|
|
1930
1265
|
if (map.has(specifier))
|
|
@@ -1946,14 +1281,14 @@ var formatNamedImport = (specifier, names) => {
|
|
|
1946
1281
|
var directivePrologueEnd = (sf) => {
|
|
1947
1282
|
let end = -1;
|
|
1948
1283
|
for (const stmt of sf.statements) {
|
|
1949
|
-
if (
|
|
1284
|
+
if (ts.isExpressionStatement(stmt) && ts.isStringLiteral(stmt.expression))
|
|
1950
1285
|
end = stmt.getEnd();
|
|
1951
1286
|
else
|
|
1952
1287
|
break;
|
|
1953
1288
|
}
|
|
1954
1289
|
return end;
|
|
1955
1290
|
};
|
|
1956
|
-
var scriptKindFor = (fileName) => fileName.endsWith(".tsx") ?
|
|
1291
|
+
var scriptKindFor = (fileName) => fileName.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
1957
1292
|
var compareNames = (a, b) => {
|
|
1958
1293
|
const [la, lb] = [a.toLowerCase(), b.toLowerCase()];
|
|
1959
1294
|
if (la !== lb)
|
|
@@ -1974,7 +1309,7 @@ var domainKindOf = (base) => {
|
|
|
1974
1309
|
var buildDomainIndex = async (libDir) => {
|
|
1975
1310
|
const index = new Map;
|
|
1976
1311
|
for (const file of await collectDomainFiles(libDir)) {
|
|
1977
|
-
const kind = domainKindOf(
|
|
1312
|
+
const kind = domainKindOf(path5.basename(file));
|
|
1978
1313
|
if (!kind)
|
|
1979
1314
|
continue;
|
|
1980
1315
|
const src = await readFile(file, "utf8").catch(() => null);
|
|
@@ -1994,7 +1329,7 @@ var collectDomainFiles = async (dir) => {
|
|
|
1994
1329
|
for (const entry of entries) {
|
|
1995
1330
|
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
1996
1331
|
continue;
|
|
1997
|
-
const full =
|
|
1332
|
+
const full = path5.join(dir, entry.name);
|
|
1998
1333
|
if (entry.isDirectory())
|
|
1999
1334
|
files.push(...await collectDomainFiles(full));
|
|
2000
1335
|
else if (domainKindOf(entry.name) && !TEST_FILE_RE.test(entry.name))
|
|
@@ -2003,18 +1338,18 @@ var collectDomainFiles = async (dir) => {
|
|
|
2003
1338
|
return files;
|
|
2004
1339
|
};
|
|
2005
1340
|
var exportedPascalNames = (source, fileName) => {
|
|
2006
|
-
const sf =
|
|
2007
|
-
const isExported = (node) =>
|
|
1341
|
+
const sf = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true);
|
|
1342
|
+
const isExported = (node) => ts.canHaveModifiers(node) && (ts.getModifiers(node) ?? []).some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
2008
1343
|
const names = [];
|
|
2009
1344
|
for (const stmt of sf.statements) {
|
|
2010
|
-
if ((
|
|
1345
|
+
if ((ts.isClassDeclaration(stmt) || ts.isFunctionDeclaration(stmt) || ts.isEnumDeclaration(stmt)) && stmt.name) {
|
|
2011
1346
|
if (isExported(stmt))
|
|
2012
1347
|
names.push(stmt.name.text);
|
|
2013
|
-
} else if (
|
|
1348
|
+
} else if (ts.isVariableStatement(stmt) && isExported(stmt)) {
|
|
2014
1349
|
for (const decl of stmt.declarationList.declarations)
|
|
2015
|
-
if (
|
|
1350
|
+
if (ts.isIdentifier(decl.name))
|
|
2016
1351
|
names.push(decl.name.text);
|
|
2017
|
-
} else if (
|
|
1352
|
+
} else if (ts.isExportDeclaration(stmt) && stmt.exportClause && ts.isNamedExports(stmt.exportClause)) {
|
|
2018
1353
|
for (const el of stmt.exportClause.elements)
|
|
2019
1354
|
names.push(el.name.text);
|
|
2020
1355
|
}
|
|
@@ -2022,430 +1357,18 @@ var exportedPascalNames = (source, fileName) => {
|
|
|
2022
1357
|
return names.filter((name) => PASCAL_CASE_RE.test(name));
|
|
2023
1358
|
};
|
|
2024
1359
|
var relativeSpecifier = (fromDir, toFile) => {
|
|
2025
|
-
const rel =
|
|
1360
|
+
const rel = path5.relative(fromDir, toFile).replace(/\.tsx?$/, "").split(path5.sep).join("/");
|
|
2026
1361
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
2027
1362
|
};
|
|
2028
1363
|
|
|
2029
|
-
// pkgs/@akanjs/devkit/frontendBuild/serverGraphFile.ts
|
|
2030
|
-
import fs4 from "fs";
|
|
2031
|
-
import path10 from "path";
|
|
2032
|
-
class ServerGraphFile {
|
|
2033
|
-
static fileName = "server-graph.json";
|
|
2034
|
-
static #cache = null;
|
|
2035
|
-
static async read(artifactDir) {
|
|
2036
|
-
const file = path10.join(artifactDir, ServerGraphFile.fileName);
|
|
2037
|
-
const stat = fs4.statSync(file, { throwIfNoEntry: false });
|
|
2038
|
-
if (!stat)
|
|
2039
|
-
return null;
|
|
2040
|
-
const stamp = `${stat.ino}:${stat.size}:${stat.mtimeMs}`;
|
|
2041
|
-
const cached = ServerGraphFile.#cache;
|
|
2042
|
-
if (cached?.file === file && cached.stamp === stamp)
|
|
2043
|
-
return cached.graph;
|
|
2044
|
-
const graph = await Bun.file(file).json().catch(() => null);
|
|
2045
|
-
if (graph)
|
|
2046
|
-
ServerGraphFile.#cache = { file, stamp, graph };
|
|
2047
|
-
return graph;
|
|
2048
|
-
}
|
|
2049
|
-
static async write(artifactDir, graph) {
|
|
2050
|
-
const file = path10.join(artifactDir, ServerGraphFile.fileName);
|
|
2051
|
-
const temp = `${file}.${process.pid}.tmp`;
|
|
2052
|
-
await Bun.write(temp, JSON.stringify(graph));
|
|
2053
|
-
await FileSys2.replace(temp, file);
|
|
2054
|
-
}
|
|
2055
|
-
static async carry(artifactDir, files) {
|
|
2056
|
-
const graph = await ServerGraphFile.read(artifactDir);
|
|
2057
|
-
if (!graph || files.length === 0)
|
|
2058
|
-
return;
|
|
2059
|
-
const carried = [...new Set([...graph.carried ?? [], ...files.map((file) => CsrDevPaths.realpath(file))])];
|
|
2060
|
-
await ServerGraphFile.write(artifactDir, { ...graph, carried });
|
|
2061
|
-
}
|
|
2062
|
-
static async touches(graph, files, exportsNow, next) {
|
|
2063
|
-
if (!graph)
|
|
2064
|
-
return true;
|
|
2065
|
-
const inputs = new Set(graph.inputs);
|
|
2066
|
-
const joined = new Set((next?.inputs ?? []).filter((input) => !inputs.has(input)));
|
|
2067
|
-
for (const rawFile of files) {
|
|
2068
|
-
const file = CsrDevPaths.realpath(rawFile);
|
|
2069
|
-
if (joined.has(file))
|
|
2070
|
-
return true;
|
|
2071
|
-
if (!inputs.has(file))
|
|
2072
|
-
continue;
|
|
2073
|
-
const before = graph.clientExports[file];
|
|
2074
|
-
if (!before)
|
|
2075
|
-
return true;
|
|
2076
|
-
const now = await exportsNow(file);
|
|
2077
|
-
if (!now || ServerGraphFile.#names(now) !== ServerGraphFile.#names(before))
|
|
2078
|
-
return true;
|
|
2079
|
-
}
|
|
2080
|
-
return false;
|
|
2081
|
-
}
|
|
2082
|
-
static async clientExportsOf(file) {
|
|
2083
|
-
const source = await Bun.file(file).text().catch(() => null);
|
|
2084
|
-
if (source === null || !hasUseClientDirective(source))
|
|
2085
|
-
return null;
|
|
2086
|
-
try {
|
|
2087
|
-
return scanUseClientExports(source, file);
|
|
2088
|
-
} catch {
|
|
2089
|
-
return null;
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
static #names(exports) {
|
|
2093
|
-
return [...exports].sort().join(",");
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
|
-
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
2098
|
-
import fs5 from "fs";
|
|
2099
|
-
import path13 from "path";
|
|
2100
|
-
|
|
2101
|
-
// pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
|
|
2102
|
-
import path11 from "path";
|
|
2103
|
-
var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
|
|
2104
|
-
var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
|
|
2105
|
-
var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
|
|
2106
|
-
var OPTIONAL_BACKEND_EXTERNAL_EXACT = new Set(["bullmq", "ioredis", "postgres", "protobufjs"]);
|
|
2107
|
-
var RUNTIME_EXTERNAL_EXACT = new Set([
|
|
2108
|
-
"react",
|
|
2109
|
-
"react-dom",
|
|
2110
|
-
"react/jsx-runtime",
|
|
2111
|
-
"react/jsx-dev-runtime",
|
|
2112
|
-
"react-server-dom-webpack",
|
|
2113
|
-
"react-server-dom-webpack/server.node",
|
|
2114
|
-
"react-server-dom-webpack/client.node",
|
|
2115
|
-
"react-server-dom-webpack/client.browser"
|
|
2116
|
-
]);
|
|
2117
|
-
var RUNTIME_EXTERNAL_PREFIX = ["react-dom/", "react-server-dom-webpack/"];
|
|
2118
|
-
var CANDIDATE_EXTS3 = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
|
|
2119
|
-
async function createExternalizeFrameworkPlugin(options) {
|
|
2120
|
-
const tsconfig = await options.app.getTsConfig();
|
|
2121
|
-
const includePrefixes = options.include ?? DEFAULT_INCLUDE;
|
|
2122
|
-
const extraExact = new Set(options.extra ?? []);
|
|
2123
|
-
const workspaceRoot = options.app.workspace.workspaceRoot;
|
|
2124
|
-
const tsconfigPaths = tsconfig.compilerOptions.paths ?? {};
|
|
2125
|
-
const rootEntries = Object.entries(tsconfigPaths).filter(([k]) => !k.endsWith("/*")).map(([k, v]) => ({ pkg: k, entryFile: v[0] ?? null })).filter((e) => e.entryFile !== null);
|
|
2126
|
-
const wildcardEntries = Object.entries(tsconfigPaths).filter(([k]) => k.endsWith("/*")).map(([k, v]) => ({ prefix: k.slice(0, -1), replacements: v })).sort((a, b) => b.prefix.length - a.prefix.length);
|
|
2127
|
-
async function resolveWorkspaceSubpath(spec) {
|
|
2128
|
-
if (!workspaceRoot)
|
|
2129
|
-
return null;
|
|
2130
|
-
for (const { prefix, replacements } of wildcardEntries) {
|
|
2131
|
-
if (!spec.startsWith(prefix))
|
|
2132
|
-
continue;
|
|
2133
|
-
const suffix = spec.slice(prefix.length);
|
|
2134
|
-
for (const repl of replacements) {
|
|
2135
|
-
const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
|
|
2136
|
-
if (!replPath)
|
|
2137
|
-
continue;
|
|
2138
|
-
const candidate = path11.resolve(workspaceRoot, replPath + suffix);
|
|
2139
|
-
const hit = await firstExisting(candidate);
|
|
2140
|
-
if (hit)
|
|
2141
|
-
return hit;
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
for (const { pkg, entryFile } of rootEntries) {
|
|
2145
|
-
if (!spec.startsWith(`${pkg}/`))
|
|
2146
|
-
continue;
|
|
2147
|
-
const suffix = spec.slice(pkg.length + 1);
|
|
2148
|
-
const pkgDir = path11.dirname(path11.resolve(workspaceRoot, entryFile));
|
|
2149
|
-
const candidate = path11.join(pkgDir, suffix);
|
|
2150
|
-
const hit = await firstExisting(candidate);
|
|
2151
|
-
if (hit)
|
|
2152
|
-
return hit;
|
|
2153
|
-
}
|
|
2154
|
-
return null;
|
|
2155
|
-
}
|
|
2156
|
-
return {
|
|
2157
|
-
name: "akan-externalize-framework",
|
|
2158
|
-
setup(build) {
|
|
2159
|
-
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
2160
|
-
const spec = args.path;
|
|
2161
|
-
if (spec === "." || spec === ".." || spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/"))
|
|
2162
|
-
return;
|
|
2163
|
-
if (extraExact.has(spec) || DEFAULT_EXCLUDE_EXACT.has(spec))
|
|
2164
|
-
return { path: spec, external: true };
|
|
2165
|
-
for (const prefix of DEFAULT_EXCLUDE_PREFIX) {
|
|
2166
|
-
if (spec.startsWith(prefix))
|
|
2167
|
-
return { path: spec, external: true };
|
|
2168
|
-
}
|
|
2169
|
-
if (OPTIONAL_BACKEND_EXTERNAL_EXACT.has(spec))
|
|
2170
|
-
return { path: spec, external: true };
|
|
2171
|
-
if (RUNTIME_EXTERNAL_EXACT.has(spec))
|
|
2172
|
-
return { path: spec, external: true };
|
|
2173
|
-
for (const prefix of RUNTIME_EXTERNAL_PREFIX) {
|
|
2174
|
-
if (spec.startsWith(prefix))
|
|
2175
|
-
return { path: spec, external: true };
|
|
2176
|
-
}
|
|
2177
|
-
if (!includePrefixes.some((prefix) => spec.startsWith(prefix)))
|
|
2178
|
-
return;
|
|
2179
|
-
const resolved = await resolveWorkspaceSubpath(spec);
|
|
2180
|
-
return resolved ? { path: resolved } : undefined;
|
|
2181
|
-
});
|
|
2182
|
-
}
|
|
2183
|
-
};
|
|
2184
|
-
}
|
|
2185
|
-
async function firstExisting(basePath) {
|
|
2186
|
-
if (await Bun.file(basePath).exists())
|
|
2187
|
-
return basePath;
|
|
2188
|
-
for (const ext of CANDIDATE_EXTS3) {
|
|
2189
|
-
const candidate = `${basePath}${ext}`;
|
|
2190
|
-
if (await Bun.file(candidate).exists())
|
|
2191
|
-
return candidate;
|
|
2192
|
-
}
|
|
2193
|
-
for (const ext of CANDIDATE_EXTS3) {
|
|
2194
|
-
const candidate = path11.join(basePath, `index${ext}`);
|
|
2195
|
-
if (await Bun.file(candidate).exists())
|
|
2196
|
-
return candidate;
|
|
2197
|
-
}
|
|
2198
|
-
return null;
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
|
-
// pkgs/@akanjs/devkit/transforms/useClientBundlePlugin.ts
|
|
2202
|
-
function createUseClientBundlePlugin(options = {}) {
|
|
2203
|
-
return {
|
|
2204
|
-
name: "akan-use-client-bundle",
|
|
2205
|
-
setup(build) {
|
|
2206
|
-
build.onLoad({ filter: /\.(tsx|ts|jsx|js)$/ }, async (args) => {
|
|
2207
|
-
if (args.path.includes("/node_modules/"))
|
|
2208
|
-
return;
|
|
2209
|
-
let source;
|
|
2210
|
-
try {
|
|
2211
|
-
source = await Bun.file(args.path).text();
|
|
2212
|
-
} catch {
|
|
2213
|
-
return;
|
|
2214
|
-
}
|
|
2215
|
-
const stubbed = transformUseClient(source, {
|
|
2216
|
-
path: args.path,
|
|
2217
|
-
workspaceRoot: options.workspaceRoot,
|
|
2218
|
-
onClientModule: options.onClientModule
|
|
2219
|
-
});
|
|
2220
|
-
if (stubbed === null)
|
|
2221
|
-
return;
|
|
2222
|
-
return { contents: stubbed, loader: loaderFor(args.path) };
|
|
2223
|
-
});
|
|
2224
|
-
}
|
|
2225
|
-
};
|
|
2226
|
-
}
|
|
2227
|
-
|
|
2228
|
-
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
2229
|
-
import path12 from "path";
|
|
2230
|
-
class PagesEntrySourceGenerator {
|
|
2231
|
-
#pageEntries;
|
|
2232
|
-
#asyncDefaults = new Map;
|
|
2233
|
-
#detect;
|
|
2234
|
-
constructor(pageEntries, { isAsyncDefault } = {}) {
|
|
2235
|
-
this.#pageEntries = pageEntries;
|
|
2236
|
-
this.#detect = isAsyncDefault ?? ((moduleAbsPath) => AsyncDefaultExportDetector.detect(moduleAbsPath));
|
|
2237
|
-
}
|
|
2238
|
-
static generate(pageEntries) {
|
|
2239
|
-
return new PagesEntrySourceGenerator(pageEntries).generate();
|
|
2240
|
-
}
|
|
2241
|
-
generate() {
|
|
2242
|
-
const lines = this.#pageEntries.map(({ key, moduleAbsPath }) => {
|
|
2243
|
-
const specifier = PagesEntrySourceGenerator.#toImportSpecifier(moduleAbsPath);
|
|
2244
|
-
return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(specifier)}),`;
|
|
2245
|
-
});
|
|
2246
|
-
return `export const pages = {
|
|
2247
|
-
${lines.join(`
|
|
2248
|
-
`)}
|
|
2249
|
-
};
|
|
2250
|
-
`;
|
|
2251
|
-
}
|
|
2252
|
-
static async generateStatic(pageEntries, { fromDir } = {}) {
|
|
2253
|
-
return await new PagesEntrySourceGenerator(pageEntries).generateStatic({ fromDir });
|
|
2254
|
-
}
|
|
2255
|
-
async generateStatic({ fromDir } = {}) {
|
|
2256
|
-
const imports = this.#pageEntries.map(({ moduleAbsPath }, index) => {
|
|
2257
|
-
const specifier = fromDir ? PagesEntrySourceGenerator.#toRelativeSpecifier(fromDir, moduleAbsPath) : PagesEntrySourceGenerator.#toImportSpecifier(moduleAbsPath);
|
|
2258
|
-
return `import * as page${index} from ${JSON.stringify(specifier)};`;
|
|
2259
|
-
});
|
|
2260
|
-
const entries = await Promise.all(this.#pageEntries.map(async ({ key, moduleAbsPath }, index) => {
|
|
2261
|
-
const isAsyncDefault = await this.#isAsyncDefault(moduleAbsPath);
|
|
2262
|
-
return ` ${JSON.stringify(key)}: { loader: async () => page${index}, isAsyncDefault: ${isAsyncDefault} },`;
|
|
2263
|
-
}));
|
|
2264
|
-
return `${imports.join(`
|
|
2265
|
-
`)}
|
|
2266
|
-
export const pages = {
|
|
2267
|
-
${entries.join(`
|
|
2268
|
-
`)}
|
|
2269
|
-
};
|
|
2270
|
-
`;
|
|
2271
|
-
}
|
|
2272
|
-
async generateHotReplace({
|
|
2273
|
-
fromDir,
|
|
2274
|
-
ownerId,
|
|
2275
|
-
moduleIds
|
|
2276
|
-
}) {
|
|
2277
|
-
const entries = await Promise.all(this.#pageEntries.map(async ({ key, moduleAbsPath }) => {
|
|
2278
|
-
const specifier = PagesEntrySourceGenerator.#toRelativeSpecifier(fromDir, moduleAbsPath);
|
|
2279
|
-
const isAsyncDefault = await this.#isAsyncDefault(moduleAbsPath);
|
|
2280
|
-
return ` ${JSON.stringify(key)}: { loader: async () => require(${JSON.stringify(specifier)}), isAsyncDefault: ${isAsyncDefault} },`;
|
|
2281
|
-
}));
|
|
2282
|
-
return `__akan.accept(${JSON.stringify(ownerId)}, ${JSON.stringify(moduleIds)}, async () => {
|
|
2283
|
-
const replaced = await akanWebkit.replacePages({
|
|
2284
|
-
${entries.join(`
|
|
2285
|
-
`)}
|
|
2286
|
-
});
|
|
2287
|
-
if (!replaced) throw new Error("the route table no longer matches the pages it was built from");
|
|
2288
|
-
});
|
|
2289
|
-
`;
|
|
2290
|
-
}
|
|
2291
|
-
#isAsyncDefault(moduleAbsPath) {
|
|
2292
|
-
const known = this.#asyncDefaults.get(moduleAbsPath);
|
|
2293
|
-
if (known)
|
|
2294
|
-
return known;
|
|
2295
|
-
const detected = this.#detect(moduleAbsPath);
|
|
2296
|
-
this.#asyncDefaults.set(moduleAbsPath, detected);
|
|
2297
|
-
return detected;
|
|
2298
|
-
}
|
|
2299
|
-
static #toImportSpecifier(moduleAbsPath) {
|
|
2300
|
-
return path12.resolve(moduleAbsPath).split(path12.sep).join("/");
|
|
2301
|
-
}
|
|
2302
|
-
static #toRelativeSpecifier(fromDir, moduleAbsPath) {
|
|
2303
|
-
const relative = path12.relative(fromDir, path12.resolve(moduleAbsPath)).split(path12.sep).join("/");
|
|
2304
|
-
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
2305
|
-
}
|
|
2306
|
-
}
|
|
2307
|
-
|
|
2308
|
-
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
2309
|
-
var VIRTUAL_PAGES_ENTRY = "akan-pages-entry";
|
|
2310
|
-
|
|
2311
|
-
class PagesBundleBuilder {
|
|
2312
|
-
#app;
|
|
2313
|
-
#command;
|
|
2314
|
-
#pageEntries;
|
|
2315
|
-
#started = Date.now();
|
|
2316
|
-
#serverEnv;
|
|
2317
|
-
constructor(app, command = "start", pageEntries, serverEnv) {
|
|
2318
|
-
this.#app = app;
|
|
2319
|
-
this.#command = command;
|
|
2320
|
-
this.#pageEntries = pageEntries;
|
|
2321
|
-
this.#serverEnv = serverEnv;
|
|
2322
|
-
}
|
|
2323
|
-
async build() {
|
|
2324
|
-
const akanConfig = await this.#app.getConfig();
|
|
2325
|
-
const resolvedEntries = this.#pageEntries ?? await resolveSsrPageEntriesForApp(this.#app, await this.#app.getPageKeys());
|
|
2326
|
-
const entrySource = PagesEntrySourceGenerator.generate(resolvedEntries);
|
|
2327
|
-
const workspaceRoot = this.#app.workspace.workspaceRoot;
|
|
2328
|
-
const dev = this.#command === "start";
|
|
2329
|
-
const clientExports = {};
|
|
2330
|
-
const onClientModule = dev ? (file, exports) => {
|
|
2331
|
-
clientExports[CsrDevPaths.realpath(file)] = exports;
|
|
2332
|
-
} : undefined;
|
|
2333
|
-
const result = await Bun.build({
|
|
2334
|
-
entrypoints: [VIRTUAL_PAGES_ENTRY],
|
|
2335
|
-
outdir: `${this.#artifactDir}/server`,
|
|
2336
|
-
target: "bun",
|
|
2337
|
-
format: "esm",
|
|
2338
|
-
splitting: this.#splitting,
|
|
2339
|
-
minify: this.#command === "build",
|
|
2340
|
-
naming: {
|
|
2341
|
-
entry: "pages-[hash].[ext]",
|
|
2342
|
-
chunk: "chunks/[name]-[hash].[ext]",
|
|
2343
|
-
asset: "assets/[name]-[hash].[ext]"
|
|
2344
|
-
},
|
|
2345
|
-
define: bundleDefine(this.#app, this.#command, "ssr"),
|
|
2346
|
-
metafile: dev,
|
|
2347
|
-
plugins: [
|
|
2348
|
-
...this.#serverEnv ? [this.#serverEnv] : [],
|
|
2349
|
-
PagesBundleBuilder.createPagesEntryPlugin(entrySource),
|
|
2350
|
-
PagesBundleBuilder.createCssStubPlugin(),
|
|
2351
|
-
PagesBundleBuilder.createServerUseClientFetchPlugin(),
|
|
2352
|
-
await createExternalizeFrameworkPlugin({ app: this.#app, extra: akanConfig.externalLibs }),
|
|
2353
|
-
akanConfig.barrelImports.length > 0 ? await createBarrelImportsPlugin(this.#app, {
|
|
2354
|
-
pipeAfter: (source, args) => transformUseClient(source, {
|
|
2355
|
-
path: args.path,
|
|
2356
|
-
workspaceRoot,
|
|
2357
|
-
onClientModule
|
|
2358
|
-
})
|
|
2359
|
-
}) : createUseClientBundlePlugin({ workspaceRoot, onClientModule })
|
|
2360
|
-
]
|
|
2361
|
-
});
|
|
2362
|
-
if (!result.success)
|
|
2363
|
-
throw new AggregateError(result.logs, "[PagesBundleBuilder] Bun.build failed");
|
|
2364
|
-
const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
|
|
2365
|
-
if (!entryArtifact)
|
|
2366
|
-
throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
|
|
2367
|
-
const bundlePath = path13.resolve(entryArtifact.path);
|
|
2368
|
-
const buildId = Date.now();
|
|
2369
|
-
if (dev && result.metafile)
|
|
2370
|
-
await ServerGraphFile.write(this.#artifactDir, this.#serverGraph(result.metafile, clientExports));
|
|
2371
|
-
const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
|
|
2372
|
-
const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
|
|
2373
|
-
this.#app.verbose(`[PagesBundleBuilder] ${path13.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
|
|
2374
|
-
return {
|
|
2375
|
-
bundlePath,
|
|
2376
|
-
buildId,
|
|
2377
|
-
splitting: this.#splitting,
|
|
2378
|
-
entryBytes: entryArtifact.size,
|
|
2379
|
-
outputBytes,
|
|
2380
|
-
outputCount: result.outputs.length,
|
|
2381
|
-
chunkCount
|
|
2382
|
-
};
|
|
2383
|
-
}
|
|
2384
|
-
#serverGraph(metafile, clientExports) {
|
|
2385
|
-
const inputs = Object.keys(metafile.inputs).filter((input) => !input.includes("node_modules")).map((input) => path13.resolve(input)).filter((input) => fs5.existsSync(input)).map((input) => CsrDevPaths.realpath(input));
|
|
2386
|
-
return { inputs, clientExports };
|
|
2387
|
-
}
|
|
2388
|
-
get #artifactDir() {
|
|
2389
|
-
return `${this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath}/.akan/artifact`;
|
|
2390
|
-
}
|
|
2391
|
-
get #splitting() {
|
|
2392
|
-
return process.env.AKAN_SERVER_PAGES_SPLITTING === "1";
|
|
2393
|
-
}
|
|
2394
|
-
static createPagesEntryPlugin(source) {
|
|
2395
|
-
return {
|
|
2396
|
-
name: "akan-pages-entry",
|
|
2397
|
-
setup(build) {
|
|
2398
|
-
build.onResolve({ filter: /^akan-pages-entry$/ }, () => ({
|
|
2399
|
-
path: VIRTUAL_PAGES_ENTRY,
|
|
2400
|
-
namespace: "akan-virtual"
|
|
2401
|
-
}));
|
|
2402
|
-
build.onLoad({ filter: /^akan-pages-entry$/, namespace: "akan-virtual" }, () => ({
|
|
2403
|
-
contents: source,
|
|
2404
|
-
loader: "tsx"
|
|
2405
|
-
}));
|
|
2406
|
-
}
|
|
2407
|
-
};
|
|
2408
|
-
}
|
|
2409
|
-
static createCssStubPlugin() {
|
|
2410
|
-
return {
|
|
2411
|
-
name: "akan-css-stub",
|
|
2412
|
-
setup(build) {
|
|
2413
|
-
build.onLoad({ filter: /\.css$/ }, () => ({
|
|
2414
|
-
contents: "",
|
|
2415
|
-
loader: "js"
|
|
2416
|
-
}));
|
|
2417
|
-
}
|
|
2418
|
-
};
|
|
2419
|
-
}
|
|
2420
|
-
static createServerUseClientFetchPlugin() {
|
|
2421
|
-
return {
|
|
2422
|
-
name: "akan-server-use-client-fetch",
|
|
2423
|
-
setup(build) {
|
|
2424
|
-
build.onLoad({ filter: /[/\\]lib[/\\]useClient\.(ts|tsx|js|jsx)$/ }, async (args) => {
|
|
2425
|
-
const source = await Bun.file(args.path).text();
|
|
2426
|
-
const transformed = PagesBundleBuilder.transformServerUseClientFetchSource(source);
|
|
2427
|
-
if (transformed === source)
|
|
2428
|
-
return;
|
|
2429
|
-
return { contents: transformed, loader: loaderFor(args.path) };
|
|
2430
|
-
});
|
|
2431
|
-
}
|
|
2432
|
-
};
|
|
2433
|
-
}
|
|
2434
|
-
static transformServerUseClientFetchSource(source) {
|
|
2435
|
-
if (!source.includes(`with { type: "macro" }`) || !source.includes("FetchClient.build"))
|
|
2436
|
-
return source;
|
|
2437
|
-
return source.replace(/import\s+\{\s*getSerializedSignal\s*\}\s+from\s+["']\.\/sig["']\s+with\s+\{\s*type\s*:\s*["']macro["']\s*\};/, `import { fetch as serverFetch } from "./sig";`).replace(/const\s+fetchProto\s*=\s*FetchClient\.build<[^;]+;/, "const fetchProto = FetchClient.build<typeof signal>(cnst, serverFetch.serializedSignal, { Err: pageProto.Err, base: serverFetch });");
|
|
2438
|
-
}
|
|
2439
|
-
}
|
|
2440
|
-
|
|
2441
1364
|
// pkgs/@akanjs/devkit/frontendBuild/csrDevPatcher.ts
|
|
2442
|
-
import
|
|
2443
|
-
import
|
|
1365
|
+
import fs4 from "fs";
|
|
1366
|
+
import path7 from "path";
|
|
2444
1367
|
import { appGenerationOf, CSR_DEV_MANIFEST_FILE } from "akanjs/server/hmr/csrDevManifest";
|
|
2445
1368
|
|
|
2446
1369
|
// pkgs/@akanjs/devkit/frontendBuild/csrDevResolver.ts
|
|
2447
|
-
import
|
|
2448
|
-
import
|
|
1370
|
+
import fs3 from "fs";
|
|
1371
|
+
import path6 from "path";
|
|
2449
1372
|
class CsrDevResolver {
|
|
2450
1373
|
static inline = "inline";
|
|
2451
1374
|
#paths;
|
|
@@ -2527,7 +1450,7 @@ class CsrDevResolver {
|
|
|
2527
1450
|
}
|
|
2528
1451
|
#record(inputs, only) {
|
|
2529
1452
|
for (const [input, { imports }] of Object.entries(inputs)) {
|
|
2530
|
-
const importer = CsrDevPaths.realpath(
|
|
1453
|
+
const importer = CsrDevPaths.realpath(path6.resolve(input));
|
|
2531
1454
|
if (only && !only.has(importer))
|
|
2532
1455
|
continue;
|
|
2533
1456
|
if (imports.every((record) => record.original))
|
|
@@ -2540,8 +1463,8 @@ class CsrDevResolver {
|
|
|
2540
1463
|
this.#remember(importer, record.original, `${CsrDevPaths.stubPrefix}${record.original}`);
|
|
2541
1464
|
continue;
|
|
2542
1465
|
}
|
|
2543
|
-
const target =
|
|
2544
|
-
if (!
|
|
1466
|
+
const target = path6.resolve(record.path);
|
|
1467
|
+
if (!fs3.existsSync(target))
|
|
2545
1468
|
continue;
|
|
2546
1469
|
this.#remember(importer, record.original, CsrDevPaths.realpath(target));
|
|
2547
1470
|
this.#runtimeResolved.get(importer)?.delete(record.original);
|
|
@@ -2568,13 +1491,13 @@ class CsrDevResolver {
|
|
|
2568
1491
|
#stillAnswers(importer, specifier, known, kind) {
|
|
2569
1492
|
if (CsrDevPaths.isStub(known))
|
|
2570
1493
|
return true;
|
|
2571
|
-
if (!
|
|
1494
|
+
if (!fs3.existsSync(known))
|
|
2572
1495
|
return false;
|
|
2573
1496
|
if (!specifier.startsWith(".") || CsrDevPaths.isVendorFile(importer))
|
|
2574
1497
|
return true;
|
|
2575
|
-
if (this.#hasBrowserMap(
|
|
1498
|
+
if (this.#hasBrowserMap(path6.dirname(importer)))
|
|
2576
1499
|
return true;
|
|
2577
|
-
const onDisk = CsrDevPaths.resolveRelative(
|
|
1500
|
+
const onDisk = CsrDevPaths.resolveRelative(path6.dirname(importer), specifier, kind);
|
|
2578
1501
|
return onDisk !== null && CsrDevPaths.realpath(onDisk) === known;
|
|
2579
1502
|
}
|
|
2580
1503
|
isRegistryModule(file) {
|
|
@@ -2589,12 +1512,12 @@ class CsrDevResolver {
|
|
|
2589
1512
|
});
|
|
2590
1513
|
}
|
|
2591
1514
|
#disabledInBrowser(importer, specifier, kind) {
|
|
2592
|
-
const map = this.#browserMapOf(
|
|
1515
|
+
const map = this.#browserMapOf(path6.dirname(importer));
|
|
2593
1516
|
if (!map || map.offFiles.size === 0 && map.offNames.size === 0)
|
|
2594
1517
|
return null;
|
|
2595
|
-
if (!specifier.startsWith(".") && !
|
|
1518
|
+
if (!specifier.startsWith(".") && !path6.isAbsolute(specifier))
|
|
2596
1519
|
return map.offNames.has(specifier) ? `${CsrDevPaths.emptyStubPrefix}${specifier}` : null;
|
|
2597
|
-
const target = CsrDevPaths.resolveRelative(
|
|
1520
|
+
const target = CsrDevPaths.resolveRelative(path6.dirname(importer), specifier, kind);
|
|
2598
1521
|
return target && map.offFiles.has(CsrDevPaths.realpath(target)) ? `${CsrDevPaths.emptyStubPrefix}${this.#paths.idOf(target)}` : null;
|
|
2599
1522
|
}
|
|
2600
1523
|
#hasBrowserMap(dir) {
|
|
@@ -2604,12 +1527,12 @@ class CsrDevResolver {
|
|
|
2604
1527
|
const cached = this.#browserMaps.get(dir);
|
|
2605
1528
|
if (cached !== undefined)
|
|
2606
1529
|
return cached;
|
|
2607
|
-
const pkgFile =
|
|
2608
|
-
const parent =
|
|
1530
|
+
const pkgFile = path6.join(dir, "package.json");
|
|
1531
|
+
const parent = path6.dirname(dir);
|
|
2609
1532
|
let map = null;
|
|
2610
|
-
if (
|
|
1533
|
+
if (fs3.existsSync(pkgFile)) {
|
|
2611
1534
|
try {
|
|
2612
|
-
const browser = JSON.parse(
|
|
1535
|
+
const browser = JSON.parse(fs3.readFileSync(pkgFile, "utf8")).browser;
|
|
2613
1536
|
if (typeof browser === "object" && browser !== null) {
|
|
2614
1537
|
const off = Object.entries(browser).filter(([, target]) => target === false).map(([key]) => key);
|
|
2615
1538
|
const files = off.filter((key) => key.startsWith(".")).map((key) => CsrDevPaths.resolveRelative(dir, key)).filter((file) => !!file);
|
|
@@ -2634,16 +1557,16 @@ class CsrDevResolver {
|
|
|
2634
1557
|
serialize() {
|
|
2635
1558
|
return Object.fromEntries([...this.#resolution].map(([importer, bySpecifier]) => [
|
|
2636
1559
|
this.#paths.idOf(importer),
|
|
2637
|
-
Object.fromEntries([...bySpecifier].filter(([, target]) => CsrDevPaths.isStub(target) ||
|
|
1560
|
+
Object.fromEntries([...bySpecifier].filter(([, target]) => CsrDevPaths.isStub(target) || fs3.existsSync(target)).map(([specifier, target]) => [specifier, CsrDevPaths.isStub(target) ? target : this.#paths.idOf(target)]))
|
|
2638
1561
|
]));
|
|
2639
1562
|
}
|
|
2640
1563
|
#resolveUnknown(importer, specifier, kind) {
|
|
2641
1564
|
if (specifier.startsWith("node:"))
|
|
2642
1565
|
return `${CsrDevPaths.stubPrefix}${specifier}`;
|
|
2643
|
-
const relative = specifier.startsWith(".") ||
|
|
1566
|
+
const relative = specifier.startsWith(".") || path6.isAbsolute(specifier);
|
|
2644
1567
|
const cannotResolve = () => new Error(`[csr-dev] cannot resolve "${specifier}" from ${this.#paths.idOf(importer)}`);
|
|
2645
1568
|
if (relative) {
|
|
2646
|
-
const onDisk = CsrDevPaths.resolveRelative(
|
|
1569
|
+
const onDisk = CsrDevPaths.resolveRelative(path6.dirname(importer), specifier, kind) ?? CsrDevResolver.#onDisk(CsrDevPaths.tryResolve(specifier, path6.dirname(importer)));
|
|
2647
1570
|
if (!onDisk)
|
|
2648
1571
|
throw cannotResolve();
|
|
2649
1572
|
return CsrDevPaths.realpath(onDisk);
|
|
@@ -2651,9 +1574,9 @@ class CsrDevResolver {
|
|
|
2651
1574
|
const sibling = this.#resolvedBySibling(importer, specifier);
|
|
2652
1575
|
if (sibling)
|
|
2653
1576
|
return sibling;
|
|
2654
|
-
const resolved = CsrDevPaths.tryResolve(specifier,
|
|
2655
|
-
const moved = resolved !== null &&
|
|
2656
|
-
const installed = resolved === null && CsrDevPaths.installedSince(specifier,
|
|
1577
|
+
const resolved = CsrDevPaths.tryResolve(specifier, path6.dirname(importer));
|
|
1578
|
+
const moved = resolved !== null && path6.isAbsolute(resolved) && !fs3.existsSync(resolved);
|
|
1579
|
+
const installed = resolved === null && CsrDevPaths.installedSince(specifier, path6.dirname(importer), this.#startedAt);
|
|
2657
1580
|
if (!this.#prepassDone || moved) {
|
|
2658
1581
|
if (resolved === null && !installed && !CsrDevPaths.isVendorFile(importer))
|
|
2659
1582
|
throw cannotResolve();
|
|
@@ -2664,14 +1587,14 @@ class CsrDevResolver {
|
|
|
2664
1587
|
return null;
|
|
2665
1588
|
throw cannotResolve();
|
|
2666
1589
|
}
|
|
2667
|
-
if (!
|
|
1590
|
+
if (!path6.isAbsolute(resolved))
|
|
2668
1591
|
return `${CsrDevPaths.stubPrefix}${specifier}`;
|
|
2669
1592
|
this.#fallbacks.add(specifier);
|
|
2670
1593
|
this.#runtimeResolved.set(importer, (this.#runtimeResolved.get(importer) ?? new Set).add(specifier));
|
|
2671
1594
|
return CsrDevPaths.realpath(resolved);
|
|
2672
1595
|
}
|
|
2673
1596
|
static #onDisk(resolved) {
|
|
2674
|
-
return resolved &&
|
|
1597
|
+
return resolved && path6.isAbsolute(resolved) && fs3.existsSync(resolved) ? resolved : null;
|
|
2675
1598
|
}
|
|
2676
1599
|
#resolvedBySibling(importer, specifier) {
|
|
2677
1600
|
const scope = CsrDevResolver.#packageScopeOf(importer);
|
|
@@ -2679,7 +1602,7 @@ class CsrDevResolver {
|
|
|
2679
1602
|
const target = bySpecifier.get(specifier);
|
|
2680
1603
|
if (!target || other === importer || this.#runtimeResolved.get(other)?.has(specifier))
|
|
2681
1604
|
continue;
|
|
2682
|
-
if (!CsrDevPaths.isStub(target) && !
|
|
1605
|
+
if (!CsrDevPaths.isStub(target) && !fs3.existsSync(target))
|
|
2683
1606
|
continue;
|
|
2684
1607
|
if (CsrDevResolver.#packageScopeOf(other) === scope)
|
|
2685
1608
|
return target;
|
|
@@ -2691,7 +1614,7 @@ class CsrDevResolver {
|
|
|
2691
1614
|
this.#resolution.set(importer, byImporter.set(specifier, target));
|
|
2692
1615
|
}
|
|
2693
1616
|
#isInlineSpecifier(specifier) {
|
|
2694
|
-
if (specifier.startsWith(".") ||
|
|
1617
|
+
if (specifier.startsWith(".") || path6.isAbsolute(specifier) || specifier.startsWith("node:"))
|
|
2695
1618
|
return false;
|
|
2696
1619
|
return this.#context.optimizeImports.some((pattern) => {
|
|
2697
1620
|
const base = CsrDevResolver.#patternBase(pattern);
|
|
@@ -2702,20 +1625,20 @@ class CsrDevResolver {
|
|
|
2702
1625
|
return pattern.endsWith("/*") ? pattern.slice(0, -2) : pattern;
|
|
2703
1626
|
}
|
|
2704
1627
|
static #packageNameOf(file) {
|
|
2705
|
-
const marker = `${
|
|
1628
|
+
const marker = `${path6.sep}node_modules${path6.sep}`;
|
|
2706
1629
|
const index = file.lastIndexOf(marker);
|
|
2707
1630
|
if (index < 0)
|
|
2708
1631
|
return null;
|
|
2709
|
-
const [scope, name] = file.slice(index + marker.length).split(
|
|
1632
|
+
const [scope, name] = file.slice(index + marker.length).split(path6.sep);
|
|
2710
1633
|
return (scope?.startsWith("@") ? `${scope}/${name}` : scope) || null;
|
|
2711
1634
|
}
|
|
2712
1635
|
static #packageScopeOf(file) {
|
|
2713
|
-
const marker = `${
|
|
1636
|
+
const marker = `${path6.sep}node_modules${path6.sep}`;
|
|
2714
1637
|
const index = file.lastIndexOf(marker);
|
|
2715
1638
|
if (index < 0)
|
|
2716
1639
|
return "";
|
|
2717
|
-
const [scope, name] = file.slice(index + marker.length).split(
|
|
2718
|
-
return file.slice(0, index + marker.length) + (scope?.startsWith("@") ? `${scope}${
|
|
1640
|
+
const [scope, name] = file.slice(index + marker.length).split(path6.sep);
|
|
1641
|
+
return file.slice(0, index + marker.length) + (scope?.startsWith("@") ? `${scope}${path6.sep}${name}` : scope);
|
|
2719
1642
|
}
|
|
2720
1643
|
}
|
|
2721
1644
|
|
|
@@ -2753,11 +1676,11 @@ class CsrDevPatcher {
|
|
|
2753
1676
|
return this.#handBack("the dev bundle config changed", generation, context);
|
|
2754
1677
|
const metadataFile = changedFiles.find((file) => this.#bundler.isMetadataFile(file));
|
|
2755
1678
|
if (metadataFile)
|
|
2756
|
-
return this.#handBack(`${
|
|
1679
|
+
return this.#handBack(`${path7.basename(metadataFile)} changed`, generation, context);
|
|
2757
1680
|
if (!resident && state.graph.metadata !== await this.#bundler.metadataFingerprint())
|
|
2758
1681
|
return this.#handBack("signal or dictionary metadata changed since the registry was built", generation, context);
|
|
2759
1682
|
this.#state = this.#resident ? state : null;
|
|
2760
|
-
const healable = appGenerationOf(state.manifest) < state.manifest.generation && this.#withoutFactory(state, (file) =>
|
|
1683
|
+
const healable = appGenerationOf(state.manifest) < state.manifest.generation && this.#withoutFactory(state, (file) => fs4.existsSync(file)).length === 0;
|
|
2761
1684
|
if (healable)
|
|
2762
1685
|
state.manifest = await this.#bundler.writer.healApp(state.graph, state.manifest, await this.#code(state));
|
|
2763
1686
|
return await this.#patch(context, state, changedFiles, generation, {
|
|
@@ -2779,7 +1702,7 @@ class CsrDevPatcher {
|
|
|
2779
1702
|
changed.add(id);
|
|
2780
1703
|
for (const file of entries.changed)
|
|
2781
1704
|
changed.add(paths.idOf(file));
|
|
2782
|
-
const rootFiles = [...Object.values(entries.files), ...roots.filter((file) =>
|
|
1705
|
+
const rootFiles = [...Object.values(entries.files), ...roots.filter((file) => fs4.existsSync(file))];
|
|
2783
1706
|
for (const file of rootFiles) {
|
|
2784
1707
|
const id = paths.idOf(file);
|
|
2785
1708
|
if (!graph.modules[id] && !(onlyRoots && await this.#parked(graph, id)))
|
|
@@ -2857,7 +1780,7 @@ class CsrDevPatcher {
|
|
|
2857
1780
|
}
|
|
2858
1781
|
const changedIds = compiled.filter((module) => !module.vendor).map((module) => module.id);
|
|
2859
1782
|
const constantId = changedIds.find((id) => id.endsWith(".constant.ts"));
|
|
2860
|
-
const reason = vendorJoined ? "an npm module joined the graph" : routesMoved ? "the route table changed" : constantId ? `${
|
|
1783
|
+
const reason = vendorJoined ? "an npm module joined the graph" : routesMoved ? "the route table changed" : constantId ? `${path7.basename(constantId)} changed` : undefined;
|
|
2861
1784
|
if (compiled.length === 0 && !reason) {
|
|
2862
1785
|
await writer.writeJson("graph.json", graph);
|
|
2863
1786
|
await writer.forgetModules(forgotten);
|
|
@@ -2971,9 +1894,9 @@ class CsrDevPatcher {
|
|
|
2971
1894
|
const messages = error instanceof AggregateError ? error.errors : [];
|
|
2972
1895
|
const named = messages.flatMap((message) => {
|
|
2973
1896
|
const text = String(message.message ?? "");
|
|
2974
|
-
const bases = [process.cwd(), ...failing.map((file) =>
|
|
1897
|
+
const bases = [process.cwd(), ...failing.map((file) => path7.dirname(file))];
|
|
2975
1898
|
return [...text.matchAll(/"([^"\n]+)"/g)].flatMap(([, quoted = ""]) => {
|
|
2976
|
-
const found = bases.map((base) =>
|
|
1899
|
+
const found = bases.map((base) => path7.resolve(base, quoted)).find((file) => CsrDevPaths.isScript(file) && fs4.existsSync(file));
|
|
2977
1900
|
return found ? [CsrDevPaths.realpath(found)] : [];
|
|
2978
1901
|
});
|
|
2979
1902
|
});
|
|
@@ -2981,7 +1904,7 @@ class CsrDevPatcher {
|
|
|
2981
1904
|
}
|
|
2982
1905
|
static #failingFiles(error) {
|
|
2983
1906
|
const messages = error instanceof AggregateError ? error.errors : [];
|
|
2984
|
-
return messages.map((message) => message.position?.file).filter((file) => typeof file === "string" &&
|
|
1907
|
+
return messages.map((message) => message.position?.file).filter((file) => typeof file === "string" && path7.isAbsolute(file)).map((file) => CsrDevPaths.realpath(file));
|
|
2985
1908
|
}
|
|
2986
1909
|
async#carriedRoots(graph, changed, present) {
|
|
2987
1910
|
const { paths } = this.#bundler;
|
|
@@ -3024,8 +1947,8 @@ class CsrDevPatcher {
|
|
|
3024
1947
|
return Object.entries(graph.modules).filter(([id, module]) => !module.vendor && !hasFactory(id) && present(paths.fileOf(id))).map(([id]) => id);
|
|
3025
1948
|
}
|
|
3026
1949
|
static #presence(changedFiles) {
|
|
3027
|
-
const caseMoved = changedFiles.some((file) =>
|
|
3028
|
-
return caseMoved ? (file) => CsrDevPaths.isNamed(file) : (file) =>
|
|
1950
|
+
const caseMoved = changedFiles.some((file) => fs4.existsSync(file) && !CsrDevPaths.isNamed(file));
|
|
1951
|
+
return caseMoved ? (file) => CsrDevPaths.isNamed(file) : (file) => fs4.existsSync(file);
|
|
3029
1952
|
}
|
|
3030
1953
|
#handBack(reason, generation, context, { first = false } = {}) {
|
|
3031
1954
|
this.#state = null;
|
|
@@ -3080,17 +2003,17 @@ class CsrDevPatcher {
|
|
|
3080
2003
|
}
|
|
3081
2004
|
#shadowedImporters(graph, changedFiles) {
|
|
3082
2005
|
const { paths } = this.#bundler;
|
|
3083
|
-
const bases = new Set(changedFiles.map((file) => CsrDevPaths.realpath(file)).filter((file) => !graph.modules[paths.idOf(file)] && CsrDevPaths.isScript(file) &&
|
|
3084
|
-
const stem = file.slice(0, file.length -
|
|
3085
|
-
return
|
|
2006
|
+
const bases = new Set(changedFiles.map((file) => CsrDevPaths.realpath(file)).filter((file) => !graph.modules[paths.idOf(file)] && CsrDevPaths.isScript(file) && fs4.existsSync(file)).flatMap((file) => {
|
|
2007
|
+
const stem = file.slice(0, file.length - path7.extname(file).length);
|
|
2008
|
+
return path7.basename(stem) === "index" ? [stem, path7.dirname(stem)] : [stem];
|
|
3086
2009
|
}));
|
|
3087
2010
|
if (bases.size === 0)
|
|
3088
2011
|
return [];
|
|
3089
2012
|
return Object.entries(graph.resolution).filter(([importer, bySpecifier]) => {
|
|
3090
2013
|
if (!graph.modules[importer] || graph.modules[importer]?.vendor)
|
|
3091
2014
|
return false;
|
|
3092
|
-
const dir =
|
|
3093
|
-
return Object.keys(bySpecifier).some((specifier) => specifier.startsWith(".") && bases.has(
|
|
2015
|
+
const dir = path7.dirname(paths.fileOf(importer));
|
|
2016
|
+
return Object.keys(bySpecifier).some((specifier) => specifier.startsWith(".") && bases.has(path7.resolve(dir, specifier)));
|
|
3094
2017
|
}).map(([importer]) => importer);
|
|
3095
2018
|
}
|
|
3096
2019
|
#forgetDeletedModules({ graph, code }, present) {
|
|
@@ -3106,39 +2029,18 @@ class CsrDevPatcher {
|
|
|
3106
2029
|
|
|
3107
2030
|
// pkgs/@akanjs/devkit/frontendBuild/csrDevBundler.ts
|
|
3108
2031
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
3109
|
-
import
|
|
2032
|
+
import path12 from "path";
|
|
3110
2033
|
import { CSR_DEV_DIRNAME, CSR_DEV_ROUTE_PREFIX } from "akanjs/server/hmr/csrDevManifest";
|
|
3111
2034
|
|
|
3112
|
-
// pkgs/@akanjs/devkit/frontendBuild/csrEntryFiles.ts
|
|
3113
|
-
import path16 from "path";
|
|
3114
|
-
|
|
3115
|
-
class CsrEntryFiles {
|
|
3116
|
-
static entryFilename(basePath) {
|
|
3117
|
-
return `${basePath || "index"}.csr.tsx`;
|
|
3118
|
-
}
|
|
3119
|
-
static pageEntriesForBasePath(pageEntries, basePath, basePaths) {
|
|
3120
|
-
return pageEntries.filter((entry) => {
|
|
3121
|
-
const entryBasePath = CsrEntryFiles.basePathOfPageKey(entry.key, basePaths);
|
|
3122
|
-
return entryBasePath === null || entryBasePath === basePath;
|
|
3123
|
-
});
|
|
3124
|
-
}
|
|
3125
|
-
static basePathOfPageKey(pageKey, basePaths) {
|
|
3126
|
-
const normalized = pageKey.split(path16.sep).join("/").replace(/^\.\//, "");
|
|
3127
|
-
const segments = normalized.split("/");
|
|
3128
|
-
const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
|
|
3129
|
-
return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
|
|
3133
2035
|
// pkgs/@akanjs/devkit/frontendBuild/devRegistryBundler.ts
|
|
3134
|
-
import
|
|
3135
|
-
import
|
|
2036
|
+
import fs7 from "fs";
|
|
2037
|
+
import path11 from "path";
|
|
3136
2038
|
import { isAkanRuntimeMetadataFile } from "akanjs/server/hmr/runtimeMetadataFile";
|
|
3137
2039
|
|
|
3138
2040
|
// pkgs/@akanjs/devkit/frontendBuild/csrDevArtifactWriter.ts
|
|
3139
|
-
import
|
|
2041
|
+
import fs5 from "fs";
|
|
3140
2042
|
import { mkdir as mkdir2, readdir as readdir2, rm } from "fs/promises";
|
|
3141
|
-
import
|
|
2043
|
+
import path8 from "path";
|
|
3142
2044
|
import {
|
|
3143
2045
|
appGenerationOf as appGenerationOf2,
|
|
3144
2046
|
CSR_DEV_APP_FILE,
|
|
@@ -3159,19 +2061,19 @@ class CsrDevArtifactWriter {
|
|
|
3159
2061
|
this.#library = library;
|
|
3160
2062
|
}
|
|
3161
2063
|
async markBuilding() {
|
|
3162
|
-
await Bun.write(
|
|
2064
|
+
await Bun.write(path8.join(this.#outDir, CsrDevArtifactWriter.#buildingMarker), String(process.pid));
|
|
3163
2065
|
}
|
|
3164
2066
|
async clearBuilding() {
|
|
3165
|
-
await CsrDevArtifactWriter.#remove(
|
|
2067
|
+
await CsrDevArtifactWriter.#remove(path8.join(this.#outDir, CsrDevArtifactWriter.#buildingMarker));
|
|
3166
2068
|
}
|
|
3167
2069
|
async isBuilding() {
|
|
3168
|
-
return await Bun.file(
|
|
2070
|
+
return await Bun.file(path8.join(this.#outDir, CsrDevArtifactWriter.#buildingMarker)).exists();
|
|
3169
2071
|
}
|
|
3170
2072
|
async forgetPatch(generation) {
|
|
3171
|
-
await Promise.all([`patch-${generation}.js`, `patch-${generation}.js.layout.json`].map((name) => CsrDevArtifactWriter.#remove(
|
|
2073
|
+
await Promise.all([`patch-${generation}.js`, `patch-${generation}.js.layout.json`].map((name) => CsrDevArtifactWriter.#remove(path8.join(this.#outDir, name))));
|
|
3172
2074
|
}
|
|
3173
2075
|
async readJson(name) {
|
|
3174
|
-
const file = Bun.file(
|
|
2076
|
+
const file = Bun.file(path8.join(this.#outDir, name));
|
|
3175
2077
|
if (!await file.exists())
|
|
3176
2078
|
return null;
|
|
3177
2079
|
return await file.json().catch(() => null);
|
|
@@ -3180,7 +2082,7 @@ class CsrDevArtifactWriter {
|
|
|
3180
2082
|
await this.#writeAtomic(name, JSON.stringify(value));
|
|
3181
2083
|
}
|
|
3182
2084
|
async writeModules(compiled) {
|
|
3183
|
-
await mkdir2(
|
|
2085
|
+
await mkdir2(path8.join(this.#outDir, "modules"), { recursive: true });
|
|
3184
2086
|
const helpers = new Map(compiled.flatMap((module) => module.helpers ? [[module.helpers.hash, module.helpers]] : []));
|
|
3185
2087
|
await Promise.all([
|
|
3186
2088
|
...compiled.flatMap((module) => [
|
|
@@ -3200,7 +2102,7 @@ class CsrDevArtifactWriter {
|
|
|
3200
2102
|
return { modules: new Map(modules), helpers: new Map(helpers) };
|
|
3201
2103
|
}
|
|
3202
2104
|
hasModule(id) {
|
|
3203
|
-
return
|
|
2105
|
+
return fs5.existsSync(this.#modulePath(id, ".js"));
|
|
3204
2106
|
}
|
|
3205
2107
|
async forgetModules(ids) {
|
|
3206
2108
|
await Promise.all(ids.flatMap((id) => [
|
|
@@ -3277,8 +2179,8 @@ class CsrDevArtifactWriter {
|
|
|
3277
2179
|
const patch = /^patch-(\d+)\.js(?:\.layout\.json)?$/.exec(name);
|
|
3278
2180
|
return patch ? Number(patch[1]) <= generation - CSR_DEV_KEPT_PATCHES : false;
|
|
3279
2181
|
});
|
|
3280
|
-
const vendors = names.filter((name) => /^vendor-[\w-]+\.js$/.test(name) && name !== vendorFile).map((name) => ({ name, mtimeMs: CsrDevPaths.mtimeOf(
|
|
3281
|
-
await Promise.all([...stale, ...vendors].map((name) => CsrDevArtifactWriter.#remove(
|
|
2182
|
+
const vendors = names.filter((name) => /^vendor-[\w-]+\.js$/.test(name) && name !== vendorFile).map((name) => ({ name, mtimeMs: CsrDevPaths.mtimeOf(path8.join(this.#outDir, name)) })).sort((a, b) => b.mtimeMs - a.mtimeMs).slice(CsrDevArtifactWriter.#keptVendors - 1).map(({ name }) => name);
|
|
2183
|
+
await Promise.all([...stale, ...vendors].map((name) => CsrDevArtifactWriter.#remove(path8.join(this.#outDir, name))));
|
|
3282
2184
|
}
|
|
3283
2185
|
async pruneAfterFullBuild(graph, vendorFile, { generation, assets }) {
|
|
3284
2186
|
const kept = new Set(Object.keys(graph.modules).flatMap((id) => [this.#modulePath(id, ".js"), this.#modulePath(id, ".js.map")]));
|
|
@@ -3286,16 +2188,16 @@ class CsrDevArtifactWriter {
|
|
|
3286
2188
|
if (module.helpers)
|
|
3287
2189
|
kept.add(this.#helpersPath(module.helpers));
|
|
3288
2190
|
for (const asset of assets)
|
|
3289
|
-
kept.add(
|
|
3290
|
-
const listed = async (dir) => (await readdir2(
|
|
2191
|
+
kept.add(path8.resolve(asset));
|
|
2192
|
+
const listed = async (dir) => (await readdir2(path8.join(this.#outDir, dir)).catch(() => [])).map((name) => path8.join(this.#outDir, dir, name));
|
|
3291
2193
|
const stale = [
|
|
3292
2194
|
...(await listed("modules")).filter((file) => !kept.has(file)),
|
|
3293
2195
|
...(await listed("assets")).filter((file) => !kept.has(file)),
|
|
3294
2196
|
...(await listed(".")).filter((file) => {
|
|
3295
|
-
const name =
|
|
2197
|
+
const name = path8.basename(file);
|
|
3296
2198
|
return /^patch-\d+\.js(?:\.layout\.json)?$/.test(name) || name.endsWith(".tmp");
|
|
3297
2199
|
}),
|
|
3298
|
-
|
|
2200
|
+
path8.join(this.#outDir, CSR_DEV_PATCHING_MARKER)
|
|
3299
2201
|
];
|
|
3300
2202
|
await Promise.all(stale.map((file) => CsrDevArtifactWriter.#remove(file)));
|
|
3301
2203
|
await this.prune(vendorFile, generation);
|
|
@@ -3325,7 +2227,7 @@ class CsrDevArtifactWriter {
|
|
|
3325
2227
|
await this.#writeAtomic(name, code);
|
|
3326
2228
|
}
|
|
3327
2229
|
async#writeAtomic(name, content) {
|
|
3328
|
-
const target =
|
|
2230
|
+
const target = path8.join(this.#outDir, name);
|
|
3329
2231
|
const temp = `${target}.${process.pid}.tmp`;
|
|
3330
2232
|
await Bun.write(temp, content);
|
|
3331
2233
|
await FileSys2.replace(temp, target);
|
|
@@ -3341,15 +2243,15 @@ class CsrDevArtifactWriter {
|
|
|
3341
2243
|
await Bun.sleep(ms);
|
|
3342
2244
|
}
|
|
3343
2245
|
#modulePath(id, extension) {
|
|
3344
|
-
return
|
|
2246
|
+
return path8.join(this.#outDir, csrDevModuleFile(id, extension));
|
|
3345
2247
|
}
|
|
3346
2248
|
#helpersPath(hash) {
|
|
3347
|
-
return
|
|
2249
|
+
return path8.join(this.#outDir, "modules", `helpers-${hash}.js`);
|
|
3348
2250
|
}
|
|
3349
2251
|
}
|
|
3350
2252
|
|
|
3351
2253
|
// pkgs/@akanjs/devkit/frontendBuild/csrDevModuleCompiler.ts
|
|
3352
|
-
import
|
|
2254
|
+
import path9 from "path";
|
|
3353
2255
|
|
|
3354
2256
|
// pkgs/@akanjs/devkit/frontendBuild/csrDevFactoryCheck.ts
|
|
3355
2257
|
class CsrDevFactoryCheck {
|
|
@@ -3499,7 +2401,7 @@ class CsrDevModuleCompiler {
|
|
|
3499
2401
|
const tangled = [];
|
|
3500
2402
|
for (const artifact of result.outputs) {
|
|
3501
2403
|
if (artifact.kind === "asset") {
|
|
3502
|
-
const assetPath =
|
|
2404
|
+
const assetPath = path9.join(this.#outDir, artifact.path);
|
|
3503
2405
|
await Bun.write(assetPath, artifact);
|
|
3504
2406
|
this.#assets.add(assetPath);
|
|
3505
2407
|
continue;
|
|
@@ -3509,8 +2411,8 @@ class CsrDevModuleCompiler {
|
|
|
3509
2411
|
const meta = outputs[artifact.path];
|
|
3510
2412
|
if (!meta?.entryPoint)
|
|
3511
2413
|
throw new Error(`[csr-dev] no entry point recorded for ${artifact.path}`);
|
|
3512
|
-
const file = CsrDevPaths.realpath(
|
|
3513
|
-
const inputs = Object.keys(meta.inputs).map((input) => CsrDevPaths.realpath(
|
|
2414
|
+
const file = CsrDevPaths.realpath(path9.resolve(meta.entryPoint));
|
|
2415
|
+
const inputs = Object.keys(meta.inputs).map((input) => CsrDevPaths.realpath(path9.resolve(input)));
|
|
3514
2416
|
if (inputs.some((input) => input !== file && this.#resolver.isRegistryModule(input))) {
|
|
3515
2417
|
tangled.push(file);
|
|
3516
2418
|
continue;
|
|
@@ -3543,7 +2445,7 @@ class CsrDevModuleCompiler {
|
|
|
3543
2445
|
const reasons = new Map;
|
|
3544
2446
|
for (const message of error.errors) {
|
|
3545
2447
|
const file = message.position?.file;
|
|
3546
|
-
if (typeof file !== "string" || !
|
|
2448
|
+
if (typeof file !== "string" || !path9.isAbsolute(file))
|
|
3547
2449
|
continue;
|
|
3548
2450
|
const real = CsrDevPaths.realpath(file);
|
|
3549
2451
|
const at = message.position?.line ? `:${message.position.line}` : "";
|
|
@@ -3642,7 +2544,7 @@ class CsrDevModuleCompiler {
|
|
|
3642
2544
|
}
|
|
3643
2545
|
#rebaseSourceMap(text) {
|
|
3644
2546
|
const map = JSON.parse(text);
|
|
3645
|
-
const files = map.sources.map((source) =>
|
|
2547
|
+
const files = map.sources.map((source) => path9.resolve(source));
|
|
3646
2548
|
map.sources = files.map((file) => `/${this.#paths.idOf(file)}`);
|
|
3647
2549
|
map.sourcesContent = files.map((file, index) => CsrDevPaths.isVendorFile(file) ? null : map.sourcesContent?.[index] ?? null);
|
|
3648
2550
|
return JSON.stringify(map);
|
|
@@ -3706,8 +2608,8 @@ ${preamble}return { ${names.join(", ")} };
|
|
|
3706
2608
|
}
|
|
3707
2609
|
|
|
3708
2610
|
// pkgs/@akanjs/devkit/frontendBuild/registryMetadataFingerprint.ts
|
|
3709
|
-
import
|
|
3710
|
-
import
|
|
2611
|
+
import fs6 from "fs";
|
|
2612
|
+
import path10 from "path";
|
|
3711
2613
|
|
|
3712
2614
|
class RegistryMetadataFingerprint {
|
|
3713
2615
|
static #sources = new Bun.Glob("**/*.{signal,dictionary}.ts");
|
|
@@ -3715,16 +2617,16 @@ class RegistryMetadataFingerprint {
|
|
|
3715
2617
|
static async of(roots, isMetadataFile) {
|
|
3716
2618
|
const stamps = [];
|
|
3717
2619
|
for (const root of new Set(roots)) {
|
|
3718
|
-
const libDir =
|
|
3719
|
-
if (!
|
|
2620
|
+
const libDir = path10.join(root, "lib");
|
|
2621
|
+
if (!fs6.existsSync(libDir))
|
|
3720
2622
|
continue;
|
|
3721
|
-
const files = RegistryMetadataFingerprint.#libFiles.map((name) =>
|
|
2623
|
+
const files = RegistryMetadataFingerprint.#libFiles.map((name) => path10.join(libDir, name));
|
|
3722
2624
|
for await (const relative of RegistryMetadataFingerprint.#sources.scan({ cwd: libDir, onlyFiles: true }))
|
|
3723
|
-
files.push(
|
|
2625
|
+
files.push(path10.join(libDir, relative));
|
|
3724
2626
|
for (const file of files) {
|
|
3725
2627
|
if (!isMetadataFile(file))
|
|
3726
2628
|
continue;
|
|
3727
|
-
const stat =
|
|
2629
|
+
const stat = fs6.statSync(file, { throwIfNoEntry: false });
|
|
3728
2630
|
if (stat)
|
|
3729
2631
|
stamps.push(`${file}:${stat.mtimeMs}:${stat.size}`);
|
|
3730
2632
|
}
|
|
@@ -3746,8 +2648,8 @@ class DevRegistryBundler {
|
|
|
3746
2648
|
this.app = app;
|
|
3747
2649
|
this.routePrefix = routePrefix;
|
|
3748
2650
|
this.paths = new CsrDevPaths(app.workspace.workspaceRoot);
|
|
3749
|
-
this.outDir =
|
|
3750
|
-
this.entryDir =
|
|
2651
|
+
this.outDir = path11.join(app.cwdPath, ".akan/artifact", dirName);
|
|
2652
|
+
this.entryDir = path11.join(app.cwdPath, ".akan/generated", dirName);
|
|
3751
2653
|
this.writer = new CsrDevArtifactWriter(this.outDir, { routePrefix, library });
|
|
3752
2654
|
}
|
|
3753
2655
|
async update(changedFiles = [], options = {}) {
|
|
@@ -3785,10 +2687,10 @@ class DevRegistryBundler {
|
|
|
3785
2687
|
return isAkanRuntimeMetadataFile(file);
|
|
3786
2688
|
}
|
|
3787
2689
|
async metadataFingerprint() {
|
|
3788
|
-
const libsContainer =
|
|
2690
|
+
const libsContainer = path11.resolve(this.app.workspace.workspaceRoot, "libs");
|
|
3789
2691
|
const roots = await new WatchRootResolver(this.app).resolve();
|
|
3790
|
-
const libRoots = roots.includes(libsContainer) ?
|
|
3791
|
-
return await RegistryMetadataFingerprint.of([
|
|
2692
|
+
const libRoots = roots.includes(libsContainer) ? fs7.readdirSync(libsContainer).map((name) => path11.join(libsContainer, name)) : roots.filter((root) => path11.dirname(root) === libsContainer);
|
|
2693
|
+
return await RegistryMetadataFingerprint.of([path11.resolve(this.app.cwdPath), ...libRoots], (file) => this.isMetadataFile(file));
|
|
3792
2694
|
}
|
|
3793
2695
|
async fullBuild(context, generation, reason) {
|
|
3794
2696
|
const metadata = await this.metadataFingerprint();
|
|
@@ -3881,7 +2783,7 @@ class CsrDevBundler extends DevRegistryBundler {
|
|
|
3881
2783
|
const files = {};
|
|
3882
2784
|
const changed = [];
|
|
3883
2785
|
for (const basePath of context.htmlBasePaths) {
|
|
3884
|
-
const file =
|
|
2786
|
+
const file = path12.join(this.entryDir, CsrEntryFiles.entryFilename(basePath));
|
|
3885
2787
|
const entryPages = CsrEntryFiles.pageEntriesForBasePath(context.pageEntries, basePath, context.basePaths);
|
|
3886
2788
|
const generator = new PagesEntrySourceGenerator(entryPages, {
|
|
3887
2789
|
isAsyncDefault: (moduleAbsPath) => this.#isAsyncDefault(moduleAbsPath)
|
|
@@ -3920,7 +2822,7 @@ ${hot}`;
|
|
|
3920
2822
|
}
|
|
3921
2823
|
#resolveRefreshRuntime() {
|
|
3922
2824
|
const akanWebkit = CsrDevPaths.tryResolve("akanjs/webkit", this.app.cwdPath);
|
|
3923
|
-
const bases = [this.app.cwdPath, this.paths.root, ...akanWebkit ? [
|
|
2825
|
+
const bases = [this.app.cwdPath, this.paths.root, ...akanWebkit ? [path12.dirname(path12.dirname(akanWebkit))] : []];
|
|
3924
2826
|
for (const base of bases) {
|
|
3925
2827
|
const resolved = CsrDevPaths.tryResolve("react-refresh/runtime", base);
|
|
3926
2828
|
if (resolved)
|
|
@@ -3931,7 +2833,7 @@ ${hot}`;
|
|
|
3931
2833
|
}
|
|
3932
2834
|
|
|
3933
2835
|
// pkgs/@akanjs/devkit/frontendBuild/devChangePlanner.ts
|
|
3934
|
-
import
|
|
2836
|
+
import path13 from "path";
|
|
3935
2837
|
var CONFIG_BASENAMES = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
3936
2838
|
var BARREL_FACETS = new Set(["common", "srvkit", "ui", "webkit", "plugin"]);
|
|
3937
2839
|
var CLIENT_SUFFIXES = [".Template.tsx", ".Unit.tsx", ".Util.tsx", ".View.tsx", ".Zone.tsx", ".store.ts"];
|
|
@@ -3942,11 +2844,11 @@ var RUNTIME_METADATA_BASENAMES = new Set(["dict.ts", "sig.ts", "useClient.ts", "
|
|
|
3942
2844
|
class DevChangePlanner {
|
|
3943
2845
|
#workspaceRoot;
|
|
3944
2846
|
constructor({ workspaceRoot }) {
|
|
3945
|
-
this.#workspaceRoot =
|
|
2847
|
+
this.#workspaceRoot = path13.resolve(workspaceRoot);
|
|
3946
2848
|
}
|
|
3947
2849
|
plan({ generation, files, kinds, generatedFiles = [] }) {
|
|
3948
2850
|
const fileList = uniqueResolved([...files, ...generatedFiles]);
|
|
3949
|
-
const generatedSet = new Set(generatedFiles.map((file) =>
|
|
2851
|
+
const generatedSet = new Set(generatedFiles.map((file) => path13.resolve(file)));
|
|
3950
2852
|
const kindSet = new Set(kinds);
|
|
3951
2853
|
const roles = new Set;
|
|
3952
2854
|
const actions = new Set;
|
|
@@ -3963,13 +2865,13 @@ class DevChangePlanner {
|
|
|
3963
2865
|
}
|
|
3964
2866
|
for (const file of fileList) {
|
|
3965
2867
|
const reasons = new Set;
|
|
3966
|
-
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(
|
|
2868
|
+
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(path13.resolve(file)), reasons });
|
|
3967
2869
|
for (const role of fileRoles)
|
|
3968
2870
|
roles.add(role);
|
|
3969
2871
|
if (reasons.has("runtime-metadata"))
|
|
3970
2872
|
actions.add("restart-builder");
|
|
3971
2873
|
if (reasons.size > 0)
|
|
3972
|
-
reasonByFile[
|
|
2874
|
+
reasonByFile[path13.resolve(file)] = [...reasons].sort();
|
|
3973
2875
|
}
|
|
3974
2876
|
if (roles.has("barrel"))
|
|
3975
2877
|
actions.add("sync-generated");
|
|
@@ -3990,12 +2892,12 @@ class DevChangePlanner {
|
|
|
3990
2892
|
}
|
|
3991
2893
|
#rolesForFile(file, { isGenerated, reasons }) {
|
|
3992
2894
|
const roles = new Set;
|
|
3993
|
-
const abs =
|
|
3994
|
-
const base =
|
|
3995
|
-
const ext =
|
|
2895
|
+
const abs = path13.resolve(file);
|
|
2896
|
+
const base = path13.basename(abs);
|
|
2897
|
+
const ext = path13.extname(abs).toLowerCase();
|
|
3996
2898
|
const isSource = SOURCE_EXTS.has(ext);
|
|
3997
|
-
const rel =
|
|
3998
|
-
const parts = rel.split(
|
|
2899
|
+
const rel = path13.relative(this.#workspaceRoot, abs);
|
|
2900
|
+
const parts = rel.split(path13.sep).filter(Boolean);
|
|
3999
2901
|
if (CONFIG_BASENAMES.has(base)) {
|
|
4000
2902
|
roles.add("config");
|
|
4001
2903
|
reasons.add("config-file");
|
|
@@ -4066,17 +2968,17 @@ class DevChangePlanner {
|
|
|
4066
2968
|
return true;
|
|
4067
2969
|
}
|
|
4068
2970
|
#isWorkspaceSource(rel) {
|
|
4069
|
-
if (!rel || rel.startsWith("..") ||
|
|
2971
|
+
if (!rel || rel.startsWith("..") || path13.isAbsolute(rel))
|
|
4070
2972
|
return false;
|
|
4071
|
-
const [scope] = rel.split(
|
|
2973
|
+
const [scope] = rel.split(path13.sep);
|
|
4072
2974
|
return scope === "apps" || scope === "libs" || scope === "pkgs";
|
|
4073
2975
|
}
|
|
4074
2976
|
}
|
|
4075
|
-
var uniqueResolved = (files) => [...new Set(files.map((file) =>
|
|
2977
|
+
var uniqueResolved = (files) => [...new Set(files.map((file) => path13.resolve(file)))].sort();
|
|
4076
2978
|
|
|
4077
2979
|
// pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
|
|
4078
2980
|
import { mkdir as mkdir4, readdir as readdir3, readFile as readFile2, rm as rm2, stat as stat2 } from "fs/promises";
|
|
4079
|
-
import
|
|
2981
|
+
import path14 from "path";
|
|
4080
2982
|
import { capitalize } from "akanjs/common";
|
|
4081
2983
|
var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit", "plugin"]);
|
|
4082
2984
|
var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
|
|
@@ -4090,7 +2992,7 @@ var SCALAR_UI_TYPES = ["Template", "Unit"];
|
|
|
4090
2992
|
class DevGeneratedIndexSync {
|
|
4091
2993
|
#workspaceRoot;
|
|
4092
2994
|
constructor({ workspaceRoot }) {
|
|
4093
|
-
this.#workspaceRoot =
|
|
2995
|
+
this.#workspaceRoot = path14.resolve(workspaceRoot);
|
|
4094
2996
|
}
|
|
4095
2997
|
async syncForBatch(files) {
|
|
4096
2998
|
const indexPaths = new Set;
|
|
@@ -4119,11 +3021,11 @@ class DevGeneratedIndexSync {
|
|
|
4119
3021
|
return { changedFiles, errors };
|
|
4120
3022
|
}
|
|
4121
3023
|
#facetIndexFor(file) {
|
|
4122
|
-
const abs =
|
|
4123
|
-
const rel =
|
|
4124
|
-
if (rel.startsWith("..") ||
|
|
3024
|
+
const abs = path14.resolve(file);
|
|
3025
|
+
const rel = path14.relative(this.#workspaceRoot, abs);
|
|
3026
|
+
if (rel.startsWith("..") || path14.isAbsolute(rel))
|
|
4125
3027
|
return null;
|
|
4126
|
-
const parts = rel.split(
|
|
3028
|
+
const parts = rel.split(path14.sep).filter(Boolean);
|
|
4127
3029
|
if (parts.length < 4)
|
|
4128
3030
|
return null;
|
|
4129
3031
|
const [scope, project, facet, child] = parts;
|
|
@@ -4131,32 +3033,32 @@ class DevGeneratedIndexSync {
|
|
|
4131
3033
|
return null;
|
|
4132
3034
|
if (!child || child.startsWith(".") || child === "index.ts" || child === "index.tsx")
|
|
4133
3035
|
return null;
|
|
4134
|
-
return
|
|
3036
|
+
return path14.join(this.#workspaceRoot, scope, project, facet, "index.ts");
|
|
4135
3037
|
}
|
|
4136
3038
|
async#moduleIndexForDirectoryEvent(file) {
|
|
4137
|
-
const abs =
|
|
4138
|
-
const rel =
|
|
4139
|
-
if (rel.startsWith("..") ||
|
|
3039
|
+
const abs = path14.resolve(file);
|
|
3040
|
+
const rel = path14.relative(this.#workspaceRoot, abs);
|
|
3041
|
+
if (rel.startsWith("..") || path14.isAbsolute(rel))
|
|
4140
3042
|
return null;
|
|
4141
|
-
const parts = rel.split(
|
|
3043
|
+
const parts = rel.split(path14.sep).filter(Boolean);
|
|
4142
3044
|
if (parts.length !== 4 && parts.length !== 5)
|
|
4143
3045
|
return null;
|
|
4144
3046
|
const [scope, project, libSegment, moduleSegment, scalarSegment] = parts;
|
|
4145
3047
|
if (scope !== "apps" && scope !== "libs" || !project || libSegment !== "lib")
|
|
4146
3048
|
return null;
|
|
4147
3049
|
const isExistingDirectory = await stat2(abs).then((s) => s.isDirectory()).catch(() => false);
|
|
4148
|
-
const looksLikeDeletedDirectory = !
|
|
3050
|
+
const looksLikeDeletedDirectory = !path14.extname(abs);
|
|
4149
3051
|
if (!isExistingDirectory && !looksLikeDeletedDirectory)
|
|
4150
3052
|
return null;
|
|
4151
3053
|
if (moduleSegment === "__scalar" && scalarSegment) {
|
|
4152
|
-
return
|
|
3054
|
+
return path14.join(this.#workspaceRoot, scope, project, "lib", "__scalar", scalarSegment, "index.ts");
|
|
4153
3055
|
}
|
|
4154
3056
|
if (!moduleSegment || moduleSegment === "__scalar")
|
|
4155
3057
|
return null;
|
|
4156
|
-
return
|
|
3058
|
+
return path14.join(this.#workspaceRoot, scope, project, "lib", moduleSegment, "index.ts");
|
|
4157
3059
|
}
|
|
4158
3060
|
async#syncIndex(indexPath) {
|
|
4159
|
-
const dir =
|
|
3061
|
+
const dir = path14.dirname(indexPath);
|
|
4160
3062
|
const content = await this.#contentForIndex(indexPath);
|
|
4161
3063
|
if (content === null) {
|
|
4162
3064
|
if (!await exists(indexPath))
|
|
@@ -4172,14 +3074,14 @@ class DevGeneratedIndexSync {
|
|
|
4172
3074
|
return true;
|
|
4173
3075
|
}
|
|
4174
3076
|
async#contentForIndex(indexPath) {
|
|
4175
|
-
const parts =
|
|
3077
|
+
const parts = path14.relative(this.#workspaceRoot, indexPath).split(path14.sep).filter(Boolean);
|
|
4176
3078
|
const facet = parts.at(-2);
|
|
4177
3079
|
if (facet && BARREL_FACETS2.has(facet))
|
|
4178
|
-
return this.#facetContent(
|
|
4179
|
-
return this.#moduleContent(
|
|
3080
|
+
return this.#facetContent(path14.dirname(indexPath));
|
|
3081
|
+
return this.#moduleContent(path14.dirname(indexPath));
|
|
4180
3082
|
}
|
|
4181
3083
|
async#facetContent(dir) {
|
|
4182
|
-
const nameCasePattern =
|
|
3084
|
+
const nameCasePattern = path14.basename(dir) === "ui" ? FACET_PASCAL_CASE_RE : FACET_CAMEL_CASE_RE;
|
|
4183
3085
|
const entries = await readdir3(dir, { withFileTypes: true }).catch(() => null);
|
|
4184
3086
|
if (!entries)
|
|
4185
3087
|
return null;
|
|
@@ -4204,8 +3106,8 @@ class DevGeneratedIndexSync {
|
|
|
4204
3106
|
`;
|
|
4205
3107
|
}
|
|
4206
3108
|
async#moduleContent(dir) {
|
|
4207
|
-
const rel =
|
|
4208
|
-
const parts = rel.split(
|
|
3109
|
+
const rel = path14.relative(this.#workspaceRoot, dir);
|
|
3110
|
+
const parts = rel.split(path14.sep).filter(Boolean);
|
|
4209
3111
|
const moduleSegment = parts.at(-1);
|
|
4210
3112
|
if (!moduleSegment)
|
|
4211
3113
|
return null;
|
|
@@ -4217,7 +3119,7 @@ class DevGeneratedIndexSync {
|
|
|
4217
3119
|
const allowedTypes = isScalar ? SCALAR_UI_TYPES : moduleSegment.startsWith("_") ? SERVICE_UI_TYPES : MODULE_UI_TYPES;
|
|
4218
3120
|
const fileTypes = [];
|
|
4219
3121
|
for (const type of allowedTypes) {
|
|
4220
|
-
if (await exists(
|
|
3122
|
+
if (await exists(path14.join(dir, `${modelName}.${type}.tsx`)))
|
|
4221
3123
|
fileTypes.push(type);
|
|
4222
3124
|
}
|
|
4223
3125
|
if (fileTypes.length === 0)
|
|
@@ -4252,7 +3154,7 @@ var formatError2 = (err) => err instanceof Error ? err.message : String(err);
|
|
|
4252
3154
|
|
|
4253
3155
|
// pkgs/@akanjs/devkit/frontendBuild/ssrDevBundler.ts
|
|
4254
3156
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
4255
|
-
import
|
|
3157
|
+
import path15 from "path";
|
|
4256
3158
|
import { SSR_DEV_DIRNAME, SSR_DEV_ROUTE_PREFIX } from "akanjs/server/hmr/csrDevManifest";
|
|
4257
3159
|
class SsrDevBundler extends DevRegistryBundler {
|
|
4258
3160
|
static #formatVersion = 2;
|
|
@@ -4281,12 +3183,12 @@ class SsrDevBundler extends DevRegistryBundler {
|
|
|
4281
3183
|
};
|
|
4282
3184
|
}
|
|
4283
3185
|
isMetadataFile(file) {
|
|
4284
|
-
return super.isMetadataFile(file) && !file.endsWith(".dictionary.ts") &&
|
|
3186
|
+
return super.isMetadataFile(file) && !file.endsWith(".dictionary.ts") && path15.basename(file) !== "dict.ts";
|
|
4285
3187
|
}
|
|
4286
3188
|
async writeEntries() {
|
|
4287
3189
|
await mkdir5(this.entryDir, { recursive: true });
|
|
4288
|
-
const file =
|
|
4289
|
-
const hasStore = await Bun.file(
|
|
3190
|
+
const file = path15.join(this.entryDir, "bootstrap.ts");
|
|
3191
|
+
const hasStore = await Bun.file(path15.join(this.app.cwdPath, "lib", "st.ts")).exists();
|
|
4290
3192
|
const source = hasStore ? `import ${JSON.stringify(`@apps/${this.app.name}/client`)};
|
|
4291
3193
|
` : `export {};
|
|
4292
3194
|
`;
|
|
@@ -4312,4 +3214,4 @@ class SsrDevBundler extends DevRegistryBundler {
|
|
|
4312
3214
|
}
|
|
4313
3215
|
}
|
|
4314
3216
|
|
|
4315
|
-
export { computeRouteSeedIndex, saveRouteSeedIndex,
|
|
3217
|
+
export { computeRouteSeedIndex, saveRouteSeedIndex, GraphClientEntryDiscovery, ClientEntriesBundler, VENDOR_SPECIFIERS, RouteClientBuilder, AutoImportSync, CsrDevPatcher, CsrDevBundler, DevChangePlanner, DevGeneratedIndexSync, SsrDevBundler };
|