@akanjs/cli 2.3.13 → 2.4.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/guidelines/componentRule/componentRule.instruction.md +8 -0
- package/guidelines/cssRule/cssRule.instruction.md +18 -0
- package/guidelines/framework/framework.instruction.md +6 -0
- package/incrementalBuilder.proc.js +926 -329
- package/index.js +961 -362
- package/package.json +2 -2
- package/templates/app/page/styles.css.template +22 -0
- package/templates/facetIndex/index.ts +3 -9
- package/templates/workspaceRoot/biome.json.template +1 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
4
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
|
|
5
|
-
import
|
|
5
|
+
import path45 from "path";
|
|
6
6
|
|
|
7
7
|
// pkgs/@akanjs/devkit/aiEditor.ts
|
|
8
8
|
import { input, select } from "@inquirer/prompts";
|
|
@@ -4287,9 +4287,10 @@ class IncrementalBuilderHost {
|
|
|
4287
4287
|
// pkgs/@akanjs/devkit/akanApp/akanApp.host.ts
|
|
4288
4288
|
var backendMsgTypeSet = new Set(["build-route"]);
|
|
4289
4289
|
var BACKEND_RESTART_DEBOUNCE_MS = 120;
|
|
4290
|
-
var BACKEND_GRACEFUL_TIMEOUT_MS =
|
|
4290
|
+
var BACKEND_GRACEFUL_TIMEOUT_MS = 8000;
|
|
4291
4291
|
var BACKEND_RECOVERY_BASE_DELAY_MS = 1000;
|
|
4292
4292
|
var BACKEND_RECOVERY_MAX_DELAY_MS = 30000;
|
|
4293
|
+
var BACKEND_RECOVERY_MAX_ATTEMPTS = 5;
|
|
4293
4294
|
var BACKEND_STDERR_TAIL_LIMIT = 40;
|
|
4294
4295
|
var BUILDER_READY_TIMEOUT_MS = 150000;
|
|
4295
4296
|
var BUILDER_START_MAX_ATTEMPTS = 3;
|
|
@@ -4314,6 +4315,8 @@ var shouldRestartBackendByDevPlan = (message) => {
|
|
|
4314
4315
|
return message.devPlan.actions.includes("restart-backend");
|
|
4315
4316
|
};
|
|
4316
4317
|
var shouldRestartBuilderByDevPlan = (message) => message.devPlan?.actions.includes("restart-builder") ?? false;
|
|
4318
|
+
var shouldAbandonBackendRecovery = (attempts, maxAttempts = BACKEND_RECOVERY_MAX_ATTEMPTS) => attempts >= maxAttempts;
|
|
4319
|
+
var normalizeBackendReportedGeneration = (generation) => generation >= 0 ? generation : undefined;
|
|
4317
4320
|
var shouldRestartDevHostByDevPlan = (message) => message.devPlan?.actions.includes("restart-dev-host") ?? message.kinds.includes("config");
|
|
4318
4321
|
var RESTART_ROLE_ORDER = ["server", "shared", "barrel", "config"];
|
|
4319
4322
|
var generationValue = (generation) => generation ?? -1;
|
|
@@ -4562,6 +4565,16 @@ class AkanAppHost {
|
|
|
4562
4565
|
this.#replayBuilderState();
|
|
4563
4566
|
return;
|
|
4564
4567
|
}
|
|
4568
|
+
if (msg.type === "build-status") {
|
|
4569
|
+
const status = this.#recordBackendBuildStatus({
|
|
4570
|
+
generation: normalizeBackendReportedGeneration(msg.data.generation),
|
|
4571
|
+
ok: msg.data.ok,
|
|
4572
|
+
files: msg.data.files,
|
|
4573
|
+
message: msg.data.message
|
|
4574
|
+
});
|
|
4575
|
+
this.#sendOrQueueBuildStatus(status);
|
|
4576
|
+
return;
|
|
4577
|
+
}
|
|
4565
4578
|
if (backendMsgTypeSet.has(msg.type))
|
|
4566
4579
|
this.#sendToBuilder(msg);
|
|
4567
4580
|
},
|
|
@@ -4723,6 +4736,19 @@ class AkanAppHost {
|
|
|
4723
4736
|
#scheduleBackendRecovery(reason) {
|
|
4724
4737
|
if (this.#backendRecoveryTimer || this.#backend)
|
|
4725
4738
|
return;
|
|
4739
|
+
if (shouldAbandonBackendRecovery(this.#backendRecoveryAttempts)) {
|
|
4740
|
+
const message = `Backend exited ${this.#backendRecoveryAttempts} times in a row (${reason}); waiting for a server-side edit to retry.`;
|
|
4741
|
+
this.#setBackendLifecycleState("stopped", `gave up after ${this.#backendRecoveryAttempts} recovery attempts`);
|
|
4742
|
+
this.logger.error(`[backend-recovery] ${message}`);
|
|
4743
|
+
if (this.#backendStderrTail.length > 0) {
|
|
4744
|
+
this.logger.error(`[backend-recovery] recent backend stderr:
|
|
4745
|
+
${this.#backendStderrTail.join(`
|
|
4746
|
+
`)}`);
|
|
4747
|
+
}
|
|
4748
|
+
const abandonedStatus = this.#recordBackendBuildStatus({ ok: false, files: [], message });
|
|
4749
|
+
this.#sendOrQueueBuildStatus(abandonedStatus);
|
|
4750
|
+
return;
|
|
4751
|
+
}
|
|
4726
4752
|
this.#setBackendLifecycleState("recovering", reason);
|
|
4727
4753
|
const attempt = this.#backendRecoveryAttempts;
|
|
4728
4754
|
const delay = Math.min(BACKEND_RECOVERY_BASE_DELAY_MS * 2 ** attempt, BACKEND_RECOVERY_MAX_DELAY_MS);
|
|
@@ -4771,6 +4797,7 @@ ${this.#backendStderrTail.join(`
|
|
|
4771
4797
|
this.#sendToBackend(message);
|
|
4772
4798
|
}
|
|
4773
4799
|
async#handleInvalidate(message) {
|
|
4800
|
+
this.#logDevPlan(message);
|
|
4774
4801
|
if (shouldRestartBuilderByDevPlan(message)) {
|
|
4775
4802
|
try {
|
|
4776
4803
|
await this.#restartDevChildren(message);
|
|
@@ -4882,12 +4909,16 @@ ${this.#backendStderrTail.join(`
|
|
|
4882
4909
|
this.#sendToBackend({ type: "build-status", data: status });
|
|
4883
4910
|
}
|
|
4884
4911
|
}
|
|
4912
|
+
#logDevPlan(message) {
|
|
4913
|
+
if (!message.devPlan)
|
|
4914
|
+
return;
|
|
4915
|
+
const { generation, roles, actions, reasonByFile } = message.devPlan;
|
|
4916
|
+
this.logger.verbose(`[dev-plan] generation=${generation} roles=${roles.join(",") || "(none)"} actions=${actions.join(",") || "(none)"} reasons=${Object.keys(reasonByFile).length}`);
|
|
4917
|
+
}
|
|
4885
4918
|
async#shouldRestartBackend(message) {
|
|
4886
4919
|
if (message.kinds.length === 1 && message.kinds[0] === "css")
|
|
4887
4920
|
return false;
|
|
4888
4921
|
if (message.devPlan) {
|
|
4889
|
-
const { generation, roles, actions, reasonByFile } = message.devPlan;
|
|
4890
|
-
this.logger.verbose(`[dev-plan] generation=${generation} roles=${roles.join(",") || "(none)"} actions=${actions.join(",") || "(none)"} reasons=${Object.keys(reasonByFile).length}`);
|
|
4891
4922
|
const shouldRestart = shouldRestartBackendByDevPlan(message) ?? false;
|
|
4892
4923
|
if (shouldRestart && message.kinds.includes("code"))
|
|
4893
4924
|
await this.#backendGraph.refresh();
|
|
@@ -8837,7 +8868,7 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
|
|
|
8837
8868
|
}
|
|
8838
8869
|
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
8839
8870
|
import { mkdir as mkdir8, rm as rm4 } from "fs/promises";
|
|
8840
|
-
import
|
|
8871
|
+
import path38 from "path";
|
|
8841
8872
|
|
|
8842
8873
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
8843
8874
|
import path22 from "path";
|
|
@@ -10620,14 +10651,538 @@ class AllRoutesBuilder {
|
|
|
10620
10651
|
this.#routeIds.push(routeId);
|
|
10621
10652
|
}
|
|
10622
10653
|
}
|
|
10654
|
+
// pkgs/@akanjs/devkit/frontendBuild/autoImportSync.ts
|
|
10655
|
+
import { readdir as readdir2, readFile, stat as stat3, writeFile } from "fs/promises";
|
|
10656
|
+
import path23 from "path";
|
|
10657
|
+
import ts8 from "typescript";
|
|
10658
|
+
var TEST_FILE_RE = /\.(test|spec)\.(ts|tsx)$/;
|
|
10659
|
+
var AKAN_BASE = {
|
|
10660
|
+
names: ["Int", "Float", "ID", "Any", "Upload", "enumOf", "dayjs"],
|
|
10661
|
+
specifier: "akanjs/base",
|
|
10662
|
+
kind: "named"
|
|
10663
|
+
};
|
|
10664
|
+
var AKAN_BASE_TYPES = { names: ["Dayjs"], specifier: "akanjs/base", kind: "named", typeOnly: true };
|
|
10665
|
+
var CNST_NS = { names: ["cnst"], specifier: "../cnst", kind: "namespace" };
|
|
10666
|
+
var DB_NS = { names: ["db"], specifier: "../db", kind: "namespace" };
|
|
10667
|
+
var SRV_NS = { names: ["srv"], specifier: "../srv", kind: "namespace" };
|
|
10668
|
+
var ERR_DICT = { names: ["Err"], specifier: "../dict", kind: "named" };
|
|
10669
|
+
var RULES = {
|
|
10670
|
+
constant: [AKAN_BASE, AKAN_BASE_TYPES, { names: ["via"], specifier: "akanjs/constant", kind: "named" }],
|
|
10671
|
+
document: [
|
|
10672
|
+
AKAN_BASE,
|
|
10673
|
+
AKAN_BASE_TYPES,
|
|
10674
|
+
CNST_NS,
|
|
10675
|
+
DB_NS,
|
|
10676
|
+
ERR_DICT,
|
|
10677
|
+
{
|
|
10678
|
+
names: ["by", "from", "into", "SchemaOf", "DataInputOf", "DocumentUpdateHelper", "documentQueryHelper", "Mdl"],
|
|
10679
|
+
specifier: "akanjs/document",
|
|
10680
|
+
kind: "named"
|
|
10681
|
+
}
|
|
10682
|
+
],
|
|
10683
|
+
service: [
|
|
10684
|
+
AKAN_BASE,
|
|
10685
|
+
AKAN_BASE_TYPES,
|
|
10686
|
+
DB_NS,
|
|
10687
|
+
SRV_NS,
|
|
10688
|
+
CNST_NS,
|
|
10689
|
+
ERR_DICT,
|
|
10690
|
+
{ names: ["serve"], specifier: "akanjs/service", kind: "named" },
|
|
10691
|
+
{
|
|
10692
|
+
names: ["DataInputOf", "ListQueryOption", "DatabaseRegistry", "getFilterInfoByKey"],
|
|
10693
|
+
specifier: "akanjs/document",
|
|
10694
|
+
kind: "named"
|
|
10695
|
+
}
|
|
10696
|
+
],
|
|
10697
|
+
signal: [
|
|
10698
|
+
AKAN_BASE,
|
|
10699
|
+
AKAN_BASE_TYPES,
|
|
10700
|
+
SRV_NS,
|
|
10701
|
+
CNST_NS,
|
|
10702
|
+
ERR_DICT,
|
|
10703
|
+
{
|
|
10704
|
+
names: ["endpoint", "internal", "slice", "Public", "Req", "Ws", "None", "Res"],
|
|
10705
|
+
specifier: "akanjs/signal",
|
|
10706
|
+
kind: "named"
|
|
10707
|
+
}
|
|
10708
|
+
],
|
|
10709
|
+
dictionary: [
|
|
10710
|
+
{
|
|
10711
|
+
names: ["modelDictionary", "scalarDictionary", "serviceDictionary"],
|
|
10712
|
+
specifier: "akanjs/dictionary",
|
|
10713
|
+
kind: "named"
|
|
10714
|
+
}
|
|
10715
|
+
],
|
|
10716
|
+
srvkit: [
|
|
10717
|
+
AKAN_BASE,
|
|
10718
|
+
AKAN_BASE_TYPES,
|
|
10719
|
+
{ names: ["Logger", "HttpClient", "sleep"], specifier: "akanjs/common", kind: "named" },
|
|
10720
|
+
{ names: ["adapt"], specifier: "akanjs/service", kind: "named" },
|
|
10721
|
+
{ names: ["SignalContext", "Guard", "InternalArg", "Middleware"], specifier: "akanjs/signal", kind: "named" }
|
|
10722
|
+
],
|
|
10723
|
+
common: [AKAN_BASE, AKAN_BASE_TYPES],
|
|
10724
|
+
store: [
|
|
10725
|
+
CNST_NS,
|
|
10726
|
+
{ names: ["store"], specifier: "akanjs/store", kind: "named" },
|
|
10727
|
+
{ names: ["fetch", "usePage", "sig"], specifier: "../useClient", kind: "named" },
|
|
10728
|
+
{ names: ["st"], specifier: "../st", kind: "named" },
|
|
10729
|
+
{ names: ["RootStore"], specifier: "../st", kind: "named", typeOnly: true }
|
|
10730
|
+
],
|
|
10731
|
+
client: [
|
|
10732
|
+
{
|
|
10733
|
+
names: ["cnst", "fetch", "st", "usePage"],
|
|
10734
|
+
specifier: (ctx) => `@${ctx.scope}/${ctx.project}/client`,
|
|
10735
|
+
kind: "named"
|
|
10736
|
+
}
|
|
10737
|
+
]
|
|
10738
|
+
};
|
|
10739
|
+
var PASCAL_CASE_RE = /^[A-Z][A-Za-z0-9]*$/;
|
|
10740
|
+
var DOMAIN_ROLE_KINDS = {
|
|
10741
|
+
constant: ["constant"],
|
|
10742
|
+
dictionary: ["constant", "document", "signal"],
|
|
10743
|
+
common: ["constant"]
|
|
10744
|
+
};
|
|
10745
|
+
var LIB_BARRELS = {
|
|
10746
|
+
Err: { barrel: "dict", kind: "named" },
|
|
10747
|
+
db: { barrel: "db", kind: "namespace" },
|
|
10748
|
+
cnst: { barrel: "cnst", kind: "namespace" },
|
|
10749
|
+
srv: { barrel: "srv", kind: "namespace" }
|
|
10750
|
+
};
|
|
10751
|
+
var DOMAIN_DENYLIST = new Set([
|
|
10752
|
+
"Map",
|
|
10753
|
+
"Set",
|
|
10754
|
+
"WeakMap",
|
|
10755
|
+
"WeakSet",
|
|
10756
|
+
"Date",
|
|
10757
|
+
"Promise",
|
|
10758
|
+
"Array",
|
|
10759
|
+
"Object",
|
|
10760
|
+
"Error",
|
|
10761
|
+
"TypeError",
|
|
10762
|
+
"RangeError",
|
|
10763
|
+
"RegExp",
|
|
10764
|
+
"Symbol",
|
|
10765
|
+
"Proxy",
|
|
10766
|
+
"Reflect",
|
|
10767
|
+
"JSON",
|
|
10768
|
+
"Math",
|
|
10769
|
+
"Number",
|
|
10770
|
+
"BigInt",
|
|
10771
|
+
"Function",
|
|
10772
|
+
"Boolean",
|
|
10773
|
+
"String",
|
|
10774
|
+
"Record",
|
|
10775
|
+
"Partial",
|
|
10776
|
+
"Required",
|
|
10777
|
+
"Readonly",
|
|
10778
|
+
"Pick",
|
|
10779
|
+
"Omit",
|
|
10780
|
+
"Exclude",
|
|
10781
|
+
"Extract",
|
|
10782
|
+
"NonNullable",
|
|
10783
|
+
"ReturnType",
|
|
10784
|
+
"Parameters",
|
|
10785
|
+
"Awaited",
|
|
10786
|
+
"InstanceType"
|
|
10787
|
+
]);
|
|
10788
|
+
|
|
10789
|
+
class AutoImportSync {
|
|
10790
|
+
#workspaceRoot;
|
|
10791
|
+
#domainCache = new Map;
|
|
10792
|
+
constructor({ workspaceRoot }) {
|
|
10793
|
+
this.#workspaceRoot = path23.resolve(workspaceRoot);
|
|
10794
|
+
}
|
|
10795
|
+
async syncForBatch(files) {
|
|
10796
|
+
const changedFiles = [];
|
|
10797
|
+
const errors = [];
|
|
10798
|
+
const seen = new Set;
|
|
10799
|
+
for (const file of files) {
|
|
10800
|
+
const pkgRoot = this.#domainPkgRootOf(file);
|
|
10801
|
+
if (pkgRoot)
|
|
10802
|
+
this.#domainCache.delete(pkgRoot);
|
|
10803
|
+
}
|
|
10804
|
+
for (const file of files) {
|
|
10805
|
+
const abs = path23.resolve(file);
|
|
10806
|
+
if (seen.has(abs))
|
|
10807
|
+
continue;
|
|
10808
|
+
seen.add(abs);
|
|
10809
|
+
const ctx = this.#contextFor(abs);
|
|
10810
|
+
if (!ctx)
|
|
10811
|
+
continue;
|
|
10812
|
+
try {
|
|
10813
|
+
const changed = await this.#syncFile(abs, ctx);
|
|
10814
|
+
if (changed)
|
|
10815
|
+
changedFiles.push(abs);
|
|
10816
|
+
} catch (err) {
|
|
10817
|
+
errors.push(`[auto-import] sync failed for ${file}: ${formatError(err)}`);
|
|
10818
|
+
}
|
|
10819
|
+
}
|
|
10820
|
+
return { changedFiles, errors };
|
|
10821
|
+
}
|
|
10822
|
+
#contextFor(abs) {
|
|
10823
|
+
const rel = path23.relative(this.#workspaceRoot, abs);
|
|
10824
|
+
if (rel.startsWith("..") || path23.isAbsolute(rel))
|
|
10825
|
+
return null;
|
|
10826
|
+
const base = path23.basename(abs);
|
|
10827
|
+
if (TEST_FILE_RE.test(base) || base === "index.ts" || base === "index.tsx" || base.endsWith(".d.ts"))
|
|
10828
|
+
return null;
|
|
10829
|
+
const parts = rel.split(path23.sep).filter(Boolean);
|
|
10830
|
+
const [scope, project, facet] = parts;
|
|
10831
|
+
if (scope !== "apps" && scope !== "libs" || !project || !facet)
|
|
10832
|
+
return null;
|
|
10833
|
+
const role = roleFor(facet, base);
|
|
10834
|
+
if (!role)
|
|
10835
|
+
return null;
|
|
10836
|
+
return { role, scope, project };
|
|
10837
|
+
}
|
|
10838
|
+
async#syncFile(abs, ctx) {
|
|
10839
|
+
const stats = await stat3(abs).catch(() => null);
|
|
10840
|
+
if (!stats?.isFile())
|
|
10841
|
+
return false;
|
|
10842
|
+
const source2 = await readFile(abs, "utf8");
|
|
10843
|
+
const resolveExtra = await this.#extraResolverFor(abs, ctx);
|
|
10844
|
+
const next = transformSource(source2, abs, ctx, resolveExtra);
|
|
10845
|
+
if (next === null || next === source2)
|
|
10846
|
+
return false;
|
|
10847
|
+
await writeFile(abs, next);
|
|
10848
|
+
return true;
|
|
10849
|
+
}
|
|
10850
|
+
async#extraResolverFor(abs, ctx) {
|
|
10851
|
+
const resolvers = [];
|
|
10852
|
+
if (ctx.role === "srvkit" || ctx.role === "common")
|
|
10853
|
+
resolvers.push(await this.#libBarrelResolver(abs, ctx));
|
|
10854
|
+
const kinds = DOMAIN_ROLE_KINDS[ctx.role];
|
|
10855
|
+
if (kinds)
|
|
10856
|
+
resolvers.push(await this.#domainResolver(abs, ctx, kinds));
|
|
10857
|
+
if (resolvers.length === 0)
|
|
10858
|
+
return;
|
|
10859
|
+
return (symbol) => {
|
|
10860
|
+
for (const resolve of resolvers) {
|
|
10861
|
+
const target = resolve(symbol);
|
|
10862
|
+
if (target)
|
|
10863
|
+
return target;
|
|
10864
|
+
}
|
|
10865
|
+
return null;
|
|
10866
|
+
};
|
|
10867
|
+
}
|
|
10868
|
+
async#domainResolver(abs, ctx, kinds) {
|
|
10869
|
+
const index = await this.#domainIndex(path23.join(this.#workspaceRoot, ctx.scope, ctx.project));
|
|
10870
|
+
const fileDir = path23.dirname(abs);
|
|
10871
|
+
return (symbol) => {
|
|
10872
|
+
if (!PASCAL_CASE_RE.test(symbol) || DOMAIN_DENYLIST.has(symbol))
|
|
10873
|
+
return null;
|
|
10874
|
+
const entries = (index.get(symbol) ?? []).filter((entry) => kinds.includes(entry.kind));
|
|
10875
|
+
if (entries.length !== 1)
|
|
10876
|
+
return null;
|
|
10877
|
+
return { specifier: relativeSpecifier(fileDir, entries[0].file), kind: "named" };
|
|
10878
|
+
};
|
|
10879
|
+
}
|
|
10880
|
+
async#libBarrelResolver(abs, ctx) {
|
|
10881
|
+
const fileDir = path23.dirname(abs);
|
|
10882
|
+
const libDir = path23.join(this.#workspaceRoot, ctx.scope, ctx.project, "lib");
|
|
10883
|
+
const available = new Map;
|
|
10884
|
+
for (const [symbol, { barrel, kind }] of Object.entries(LIB_BARRELS)) {
|
|
10885
|
+
if (await fileExists2(path23.join(libDir, `${barrel}.ts`)))
|
|
10886
|
+
available.set(symbol, { specifier: relativeSpecifier(fileDir, path23.join(libDir, barrel)), kind });
|
|
10887
|
+
}
|
|
10888
|
+
return (symbol) => available.get(symbol) ?? null;
|
|
10889
|
+
}
|
|
10890
|
+
async#domainIndex(pkgRoot) {
|
|
10891
|
+
const cached = this.#domainCache.get(pkgRoot);
|
|
10892
|
+
if (cached)
|
|
10893
|
+
return cached;
|
|
10894
|
+
const index = await buildDomainIndex(path23.join(pkgRoot, "lib"));
|
|
10895
|
+
this.#domainCache.set(pkgRoot, index);
|
|
10896
|
+
return index;
|
|
10897
|
+
}
|
|
10898
|
+
#domainPkgRootOf(file) {
|
|
10899
|
+
const rel = path23.relative(this.#workspaceRoot, path23.resolve(file));
|
|
10900
|
+
if (rel.startsWith("..") || path23.isAbsolute(rel))
|
|
10901
|
+
return null;
|
|
10902
|
+
const [scope, project, facet] = rel.split(path23.sep).filter(Boolean);
|
|
10903
|
+
if (scope !== "apps" && scope !== "libs" || !project || facet !== "lib")
|
|
10904
|
+
return null;
|
|
10905
|
+
if (!domainKindOf(path23.basename(file)))
|
|
10906
|
+
return null;
|
|
10907
|
+
return path23.join(this.#workspaceRoot, scope, project);
|
|
10908
|
+
}
|
|
10909
|
+
}
|
|
10910
|
+
var roleFor = (facet, base) => {
|
|
10911
|
+
if (facet === "lib") {
|
|
10912
|
+
if (base.endsWith(".constant.ts"))
|
|
10913
|
+
return "constant";
|
|
10914
|
+
if (base.endsWith(".document.ts"))
|
|
10915
|
+
return "document";
|
|
10916
|
+
if (base.endsWith(".service.ts"))
|
|
10917
|
+
return "service";
|
|
10918
|
+
if (base.endsWith(".signal.ts"))
|
|
10919
|
+
return "signal";
|
|
10920
|
+
if (base.endsWith(".dictionary.ts"))
|
|
10921
|
+
return "dictionary";
|
|
10922
|
+
if (base.endsWith(".store.ts"))
|
|
10923
|
+
return "store";
|
|
10924
|
+
if (base.endsWith(".tsx"))
|
|
10925
|
+
return "client";
|
|
10926
|
+
return null;
|
|
10927
|
+
}
|
|
10928
|
+
if (facet === "ui" || facet === "page")
|
|
10929
|
+
return base.endsWith(".tsx") ? "client" : null;
|
|
10930
|
+
if (facet === "webkit")
|
|
10931
|
+
return base.endsWith(".ts") || base.endsWith(".tsx") ? "client" : null;
|
|
10932
|
+
if (facet === "srvkit")
|
|
10933
|
+
return base.endsWith(".ts") ? "srvkit" : null;
|
|
10934
|
+
if (facet === "common")
|
|
10935
|
+
return base.endsWith(".ts") || base.endsWith(".tsx") ? "common" : null;
|
|
10936
|
+
return null;
|
|
10937
|
+
};
|
|
10938
|
+
var targetFor = (symbol, ctx) => {
|
|
10939
|
+
for (const rule of RULES[ctx.role]) {
|
|
10940
|
+
if (!rule.names.includes(symbol))
|
|
10941
|
+
continue;
|
|
10942
|
+
const specifier = typeof rule.specifier === "function" ? rule.specifier(ctx) : rule.specifier;
|
|
10943
|
+
return { specifier, kind: rule.kind, typeOnly: rule.typeOnly };
|
|
10944
|
+
}
|
|
10945
|
+
return null;
|
|
10946
|
+
};
|
|
10947
|
+
var transformSource = (source2, fileName, ctx, resolveExtra) => {
|
|
10948
|
+
const sf = ts8.createSourceFile(fileName, source2, ts8.ScriptTarget.Latest, true, scriptKindFor(fileName));
|
|
10949
|
+
const bound = collectBoundNames(sf);
|
|
10950
|
+
const used = collectUsedReferences(sf);
|
|
10951
|
+
const namedBySpecifier = new Map;
|
|
10952
|
+
const namespaceImports = [];
|
|
10953
|
+
for (const name of used) {
|
|
10954
|
+
if (bound.has(name))
|
|
10955
|
+
continue;
|
|
10956
|
+
const target = targetFor(name, ctx) ?? resolveExtra?.(name) ?? null;
|
|
10957
|
+
if (!target)
|
|
10958
|
+
continue;
|
|
10959
|
+
if (target.kind === "namespace")
|
|
10960
|
+
namespaceImports.push({ name, specifier: target.specifier });
|
|
10961
|
+
else {
|
|
10962
|
+
const names = namedBySpecifier.get(target.specifier) ?? new Map;
|
|
10963
|
+
names.set(name, target.typeOnly ?? false);
|
|
10964
|
+
namedBySpecifier.set(target.specifier, names);
|
|
10965
|
+
}
|
|
10966
|
+
}
|
|
10967
|
+
if (namedBySpecifier.size === 0 && namespaceImports.length === 0)
|
|
10968
|
+
return null;
|
|
10969
|
+
const importDecls = sf.statements.filter(ts8.isImportDeclaration);
|
|
10970
|
+
const anchor = importDecls.at(-1) ?? null;
|
|
10971
|
+
const namedImportsBySpecifier = collectExistingNamedImports(importDecls);
|
|
10972
|
+
const edits = [];
|
|
10973
|
+
const newStatements = [];
|
|
10974
|
+
for (const [specifier, names] of namedBySpecifier) {
|
|
10975
|
+
const existing = namedImportsBySpecifier.get(specifier);
|
|
10976
|
+
if (existing) {
|
|
10977
|
+
const merged = new Map(existing.names);
|
|
10978
|
+
for (const [name, isType] of names)
|
|
10979
|
+
if (!merged.has(name))
|
|
10980
|
+
merged.set(name, isType);
|
|
10981
|
+
edits.push({
|
|
10982
|
+
start: existing.decl.getStart(sf),
|
|
10983
|
+
end: existing.decl.getEnd(),
|
|
10984
|
+
text: formatNamedImport(specifier, merged)
|
|
10985
|
+
});
|
|
10986
|
+
} else
|
|
10987
|
+
newStatements.push(formatNamedImport(specifier, names));
|
|
10988
|
+
}
|
|
10989
|
+
for (const ns of namespaceImports)
|
|
10990
|
+
newStatements.push(`import * as ${ns.name} from "${ns.specifier}";`);
|
|
10991
|
+
if (newStatements.length > 0) {
|
|
10992
|
+
const anchorEdit = anchor ? edits.find((edit) => edit.start === anchor.getStart(sf)) : undefined;
|
|
10993
|
+
if (anchorEdit)
|
|
10994
|
+
anchorEdit.text = `${anchorEdit.text}
|
|
10995
|
+
${newStatements.join(`
|
|
10996
|
+
`)}`;
|
|
10997
|
+
else if (anchor)
|
|
10998
|
+
edits.push({ start: anchor.getEnd(), end: anchor.getEnd(), text: `
|
|
10999
|
+
${newStatements.join(`
|
|
11000
|
+
`)}` });
|
|
11001
|
+
else {
|
|
11002
|
+
const prologueEnd = directivePrologueEnd(sf);
|
|
11003
|
+
if (prologueEnd >= 0)
|
|
11004
|
+
edits.push({ start: prologueEnd, end: prologueEnd, text: `
|
|
11005
|
+
${newStatements.join(`
|
|
11006
|
+
`)}` });
|
|
11007
|
+
else
|
|
11008
|
+
edits.push({ start: 0, end: 0, text: `${newStatements.join(`
|
|
11009
|
+
`)}
|
|
11010
|
+
|
|
11011
|
+
` });
|
|
11012
|
+
}
|
|
11013
|
+
}
|
|
11014
|
+
if (edits.length === 0)
|
|
11015
|
+
return null;
|
|
11016
|
+
edits.sort((a, b) => b.start - a.start);
|
|
11017
|
+
let out = source2;
|
|
11018
|
+
for (const edit of edits)
|
|
11019
|
+
out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
|
|
11020
|
+
return out === source2 ? null : out;
|
|
11021
|
+
};
|
|
11022
|
+
var collectBoundNames = (sf) => {
|
|
11023
|
+
const names = new Set;
|
|
11024
|
+
const visit = (node) => {
|
|
11025
|
+
if (ts8.isImportClause(node)) {
|
|
11026
|
+
if (node.name)
|
|
11027
|
+
names.add(node.name.text);
|
|
11028
|
+
const bindings = node.namedBindings;
|
|
11029
|
+
if (bindings && ts8.isNamespaceImport(bindings))
|
|
11030
|
+
names.add(bindings.name.text);
|
|
11031
|
+
if (bindings && ts8.isNamedImports(bindings))
|
|
11032
|
+
for (const el of bindings.elements)
|
|
11033
|
+
names.add(el.name.text);
|
|
11034
|
+
}
|
|
11035
|
+
if ((ts8.isVariableDeclaration(node) || ts8.isFunctionDeclaration(node) || ts8.isClassDeclaration(node) || ts8.isParameter(node) || ts8.isBindingElement(node) || ts8.isEnumDeclaration(node) || ts8.isTypeAliasDeclaration(node) || ts8.isInterfaceDeclaration(node)) && node.name && ts8.isIdentifier(node.name))
|
|
11036
|
+
names.add(node.name.text);
|
|
11037
|
+
ts8.forEachChild(node, visit);
|
|
11038
|
+
};
|
|
11039
|
+
ts8.forEachChild(sf, visit);
|
|
11040
|
+
return names;
|
|
11041
|
+
};
|
|
11042
|
+
var collectUsedReferences = (sf) => {
|
|
11043
|
+
const used = new Set;
|
|
11044
|
+
const visit = (node) => {
|
|
11045
|
+
if (ts8.isIdentifier(node) && isReferencePosition(node))
|
|
11046
|
+
used.add(node.text);
|
|
11047
|
+
ts8.forEachChild(node, visit);
|
|
11048
|
+
};
|
|
11049
|
+
ts8.forEachChild(sf, visit);
|
|
11050
|
+
return used;
|
|
11051
|
+
};
|
|
11052
|
+
var isReferencePosition = (node) => {
|
|
11053
|
+
const parent = node.parent;
|
|
11054
|
+
if (!parent)
|
|
11055
|
+
return true;
|
|
11056
|
+
if (ts8.isPropertyAccessExpression(parent) && parent.name === node)
|
|
11057
|
+
return false;
|
|
11058
|
+
if (ts8.isQualifiedName(parent) && parent.right === node)
|
|
11059
|
+
return false;
|
|
11060
|
+
if (ts8.isPropertyAssignment(parent) && parent.name === node)
|
|
11061
|
+
return false;
|
|
11062
|
+
if (ts8.isPropertySignature(parent) && parent.name === node)
|
|
11063
|
+
return false;
|
|
11064
|
+
if (ts8.isBindingElement(parent) && parent.propertyName === node)
|
|
11065
|
+
return false;
|
|
11066
|
+
if (ts8.isImportSpecifier(parent) || ts8.isExportSpecifier(parent))
|
|
11067
|
+
return false;
|
|
11068
|
+
return true;
|
|
11069
|
+
};
|
|
11070
|
+
var collectExistingNamedImports = (importDecls) => {
|
|
11071
|
+
const map = new Map;
|
|
11072
|
+
for (const decl of importDecls) {
|
|
11073
|
+
const clause = decl.importClause;
|
|
11074
|
+
const bindings = clause?.namedBindings;
|
|
11075
|
+
if (!clause || !bindings || !ts8.isNamedImports(bindings))
|
|
11076
|
+
continue;
|
|
11077
|
+
if (!ts8.isStringLiteral(decl.moduleSpecifier))
|
|
11078
|
+
continue;
|
|
11079
|
+
const specifier = decl.moduleSpecifier.text;
|
|
11080
|
+
if (map.has(specifier))
|
|
11081
|
+
continue;
|
|
11082
|
+
const names = new Map;
|
|
11083
|
+
for (const el of bindings.elements)
|
|
11084
|
+
names.set(el.name.text, clause.isTypeOnly || el.isTypeOnly);
|
|
11085
|
+
map.set(specifier, { decl, names });
|
|
11086
|
+
}
|
|
11087
|
+
return map;
|
|
11088
|
+
};
|
|
11089
|
+
var formatNamedImport = (specifier, names) => {
|
|
11090
|
+
const entries = [...names.entries()].sort((a, b) => compareNames(a[0], b[0]));
|
|
11091
|
+
if (entries.every(([, isType]) => isType))
|
|
11092
|
+
return `import type { ${entries.map(([name]) => name).join(", ")} } from "${specifier}";`;
|
|
11093
|
+
const parts = entries.map(([name, isType]) => isType ? `type ${name}` : name);
|
|
11094
|
+
return `import { ${parts.join(", ")} } from "${specifier}";`;
|
|
11095
|
+
};
|
|
11096
|
+
var directivePrologueEnd = (sf) => {
|
|
11097
|
+
let end = -1;
|
|
11098
|
+
for (const stmt of sf.statements) {
|
|
11099
|
+
if (ts8.isExpressionStatement(stmt) && ts8.isStringLiteral(stmt.expression))
|
|
11100
|
+
end = stmt.getEnd();
|
|
11101
|
+
else
|
|
11102
|
+
break;
|
|
11103
|
+
}
|
|
11104
|
+
return end;
|
|
11105
|
+
};
|
|
11106
|
+
var scriptKindFor = (fileName) => fileName.endsWith(".tsx") ? ts8.ScriptKind.TSX : ts8.ScriptKind.TS;
|
|
11107
|
+
var compareNames = (a, b) => {
|
|
11108
|
+
const [la, lb] = [a.toLowerCase(), b.toLowerCase()];
|
|
11109
|
+
if (la !== lb)
|
|
11110
|
+
return la < lb ? -1 : 1;
|
|
11111
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
11112
|
+
};
|
|
11113
|
+
var formatError = (err) => err instanceof Error ? err.message : String(err);
|
|
11114
|
+
var fileExists2 = async (file) => stat3(file).then((s) => s.isFile()).catch(() => false);
|
|
11115
|
+
var domainKindOf = (base) => {
|
|
11116
|
+
if (base.endsWith(".constant.ts"))
|
|
11117
|
+
return "constant";
|
|
11118
|
+
if (base.endsWith(".document.ts"))
|
|
11119
|
+
return "document";
|
|
11120
|
+
if (base.endsWith(".signal.ts"))
|
|
11121
|
+
return "signal";
|
|
11122
|
+
return null;
|
|
11123
|
+
};
|
|
11124
|
+
var buildDomainIndex = async (libDir) => {
|
|
11125
|
+
const index = new Map;
|
|
11126
|
+
for (const file of await collectDomainFiles(libDir)) {
|
|
11127
|
+
const kind = domainKindOf(path23.basename(file));
|
|
11128
|
+
if (!kind)
|
|
11129
|
+
continue;
|
|
11130
|
+
const src = await readFile(file, "utf8").catch(() => null);
|
|
11131
|
+
if (src === null)
|
|
11132
|
+
continue;
|
|
11133
|
+
for (const name of exportedPascalNames(src, file)) {
|
|
11134
|
+
const entries = index.get(name) ?? [];
|
|
11135
|
+
entries.push({ file, kind });
|
|
11136
|
+
index.set(name, entries);
|
|
11137
|
+
}
|
|
11138
|
+
}
|
|
11139
|
+
return index;
|
|
11140
|
+
};
|
|
11141
|
+
var collectDomainFiles = async (dir) => {
|
|
11142
|
+
const entries = await readdir2(dir, { withFileTypes: true }).catch(() => []);
|
|
11143
|
+
const files = [];
|
|
11144
|
+
for (const entry of entries) {
|
|
11145
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
11146
|
+
continue;
|
|
11147
|
+
const full = path23.join(dir, entry.name);
|
|
11148
|
+
if (entry.isDirectory())
|
|
11149
|
+
files.push(...await collectDomainFiles(full));
|
|
11150
|
+
else if (domainKindOf(entry.name) && !TEST_FILE_RE.test(entry.name))
|
|
11151
|
+
files.push(full);
|
|
11152
|
+
}
|
|
11153
|
+
return files;
|
|
11154
|
+
};
|
|
11155
|
+
var exportedPascalNames = (source2, fileName) => {
|
|
11156
|
+
const sf = ts8.createSourceFile(fileName, source2, ts8.ScriptTarget.Latest, true);
|
|
11157
|
+
const isExported = (node) => ts8.canHaveModifiers(node) && (ts8.getModifiers(node) ?? []).some((m) => m.kind === ts8.SyntaxKind.ExportKeyword);
|
|
11158
|
+
const names = [];
|
|
11159
|
+
for (const stmt of sf.statements) {
|
|
11160
|
+
if ((ts8.isClassDeclaration(stmt) || ts8.isFunctionDeclaration(stmt) || ts8.isEnumDeclaration(stmt)) && stmt.name) {
|
|
11161
|
+
if (isExported(stmt))
|
|
11162
|
+
names.push(stmt.name.text);
|
|
11163
|
+
} else if (ts8.isVariableStatement(stmt) && isExported(stmt)) {
|
|
11164
|
+
for (const decl of stmt.declarationList.declarations)
|
|
11165
|
+
if (ts8.isIdentifier(decl.name))
|
|
11166
|
+
names.push(decl.name.text);
|
|
11167
|
+
} else if (ts8.isExportDeclaration(stmt) && stmt.exportClause && ts8.isNamedExports(stmt.exportClause)) {
|
|
11168
|
+
for (const el of stmt.exportClause.elements)
|
|
11169
|
+
names.push(el.name.text);
|
|
11170
|
+
}
|
|
11171
|
+
}
|
|
11172
|
+
return names.filter((name) => PASCAL_CASE_RE.test(name));
|
|
11173
|
+
};
|
|
11174
|
+
var relativeSpecifier = (fromDir, toFile) => {
|
|
11175
|
+
const rel = path23.relative(fromDir, toFile).replace(/\.tsx?$/, "").split(path23.sep).join("/");
|
|
11176
|
+
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
11177
|
+
};
|
|
10623
11178
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
10624
11179
|
import { mkdir as mkdir5, rm as rm2, unlink } from "fs/promises";
|
|
10625
|
-
import
|
|
11180
|
+
import path25 from "path";
|
|
10626
11181
|
|
|
10627
11182
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
10628
11183
|
import fs3 from "fs";
|
|
10629
|
-
import
|
|
10630
|
-
import
|
|
11184
|
+
import path24 from "path";
|
|
11185
|
+
import ts9 from "typescript";
|
|
10631
11186
|
|
|
10632
11187
|
class PagesEntrySourceGenerator {
|
|
10633
11188
|
#pageEntries;
|
|
@@ -10669,12 +11224,12 @@ ${entries.join(`
|
|
|
10669
11224
|
`;
|
|
10670
11225
|
}
|
|
10671
11226
|
static #toImportSpecifier(moduleAbsPath) {
|
|
10672
|
-
return
|
|
11227
|
+
return path24.resolve(moduleAbsPath).split(path24.sep).join("/");
|
|
10673
11228
|
}
|
|
10674
11229
|
static #hasAsyncDefaultExport(moduleAbsPath) {
|
|
10675
11230
|
try {
|
|
10676
|
-
const source2 = fs3.readFileSync(
|
|
10677
|
-
const sourceFile2 =
|
|
11231
|
+
const source2 = fs3.readFileSync(path24.resolve(moduleAbsPath), "utf8");
|
|
11232
|
+
const sourceFile2 = ts9.createSourceFile(moduleAbsPath, source2, ts9.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
|
|
10678
11233
|
return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
|
|
10679
11234
|
} catch {
|
|
10680
11235
|
return false;
|
|
@@ -10684,31 +11239,31 @@ ${entries.join(`
|
|
|
10684
11239
|
const asyncBindings = new Map;
|
|
10685
11240
|
let defaultIdentifier = null;
|
|
10686
11241
|
for (const statement of sourceFile2.statements) {
|
|
10687
|
-
if (
|
|
10688
|
-
if (PagesEntrySourceGenerator.#hasModifier(statement,
|
|
10689
|
-
return PagesEntrySourceGenerator.#hasModifier(statement,
|
|
11242
|
+
if (ts9.isFunctionDeclaration(statement)) {
|
|
11243
|
+
if (PagesEntrySourceGenerator.#hasModifier(statement, ts9.SyntaxKind.DefaultKeyword)) {
|
|
11244
|
+
return PagesEntrySourceGenerator.#hasModifier(statement, ts9.SyntaxKind.AsyncKeyword);
|
|
10690
11245
|
}
|
|
10691
11246
|
if (statement.name) {
|
|
10692
|
-
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement,
|
|
11247
|
+
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts9.SyntaxKind.AsyncKeyword));
|
|
10693
11248
|
}
|
|
10694
11249
|
continue;
|
|
10695
11250
|
}
|
|
10696
|
-
if (
|
|
11251
|
+
if (ts9.isVariableStatement(statement)) {
|
|
10697
11252
|
for (const declaration of statement.declarationList.declarations) {
|
|
10698
|
-
if (!
|
|
11253
|
+
if (!ts9.isIdentifier(declaration.name))
|
|
10699
11254
|
continue;
|
|
10700
11255
|
asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
|
|
10701
11256
|
}
|
|
10702
11257
|
continue;
|
|
10703
11258
|
}
|
|
10704
|
-
if (
|
|
11259
|
+
if (ts9.isExportAssignment(statement)) {
|
|
10705
11260
|
if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
|
|
10706
11261
|
return true;
|
|
10707
|
-
if (
|
|
11262
|
+
if (ts9.isIdentifier(statement.expression))
|
|
10708
11263
|
defaultIdentifier = statement.expression.text;
|
|
10709
11264
|
continue;
|
|
10710
11265
|
}
|
|
10711
|
-
if (
|
|
11266
|
+
if (ts9.isExportDeclaration(statement) && statement.exportClause && ts9.isNamedExports(statement.exportClause)) {
|
|
10712
11267
|
const exportClause = statement.exportClause;
|
|
10713
11268
|
for (const specifier of exportClause.elements) {
|
|
10714
11269
|
if (specifier.name.text !== "default")
|
|
@@ -10720,13 +11275,13 @@ ${entries.join(`
|
|
|
10720
11275
|
return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
|
|
10721
11276
|
}
|
|
10722
11277
|
static #hasModifier(node, kind) {
|
|
10723
|
-
return
|
|
11278
|
+
return ts9.canHaveModifiers(node) && (ts9.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
|
|
10724
11279
|
}
|
|
10725
11280
|
static #isAsyncFunctionExpression(node) {
|
|
10726
|
-
return Boolean(node && (
|
|
11281
|
+
return Boolean(node && (ts9.isArrowFunction(node) || ts9.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts9.SyntaxKind.AsyncKeyword));
|
|
10727
11282
|
}
|
|
10728
11283
|
static #scriptKind(moduleAbsPath) {
|
|
10729
|
-
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ?
|
|
11284
|
+
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts9.ScriptKind.TSX : ts9.ScriptKind.TS;
|
|
10730
11285
|
}
|
|
10731
11286
|
}
|
|
10732
11287
|
|
|
@@ -10752,7 +11307,7 @@ class CsrArtifactBuilder {
|
|
|
10752
11307
|
const csrBasePaths = [...akanConfig2.basePaths];
|
|
10753
11308
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
10754
11309
|
await rm2(this.#outputDir, { recursive: true, force: true });
|
|
10755
|
-
await mkdir5(
|
|
11310
|
+
await mkdir5(path25.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
10756
11311
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
|
|
10757
11312
|
const result = await Bun.build({
|
|
10758
11313
|
target: "browser",
|
|
@@ -10784,7 +11339,7 @@ ${logs}` : ""}`);
|
|
|
10784
11339
|
return { outputDir: this.#outputDir };
|
|
10785
11340
|
}
|
|
10786
11341
|
get #outputDir() {
|
|
10787
|
-
return
|
|
11342
|
+
return path25.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
|
|
10788
11343
|
}
|
|
10789
11344
|
#define() {
|
|
10790
11345
|
const nodeEnv = this.#command === "build" ? "production" : "development";
|
|
@@ -10815,8 +11370,8 @@ ${logs}` : ""}`);
|
|
|
10815
11370
|
];
|
|
10816
11371
|
}
|
|
10817
11372
|
async#loadCsrArtifact() {
|
|
10818
|
-
const artifactDir =
|
|
10819
|
-
const artifactFile = Bun.file(
|
|
11373
|
+
const artifactDir = path25.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
|
|
11374
|
+
const artifactFile = Bun.file(path25.join(artifactDir, "base-artifact.json"));
|
|
10820
11375
|
if (!await artifactFile.exists())
|
|
10821
11376
|
return { cssAssets: {} };
|
|
10822
11377
|
const artifact = await artifactFile.json();
|
|
@@ -10829,7 +11384,7 @@ ${logs}` : ""}`);
|
|
|
10829
11384
|
const htmlFile = Bun.file(htmlPath);
|
|
10830
11385
|
if (!await htmlFile.exists())
|
|
10831
11386
|
continue;
|
|
10832
|
-
const basePath2 =
|
|
11387
|
+
const basePath2 = path25.basename(htmlPath, ".html") === "index" ? "" : path25.basename(htmlPath, ".html");
|
|
10833
11388
|
const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAssets[basePath2]);
|
|
10834
11389
|
for (const filePath of inlined.jsFiles)
|
|
10835
11390
|
jsFiles.add(filePath);
|
|
@@ -10871,7 +11426,7 @@ ${remainingAssets.join(`
|
|
|
10871
11426
|
next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
|
|
10872
11427
|
}
|
|
10873
11428
|
if (cssAsset) {
|
|
10874
|
-
const cssPath =
|
|
11429
|
+
const cssPath = path25.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
|
|
10875
11430
|
const css = await Bun.file(cssPath).text();
|
|
10876
11431
|
const style = CsrArtifactBuilder.createInlineStyle(css);
|
|
10877
11432
|
if (!next.includes(style))
|
|
@@ -10942,16 +11497,16 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
10942
11497
|
throw new Error(`[csr-build] cannot inline external script: ${src}`);
|
|
10943
11498
|
}
|
|
10944
11499
|
const normalized = src.startsWith("/") ? src.slice(1) : src;
|
|
10945
|
-
return
|
|
11500
|
+
return path25.resolve(path25.dirname(htmlPath), normalized);
|
|
10946
11501
|
}
|
|
10947
11502
|
}
|
|
10948
11503
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
10949
|
-
import
|
|
11504
|
+
import path27 from "path";
|
|
10950
11505
|
import { Logger as Logger8 } from "akanjs/common";
|
|
10951
11506
|
import { compile } from "tailwindcss";
|
|
10952
11507
|
|
|
10953
11508
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
10954
|
-
import
|
|
11509
|
+
import path26 from "path";
|
|
10955
11510
|
var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
|
|
10956
11511
|
|
|
10957
11512
|
class CssImportResolver {
|
|
@@ -11004,7 +11559,7 @@ class CssImportResolver {
|
|
|
11004
11559
|
const exact = this.#paths[id];
|
|
11005
11560
|
if (exact) {
|
|
11006
11561
|
for (const repl of exact) {
|
|
11007
|
-
const resolved = await this.#firstExisting(
|
|
11562
|
+
const resolved = await this.#firstExisting(path26.resolve(this.#workspaceRoot, repl));
|
|
11008
11563
|
if (resolved)
|
|
11009
11564
|
return resolved;
|
|
11010
11565
|
}
|
|
@@ -11015,7 +11570,7 @@ class CssImportResolver {
|
|
|
11015
11570
|
const suffix = id.slice(prefix.length);
|
|
11016
11571
|
for (const repl of replacements) {
|
|
11017
11572
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
11018
|
-
const resolved = await this.#firstExisting(
|
|
11573
|
+
const resolved = await this.#firstExisting(path26.resolve(this.#workspaceRoot, replPath + suffix));
|
|
11019
11574
|
if (resolved)
|
|
11020
11575
|
return resolved;
|
|
11021
11576
|
}
|
|
@@ -11045,25 +11600,25 @@ class CssImportResolver {
|
|
|
11045
11600
|
try {
|
|
11046
11601
|
if (!await Bun.file(pkgPath).exists())
|
|
11047
11602
|
return null;
|
|
11048
|
-
const pkgDir =
|
|
11603
|
+
const pkgDir = path26.dirname(pkgPath);
|
|
11049
11604
|
const pkg = await Bun.file(pkgPath).json();
|
|
11050
11605
|
const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
|
|
11051
11606
|
const exportValue = pkg.exports?.[subpath];
|
|
11052
11607
|
const styleEntry = (typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default) || pkg.exports?.["."]?.style || pkg.style || "index.css";
|
|
11053
|
-
return await this.#firstExisting(
|
|
11608
|
+
return await this.#firstExisting(path26.resolve(pkgDir, styleEntry));
|
|
11054
11609
|
} catch {
|
|
11055
11610
|
return null;
|
|
11056
11611
|
}
|
|
11057
11612
|
}
|
|
11058
11613
|
#resolutionBases(fromBase) {
|
|
11059
|
-
return [fromBase, this.#workspaceRoot,
|
|
11614
|
+
return [fromBase, this.#workspaceRoot, path26.dirname(Bun.main), path26.resolve(path26.dirname(Bun.main), "../..")];
|
|
11060
11615
|
}
|
|
11061
11616
|
#packageJsonCandidates(pkgName) {
|
|
11062
11617
|
return [
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11618
|
+
path26.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
|
|
11619
|
+
path26.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
|
|
11620
|
+
path26.join(path26.dirname(Bun.main), "node_modules", pkgName, "package.json"),
|
|
11621
|
+
path26.join(path26.dirname(Bun.main), "../../", pkgName, "package.json")
|
|
11067
11622
|
];
|
|
11068
11623
|
}
|
|
11069
11624
|
async#firstExisting(basePath2) {
|
|
@@ -11081,7 +11636,7 @@ class CssImportResolver {
|
|
|
11081
11636
|
return parts[0] ?? null;
|
|
11082
11637
|
}
|
|
11083
11638
|
static isCssFile(filePath) {
|
|
11084
|
-
return
|
|
11639
|
+
return path26.extname(filePath) === ".css";
|
|
11085
11640
|
}
|
|
11086
11641
|
}
|
|
11087
11642
|
|
|
@@ -11148,7 +11703,7 @@ class CssCompiler {
|
|
|
11148
11703
|
pageKeys
|
|
11149
11704
|
} = {}) {
|
|
11150
11705
|
pageKeys ??= await this.#app.getPageKeys({ refresh });
|
|
11151
|
-
const seeds = pageKeys.map((key) =>
|
|
11706
|
+
const seeds = pageKeys.map((key) => path27.resolve(this.#app.cwdPath, "page", key));
|
|
11152
11707
|
const cssFiles = new Set;
|
|
11153
11708
|
const sourceFiles = new Set;
|
|
11154
11709
|
const queue = [...seeds];
|
|
@@ -11180,7 +11735,7 @@ class CssCompiler {
|
|
|
11180
11735
|
} catch {
|
|
11181
11736
|
continue;
|
|
11182
11737
|
}
|
|
11183
|
-
const importerDir =
|
|
11738
|
+
const importerDir = path27.dirname(filePath);
|
|
11184
11739
|
for (const imp of imports) {
|
|
11185
11740
|
const spec = imp.path;
|
|
11186
11741
|
if (!spec)
|
|
@@ -11206,7 +11761,7 @@ class CssCompiler {
|
|
|
11206
11761
|
const compileStarted = Date.now();
|
|
11207
11762
|
const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
|
|
11208
11763
|
const css = await Bun.file(cssPath).text();
|
|
11209
|
-
const base =
|
|
11764
|
+
const base = path27.dirname(cssPath);
|
|
11210
11765
|
const compiler = await compile(css, {
|
|
11211
11766
|
base,
|
|
11212
11767
|
loadStylesheet: (id, fromBase) => this.#loadStylesheet(id, fromBase),
|
|
@@ -11237,11 +11792,11 @@ class CssCompiler {
|
|
|
11237
11792
|
async#loadStylesheet(id, fromBase) {
|
|
11238
11793
|
const p = await this.#resolveCssImport(id, fromBase);
|
|
11239
11794
|
const content = await Bun.file(p).text();
|
|
11240
|
-
return { path: p, base:
|
|
11795
|
+
return { path: p, base: path27.dirname(p), content };
|
|
11241
11796
|
}
|
|
11242
11797
|
async#resolveCssImport(id, fromBase) {
|
|
11243
11798
|
if (id.startsWith(".") || id.startsWith("/"))
|
|
11244
|
-
return
|
|
11799
|
+
return path27.resolve(fromBase, id);
|
|
11245
11800
|
const resolver = await this.#getCssImportResolver();
|
|
11246
11801
|
const resolved = await resolver.resolve(id, fromBase);
|
|
11247
11802
|
if (resolved)
|
|
@@ -11257,11 +11812,11 @@ class CssCompiler {
|
|
|
11257
11812
|
async#loadModule(id, fromBase) {
|
|
11258
11813
|
const p = __require.resolve(id, { paths: [fromBase] });
|
|
11259
11814
|
const mod = await import(p);
|
|
11260
|
-
return { path: p, base:
|
|
11815
|
+
return { path: p, base: path27.dirname(p), module: mod.default ?? mod };
|
|
11261
11816
|
}
|
|
11262
11817
|
async#resolveSourceImport(id, fromBase, resolvePackage) {
|
|
11263
11818
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
11264
|
-
const abs = id.startsWith("/") ? id :
|
|
11819
|
+
const abs = id.startsWith("/") ? id : path27.resolve(fromBase, id);
|
|
11265
11820
|
return resolveSourceFileCandidate(abs);
|
|
11266
11821
|
}
|
|
11267
11822
|
const pkg = await resolvePackage(id);
|
|
@@ -11303,7 +11858,7 @@ async function resolveSourceFileCandidate(absPathNoExt) {
|
|
|
11303
11858
|
return filePath;
|
|
11304
11859
|
}
|
|
11305
11860
|
for (const ext of SOURCE_EXTS3) {
|
|
11306
|
-
const filePath =
|
|
11861
|
+
const filePath = path27.join(absPathNoExt, `index${ext}`);
|
|
11307
11862
|
if (await Bun.file(filePath).exists())
|
|
11308
11863
|
return filePath;
|
|
11309
11864
|
}
|
|
@@ -11326,19 +11881,19 @@ function resolveSourceWithRequire(id, fromBase) {
|
|
|
11326
11881
|
}
|
|
11327
11882
|
}
|
|
11328
11883
|
function isSourceFile(filePath) {
|
|
11329
|
-
return SOURCE_EXTS3.includes(
|
|
11884
|
+
return SOURCE_EXTS3.includes(path27.extname(filePath));
|
|
11330
11885
|
}
|
|
11331
11886
|
function isIgnoredNodeModuleSource(filePath) {
|
|
11332
11887
|
return NODE_MODULES_RE3.test(filePath) && !AKANJS_NODE_MODULE_RE3.test(filePath);
|
|
11333
11888
|
}
|
|
11334
11889
|
function getPageKeyBasePath(pageKey, basePaths) {
|
|
11335
|
-
const normalized = pageKey.split(
|
|
11890
|
+
const normalized = pageKey.split(path27.sep).join("/").replace(/^\.\//, "");
|
|
11336
11891
|
const segments = normalized.split("/");
|
|
11337
11892
|
const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
|
|
11338
11893
|
return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
|
|
11339
11894
|
}
|
|
11340
11895
|
// pkgs/@akanjs/devkit/frontendBuild/devChangePlanner.ts
|
|
11341
|
-
import
|
|
11896
|
+
import path28 from "path";
|
|
11342
11897
|
var SOURCE_EXTS4 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
11343
11898
|
var CONFIG_BASENAMES = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
11344
11899
|
var BARREL_FACETS = new Set(["common", "srvkit", "ui", "webkit", "plugin"]);
|
|
@@ -11350,11 +11905,11 @@ var RUNTIME_METADATA_BASENAMES2 = new Set(["dict.ts", "sig.ts", "useClient.ts",
|
|
|
11350
11905
|
class DevChangePlanner {
|
|
11351
11906
|
#workspaceRoot;
|
|
11352
11907
|
constructor({ workspaceRoot }) {
|
|
11353
|
-
this.#workspaceRoot =
|
|
11908
|
+
this.#workspaceRoot = path28.resolve(workspaceRoot);
|
|
11354
11909
|
}
|
|
11355
11910
|
plan({ generation, files, kinds, generatedFiles: generatedFiles2 = [] }) {
|
|
11356
11911
|
const fileList = uniqueResolved([...files, ...generatedFiles2]);
|
|
11357
|
-
const generatedSet = new Set(generatedFiles2.map((file) =>
|
|
11912
|
+
const generatedSet = new Set(generatedFiles2.map((file) => path28.resolve(file)));
|
|
11358
11913
|
const kindSet = new Set(kinds);
|
|
11359
11914
|
const roles = new Set;
|
|
11360
11915
|
const actions = new Set;
|
|
@@ -11371,13 +11926,13 @@ class DevChangePlanner {
|
|
|
11371
11926
|
}
|
|
11372
11927
|
for (const file of fileList) {
|
|
11373
11928
|
const reasons = new Set;
|
|
11374
|
-
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(
|
|
11929
|
+
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(path28.resolve(file)), reasons });
|
|
11375
11930
|
for (const role of fileRoles)
|
|
11376
11931
|
roles.add(role);
|
|
11377
11932
|
if (reasons.has("runtime-metadata"))
|
|
11378
11933
|
actions.add("restart-builder");
|
|
11379
11934
|
if (reasons.size > 0)
|
|
11380
|
-
reasonByFile[
|
|
11935
|
+
reasonByFile[path28.resolve(file)] = [...reasons].sort();
|
|
11381
11936
|
}
|
|
11382
11937
|
if (roles.has("barrel"))
|
|
11383
11938
|
actions.add("sync-generated");
|
|
@@ -11398,12 +11953,12 @@ class DevChangePlanner {
|
|
|
11398
11953
|
}
|
|
11399
11954
|
#rolesForFile(file, { isGenerated, reasons }) {
|
|
11400
11955
|
const roles = new Set;
|
|
11401
|
-
const abs =
|
|
11402
|
-
const base =
|
|
11403
|
-
const ext =
|
|
11956
|
+
const abs = path28.resolve(file);
|
|
11957
|
+
const base = path28.basename(abs);
|
|
11958
|
+
const ext = path28.extname(abs).toLowerCase();
|
|
11404
11959
|
const isSource = SOURCE_EXTS4.has(ext);
|
|
11405
|
-
const rel =
|
|
11406
|
-
const parts = rel.split(
|
|
11960
|
+
const rel = path28.relative(this.#workspaceRoot, abs);
|
|
11961
|
+
const parts = rel.split(path28.sep).filter(Boolean);
|
|
11407
11962
|
if (CONFIG_BASENAMES.has(base)) {
|
|
11408
11963
|
roles.add("config");
|
|
11409
11964
|
reasons.add("config-file");
|
|
@@ -11444,15 +11999,15 @@ class DevChangePlanner {
|
|
|
11444
11999
|
return roles;
|
|
11445
12000
|
}
|
|
11446
12001
|
#isServerBiased(abs, parts) {
|
|
11447
|
-
const base =
|
|
12002
|
+
const base = path28.basename(abs);
|
|
11448
12003
|
return parts.includes("srvkit") || SERVER_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || base === "main.ts" || base === "server.ts";
|
|
11449
12004
|
}
|
|
11450
12005
|
#isClientBiased(abs, parts) {
|
|
11451
|
-
const base =
|
|
12006
|
+
const base = path28.basename(abs);
|
|
11452
12007
|
return parts.includes("ui") || parts.includes("webkit") || parts.includes("page") || CLIENT_SUFFIXES.some((suffix) => base.endsWith(suffix));
|
|
11453
12008
|
}
|
|
11454
12009
|
#isSharedBiased(abs, parts) {
|
|
11455
|
-
const base =
|
|
12010
|
+
const base = path28.basename(abs);
|
|
11456
12011
|
return parts.includes("common") || SHARED_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || RUNTIME_METADATA_BASENAMES2.has(base);
|
|
11457
12012
|
}
|
|
11458
12013
|
#isRuntimeMetadataFile(parts, base) {
|
|
@@ -11477,16 +12032,16 @@ class DevChangePlanner {
|
|
|
11477
12032
|
return true;
|
|
11478
12033
|
}
|
|
11479
12034
|
#isWorkspaceSource(rel) {
|
|
11480
|
-
if (!rel || rel.startsWith("..") ||
|
|
12035
|
+
if (!rel || rel.startsWith("..") || path28.isAbsolute(rel))
|
|
11481
12036
|
return false;
|
|
11482
|
-
const [scope] = rel.split(
|
|
12037
|
+
const [scope] = rel.split(path28.sep);
|
|
11483
12038
|
return scope === "apps" || scope === "libs" || scope === "pkgs";
|
|
11484
12039
|
}
|
|
11485
12040
|
}
|
|
11486
|
-
var uniqueResolved = (files) => [...new Set(files.map((file) =>
|
|
12041
|
+
var uniqueResolved = (files) => [...new Set(files.map((file) => path28.resolve(file)))].sort();
|
|
11487
12042
|
// pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
|
|
11488
|
-
import { mkdir as mkdir6, readdir as
|
|
11489
|
-
import
|
|
12043
|
+
import { mkdir as mkdir6, readdir as readdir3, readFile as readFile2, rm as rm3, stat as stat4, writeFile as writeFile2 } from "fs/promises";
|
|
12044
|
+
import path29 from "path";
|
|
11490
12045
|
var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit", "plugin"]);
|
|
11491
12046
|
var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
|
|
11492
12047
|
var FACET_EXCLUDED_FILE_RE = /(^index\.tsx?$|\.d\.ts$|\.(test|spec)\.(ts|tsx)$|\.css$|\.scss$|\.sass$)/;
|
|
@@ -11499,7 +12054,7 @@ var SCALAR_UI_TYPES = ["Template", "Unit"];
|
|
|
11499
12054
|
class DevGeneratedIndexSync {
|
|
11500
12055
|
#workspaceRoot;
|
|
11501
12056
|
constructor({ workspaceRoot }) {
|
|
11502
|
-
this.#workspaceRoot =
|
|
12057
|
+
this.#workspaceRoot = path29.resolve(workspaceRoot);
|
|
11503
12058
|
}
|
|
11504
12059
|
async syncForBatch(files) {
|
|
11505
12060
|
const indexPaths = new Set;
|
|
@@ -11509,7 +12064,7 @@ class DevGeneratedIndexSync {
|
|
|
11509
12064
|
if (facetIndex)
|
|
11510
12065
|
indexPaths.add(facetIndex);
|
|
11511
12066
|
const moduleIndex2 = await this.#moduleIndexForDirectoryEvent(file).catch((err) => {
|
|
11512
|
-
errors.push(`[generated-index] module detection failed for ${file}: ${
|
|
12067
|
+
errors.push(`[generated-index] module detection failed for ${file}: ${formatError2(err)}`);
|
|
11513
12068
|
return null;
|
|
11514
12069
|
});
|
|
11515
12070
|
if (moduleIndex2)
|
|
@@ -11522,17 +12077,17 @@ class DevGeneratedIndexSync {
|
|
|
11522
12077
|
if (changed)
|
|
11523
12078
|
changedFiles.push(indexPath);
|
|
11524
12079
|
} catch (err) {
|
|
11525
|
-
errors.push(`[generated-index] sync failed for ${indexPath}: ${
|
|
12080
|
+
errors.push(`[generated-index] sync failed for ${indexPath}: ${formatError2(err)}`);
|
|
11526
12081
|
}
|
|
11527
12082
|
}
|
|
11528
12083
|
return { changedFiles, errors };
|
|
11529
12084
|
}
|
|
11530
12085
|
#facetIndexFor(file) {
|
|
11531
|
-
const abs =
|
|
11532
|
-
const rel =
|
|
11533
|
-
if (rel.startsWith("..") ||
|
|
12086
|
+
const abs = path29.resolve(file);
|
|
12087
|
+
const rel = path29.relative(this.#workspaceRoot, abs);
|
|
12088
|
+
if (rel.startsWith("..") || path29.isAbsolute(rel))
|
|
11534
12089
|
return null;
|
|
11535
|
-
const parts = rel.split(
|
|
12090
|
+
const parts = rel.split(path29.sep).filter(Boolean);
|
|
11536
12091
|
if (parts.length < 4)
|
|
11537
12092
|
return null;
|
|
11538
12093
|
const [scope, project, facet, child] = parts;
|
|
@@ -11540,32 +12095,32 @@ class DevGeneratedIndexSync {
|
|
|
11540
12095
|
return null;
|
|
11541
12096
|
if (!child || child.startsWith(".") || child === "index.ts" || child === "index.tsx")
|
|
11542
12097
|
return null;
|
|
11543
|
-
return
|
|
12098
|
+
return path29.join(this.#workspaceRoot, scope, project, facet, "index.ts");
|
|
11544
12099
|
}
|
|
11545
12100
|
async#moduleIndexForDirectoryEvent(file) {
|
|
11546
|
-
const abs =
|
|
11547
|
-
const rel =
|
|
11548
|
-
if (rel.startsWith("..") ||
|
|
12101
|
+
const abs = path29.resolve(file);
|
|
12102
|
+
const rel = path29.relative(this.#workspaceRoot, abs);
|
|
12103
|
+
if (rel.startsWith("..") || path29.isAbsolute(rel))
|
|
11549
12104
|
return null;
|
|
11550
|
-
const parts = rel.split(
|
|
12105
|
+
const parts = rel.split(path29.sep).filter(Boolean);
|
|
11551
12106
|
if (parts.length !== 4 && parts.length !== 5)
|
|
11552
12107
|
return null;
|
|
11553
12108
|
const [scope, project, libSegment, moduleSegment, scalarSegment] = parts;
|
|
11554
12109
|
if (scope !== "apps" && scope !== "libs" || !project || libSegment !== "lib")
|
|
11555
12110
|
return null;
|
|
11556
|
-
const isExistingDirectory = await
|
|
11557
|
-
const looksLikeDeletedDirectory = !
|
|
12111
|
+
const isExistingDirectory = await stat4(abs).then((s) => s.isDirectory()).catch(() => false);
|
|
12112
|
+
const looksLikeDeletedDirectory = !path29.extname(abs);
|
|
11558
12113
|
if (!isExistingDirectory && !looksLikeDeletedDirectory)
|
|
11559
12114
|
return null;
|
|
11560
12115
|
if (moduleSegment === "__scalar" && scalarSegment) {
|
|
11561
|
-
return
|
|
12116
|
+
return path29.join(this.#workspaceRoot, scope, project, "lib", "__scalar", scalarSegment, "index.ts");
|
|
11562
12117
|
}
|
|
11563
12118
|
if (!moduleSegment || moduleSegment === "__scalar")
|
|
11564
12119
|
return null;
|
|
11565
|
-
return
|
|
12120
|
+
return path29.join(this.#workspaceRoot, scope, project, "lib", moduleSegment, "index.ts");
|
|
11566
12121
|
}
|
|
11567
12122
|
async#syncIndex(indexPath) {
|
|
11568
|
-
const dir =
|
|
12123
|
+
const dir = path29.dirname(indexPath);
|
|
11569
12124
|
const content = await this.#contentForIndex(indexPath);
|
|
11570
12125
|
if (content === null) {
|
|
11571
12126
|
if (!await exists(indexPath))
|
|
@@ -11573,23 +12128,23 @@ class DevGeneratedIndexSync {
|
|
|
11573
12128
|
await rm3(indexPath, { force: true });
|
|
11574
12129
|
return true;
|
|
11575
12130
|
}
|
|
11576
|
-
const current = await
|
|
12131
|
+
const current = await readFile2(indexPath, "utf8").catch(() => null);
|
|
11577
12132
|
if (current === content)
|
|
11578
12133
|
return false;
|
|
11579
12134
|
await mkdir6(dir, { recursive: true });
|
|
11580
|
-
await
|
|
12135
|
+
await writeFile2(indexPath, content);
|
|
11581
12136
|
return true;
|
|
11582
12137
|
}
|
|
11583
12138
|
async#contentForIndex(indexPath) {
|
|
11584
|
-
const parts =
|
|
12139
|
+
const parts = path29.relative(this.#workspaceRoot, indexPath).split(path29.sep).filter(Boolean);
|
|
11585
12140
|
const facet = parts.at(-2);
|
|
11586
12141
|
if (facet && BARREL_FACETS2.has(facet))
|
|
11587
|
-
return this.#facetContent(
|
|
11588
|
-
return this.#moduleContent(
|
|
12142
|
+
return this.#facetContent(path29.dirname(indexPath));
|
|
12143
|
+
return this.#moduleContent(path29.dirname(indexPath));
|
|
11589
12144
|
}
|
|
11590
12145
|
async#facetContent(dir) {
|
|
11591
|
-
const nameCasePattern =
|
|
11592
|
-
const entries = await
|
|
12146
|
+
const nameCasePattern = path29.basename(dir) === "ui" ? FACET_PASCAL_CASE_RE : FACET_CAMEL_CASE_RE;
|
|
12147
|
+
const entries = await readdir3(dir, { withFileTypes: true }).catch(() => []);
|
|
11593
12148
|
const exportNames = entries.flatMap((entry) => {
|
|
11594
12149
|
const name = entry.name;
|
|
11595
12150
|
if (name.startsWith("."))
|
|
@@ -11610,8 +12165,8 @@ class DevGeneratedIndexSync {
|
|
|
11610
12165
|
`;
|
|
11611
12166
|
}
|
|
11612
12167
|
async#moduleContent(dir) {
|
|
11613
|
-
const rel =
|
|
11614
|
-
const parts = rel.split(
|
|
12168
|
+
const rel = path29.relative(this.#workspaceRoot, dir);
|
|
12169
|
+
const parts = rel.split(path29.sep).filter(Boolean);
|
|
11615
12170
|
const moduleSegment = parts.at(-1);
|
|
11616
12171
|
if (!moduleSegment)
|
|
11617
12172
|
return null;
|
|
@@ -11623,7 +12178,7 @@ class DevGeneratedIndexSync {
|
|
|
11623
12178
|
const allowedTypes = isScalar ? SCALAR_UI_TYPES : moduleSegment.startsWith("_") ? SERVICE_UI_TYPES : MODULE_UI_TYPES;
|
|
11624
12179
|
const fileTypes = [];
|
|
11625
12180
|
for (const type of allowedTypes) {
|
|
11626
|
-
if (await exists(
|
|
12181
|
+
if (await exists(path29.join(dir, `${modelName}.${type}.tsx`)))
|
|
11627
12182
|
fileTypes.push(type);
|
|
11628
12183
|
}
|
|
11629
12184
|
if (fileTypes.length === 0)
|
|
@@ -11635,12 +12190,12 @@ ${fileTypes.map((type) => `import * as ${type} from "./${modelName}.${type}";`).
|
|
|
11635
12190
|
export const ${modelName} = { ${fileTypes.join(", ")} };`;
|
|
11636
12191
|
}
|
|
11637
12192
|
}
|
|
11638
|
-
var exists = async (file) =>
|
|
12193
|
+
var exists = async (file) => stat4(file).then(() => true).catch(() => false);
|
|
11639
12194
|
var capitalize4 = (value) => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
|
|
11640
|
-
var
|
|
12195
|
+
var formatError2 = (err) => err instanceof Error ? err.message : String(err);
|
|
11641
12196
|
// pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
|
|
11642
12197
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
11643
|
-
import
|
|
12198
|
+
import path30 from "path";
|
|
11644
12199
|
import {
|
|
11645
12200
|
generateFontFace,
|
|
11646
12201
|
getMetricsForFamily,
|
|
@@ -11649,7 +12204,7 @@ import {
|
|
|
11649
12204
|
} from "fontaine";
|
|
11650
12205
|
import { createFont, woff2 } from "fonteditor-core";
|
|
11651
12206
|
import subsetFont from "subset-font";
|
|
11652
|
-
import
|
|
12207
|
+
import ts10 from "typescript";
|
|
11653
12208
|
var FONT_URL_PREFIX = "/_akan/fonts";
|
|
11654
12209
|
var DEFAULT_FONT_SUBSETS = ["latin"];
|
|
11655
12210
|
|
|
@@ -11664,7 +12219,7 @@ class FontOptimizer {
|
|
|
11664
12219
|
constructor(app, command = "start") {
|
|
11665
12220
|
this.#app = app;
|
|
11666
12221
|
this.#command = command;
|
|
11667
|
-
this.#artifactRoot =
|
|
12222
|
+
this.#artifactRoot = path30.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
|
|
11668
12223
|
}
|
|
11669
12224
|
async optimize() {
|
|
11670
12225
|
const fonts = await this.discoverFonts();
|
|
@@ -11683,7 +12238,7 @@ class FontOptimizer {
|
|
|
11683
12238
|
const pageKeys = await this.#app.getPageKeys();
|
|
11684
12239
|
const fonts = [];
|
|
11685
12240
|
await Promise.all(pageKeys.map(async (key) => {
|
|
11686
|
-
const filePath =
|
|
12241
|
+
const filePath = path30.resolve(this.#app.cwdPath, "page", key);
|
|
11687
12242
|
const file = Bun.file(filePath);
|
|
11688
12243
|
if (!await file.exists())
|
|
11689
12244
|
return;
|
|
@@ -11699,8 +12254,8 @@ class FontOptimizer {
|
|
|
11699
12254
|
this.#app.logger.warn(`[font] source not found: ${face.src}`);
|
|
11700
12255
|
continue;
|
|
11701
12256
|
}
|
|
11702
|
-
const outputPath =
|
|
11703
|
-
await mkdir7(
|
|
12257
|
+
const outputPath = path30.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
|
|
12258
|
+
await mkdir7(path30.dirname(outputPath), { recursive: true });
|
|
11704
12259
|
const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
|
|
11705
12260
|
const outputBuffer = font.subset === false ? await this.#convertToWoff2(sourceBuffer, sourcePath) : await subsetFont(sourceBuffer, await this.#getSubsetText(font), { targetFormat: "woff2" });
|
|
11706
12261
|
await Bun.write(outputPath, outputBuffer);
|
|
@@ -11714,17 +12269,17 @@ class FontOptimizer {
|
|
|
11714
12269
|
this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
|
|
11715
12270
|
}
|
|
11716
12271
|
#extractFontsExport(source2, filePath) {
|
|
11717
|
-
const sourceFile2 =
|
|
12272
|
+
const sourceFile2 = ts10.createSourceFile(filePath, source2, ts10.ScriptTarget.Latest, true, ts10.ScriptKind.TSX);
|
|
11718
12273
|
const fonts = [];
|
|
11719
12274
|
for (const statement of sourceFile2.statements) {
|
|
11720
|
-
if (!
|
|
12275
|
+
if (!ts10.isVariableStatement(statement))
|
|
11721
12276
|
continue;
|
|
11722
|
-
const modifiers =
|
|
11723
|
-
const isExported = modifiers?.some((modifier) => modifier.kind ===
|
|
12277
|
+
const modifiers = ts10.canHaveModifiers(statement) ? ts10.getModifiers(statement) : undefined;
|
|
12278
|
+
const isExported = modifiers?.some((modifier) => modifier.kind === ts10.SyntaxKind.ExportKeyword) ?? false;
|
|
11724
12279
|
if (!isExported)
|
|
11725
12280
|
continue;
|
|
11726
12281
|
for (const declaration of statement.declarationList.declarations) {
|
|
11727
|
-
if (!
|
|
12282
|
+
if (!ts10.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
|
|
11728
12283
|
continue;
|
|
11729
12284
|
const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
|
|
11730
12285
|
if (Array.isArray(value)) {
|
|
@@ -11735,20 +12290,20 @@ class FontOptimizer {
|
|
|
11735
12290
|
return fonts;
|
|
11736
12291
|
}
|
|
11737
12292
|
#literalToValue(node) {
|
|
11738
|
-
if (
|
|
12293
|
+
if (ts10.isStringLiteralLike(node))
|
|
11739
12294
|
return node.text;
|
|
11740
|
-
if (
|
|
12295
|
+
if (ts10.isNumericLiteral(node))
|
|
11741
12296
|
return Number(node.text);
|
|
11742
|
-
if (node.kind ===
|
|
12297
|
+
if (node.kind === ts10.SyntaxKind.TrueKeyword)
|
|
11743
12298
|
return true;
|
|
11744
|
-
if (node.kind ===
|
|
12299
|
+
if (node.kind === ts10.SyntaxKind.FalseKeyword)
|
|
11745
12300
|
return false;
|
|
11746
|
-
if (
|
|
12301
|
+
if (ts10.isArrayLiteralExpression(node))
|
|
11747
12302
|
return node.elements.map((element) => this.#literalToValue(element));
|
|
11748
|
-
if (
|
|
12303
|
+
if (ts10.isObjectLiteralExpression(node)) {
|
|
11749
12304
|
const obj = {};
|
|
11750
12305
|
for (const prop of node.properties) {
|
|
11751
|
-
if (!
|
|
12306
|
+
if (!ts10.isPropertyAssignment(prop))
|
|
11752
12307
|
continue;
|
|
11753
12308
|
const name = this.#getPropertyName(prop.name);
|
|
11754
12309
|
if (!name)
|
|
@@ -11757,13 +12312,13 @@ class FontOptimizer {
|
|
|
11757
12312
|
}
|
|
11758
12313
|
return obj;
|
|
11759
12314
|
}
|
|
11760
|
-
if (
|
|
12315
|
+
if (ts10.isAsExpression(node) || ts10.isSatisfiesExpression(node) || ts10.isParenthesizedExpression(node)) {
|
|
11761
12316
|
return this.#literalToValue(node.expression);
|
|
11762
12317
|
}
|
|
11763
12318
|
return;
|
|
11764
12319
|
}
|
|
11765
12320
|
#getPropertyName(name) {
|
|
11766
|
-
if (
|
|
12321
|
+
if (ts10.isIdentifier(name) || ts10.isStringLiteral(name) || ts10.isNumericLiteral(name))
|
|
11767
12322
|
return name.text;
|
|
11768
12323
|
return null;
|
|
11769
12324
|
}
|
|
@@ -11847,8 +12402,8 @@ class FontOptimizer {
|
|
|
11847
12402
|
return null;
|
|
11848
12403
|
const rel = src.replace(/^\//, "");
|
|
11849
12404
|
const candidates = [
|
|
11850
|
-
this.#command === "build" ?
|
|
11851
|
-
|
|
12405
|
+
this.#command === "build" ? path30.join(this.#app.dist.cwdPath, "public", rel) : null,
|
|
12406
|
+
path30.join(this.#app.cwdPath, "public", rel),
|
|
11852
12407
|
this.#resolveWorkspacePublicPath(rel)
|
|
11853
12408
|
].filter(Boolean);
|
|
11854
12409
|
for (const candidate of candidates) {
|
|
@@ -11876,7 +12431,7 @@ class FontOptimizer {
|
|
|
11876
12431
|
return "woff2";
|
|
11877
12432
|
if (signature === "OTTO")
|
|
11878
12433
|
return "otf";
|
|
11879
|
-
const ext =
|
|
12434
|
+
const ext = path30.extname(sourcePath).slice(1).toLowerCase();
|
|
11880
12435
|
if (ext === "otf" || ext === "woff" || ext === "woff2")
|
|
11881
12436
|
return ext;
|
|
11882
12437
|
return "ttf";
|
|
@@ -11885,7 +12440,7 @@ class FontOptimizer {
|
|
|
11885
12440
|
const [root, dep, ...rest] = rel.split("/");
|
|
11886
12441
|
if (root !== "libs" || !dep || rest.length === 0)
|
|
11887
12442
|
return null;
|
|
11888
|
-
return
|
|
12443
|
+
return path30.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
|
|
11889
12444
|
}
|
|
11890
12445
|
async#getSubsetText(font) {
|
|
11891
12446
|
const parts = new Set;
|
|
@@ -11895,7 +12450,7 @@ class FontOptimizer {
|
|
|
11895
12450
|
if (font.subsetText)
|
|
11896
12451
|
parts.add(font.subsetText);
|
|
11897
12452
|
for (const filePath of font.subsetFiles ?? []) {
|
|
11898
|
-
const abs =
|
|
12453
|
+
const abs = path30.isAbsolute(filePath) ? filePath : path30.join(this.#app.cwdPath, filePath);
|
|
11899
12454
|
const file = Bun.file(abs);
|
|
11900
12455
|
if (await file.exists())
|
|
11901
12456
|
parts.add(await file.text());
|
|
@@ -11914,7 +12469,7 @@ class FontOptimizer {
|
|
|
11914
12469
|
return "";
|
|
11915
12470
|
}
|
|
11916
12471
|
async#collectAutoSubsetText() {
|
|
11917
|
-
const roots = ["page", "ui"].map((dir) =>
|
|
12472
|
+
const roots = ["page", "ui"].map((dir) => path30.join(this.#app.cwdPath, dir));
|
|
11918
12473
|
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
|
|
11919
12474
|
const parts = [];
|
|
11920
12475
|
await Promise.all(roots.map(async (root) => {
|
|
@@ -12028,7 +12583,7 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
|
|
|
12028
12583
|
}
|
|
12029
12584
|
}
|
|
12030
12585
|
// pkgs/@akanjs/devkit/frontendBuild/hmrChangeClassifier.ts
|
|
12031
|
-
import
|
|
12586
|
+
import path31 from "path";
|
|
12032
12587
|
var SOURCE_EXTS5 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
12033
12588
|
var CSS_EXTS = new Set([".css"]);
|
|
12034
12589
|
var CONFIG_BASENAMES2 = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
@@ -12037,10 +12592,10 @@ class HmrChangeClassifier {
|
|
|
12037
12592
|
classify(abs) {
|
|
12038
12593
|
if (this.#isUninteresting(abs))
|
|
12039
12594
|
return "ignore";
|
|
12040
|
-
const base =
|
|
12595
|
+
const base = path31.basename(abs);
|
|
12041
12596
|
if (CONFIG_BASENAMES2.has(base))
|
|
12042
12597
|
return "config";
|
|
12043
|
-
const ext =
|
|
12598
|
+
const ext = path31.extname(abs).toLowerCase();
|
|
12044
12599
|
if (CSS_EXTS.has(ext))
|
|
12045
12600
|
return "css";
|
|
12046
12601
|
if (SOURCE_EXTS5.has(ext))
|
|
@@ -12048,23 +12603,23 @@ class HmrChangeClassifier {
|
|
|
12048
12603
|
return "ignore";
|
|
12049
12604
|
}
|
|
12050
12605
|
#isUninteresting(abs) {
|
|
12051
|
-
const base =
|
|
12606
|
+
const base = path31.basename(abs);
|
|
12052
12607
|
if (!base)
|
|
12053
12608
|
return true;
|
|
12054
12609
|
if (base.startsWith("."))
|
|
12055
12610
|
return true;
|
|
12056
12611
|
if (base.endsWith("~") || base.endsWith(".swp") || base.endsWith(".swx") || base.endsWith(".tmp"))
|
|
12057
12612
|
return true;
|
|
12058
|
-
if (abs.includes(`${
|
|
12613
|
+
if (abs.includes(`${path31.sep}node_modules${path31.sep}`))
|
|
12059
12614
|
return true;
|
|
12060
|
-
if (abs.includes(`${
|
|
12615
|
+
if (abs.includes(`${path31.sep}.akan${path31.sep}`))
|
|
12061
12616
|
return true;
|
|
12062
12617
|
return false;
|
|
12063
12618
|
}
|
|
12064
12619
|
}
|
|
12065
12620
|
// pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
|
|
12066
12621
|
import fs4 from "fs";
|
|
12067
|
-
import
|
|
12622
|
+
import path32 from "path";
|
|
12068
12623
|
class HmrWatcher {
|
|
12069
12624
|
#roots;
|
|
12070
12625
|
#debounceMs;
|
|
@@ -12077,7 +12632,7 @@ class HmrWatcher {
|
|
|
12077
12632
|
#stopped = false;
|
|
12078
12633
|
#flushing = false;
|
|
12079
12634
|
constructor(opts) {
|
|
12080
|
-
this.#roots = [...new Set(opts.roots.map((r) =>
|
|
12635
|
+
this.#roots = [...new Set(opts.roots.map((r) => path32.resolve(r)))];
|
|
12081
12636
|
this.#debounceMs = opts.debounceMs ?? 80;
|
|
12082
12637
|
this.#onBatch = opts.onBatch;
|
|
12083
12638
|
this.#logger = opts.logger;
|
|
@@ -12088,7 +12643,7 @@ class HmrWatcher {
|
|
|
12088
12643
|
const w = fs4.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
|
|
12089
12644
|
if (!filename)
|
|
12090
12645
|
return;
|
|
12091
|
-
const abs =
|
|
12646
|
+
const abs = path32.resolve(root, filename.toString());
|
|
12092
12647
|
this.#queue(abs);
|
|
12093
12648
|
});
|
|
12094
12649
|
this.#watchers.push(w);
|
|
@@ -12146,10 +12701,10 @@ class HmrWatcher {
|
|
|
12146
12701
|
}
|
|
12147
12702
|
}
|
|
12148
12703
|
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
12149
|
-
import
|
|
12704
|
+
import path34 from "path";
|
|
12150
12705
|
|
|
12151
12706
|
// pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
|
|
12152
|
-
import
|
|
12707
|
+
import path33 from "path";
|
|
12153
12708
|
var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
|
|
12154
12709
|
var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
|
|
12155
12710
|
var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
|
|
@@ -12192,7 +12747,7 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
12192
12747
|
const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
|
|
12193
12748
|
if (!replPath)
|
|
12194
12749
|
continue;
|
|
12195
|
-
const candidate =
|
|
12750
|
+
const candidate = path33.resolve(workspaceRoot, replPath + suffix);
|
|
12196
12751
|
const hit = await firstExisting(candidate);
|
|
12197
12752
|
if (hit)
|
|
12198
12753
|
return hit;
|
|
@@ -12204,8 +12759,8 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
12204
12759
|
if (spec === pkg)
|
|
12205
12760
|
continue;
|
|
12206
12761
|
const suffix = spec.slice(pkg.length + 1);
|
|
12207
|
-
const pkgDir =
|
|
12208
|
-
const candidate =
|
|
12762
|
+
const pkgDir = path33.dirname(path33.resolve(workspaceRoot, entryFile));
|
|
12763
|
+
const candidate = path33.join(pkgDir, suffix);
|
|
12209
12764
|
const hit = await firstExisting(candidate);
|
|
12210
12765
|
if (hit)
|
|
12211
12766
|
return hit;
|
|
@@ -12255,7 +12810,7 @@ async function firstExisting(basePath2) {
|
|
|
12255
12810
|
return candidate;
|
|
12256
12811
|
}
|
|
12257
12812
|
for (const ext of CANDIDATE_EXTS3) {
|
|
12258
|
-
const candidate =
|
|
12813
|
+
const candidate = path33.join(basePath2, `index${ext}`);
|
|
12259
12814
|
if (await Bun.file(candidate).exists())
|
|
12260
12815
|
return candidate;
|
|
12261
12816
|
}
|
|
@@ -12346,11 +12901,11 @@ class PagesBundleBuilder {
|
|
|
12346
12901
|
const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
|
|
12347
12902
|
if (!entryArtifact)
|
|
12348
12903
|
throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
|
|
12349
|
-
const bundlePath =
|
|
12904
|
+
const bundlePath = path34.resolve(entryArtifact.path);
|
|
12350
12905
|
const buildId = Date.now();
|
|
12351
12906
|
const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
|
|
12352
12907
|
const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
|
|
12353
|
-
this.#app.verbose(`[PagesBundleBuilder] ${
|
|
12908
|
+
this.#app.verbose(`[PagesBundleBuilder] ${path34.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`);
|
|
12354
12909
|
return {
|
|
12355
12910
|
bundlePath,
|
|
12356
12911
|
buildId,
|
|
@@ -12432,11 +12987,11 @@ function loaderFor4(absPath) {
|
|
|
12432
12987
|
}
|
|
12433
12988
|
// pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
|
|
12434
12989
|
import fs5 from "fs";
|
|
12435
|
-
import
|
|
12990
|
+
import path35 from "path";
|
|
12436
12991
|
var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
|
|
12437
12992
|
var MIN_COMPRESS_BYTES = 1024;
|
|
12438
12993
|
async function precompressArtifacts(app) {
|
|
12439
|
-
const roots = [
|
|
12994
|
+
const roots = [path35.join(app.dist.cwdPath, ".akan/artifact/client")];
|
|
12440
12995
|
const result = { files: 0, inputBytes: 0, outputBytes: 0 };
|
|
12441
12996
|
await Promise.all(roots.map((root) => precompressRoot(root, result)));
|
|
12442
12997
|
if (result.files > 0) {
|
|
@@ -12462,7 +13017,7 @@ async function precompressRoot(root, result) {
|
|
|
12462
13017
|
async function shouldPrecompress(filePath) {
|
|
12463
13018
|
if (filePath.endsWith(".gz"))
|
|
12464
13019
|
return false;
|
|
12465
|
-
if (!COMPRESSIBLE_EXTS.has(
|
|
13020
|
+
if (!COMPRESSIBLE_EXTS.has(path35.extname(filePath).toLowerCase()))
|
|
12466
13021
|
return false;
|
|
12467
13022
|
const file = Bun.file(filePath);
|
|
12468
13023
|
if (!await file.exists())
|
|
@@ -12480,7 +13035,7 @@ function formatBytes(bytes) {
|
|
|
12480
13035
|
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
12481
13036
|
}
|
|
12482
13037
|
// pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
|
|
12483
|
-
import
|
|
13038
|
+
import path36 from "path";
|
|
12484
13039
|
import { optimize } from "@tailwindcss/node";
|
|
12485
13040
|
function prepareCssAsset(command, basePath2, cssText) {
|
|
12486
13041
|
return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: command === "build" }).code;
|
|
@@ -12496,7 +13051,7 @@ class SsrBaseArtifactBuilder {
|
|
|
12496
13051
|
this.#app = app;
|
|
12497
13052
|
this.#command = command;
|
|
12498
13053
|
this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
|
|
12499
|
-
this.#absArtifactDir =
|
|
13054
|
+
this.#absArtifactDir = path36.resolve(this.#artifactDir);
|
|
12500
13055
|
}
|
|
12501
13056
|
async build() {
|
|
12502
13057
|
const akanConfig2 = await this.#app.getConfig();
|
|
@@ -12518,7 +13073,7 @@ class SsrBaseArtifactBuilder {
|
|
|
12518
13073
|
rscRuntimeSsrManifest,
|
|
12519
13074
|
vendorMap,
|
|
12520
13075
|
cssAssets,
|
|
12521
|
-
pagesBundlePath: this.#command === "build" ?
|
|
13076
|
+
pagesBundlePath: this.#command === "build" ? path36.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
|
|
12522
13077
|
pagesBundleBuildId: pagesBundle.buildId,
|
|
12523
13078
|
domains: [...akanConfig2.domains],
|
|
12524
13079
|
subRoutes: Object.fromEntries(Array.from(akanConfig2.subRoutes.entries()).map(([basePath2, domains]) => [basePath2, [...domains]])),
|
|
@@ -12534,18 +13089,18 @@ class SsrBaseArtifactBuilder {
|
|
|
12534
13089
|
androidSha256CertFingerprints: target.deepLinks?.android?.sha256CertFingerprints
|
|
12535
13090
|
}))
|
|
12536
13091
|
};
|
|
12537
|
-
await Bun.write(
|
|
13092
|
+
await Bun.write(path36.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
|
|
12538
13093
|
`);
|
|
12539
13094
|
this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
|
|
12540
13095
|
return { artifact, seedIndex, cssCompiler, optimizedFonts };
|
|
12541
13096
|
}
|
|
12542
13097
|
async#buildRuntimeClientEntries() {
|
|
12543
13098
|
const akanServerPath = await this.#resolveAkanServerPath();
|
|
12544
|
-
const rscClientEntry =
|
|
12545
|
-
const rscSegmentOutletEntry =
|
|
13099
|
+
const rscClientEntry = path36.resolve(akanServerPath, "rscClient.tsx");
|
|
13100
|
+
const rscSegmentOutletEntry = path36.resolve(akanServerPath, "rscSegmentOutlet.tsx");
|
|
12546
13101
|
const vendorEntries = VENDOR_SPECIFIERS.map((specifier) => ({
|
|
12547
13102
|
specifier,
|
|
12548
|
-
absPath:
|
|
13103
|
+
absPath: path36.resolve(akanServerPath, "vendor", `${specifier.replaceAll("/", "-").replaceAll(".", "-")}.ts`)
|
|
12549
13104
|
}));
|
|
12550
13105
|
const entries = [rscClientEntry, rscSegmentOutletEntry, ...vendorEntries.map((v) => v.absPath)];
|
|
12551
13106
|
const clientBundle = await new ClientEntriesBundler({ app: this.#app, entries, command: this.#command }).bundle();
|
|
@@ -12582,15 +13137,15 @@ class SsrBaseArtifactBuilder {
|
|
|
12582
13137
|
async#resolveAkanServerPath() {
|
|
12583
13138
|
const candidates = [];
|
|
12584
13139
|
try {
|
|
12585
|
-
candidates.push(
|
|
13140
|
+
candidates.push(path36.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
|
|
12586
13141
|
} catch {}
|
|
12587
|
-
candidates.push(
|
|
13142
|
+
candidates.push(path36.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path36.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
|
|
12588
13143
|
try {
|
|
12589
|
-
candidates.push(
|
|
13144
|
+
candidates.push(path36.dirname(Bun.resolveSync("akanjs/server", path36.dirname(Bun.main))));
|
|
12590
13145
|
} catch {}
|
|
12591
|
-
candidates.push(
|
|
13146
|
+
candidates.push(path36.join(path36.dirname(Bun.main), "node_modules/akanjs/server"), path36.join(path36.dirname(Bun.main), "../../akanjs/server"), path36.resolve(import.meta.dir, "../../server"), path36.resolve(import.meta.dir, "../server"));
|
|
12592
13147
|
for (const candidate of candidates) {
|
|
12593
|
-
if (await Bun.file(
|
|
13148
|
+
if (await Bun.file(path36.join(candidate, "rscClient.tsx")).exists())
|
|
12594
13149
|
return candidate;
|
|
12595
13150
|
}
|
|
12596
13151
|
throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
|
|
@@ -12619,14 +13174,14 @@ ${preparedCssText}`).toString(36);
|
|
|
12619
13174
|
`styles/${cssAssetName}-${cssHash}.css`,
|
|
12620
13175
|
`/_akan/styles/${cssAssetName}-${cssHash}.css`
|
|
12621
13176
|
];
|
|
12622
|
-
await Bun.write(
|
|
13177
|
+
await Bun.write(path36.join(this.#absArtifactDir, cssRelPath), preparedCssText);
|
|
12623
13178
|
this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
|
|
12624
13179
|
return [basePath2, { cssUrl, cssRelPath }];
|
|
12625
13180
|
}
|
|
12626
13181
|
}
|
|
12627
13182
|
// pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
|
|
12628
13183
|
import fs6 from "fs";
|
|
12629
|
-
import
|
|
13184
|
+
import path37 from "path";
|
|
12630
13185
|
|
|
12631
13186
|
class WatchRootResolver {
|
|
12632
13187
|
#app;
|
|
@@ -12636,15 +13191,15 @@ class WatchRootResolver {
|
|
|
12636
13191
|
async resolve() {
|
|
12637
13192
|
const tsconfig = await this.#app.getTsConfig();
|
|
12638
13193
|
const set = new Set;
|
|
12639
|
-
set.add(
|
|
13194
|
+
set.add(path37.resolve(`${this.#app.cwdPath}/page`));
|
|
12640
13195
|
for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
|
|
12641
13196
|
for (const target of targets) {
|
|
12642
13197
|
if (!target)
|
|
12643
13198
|
continue;
|
|
12644
|
-
if (
|
|
13199
|
+
if (path37.isAbsolute(target))
|
|
12645
13200
|
continue;
|
|
12646
13201
|
const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
|
|
12647
|
-
const resolved =
|
|
13202
|
+
const resolved = path37.resolve(this.#app.workspace.workspaceRoot, cleaned);
|
|
12648
13203
|
if (fs6.existsSync(resolved))
|
|
12649
13204
|
set.add(resolved);
|
|
12650
13205
|
}
|
|
@@ -12711,7 +13266,7 @@ class ApplicationBuildRunner {
|
|
|
12711
13266
|
phases: this.#phases,
|
|
12712
13267
|
durationMs: Date.now() - this.#startedAt,
|
|
12713
13268
|
outputDir: this.#app.dist.cwdPath,
|
|
12714
|
-
artifactDir:
|
|
13269
|
+
artifactDir: path38.join(this.#app.dist.cwdPath, ".akan/artifact")
|
|
12715
13270
|
};
|
|
12716
13271
|
}
|
|
12717
13272
|
async typecheck(options = {}) {
|
|
@@ -12719,7 +13274,7 @@ class ApplicationBuildRunner {
|
|
|
12719
13274
|
await this.#app.getPageKeys({ refresh: true });
|
|
12720
13275
|
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
12721
13276
|
if (clean)
|
|
12722
|
-
await rm4(
|
|
13277
|
+
await rm4(path38.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
12723
13278
|
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
12724
13279
|
}
|
|
12725
13280
|
async#runPhase(id, label, task, summarize, options = {}) {
|
|
@@ -12791,7 +13346,7 @@ class ApplicationBuildRunner {
|
|
|
12791
13346
|
};
|
|
12792
13347
|
}
|
|
12793
13348
|
async#writeConsoleShim() {
|
|
12794
|
-
await Bun.write(
|
|
13349
|
+
await Bun.write(path38.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
|
|
12795
13350
|
import { assertAkanConsoleAllowed, startAkanConsole } from "./console-runtime.js";
|
|
12796
13351
|
|
|
12797
13352
|
const run = async () => {
|
|
@@ -12814,14 +13369,14 @@ void run().catch((error) => {
|
|
|
12814
13369
|
try {
|
|
12815
13370
|
return Bun.resolveSync("akanjs/server/rsc-worker", import.meta.dir);
|
|
12816
13371
|
} catch {
|
|
12817
|
-
return
|
|
13372
|
+
return path38.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
|
|
12818
13373
|
}
|
|
12819
13374
|
}
|
|
12820
13375
|
#resolveConsoleRuntimeBuildEntry() {
|
|
12821
13376
|
try {
|
|
12822
|
-
return
|
|
13377
|
+
return path38.join(path38.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
|
|
12823
13378
|
} catch {
|
|
12824
|
-
return
|
|
13379
|
+
return path38.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
|
|
12825
13380
|
}
|
|
12826
13381
|
}
|
|
12827
13382
|
async#buildCsr() {
|
|
@@ -12838,7 +13393,7 @@ void run().catch((error) => {
|
|
|
12838
13393
|
return { base, allRoutes };
|
|
12839
13394
|
}
|
|
12840
13395
|
async#writeTypecheckTsconfig({ incremental = true } = {}) {
|
|
12841
|
-
const typecheckDir =
|
|
13396
|
+
const typecheckDir = path38.join(this.#app.cwdPath, ".akan", "typecheck");
|
|
12842
13397
|
await mkdir8(typecheckDir, { recursive: true });
|
|
12843
13398
|
const tsconfig = {
|
|
12844
13399
|
extends: "../../tsconfig.json",
|
|
@@ -12857,7 +13412,7 @@ void run().catch((error) => {
|
|
|
12857
13412
|
],
|
|
12858
13413
|
references: []
|
|
12859
13414
|
};
|
|
12860
|
-
const tsconfigPath =
|
|
13415
|
+
const tsconfigPath = path38.join(typecheckDir, "tsconfig.json");
|
|
12861
13416
|
await Bun.write(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
12862
13417
|
`);
|
|
12863
13418
|
return { typecheckDir, tsconfigPath };
|
|
@@ -12883,10 +13438,10 @@ void run().catch((error) => {
|
|
|
12883
13438
|
}
|
|
12884
13439
|
async#resolveTypecheckWorkerEntry() {
|
|
12885
13440
|
const candidates = [
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
13441
|
+
path38.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
13442
|
+
path38.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
13443
|
+
path38.join(import.meta.dir, "typecheck.proc.js"),
|
|
13444
|
+
path38.join(import.meta.dir, "typecheck.proc.ts")
|
|
12890
13445
|
];
|
|
12891
13446
|
for (const candidate of candidates)
|
|
12892
13447
|
if (await Bun.file(candidate).exists())
|
|
@@ -12920,7 +13475,7 @@ void run().catch((error) => {
|
|
|
12920
13475
|
}
|
|
12921
13476
|
// pkgs/@akanjs/devkit/applicationReleasePackager.ts
|
|
12922
13477
|
import { cp, mkdir as mkdir9, rm as rm5 } from "fs/promises";
|
|
12923
|
-
import
|
|
13478
|
+
import path39 from "path";
|
|
12924
13479
|
|
|
12925
13480
|
// pkgs/@akanjs/devkit/uploadRelease.ts
|
|
12926
13481
|
import { HttpClient as HttpClient2, Logger as Logger9 } from "akanjs/common";
|
|
@@ -13037,7 +13592,7 @@ class ApplicationReleasePackager {
|
|
|
13037
13592
|
await cp(this.#app.dist.cwdPath, buildRoot, { recursive: true });
|
|
13038
13593
|
await rm5(`${buildRoot}/frontend/.next`, { recursive: true, force: true });
|
|
13039
13594
|
const releaseRoot = this.#app.workspace.workspaceRoot;
|
|
13040
|
-
const releaseArchivePath =
|
|
13595
|
+
const releaseArchivePath = path39.relative(releaseRoot, `${releaseRoot}/releases/builds/${this.#app.name}-release.tar.gz`).split(path39.sep).join("/");
|
|
13041
13596
|
await this.#app.workspace.spawn("tar", ["-zcf", releaseArchivePath, "-C", buildRoot, "./"], { cwd: releaseRoot });
|
|
13042
13597
|
await this.#writeCsrZipIfPresent();
|
|
13043
13598
|
return { platformVersion };
|
|
@@ -13059,17 +13614,17 @@ class ApplicationReleasePackager {
|
|
|
13059
13614
|
await cp(this.#app.dist.cwdPath, `${sourceRoot}/apps/${this.#app.name}`, { recursive: true });
|
|
13060
13615
|
const libDeps = ["social", "shared", "platform", "util"];
|
|
13061
13616
|
await Promise.all(libDeps.map((lib) => cp(`${this.#app.workspace.cwdPath}/libs/${lib}`, `${sourceRoot}/libs/${lib}`, { recursive: true })));
|
|
13062
|
-
await Promise.all([".next", "ios", "android", "public/libs"].map(async (
|
|
13063
|
-
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${
|
|
13617
|
+
await Promise.all([".next", "ios", "android", "public/libs"].map(async (path40) => {
|
|
13618
|
+
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path40}`;
|
|
13064
13619
|
if (await FileSys.dirExists(targetPath))
|
|
13065
13620
|
await rm5(targetPath, { recursive: true, force: true });
|
|
13066
13621
|
}));
|
|
13067
13622
|
const syncPaths = [".husky", ".gitignore", "package.json"];
|
|
13068
|
-
await Promise.all(syncPaths.map((
|
|
13623
|
+
await Promise.all(syncPaths.map((path40) => cp(`${this.#app.workspace.cwdPath}/${path40}`, `${sourceRoot}/${path40}`, { recursive: true })));
|
|
13069
13624
|
await this.#writeSourceTsconfig(sourceRoot, libDeps);
|
|
13070
13625
|
await Bun.write(`${sourceRoot}/README.md`, readme);
|
|
13071
13626
|
const sourceCwd = this.#app.workspace.cwdPath;
|
|
13072
|
-
const sourceArchivePath =
|
|
13627
|
+
const sourceArchivePath = path39.relative(sourceCwd, `${sourceCwd}/releases/sources/${this.#app.name}-source.tar.gz`).split(path39.sep).join("/");
|
|
13073
13628
|
await this.#app.workspace.spawn("tar", ["-zcf", sourceArchivePath, "-C", sourceRoot, "./"], { cwd: sourceCwd });
|
|
13074
13629
|
}
|
|
13075
13630
|
async#resetSourceRoot(sourceRoot) {
|
|
@@ -13152,20 +13707,20 @@ class ApplicationReleasePackager {
|
|
|
13152
13707
|
}
|
|
13153
13708
|
}
|
|
13154
13709
|
// pkgs/@akanjs/devkit/applicationTestPreload.ts
|
|
13155
|
-
import
|
|
13710
|
+
import path40 from "path";
|
|
13156
13711
|
var SIGNAL_TEST_PRELOAD_PATH = "test/signalTest.preload.ts";
|
|
13157
13712
|
async function resolveSignalTestPreloadPath(target) {
|
|
13158
13713
|
const candidates = [];
|
|
13159
13714
|
const addResolvedPackageCandidate = (basePath2) => {
|
|
13160
13715
|
try {
|
|
13161
|
-
candidates.push(
|
|
13716
|
+
candidates.push(path40.join(path40.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
|
|
13162
13717
|
} catch {}
|
|
13163
13718
|
};
|
|
13164
13719
|
addResolvedPackageCandidate(target.cwdPath);
|
|
13165
13720
|
addResolvedPackageCandidate(process.cwd());
|
|
13166
|
-
addResolvedPackageCandidate(
|
|
13721
|
+
addResolvedPackageCandidate(path40.dirname(Bun.main));
|
|
13167
13722
|
addResolvedPackageCandidate(import.meta.dir);
|
|
13168
|
-
candidates.push(
|
|
13723
|
+
candidates.push(path40.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path40.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path40.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path40.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path40.join(path40.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path40.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
|
|
13169
13724
|
const uniqueCandidates = [...new Set(candidates)];
|
|
13170
13725
|
for (const candidate of uniqueCandidates) {
|
|
13171
13726
|
if (await Bun.file(candidate).exists())
|
|
@@ -13179,7 +13734,7 @@ ${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
|
|
|
13179
13734
|
// pkgs/@akanjs/devkit/builder.ts
|
|
13180
13735
|
import { existsSync as existsSync2 } from "fs";
|
|
13181
13736
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
13182
|
-
import
|
|
13737
|
+
import path41 from "path";
|
|
13183
13738
|
var SKIP_ENTRY_DIR_SET = new Set(["node_modules", "dist", "build", ".git", ".next"]);
|
|
13184
13739
|
var assetExtensions = [".css", ".md", ".js", ".png", ".ico", ".svg", ".json", ".template"];
|
|
13185
13740
|
var assetLoader = Object.fromEntries(assetExtensions.map((ext) => [ext, "file"]));
|
|
@@ -13196,14 +13751,14 @@ class Builder {
|
|
|
13196
13751
|
#globEntrypoints(cwd, pattern) {
|
|
13197
13752
|
const glob = new Bun.Glob(pattern);
|
|
13198
13753
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
13199
|
-
const segments = relativePath.split(
|
|
13754
|
+
const segments = relativePath.split(path41.sep);
|
|
13200
13755
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
13201
|
-
}).map((rel) =>
|
|
13756
|
+
}).map((rel) => path41.join(cwd, rel));
|
|
13202
13757
|
}
|
|
13203
13758
|
#globFiles(cwd, pattern = "**/*.*") {
|
|
13204
13759
|
const glob = new Bun.Glob(pattern);
|
|
13205
13760
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
13206
|
-
const segments = relativePath.split(
|
|
13761
|
+
const segments = relativePath.split(path41.sep);
|
|
13207
13762
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
13208
13763
|
});
|
|
13209
13764
|
}
|
|
@@ -13211,17 +13766,17 @@ class Builder {
|
|
|
13211
13766
|
const out = [];
|
|
13212
13767
|
for (const p of additionalEntryPoints) {
|
|
13213
13768
|
if (p.includes("*")) {
|
|
13214
|
-
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${
|
|
13769
|
+
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path41.sep}`) ? p.slice(cwd.length + 1) : p;
|
|
13215
13770
|
out.push(...this.#globEntrypoints(cwd, rel));
|
|
13216
13771
|
} else
|
|
13217
|
-
out.push(
|
|
13772
|
+
out.push(path41.isAbsolute(p) ? p : path41.join(cwd, p));
|
|
13218
13773
|
}
|
|
13219
13774
|
return out;
|
|
13220
13775
|
}
|
|
13221
13776
|
#getBuildOptions({ bundle = false, additionalEntryPoints = [] } = {}) {
|
|
13222
13777
|
const cwd = this.#executor.cwdPath;
|
|
13223
13778
|
const entrypoints = [
|
|
13224
|
-
...bundle ? [
|
|
13779
|
+
...bundle ? [path41.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
|
|
13225
13780
|
...this.#resolveAdditionalEntrypoints(cwd, additionalEntryPoints)
|
|
13226
13781
|
];
|
|
13227
13782
|
return {
|
|
@@ -13242,9 +13797,9 @@ class Builder {
|
|
|
13242
13797
|
for (const relativePath of this.#globFiles(cwd)) {
|
|
13243
13798
|
if (relativePath === "package.json")
|
|
13244
13799
|
continue;
|
|
13245
|
-
const sourcePath =
|
|
13246
|
-
const targetPath =
|
|
13247
|
-
await mkdir10(
|
|
13800
|
+
const sourcePath = path41.join(cwd, relativePath);
|
|
13801
|
+
const targetPath = path41.join(this.#distExecutor.cwdPath, relativePath);
|
|
13802
|
+
await mkdir10(path41.dirname(targetPath), { recursive: true });
|
|
13248
13803
|
await Bun.write(targetPath, Bun.file(sourcePath));
|
|
13249
13804
|
}
|
|
13250
13805
|
}
|
|
@@ -13255,13 +13810,13 @@ class Builder {
|
|
|
13255
13810
|
return withoutFormatDir;
|
|
13256
13811
|
if (!hasDotSlash && withoutFormatDir === publishedPath)
|
|
13257
13812
|
return publishedPath;
|
|
13258
|
-
const parsed =
|
|
13813
|
+
const parsed = path41.posix.parse(withoutFormatDir);
|
|
13259
13814
|
if (![".js", ".mjs", ".cjs"].includes(parsed.ext))
|
|
13260
13815
|
return withoutFormatDir;
|
|
13261
|
-
const withoutExt =
|
|
13816
|
+
const withoutExt = path41.posix.join(parsed.dir, parsed.name);
|
|
13262
13817
|
const sourcePath = withoutExt.startsWith("./") ? withoutExt.slice(2) : withoutExt;
|
|
13263
13818
|
const sourceCandidates = [`${sourcePath}.ts`, `${sourcePath}.tsx`];
|
|
13264
|
-
const matchedSource = sourceCandidates.find((candidate) => existsSync2(
|
|
13819
|
+
const matchedSource = sourceCandidates.find((candidate) => existsSync2(path41.join(this.#executor.cwdPath, candidate)));
|
|
13265
13820
|
if (!matchedSource)
|
|
13266
13821
|
return withoutFormatDir;
|
|
13267
13822
|
return hasDotSlash ? `./${matchedSource}` : matchedSource;
|
|
@@ -13310,9 +13865,9 @@ class Builder {
|
|
|
13310
13865
|
}
|
|
13311
13866
|
}
|
|
13312
13867
|
// pkgs/@akanjs/devkit/capacitorApp.ts
|
|
13313
|
-
import { cp as cp2, mkdir as mkdir11, readFile as
|
|
13868
|
+
import { cp as cp2, mkdir as mkdir11, readFile as readFile3, rm as rm6, writeFile as writeFile3 } from "fs/promises";
|
|
13314
13869
|
import os from "os";
|
|
13315
|
-
import
|
|
13870
|
+
import path42 from "path";
|
|
13316
13871
|
import { select as select2 } from "@inquirer/prompts";
|
|
13317
13872
|
import { MobileProject } from "@trapezedev/project";
|
|
13318
13873
|
import { capitalize as capitalize5 } from "akanjs/common";
|
|
@@ -13519,13 +14074,13 @@ var rootCapacitorConfigFilenames = [
|
|
|
13519
14074
|
"capacitor.config.js",
|
|
13520
14075
|
"capacitor.config.json"
|
|
13521
14076
|
];
|
|
13522
|
-
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) =>
|
|
14077
|
+
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path42.join(appRoot, file));
|
|
13523
14078
|
async function clearRootCapacitorConfigs(appRoot) {
|
|
13524
14079
|
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) => rm6(file, { force: true })));
|
|
13525
14080
|
}
|
|
13526
14081
|
async function writeRootCapacitorConfig(appRoot, content) {
|
|
13527
14082
|
await clearRootCapacitorConfigs(appRoot);
|
|
13528
|
-
await Bun.write(
|
|
14083
|
+
await Bun.write(path42.join(appRoot, "capacitor.config.json"), content);
|
|
13529
14084
|
}
|
|
13530
14085
|
var getLocalIP = () => {
|
|
13531
14086
|
const interfaces = os.networkInterfaces();
|
|
@@ -13634,13 +14189,13 @@ function buildIosNativeRunCommand({
|
|
|
13634
14189
|
scheme = "App",
|
|
13635
14190
|
configuration = "Debug"
|
|
13636
14191
|
}) {
|
|
13637
|
-
const derivedDataPath =
|
|
14192
|
+
const derivedDataPath = path42.join(appRoot, "ios/DerivedData", device.id);
|
|
13638
14193
|
const productPlatform = device.kind === "device" ? "iphoneos" : "iphonesimulator";
|
|
13639
14194
|
const destination = device.kind === "device" ? `id=${device.xcodebuildId ?? device.id}` : `platform=iOS Simulator,id=${device.id}`;
|
|
13640
14195
|
return {
|
|
13641
14196
|
configuration,
|
|
13642
14197
|
derivedDataPath,
|
|
13643
|
-
appPath:
|
|
14198
|
+
appPath: path42.join(derivedDataPath, "Build/Products", `${configuration}-${productPlatform}`, "App.app"),
|
|
13644
14199
|
xcodebuildArgs: [
|
|
13645
14200
|
"-project",
|
|
13646
14201
|
"App.xcodeproj",
|
|
@@ -13853,7 +14408,7 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
13853
14408
|
...capacitorConfig,
|
|
13854
14409
|
appId,
|
|
13855
14410
|
appName,
|
|
13856
|
-
webDir:
|
|
14411
|
+
webDir: path42.posix.join(".akan", "mobile", name, "www"),
|
|
13857
14412
|
plugins: {
|
|
13858
14413
|
CapacitorCookies: { enabled: true },
|
|
13859
14414
|
...pluginsConfig,
|
|
@@ -13917,10 +14472,10 @@ class CapacitorApp {
|
|
|
13917
14472
|
constructor(app, target) {
|
|
13918
14473
|
this.app = app;
|
|
13919
14474
|
this.target = target;
|
|
13920
|
-
this.targetRootPath =
|
|
13921
|
-
this.targetRoot =
|
|
13922
|
-
this.targetWebRoot =
|
|
13923
|
-
this.targetAssetRoot =
|
|
14475
|
+
this.targetRootPath = path42.posix.join(".akan", "mobile", this.target.name);
|
|
14476
|
+
this.targetRoot = path42.join(this.app.cwdPath, this.targetRootPath);
|
|
14477
|
+
this.targetWebRoot = path42.join(this.targetRoot, "www");
|
|
14478
|
+
this.targetAssetRoot = path42.join(this.targetRoot, "assets");
|
|
13924
14479
|
this.project = new MobileProject(this.app.cwdPath, {
|
|
13925
14480
|
android: { path: this.androidRootPath },
|
|
13926
14481
|
ios: { path: this.iosProjectPath }
|
|
@@ -13935,9 +14490,9 @@ class CapacitorApp {
|
|
|
13935
14490
|
await mkdir11(this.targetRoot, { recursive: true });
|
|
13936
14491
|
if (regenerate) {
|
|
13937
14492
|
if (!platform || platform === "ios")
|
|
13938
|
-
await rm6(
|
|
14493
|
+
await rm6(path42.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
|
|
13939
14494
|
if (!platform || platform === "android")
|
|
13940
|
-
await rm6(
|
|
14495
|
+
await rm6(path42.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
|
|
13941
14496
|
}
|
|
13942
14497
|
const project = this.project;
|
|
13943
14498
|
await this.project.load();
|
|
@@ -14061,7 +14616,7 @@ ${textError instanceof Error ? textError.message : ""}`);
|
|
|
14061
14616
|
const xcodebuildArgs = noAllowProvisioningUpdates ? command.xcodebuildArgs : [...command.xcodebuildArgs.slice(0, -1), "-allowProvisioningUpdates", ...command.xcodebuildArgs.slice(-1)];
|
|
14062
14617
|
try {
|
|
14063
14618
|
await this.#spawn("xcodebuild", xcodebuildArgs, {
|
|
14064
|
-
cwd:
|
|
14619
|
+
cwd: path42.join(this.app.cwdPath, this.iosProjectPath),
|
|
14065
14620
|
env: mobileEnv
|
|
14066
14621
|
});
|
|
14067
14622
|
const devicectlId = runTarget.devicectlId ?? runTarget.id;
|
|
@@ -14086,7 +14641,7 @@ ${textError instanceof Error ? textError.message : ""}`);
|
|
|
14086
14641
|
return isRecord2(this.target.ios) && typeof this.target.ios.scheme === "string" ? this.target.ios.scheme : "App";
|
|
14087
14642
|
}
|
|
14088
14643
|
async#getIosDevelopmentTeam() {
|
|
14089
|
-
const pbxprojPath =
|
|
14644
|
+
const pbxprojPath = path42.join(this.app.cwdPath, this.iosProjectPath, "App.xcodeproj/project.pbxproj");
|
|
14090
14645
|
if (!await Bun.file(pbxprojPath).exists())
|
|
14091
14646
|
return;
|
|
14092
14647
|
return (await Bun.file(pbxprojPath).text()).match(/DEVELOPMENT_TEAM = ([^;]+);/)?.[1]?.trim();
|
|
@@ -14113,7 +14668,7 @@ ${error.message}`;
|
|
|
14113
14668
|
await this.#setDeepLinksInAndroid(this.target.deepLinks?.schemes ?? [], this.target.deepLinks?.domains ?? []);
|
|
14114
14669
|
}
|
|
14115
14670
|
async#updateAndroidBuildTypes() {
|
|
14116
|
-
const appGradle = await FileEditor.create(
|
|
14671
|
+
const appGradle = await FileEditor.create(path42.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
|
|
14117
14672
|
const buildTypesBlock = `
|
|
14118
14673
|
debug {
|
|
14119
14674
|
applicationIdSuffix ".debug"
|
|
@@ -14157,7 +14712,7 @@ ${error.message}`;
|
|
|
14157
14712
|
const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
|
|
14158
14713
|
await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
|
|
14159
14714
|
stdio: "inherit",
|
|
14160
|
-
cwd:
|
|
14715
|
+
cwd: path42.join(this.app.cwdPath, this.androidRootPath),
|
|
14161
14716
|
env: await this.#commandEnv("release", env)
|
|
14162
14717
|
});
|
|
14163
14718
|
}
|
|
@@ -14165,10 +14720,10 @@ ${error.message}`;
|
|
|
14165
14720
|
await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
|
|
14166
14721
|
}
|
|
14167
14722
|
async#ensureAndroidAssetsDir() {
|
|
14168
|
-
await mkdir11(
|
|
14723
|
+
await mkdir11(path42.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
|
|
14169
14724
|
}
|
|
14170
14725
|
async#ensureAndroidDebugKeystore() {
|
|
14171
|
-
const keystorePath =
|
|
14726
|
+
const keystorePath = path42.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
|
|
14172
14727
|
if (await Bun.file(keystorePath).exists())
|
|
14173
14728
|
return;
|
|
14174
14729
|
await this.#spawn("keytool", [
|
|
@@ -14207,7 +14762,7 @@ ${error.message}`;
|
|
|
14207
14762
|
await this.#spawnMobile("npx", args, { operation, env }, { stdio: "inherit" });
|
|
14208
14763
|
}
|
|
14209
14764
|
async#assertAndroidReleaseSigningConfig() {
|
|
14210
|
-
const gradlePropertiesPath =
|
|
14765
|
+
const gradlePropertiesPath = path42.join(this.app.cwdPath, this.androidRootPath, "gradle.properties");
|
|
14211
14766
|
const gradleProperties = await Bun.file(gradlePropertiesPath).exists() ? await Bun.file(gradlePropertiesPath).text() : "";
|
|
14212
14767
|
const missingKeys = getMissingAndroidReleaseSigningKeys({ gradleProperties });
|
|
14213
14768
|
if (missingKeys.length > 0)
|
|
@@ -14234,12 +14789,12 @@ ${error.message}`;
|
|
|
14234
14789
|
await this.#prepareAndroid({ operation: "release", env: "main" });
|
|
14235
14790
|
}
|
|
14236
14791
|
async prepareWww() {
|
|
14237
|
-
const htmlSource =
|
|
14792
|
+
const htmlSource = path42.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
|
|
14238
14793
|
if (!await Bun.file(htmlSource).exists())
|
|
14239
14794
|
throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
|
|
14240
14795
|
await rm6(this.targetWebRoot, { recursive: true, force: true });
|
|
14241
14796
|
await mkdir11(this.targetWebRoot, { recursive: true });
|
|
14242
|
-
await Bun.write(
|
|
14797
|
+
await Bun.write(path42.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
|
|
14243
14798
|
}
|
|
14244
14799
|
#injectMobileTargetMeta(html) {
|
|
14245
14800
|
const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
|
|
@@ -14263,7 +14818,7 @@ ${error.message}`;
|
|
|
14263
14818
|
});
|
|
14264
14819
|
const content = `${JSON.stringify(config, null, 2)}
|
|
14265
14820
|
`;
|
|
14266
|
-
await Bun.write(
|
|
14821
|
+
await Bun.write(path42.join(this.targetRoot, "capacitor.config.json"), content);
|
|
14267
14822
|
return content;
|
|
14268
14823
|
}
|
|
14269
14824
|
async#prepareTargetAssets() {
|
|
@@ -14271,11 +14826,11 @@ ${error.message}`;
|
|
|
14271
14826
|
return;
|
|
14272
14827
|
await mkdir11(this.targetAssetRoot, { recursive: true });
|
|
14273
14828
|
if (this.target.assets.icon)
|
|
14274
|
-
await cp2(
|
|
14829
|
+
await cp2(path42.join(this.app.cwdPath, this.target.assets.icon), path42.join(this.targetAssetRoot, "icon.png"), {
|
|
14275
14830
|
force: true
|
|
14276
14831
|
});
|
|
14277
14832
|
if (this.target.assets.splash)
|
|
14278
|
-
await cp2(
|
|
14833
|
+
await cp2(path42.join(this.app.cwdPath, this.target.assets.splash), path42.join(this.targetAssetRoot, "splash.png"), {
|
|
14279
14834
|
force: true
|
|
14280
14835
|
});
|
|
14281
14836
|
}
|
|
@@ -14283,11 +14838,11 @@ ${error.message}`;
|
|
|
14283
14838
|
const files = this.target.files?.[platform];
|
|
14284
14839
|
if (!files)
|
|
14285
14840
|
return;
|
|
14286
|
-
const platformRoot =
|
|
14841
|
+
const platformRoot = path42.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
|
|
14287
14842
|
await Promise.all(Object.entries(files).map(async ([to, from]) => {
|
|
14288
|
-
const targetPath =
|
|
14289
|
-
await mkdir11(
|
|
14290
|
-
await cp2(
|
|
14843
|
+
const targetPath = path42.join(platformRoot, to);
|
|
14844
|
+
await mkdir11(path42.dirname(targetPath), { recursive: true });
|
|
14845
|
+
await cp2(path42.join(this.app.cwdPath, from), targetPath, { force: true });
|
|
14291
14846
|
}));
|
|
14292
14847
|
}
|
|
14293
14848
|
async#generateAssets({ operation, env }) {
|
|
@@ -14297,7 +14852,7 @@ ${error.message}`;
|
|
|
14297
14852
|
"@capacitor/assets",
|
|
14298
14853
|
"generate",
|
|
14299
14854
|
"--assetPath",
|
|
14300
|
-
|
|
14855
|
+
path42.posix.join(this.targetRootPath, "assets"),
|
|
14301
14856
|
"--iosProject",
|
|
14302
14857
|
this.iosProjectPath,
|
|
14303
14858
|
"--androidProject",
|
|
@@ -14331,13 +14886,18 @@ ${error.message}`;
|
|
|
14331
14886
|
}
|
|
14332
14887
|
for (const permission of this.target.permissions ?? []) {
|
|
14333
14888
|
const claimants = nativePlugins.get(permission);
|
|
14334
|
-
if (
|
|
14335
|
-
|
|
14889
|
+
if (claimants?.length) {
|
|
14890
|
+
const ctx = this.#makeNativeContext({ operation, env });
|
|
14891
|
+
for (const plugin of claimants)
|
|
14892
|
+
await plugin.capacitor?.configureNative?.(ctx);
|
|
14336
14893
|
continue;
|
|
14337
14894
|
}
|
|
14338
|
-
|
|
14339
|
-
|
|
14340
|
-
|
|
14895
|
+
if (permission === "camera")
|
|
14896
|
+
await this.addCamera();
|
|
14897
|
+
else if (permission === "contacts")
|
|
14898
|
+
await this.addContact();
|
|
14899
|
+
else if (permission === "location")
|
|
14900
|
+
await this.addLocation();
|
|
14341
14901
|
}
|
|
14342
14902
|
}
|
|
14343
14903
|
#makeNativeContext({ operation, env }) {
|
|
@@ -14454,11 +15014,33 @@ ${error.message}`;
|
|
|
14454
15014
|
await this.#clearRootCapacitorConfigs();
|
|
14455
15015
|
}
|
|
14456
15016
|
}
|
|
15017
|
+
async addCamera() {
|
|
15018
|
+
await this.#setPermissionInIos({
|
|
15019
|
+
cameraUsageDescription: "$(PRODUCT_NAME) requires access to the camera to take photos.",
|
|
15020
|
+
photoAddUsageDescription: "$(PRODUCT_NAME) requires access to the photo library to take photos.",
|
|
15021
|
+
photoUsageDescription: "$(PRODUCT_NAME) requires access to the photo library to take photos."
|
|
15022
|
+
});
|
|
15023
|
+
this.#setPermissionsInAndroid(["READ_MEDIA_IMAGES", "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"]);
|
|
15024
|
+
}
|
|
15025
|
+
async addContact() {
|
|
15026
|
+
await this.#setPermissionInIos({
|
|
15027
|
+
contactsUsageDescription: "$(PRODUCT_NAME) requires access to the contacts to add new contacts."
|
|
15028
|
+
});
|
|
15029
|
+
this.#setPermissionsInAndroid(["READ_CONTACTS", "WRITE_CONTACTS"]);
|
|
15030
|
+
}
|
|
15031
|
+
async addLocation() {
|
|
15032
|
+
await this.#setPermissionInIos({
|
|
15033
|
+
locationAlwaysUsageDescription: "$(PRODUCT_NAME) requires access to the location to get the user's location.",
|
|
15034
|
+
locationWhenInUseUsageDescription: "$(PRODUCT_NAME) requires access to the location to get the user's location."
|
|
15035
|
+
});
|
|
15036
|
+
this.#setPermissionsInAndroid(["ACCESS_COARSE_LOCATION", "ACCESS_FINE_LOCATION"]);
|
|
15037
|
+
this.#setFeaturesInAndroid(["android.hardware.location.gps"]);
|
|
15038
|
+
}
|
|
14457
15039
|
#addIosEntitlements(entitlements) {
|
|
14458
15040
|
Object.assign(this.#iosEntitlements, entitlements);
|
|
14459
15041
|
}
|
|
14460
15042
|
async#editIosAppDelegate(transform) {
|
|
14461
|
-
const appDelegatePath =
|
|
15043
|
+
const appDelegatePath = path42.join(this.app.cwdPath, this.iosProjectPath, "App/AppDelegate.swift");
|
|
14462
15044
|
if (!await Bun.file(appDelegatePath).exists())
|
|
14463
15045
|
return;
|
|
14464
15046
|
const editor = await FileEditor.create(appDelegatePath);
|
|
@@ -14500,7 +15082,7 @@ ${error.message}`;
|
|
|
14500
15082
|
if (Object.keys(this.#iosEntitlements).length === 0)
|
|
14501
15083
|
return;
|
|
14502
15084
|
const entitlementsRelPath = "App/App.entitlements";
|
|
14503
|
-
const entitlementsPath =
|
|
15085
|
+
const entitlementsPath = path42.join(this.app.cwdPath, this.iosProjectPath, entitlementsRelPath);
|
|
14504
15086
|
const body = [
|
|
14505
15087
|
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
14506
15088
|
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
@@ -14514,12 +15096,12 @@ ${error.message}`;
|
|
|
14514
15096
|
`);
|
|
14515
15097
|
const currentBody = await Bun.file(entitlementsPath).exists() ? await Bun.file(entitlementsPath).text() : undefined;
|
|
14516
15098
|
if (currentBody !== body)
|
|
14517
|
-
await
|
|
15099
|
+
await writeFile3(entitlementsPath, body);
|
|
14518
15100
|
await this.#setCodeSignEntitlementsInIos(entitlementsRelPath);
|
|
14519
15101
|
}
|
|
14520
15102
|
async#setCodeSignEntitlementsInIos(entitlementsRelPath) {
|
|
14521
|
-
const pbxprojPath =
|
|
14522
|
-
const lines = (await
|
|
15103
|
+
const pbxprojPath = path42.join(this.app.cwdPath, this.iosProjectPath, "App.xcodeproj/project.pbxproj");
|
|
15104
|
+
const lines = (await readFile3(pbxprojPath, "utf8")).split(`
|
|
14523
15105
|
`);
|
|
14524
15106
|
let changed = false;
|
|
14525
15107
|
for (let index = 0;index < lines.length; index++) {
|
|
@@ -14541,12 +15123,12 @@ ${error.message}`;
|
|
|
14541
15123
|
changed = true;
|
|
14542
15124
|
}
|
|
14543
15125
|
if (changed)
|
|
14544
|
-
await
|
|
15126
|
+
await writeFile3(pbxprojPath, lines.join(`
|
|
14545
15127
|
`));
|
|
14546
15128
|
}
|
|
14547
15129
|
async#setUrlSchemesInAndroid(schemes) {
|
|
14548
|
-
const manifestPath =
|
|
14549
|
-
let manifest = await
|
|
15130
|
+
const manifestPath = path42.join(this.app.cwdPath, this.androidRootPath, "app/src/main/AndroidManifest.xml");
|
|
15131
|
+
let manifest = await readFile3(manifestPath, "utf8");
|
|
14550
15132
|
let changed = false;
|
|
14551
15133
|
for (const scheme of schemes) {
|
|
14552
15134
|
if (manifest.includes(`android:scheme="${scheme}"`))
|
|
@@ -14565,12 +15147,12 @@ ${filter}$1`);
|
|
|
14565
15147
|
changed = true;
|
|
14566
15148
|
}
|
|
14567
15149
|
if (changed)
|
|
14568
|
-
await
|
|
15150
|
+
await writeFile3(manifestPath, manifest);
|
|
14569
15151
|
}
|
|
14570
15152
|
async#setDeepLinksInAndroid(schemes, domains) {
|
|
14571
15153
|
await this.#setUrlSchemesInAndroid(schemes);
|
|
14572
|
-
const manifestPath =
|
|
14573
|
-
let manifest = await
|
|
15154
|
+
const manifestPath = path42.join(this.app.cwdPath, this.androidRootPath, "app/src/main/AndroidManifest.xml");
|
|
15155
|
+
let manifest = await readFile3(manifestPath, "utf8");
|
|
14574
15156
|
let changed = false;
|
|
14575
15157
|
const pathPrefix = resolveMobilePath(this.target, "/");
|
|
14576
15158
|
for (const domain of domains) {
|
|
@@ -14590,7 +15172,7 @@ ${filter}$1`);
|
|
|
14590
15172
|
changed = true;
|
|
14591
15173
|
}
|
|
14592
15174
|
if (changed)
|
|
14593
|
-
await
|
|
15175
|
+
await writeFile3(manifestPath, manifest);
|
|
14594
15176
|
}
|
|
14595
15177
|
#setFeaturesInAndroid(features) {
|
|
14596
15178
|
for (const feature of features) {
|
|
@@ -14671,7 +15253,7 @@ var Pkg = createInternalArgToken("Pkg");
|
|
|
14671
15253
|
var Module = createInternalArgToken("Module");
|
|
14672
15254
|
var Workspace = createInternalArgToken("Workspace");
|
|
14673
15255
|
// pkgs/@akanjs/devkit/commandDecorators/command.ts
|
|
14674
|
-
import
|
|
15256
|
+
import path43 from "path";
|
|
14675
15257
|
import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
|
|
14676
15258
|
import { Logger as Logger10 } from "akanjs/common";
|
|
14677
15259
|
import chalk6 from "chalk";
|
|
@@ -15175,7 +15757,7 @@ var runCommands = async (...commands) => {
|
|
|
15175
15757
|
process.exit(1);
|
|
15176
15758
|
});
|
|
15177
15759
|
const __dirname2 = getDirname(import.meta.url);
|
|
15178
|
-
const packageJsonCandidates = [`${
|
|
15760
|
+
const packageJsonCandidates = [`${path43.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
|
|
15179
15761
|
let cliPackageJson = null;
|
|
15180
15762
|
for (const packageJsonPath of packageJsonCandidates) {
|
|
15181
15763
|
if (!await FileSys.fileExists(packageJsonPath))
|
|
@@ -15422,7 +16004,7 @@ import { capitalize as capitalize7 } from "akanjs/common";
|
|
|
15422
16004
|
// pkgs/@akanjs/devkit/getRelatedCnsts.ts
|
|
15423
16005
|
import { readFileSync as readFileSync4, realpathSync } from "fs";
|
|
15424
16006
|
import ora2 from "ora";
|
|
15425
|
-
import * as
|
|
16007
|
+
import * as ts11 from "typescript";
|
|
15426
16008
|
var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
15427
16009
|
var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
|
|
15428
16010
|
var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
|
|
@@ -15455,10 +16037,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
|
|
|
15455
16037
|
return importSpecifiers;
|
|
15456
16038
|
};
|
|
15457
16039
|
var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
|
|
15458
|
-
const configFile =
|
|
15459
|
-
return
|
|
16040
|
+
const configFile = ts11.readConfigFile(tsConfigPath, (path44) => {
|
|
16041
|
+
return ts11.sys.readFile(path44);
|
|
15460
16042
|
});
|
|
15461
|
-
return
|
|
16043
|
+
return ts11.parseJsonConfigFileContent(configFile.config, ts11.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
|
|
15462
16044
|
};
|
|
15463
16045
|
var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
15464
16046
|
const allFilesToAnalyze = new Set([constantFilePath]);
|
|
@@ -15473,7 +16055,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
15473
16055
|
for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
|
|
15474
16056
|
if (!importPath.startsWith("."))
|
|
15475
16057
|
continue;
|
|
15476
|
-
const resolved =
|
|
16058
|
+
const resolved = ts11.resolveModuleName(importPath, filePath, parsedConfig.options, ts11.sys).resolvedModule?.resolvedFileName;
|
|
15477
16059
|
if (resolved && !allFilesToAnalyze.has(resolved)) {
|
|
15478
16060
|
allFilesToAnalyze.add(resolved);
|
|
15479
16061
|
collectImported(resolved);
|
|
@@ -15490,7 +16072,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
15490
16072
|
var createTsProgram = (filePaths, options) => {
|
|
15491
16073
|
const spinner = ora2("Creating TypeScript program for all files...");
|
|
15492
16074
|
spinner.start();
|
|
15493
|
-
const program2 =
|
|
16075
|
+
const program2 = ts11.createProgram(Array.from(filePaths), options);
|
|
15494
16076
|
const checker = program2.getTypeChecker();
|
|
15495
16077
|
spinner.succeed("TypeScript program created.");
|
|
15496
16078
|
return {
|
|
@@ -15530,17 +16112,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
15530
16112
|
function visit(node) {
|
|
15531
16113
|
if (!source2)
|
|
15532
16114
|
return;
|
|
15533
|
-
if (
|
|
16115
|
+
if (ts11.isPropertyAccessExpression(node)) {
|
|
15534
16116
|
const left = node.expression;
|
|
15535
16117
|
const right = node.name;
|
|
15536
|
-
const { line } =
|
|
15537
|
-
if (
|
|
16118
|
+
const { line } = ts11.getLineAndCharacterOfPosition(source2, node.getStart());
|
|
16119
|
+
if (ts11.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
|
|
15538
16120
|
const symbol = getCachedSymbol(right);
|
|
15539
16121
|
if (symbol?.declarations && symbol.declarations.length > 0) {
|
|
15540
16122
|
const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
|
|
15541
16123
|
const property = propertyMap.get(key);
|
|
15542
16124
|
const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
|
|
15543
|
-
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${
|
|
16125
|
+
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts11.sys.getCurrentDirectory()}/`, "");
|
|
15544
16126
|
if (!symbolFilePath)
|
|
15545
16127
|
throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
|
|
15546
16128
|
if (property) {
|
|
@@ -15564,10 +16146,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
15564
16146
|
}
|
|
15565
16147
|
}
|
|
15566
16148
|
}
|
|
15567
|
-
} else if (
|
|
16149
|
+
} else if (ts11.isImportDeclaration(node) && ts11.isStringLiteral(node.moduleSpecifier)) {
|
|
15568
16150
|
const importPath = node.moduleSpecifier.text;
|
|
15569
16151
|
if (importPath.startsWith(".")) {
|
|
15570
|
-
const resolved =
|
|
16152
|
+
const resolved = ts11.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts11.sys).resolvedModule?.resolvedFileName;
|
|
15571
16153
|
const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
|
|
15572
16154
|
const property = propertyMap.get(moduleName);
|
|
15573
16155
|
const isScalar = importPath.includes("_");
|
|
@@ -15582,7 +16164,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
15582
16164
|
}
|
|
15583
16165
|
}
|
|
15584
16166
|
}
|
|
15585
|
-
|
|
16167
|
+
ts11.forEachChild(node, visit);
|
|
15586
16168
|
}
|
|
15587
16169
|
visit(source2);
|
|
15588
16170
|
}
|
|
@@ -15674,10 +16256,10 @@ ${document}
|
|
|
15674
16256
|
}
|
|
15675
16257
|
// pkgs/@akanjs/devkit/qualityScanner.ts
|
|
15676
16258
|
import { createHash } from "crypto";
|
|
15677
|
-
import { readdir as
|
|
15678
|
-
import
|
|
16259
|
+
import { readdir as readdir4, readFile as readFile4, stat as stat5 } from "fs/promises";
|
|
16260
|
+
import path44 from "path";
|
|
15679
16261
|
import ignore2 from "ignore";
|
|
15680
|
-
import
|
|
16262
|
+
import ts12 from "typescript";
|
|
15681
16263
|
var MAX_FILE_LINES = 2000;
|
|
15682
16264
|
var PLACEHOLDER_EXPORT_NAMES = new Set([
|
|
15683
16265
|
"aa",
|
|
@@ -15789,7 +16371,7 @@ class AkanQualityScanner {
|
|
|
15789
16371
|
const ignoreFilter = ignore2().add(await this.#readGitIgnore(workspaceRoot));
|
|
15790
16372
|
const files = [];
|
|
15791
16373
|
for (const targetRoot of ["apps", "libs"]) {
|
|
15792
|
-
const absoluteTargetRoot =
|
|
16374
|
+
const absoluteTargetRoot = path44.join(workspaceRoot, targetRoot);
|
|
15793
16375
|
if (!await isDirectory(absoluteTargetRoot))
|
|
15794
16376
|
continue;
|
|
15795
16377
|
await this.#walkTargetFiles(workspaceRoot, absoluteTargetRoot, ignoreFilter, files);
|
|
@@ -15797,16 +16379,16 @@ class AkanQualityScanner {
|
|
|
15797
16379
|
return files.sort();
|
|
15798
16380
|
}
|
|
15799
16381
|
async#readGitIgnore(workspaceRoot) {
|
|
15800
|
-
const gitIgnorePath =
|
|
16382
|
+
const gitIgnorePath = path44.join(workspaceRoot, ".gitignore");
|
|
15801
16383
|
if (!await Bun.file(gitIgnorePath).exists())
|
|
15802
16384
|
return [];
|
|
15803
|
-
return (await
|
|
16385
|
+
return (await readFile4(gitIgnorePath, "utf8")).split(/\r?\n/);
|
|
15804
16386
|
}
|
|
15805
16387
|
async#walkTargetFiles(workspaceRoot, currentPath, ignoreFilter, files) {
|
|
15806
|
-
const entries = await
|
|
16388
|
+
const entries = await readdir4(currentPath, { withFileTypes: true });
|
|
15807
16389
|
for (const entry of entries) {
|
|
15808
|
-
const absolutePath =
|
|
15809
|
-
const relativePath = toPosix(
|
|
16390
|
+
const absolutePath = path44.join(currentPath, entry.name);
|
|
16391
|
+
const relativePath = toPosix(path44.relative(workspaceRoot, absolutePath));
|
|
15810
16392
|
if (shouldSkipPath(relativePath, entry.isDirectory(), ignoreFilter))
|
|
15811
16393
|
continue;
|
|
15812
16394
|
if (entry.isDirectory()) {
|
|
@@ -15819,13 +16401,13 @@ class AkanQualityScanner {
|
|
|
15819
16401
|
}
|
|
15820
16402
|
}
|
|
15821
16403
|
async#readSourceFile(workspaceRoot, file) {
|
|
15822
|
-
const absolutePath =
|
|
15823
|
-
const content = await
|
|
16404
|
+
const absolutePath = path44.join(workspaceRoot, file);
|
|
16405
|
+
const content = await readFile4(absolutePath, "utf8");
|
|
15824
16406
|
return {
|
|
15825
16407
|
file,
|
|
15826
16408
|
absolutePath,
|
|
15827
16409
|
content,
|
|
15828
|
-
sourceFile:
|
|
16410
|
+
sourceFile: ts12.createSourceFile(file, content, ts12.ScriptTarget.Latest, true, getScriptKind(file))
|
|
15829
16411
|
};
|
|
15830
16412
|
}
|
|
15831
16413
|
#scanGlobalQuality(sourceFiles) {
|
|
@@ -15950,7 +16532,7 @@ class AkanQualityScanner {
|
|
|
15950
16532
|
const suffix = CONVENTION_SUFFIXES.find((candidate) => sourceFile2.file.endsWith(candidate));
|
|
15951
16533
|
if (!suffix)
|
|
15952
16534
|
return [];
|
|
15953
|
-
const modelName = toPascalCase(
|
|
16535
|
+
const modelName = toPascalCase(path44.basename(sourceFile2.file, suffix));
|
|
15954
16536
|
const warnings = [];
|
|
15955
16537
|
for (const declaration of getTopLevelDeclarations(sourceFile2)) {
|
|
15956
16538
|
if (isAllowedConventionDeclaration(suffix, modelName, declaration))
|
|
@@ -15961,7 +16543,7 @@ class AkanQualityScanner {
|
|
|
15961
16543
|
severity: "warning",
|
|
15962
16544
|
file: sourceFile2.file,
|
|
15963
16545
|
line: declaration.line,
|
|
15964
|
-
message: `${
|
|
16546
|
+
message: `${path44.basename(sourceFile2.file)} should not declare top-level ${declaration.kind} "${declaration.name}". Allowed declarations: ${getConventionDescription(suffix, modelName)}.`
|
|
15965
16547
|
});
|
|
15966
16548
|
}
|
|
15967
16549
|
return warnings;
|
|
@@ -16033,7 +16615,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
16033
16615
|
const declarations = [];
|
|
16034
16616
|
const nameExempt = isPageRouteFile(sourceFile2.file) || isUiComponentFile(sourceFile2.file);
|
|
16035
16617
|
for (const statement of sourceFile2.sourceFile.statements) {
|
|
16036
|
-
if (
|
|
16618
|
+
if (ts12.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
|
|
16037
16619
|
declarations.push({
|
|
16038
16620
|
name: statement.name.text,
|
|
16039
16621
|
kind: "function",
|
|
@@ -16043,7 +16625,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
16043
16625
|
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, false)
|
|
16044
16626
|
});
|
|
16045
16627
|
}
|
|
16046
|
-
if (
|
|
16628
|
+
if (ts12.isClassDeclaration(statement) && statement.name && isExported(statement)) {
|
|
16047
16629
|
declarations.push({
|
|
16048
16630
|
name: statement.name.text,
|
|
16049
16631
|
kind: "class",
|
|
@@ -16053,9 +16635,9 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
16053
16635
|
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, isEnumClassStatement(sourceFile2.sourceFile, statement))
|
|
16054
16636
|
});
|
|
16055
16637
|
}
|
|
16056
|
-
if (
|
|
16638
|
+
if (ts12.isVariableStatement(statement) && isExported(statement)) {
|
|
16057
16639
|
for (const declaration of statement.declarationList.declarations) {
|
|
16058
|
-
if (!
|
|
16640
|
+
if (!ts12.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
|
|
16059
16641
|
continue;
|
|
16060
16642
|
declarations.push({
|
|
16061
16643
|
name: declaration.name.text,
|
|
@@ -16094,14 +16676,14 @@ function isInLibModule(file) {
|
|
|
16094
16676
|
return (segments[0] === "apps" || segments[0] === "libs") && segments.includes("lib");
|
|
16095
16677
|
}
|
|
16096
16678
|
function isEnumClassStatement(sourceFile2, statement) {
|
|
16097
|
-
if (!
|
|
16679
|
+
if (!ts12.isClassDeclaration(statement))
|
|
16098
16680
|
return false;
|
|
16099
|
-
const heritageClause = statement.heritageClauses?.find((clause) => clause.token ===
|
|
16681
|
+
const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts12.SyntaxKind.ExtendsKeyword);
|
|
16100
16682
|
const expression = heritageClause?.types[0]?.expression;
|
|
16101
16683
|
return !!expression && expression.getText(sourceFile2).startsWith("enumOf(");
|
|
16102
16684
|
}
|
|
16103
16685
|
function getExportedClassNames(sourceFile2) {
|
|
16104
|
-
return sourceFile2.statements.filter((statement) =>
|
|
16686
|
+
return sourceFile2.statements.filter((statement) => ts12.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
|
|
16105
16687
|
}
|
|
16106
16688
|
function isComponentDeclarationFile(file) {
|
|
16107
16689
|
if (!file.endsWith(".tsx"))
|
|
@@ -16117,7 +16699,7 @@ function isComponentDeclarationFile(file) {
|
|
|
16117
16699
|
function getComponentFileDeclarations(sourceFile2) {
|
|
16118
16700
|
const reExportedNames = new Set;
|
|
16119
16701
|
for (const statement of sourceFile2.statements) {
|
|
16120
|
-
if (
|
|
16702
|
+
if (ts12.isExportDeclaration(statement) && statement.exportClause && ts12.isNamedExports(statement.exportClause)) {
|
|
16121
16703
|
for (const element of statement.exportClause.elements)
|
|
16122
16704
|
reExportedNames.add((element.propertyName ?? element.name).text);
|
|
16123
16705
|
}
|
|
@@ -16127,19 +16709,19 @@ function getComponentFileDeclarations(sourceFile2) {
|
|
|
16127
16709
|
const isDefaultExport = isDefaultExportStatement(statement);
|
|
16128
16710
|
const inlineExported = isExported(statement);
|
|
16129
16711
|
const add = (name, kind, line) => declarations.push({ name, kind, line, exported: inlineExported || reExportedNames.has(name), isDefaultExport });
|
|
16130
|
-
if (
|
|
16712
|
+
if (ts12.isInterfaceDeclaration(statement))
|
|
16131
16713
|
add(statement.name.text, "interface", getLine(sourceFile2, statement));
|
|
16132
|
-
else if (
|
|
16714
|
+
else if (ts12.isTypeAliasDeclaration(statement))
|
|
16133
16715
|
add(statement.name.text, "type", getLine(sourceFile2, statement));
|
|
16134
|
-
else if (
|
|
16716
|
+
else if (ts12.isEnumDeclaration(statement))
|
|
16135
16717
|
add(statement.name.text, "enum", getLine(sourceFile2, statement));
|
|
16136
|
-
else if (
|
|
16718
|
+
else if (ts12.isFunctionDeclaration(statement) && statement.name)
|
|
16137
16719
|
add(statement.name.text, "function", getLine(sourceFile2, statement));
|
|
16138
|
-
else if (
|
|
16720
|
+
else if (ts12.isClassDeclaration(statement) && statement.name)
|
|
16139
16721
|
add(statement.name.text, "class", getLine(sourceFile2, statement));
|
|
16140
|
-
else if (
|
|
16722
|
+
else if (ts12.isVariableStatement(statement)) {
|
|
16141
16723
|
for (const declaration of statement.declarationList.declarations) {
|
|
16142
|
-
if (!
|
|
16724
|
+
if (!ts12.isIdentifier(declaration.name))
|
|
16143
16725
|
continue;
|
|
16144
16726
|
const kind = isFunctionLikeInitializer(declaration.initializer) ? "function" : "variable";
|
|
16145
16727
|
add(declaration.name.text, kind, getLine(sourceFile2, declaration));
|
|
@@ -16151,15 +16733,15 @@ function getComponentFileDeclarations(sourceFile2) {
|
|
|
16151
16733
|
function getCompoundComponentNames(sourceFile2) {
|
|
16152
16734
|
const names = new Set;
|
|
16153
16735
|
for (const statement of sourceFile2.statements) {
|
|
16154
|
-
if (!
|
|
16736
|
+
if (!ts12.isExpressionStatement(statement))
|
|
16155
16737
|
continue;
|
|
16156
16738
|
const { expression } = statement;
|
|
16157
|
-
if (!
|
|
16739
|
+
if (!ts12.isBinaryExpression(expression) || expression.operatorToken.kind !== ts12.SyntaxKind.EqualsToken)
|
|
16158
16740
|
continue;
|
|
16159
|
-
if (!
|
|
16741
|
+
if (!ts12.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
|
|
16160
16742
|
continue;
|
|
16161
16743
|
names.add(expression.left.name.text);
|
|
16162
|
-
if (
|
|
16744
|
+
if (ts12.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
|
|
16163
16745
|
names.add(expression.right.text);
|
|
16164
16746
|
}
|
|
16165
16747
|
return names;
|
|
@@ -16179,9 +16761,9 @@ function isPascalCaseName(name) {
|
|
|
16179
16761
|
return /^[A-Z]/.test(name) && !/^[A-Z0-9_]+$/.test(name);
|
|
16180
16762
|
}
|
|
16181
16763
|
function isDefaultExportStatement(statement) {
|
|
16182
|
-
if (
|
|
16764
|
+
if (ts12.isExportAssignment(statement))
|
|
16183
16765
|
return !statement.isExportEquals;
|
|
16184
|
-
return !!(
|
|
16766
|
+
return !!(ts12.getCombinedModifierFlags(statement) & ts12.ModifierFlags.Default);
|
|
16185
16767
|
}
|
|
16186
16768
|
function getPlaceholderExportWarnings(sourceFile2) {
|
|
16187
16769
|
if (!sourceFile2.file.endsWith("/index.ts") && !sourceFile2.file.endsWith("/index.tsx"))
|
|
@@ -16211,7 +16793,7 @@ function getDictionaryTextWarnings(sourceFile2) {
|
|
|
16211
16793
|
function getGlobalMutationWarnings(sourceFile2) {
|
|
16212
16794
|
const warnings = [];
|
|
16213
16795
|
for (const statement of sourceFile2.sourceFile.statements) {
|
|
16214
|
-
if (
|
|
16796
|
+
if (ts12.isModuleDeclaration(statement) && statement.name.getText(sourceFile2.sourceFile) === "global") {
|
|
16215
16797
|
warnings.push({
|
|
16216
16798
|
rule: "akan.file.global-declaration",
|
|
16217
16799
|
scope: "file",
|
|
@@ -16221,7 +16803,7 @@ function getGlobalMutationWarnings(sourceFile2) {
|
|
|
16221
16803
|
message: "Global declarations require an explicit low-level integration allowlist."
|
|
16222
16804
|
});
|
|
16223
16805
|
}
|
|
16224
|
-
if (
|
|
16806
|
+
if (ts12.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
|
|
16225
16807
|
warnings.push({
|
|
16226
16808
|
rule: "akan.file.window-augmentation",
|
|
16227
16809
|
scope: "file",
|
|
@@ -16231,7 +16813,7 @@ function getGlobalMutationWarnings(sourceFile2) {
|
|
|
16231
16813
|
message: "Window augmentation should be isolated to approved browser integration files."
|
|
16232
16814
|
});
|
|
16233
16815
|
}
|
|
16234
|
-
if (
|
|
16816
|
+
if (ts12.isExpressionStatement(statement) && statement.expression.getText(sourceFile2.sourceFile).includes(".prototype.")) {
|
|
16235
16817
|
warnings.push({
|
|
16236
16818
|
rule: "akan.file.prototype-mutation",
|
|
16237
16819
|
scope: "file",
|
|
@@ -16249,23 +16831,23 @@ function getTopLevelDeclarations(sourceFile2) {
|
|
|
16249
16831
|
}
|
|
16250
16832
|
function getTopLevelDeclaration(sourceFile2, statement) {
|
|
16251
16833
|
const line = getLine(sourceFile2, statement);
|
|
16252
|
-
if (
|
|
16834
|
+
if (ts12.isClassDeclaration(statement) && statement.name) {
|
|
16253
16835
|
return [{ name: statement.name.text, kind: "class", line, exported: isExported(statement), node: statement }];
|
|
16254
16836
|
}
|
|
16255
|
-
if (
|
|
16837
|
+
if (ts12.isFunctionDeclaration(statement) && statement.name) {
|
|
16256
16838
|
return [{ name: statement.name.text, kind: "function", line, exported: isExported(statement), node: statement }];
|
|
16257
16839
|
}
|
|
16258
|
-
if (
|
|
16840
|
+
if (ts12.isInterfaceDeclaration(statement)) {
|
|
16259
16841
|
return [{ name: statement.name.text, kind: "interface", line, exported: isExported(statement), node: statement }];
|
|
16260
16842
|
}
|
|
16261
|
-
if (
|
|
16843
|
+
if (ts12.isTypeAliasDeclaration(statement)) {
|
|
16262
16844
|
return [{ name: statement.name.text, kind: "type", line, exported: isExported(statement), node: statement }];
|
|
16263
16845
|
}
|
|
16264
|
-
if (
|
|
16846
|
+
if (ts12.isEnumDeclaration(statement)) {
|
|
16265
16847
|
return [{ name: statement.name.text, kind: "enum", line, exported: isExported(statement), node: statement }];
|
|
16266
16848
|
}
|
|
16267
|
-
if (
|
|
16268
|
-
return statement.declarationList.declarations.filter((declaration) =>
|
|
16849
|
+
if (ts12.isVariableStatement(statement)) {
|
|
16850
|
+
return statement.declarationList.declarations.filter((declaration) => ts12.isIdentifier(declaration.name)).map((declaration) => ({
|
|
16269
16851
|
name: declaration.name.text,
|
|
16270
16852
|
kind: "variable",
|
|
16271
16853
|
line: getLine(sourceFile2, declaration),
|
|
@@ -16273,7 +16855,7 @@ function getTopLevelDeclaration(sourceFile2, statement) {
|
|
|
16273
16855
|
node: statement
|
|
16274
16856
|
}));
|
|
16275
16857
|
}
|
|
16276
|
-
if (
|
|
16858
|
+
if (ts12.isExportDeclaration(statement)) {
|
|
16277
16859
|
return [{ name: "export declaration", kind: "export", line, exported: true, node: statement }];
|
|
16278
16860
|
}
|
|
16279
16861
|
return [];
|
|
@@ -16298,9 +16880,9 @@ function isAllowedConstantDeclaration(modelName, declaration) {
|
|
|
16298
16880
|
return false;
|
|
16299
16881
|
if ([`${modelName}Input`, `${modelName}Object`, modelName, `Light${modelName}`, `${modelName}Insight`].includes(declaration.name))
|
|
16300
16882
|
return true;
|
|
16301
|
-
if (!
|
|
16883
|
+
if (!ts12.isClassDeclaration(declaration.node))
|
|
16302
16884
|
return false;
|
|
16303
|
-
const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token ===
|
|
16885
|
+
const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts12.SyntaxKind.ExtendsKeyword);
|
|
16304
16886
|
const expression = heritageClause?.types[0]?.expression;
|
|
16305
16887
|
return !!expression && expression.getText().startsWith("enumOf(");
|
|
16306
16888
|
}
|
|
@@ -16366,13 +16948,13 @@ function getModuleInfo(file) {
|
|
|
16366
16948
|
return { moduleName, fileName, kind: "database" };
|
|
16367
16949
|
}
|
|
16368
16950
|
function isExportedConst(declaration) {
|
|
16369
|
-
return declaration.exported &&
|
|
16951
|
+
return declaration.exported && ts12.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts12.NodeFlags.Const) !== 0;
|
|
16370
16952
|
}
|
|
16371
16953
|
function isExported(node) {
|
|
16372
|
-
return !!
|
|
16954
|
+
return !!ts12.getCombinedModifierFlags(node) && !!(ts12.getCombinedModifierFlags(node) & ts12.ModifierFlags.Export);
|
|
16373
16955
|
}
|
|
16374
16956
|
function isFunctionLikeInitializer(node) {
|
|
16375
|
-
return !!node && (
|
|
16957
|
+
return !!node && (ts12.isArrowFunction(node) || ts12.isFunctionExpression(node));
|
|
16376
16958
|
}
|
|
16377
16959
|
function getBodyFingerprint(sourceFile2, node) {
|
|
16378
16960
|
if (!node)
|
|
@@ -16388,13 +16970,13 @@ function shouldSkipPath(relativePath, isDirectory, ignoreFilter) {
|
|
|
16388
16970
|
}
|
|
16389
16971
|
async function isDirectory(absolutePath) {
|
|
16390
16972
|
try {
|
|
16391
|
-
return (await
|
|
16973
|
+
return (await stat5(absolutePath)).isDirectory();
|
|
16392
16974
|
} catch {
|
|
16393
16975
|
return false;
|
|
16394
16976
|
}
|
|
16395
16977
|
}
|
|
16396
16978
|
function getScriptKind(file) {
|
|
16397
|
-
return file.endsWith(".tsx") ?
|
|
16979
|
+
return file.endsWith(".tsx") ? ts12.ScriptKind.TSX : ts12.ScriptKind.TS;
|
|
16398
16980
|
}
|
|
16399
16981
|
function getLine(sourceFile2, node) {
|
|
16400
16982
|
return sourceFile2.getLineAndCharacterOfPosition(node.getStart(sourceFile2)).line + 1;
|
|
@@ -16415,7 +16997,7 @@ function toPascalCase(value) {
|
|
|
16415
16997
|
return value.replace(/(^|[-_./])([a-zA-Z0-9])/g, (_, __, char) => char.toUpperCase()).replace(/[-_./]/g, "");
|
|
16416
16998
|
}
|
|
16417
16999
|
function toPosix(value) {
|
|
16418
|
-
return value.split(
|
|
17000
|
+
return value.split(path44.sep).join("/");
|
|
16419
17001
|
}
|
|
16420
17002
|
function groupBy(items, getKey) {
|
|
16421
17003
|
const grouped = new Map;
|
|
@@ -16464,6 +17046,7 @@ class IncrementalBuilder {
|
|
|
16464
17046
|
#discovery;
|
|
16465
17047
|
#changePlanner;
|
|
16466
17048
|
#generatedIndexSync;
|
|
17049
|
+
#autoImportSync;
|
|
16467
17050
|
#generation = 0;
|
|
16468
17051
|
#workQueue = Promise.resolve();
|
|
16469
17052
|
#cssRebuildQueue = Promise.resolve();
|
|
@@ -16478,6 +17061,7 @@ class IncrementalBuilder {
|
|
|
16478
17061
|
this.#discovery = options.discovery;
|
|
16479
17062
|
this.#changePlanner = new DevChangePlanner({ workspaceRoot: options.app.workspace.workspaceRoot });
|
|
16480
17063
|
this.#generatedIndexSync = new DevGeneratedIndexSync({ workspaceRoot: options.app.workspace.workspaceRoot });
|
|
17064
|
+
this.#autoImportSync = new AutoImportSync({ workspaceRoot: options.app.workspace.workspaceRoot });
|
|
16481
17065
|
}
|
|
16482
17066
|
async handleBuildRoute(msg) {
|
|
16483
17067
|
return this.#enqueueWork(`build-route:${msg.routeId}`, async () => this.#handleBuildRoute(msg));
|
|
@@ -16545,10 +17129,10 @@ class IncrementalBuilder {
|
|
|
16545
17129
|
}
|
|
16546
17130
|
}
|
|
16547
17131
|
batchTouchesPagesTree(appDir, batch) {
|
|
16548
|
-
const absAppDir =
|
|
17132
|
+
const absAppDir = path45.resolve(appDir);
|
|
16549
17133
|
for (const f of batch.files) {
|
|
16550
|
-
const abs =
|
|
16551
|
-
if (!abs.startsWith(`${absAppDir}${
|
|
17134
|
+
const abs = path45.resolve(f);
|
|
17135
|
+
if (!abs.startsWith(`${absAppDir}${path45.sep}`) && abs !== absAppDir)
|
|
16552
17136
|
continue;
|
|
16553
17137
|
if (/\.(tsx|ts|jsx|js)$/.test(abs))
|
|
16554
17138
|
return true;
|
|
@@ -16556,15 +17140,15 @@ class IncrementalBuilder {
|
|
|
16556
17140
|
return false;
|
|
16557
17141
|
}
|
|
16558
17142
|
async batchMayChangePageKeys(appDir, batch) {
|
|
16559
|
-
const absAppDir =
|
|
16560
|
-
const pageKeys = new Set((await this.#app.getPageKeys()).map((key) =>
|
|
17143
|
+
const absAppDir = path45.resolve(appDir);
|
|
17144
|
+
const pageKeys = new Set((await this.#app.getPageKeys()).map((key) => path45.normalize(key)));
|
|
16561
17145
|
for (const f of batch.files) {
|
|
16562
|
-
const abs =
|
|
16563
|
-
if (!abs.startsWith(`${absAppDir}${
|
|
17146
|
+
const abs = path45.resolve(f);
|
|
17147
|
+
if (!abs.startsWith(`${absAppDir}${path45.sep}`) && abs !== absAppDir)
|
|
16564
17148
|
continue;
|
|
16565
17149
|
if (!/\.(tsx|ts|jsx|js)$/.test(abs))
|
|
16566
17150
|
continue;
|
|
16567
|
-
const rel =
|
|
17151
|
+
const rel = path45.normalize(path45.relative(absAppDir, abs));
|
|
16568
17152
|
if (!await Bun.file(abs).exists() || !pageKeys.has(rel))
|
|
16569
17153
|
return true;
|
|
16570
17154
|
}
|
|
@@ -16592,7 +17176,7 @@ class IncrementalBuilder {
|
|
|
16592
17176
|
${cssText}`).toString(36);
|
|
16593
17177
|
const cssRelPath = `styles/${cssAssetName}-${cssHash}.css`;
|
|
16594
17178
|
const cssUrl = `/_akan/styles/${cssAssetName}-${cssHash}.css`;
|
|
16595
|
-
await Bun.write(
|
|
17179
|
+
await Bun.write(path45.join(artifactDir, cssRelPath), cssText);
|
|
16596
17180
|
cssAssetEntries.push([basePath2, { cssUrl, cssRelPath }]);
|
|
16597
17181
|
cssBase64ByUrl[cssUrl] = Buffer.from(new TextEncoder().encode(cssText)).toString("base64");
|
|
16598
17182
|
})()
|
|
@@ -16660,10 +17244,10 @@ ${cssText}`).toString(36);
|
|
|
16660
17244
|
if (changedFiles.length === 0)
|
|
16661
17245
|
return false;
|
|
16662
17246
|
return changedFiles.some((file) => {
|
|
16663
|
-
const normalized =
|
|
17247
|
+
const normalized = path45.resolve(file);
|
|
16664
17248
|
if (/\.(woff2?|ttf|otf)$/i.test(normalized))
|
|
16665
17249
|
return true;
|
|
16666
|
-
return this.#optimizedFonts.files.some((fontFile) =>
|
|
17250
|
+
return this.#optimizedFonts.files.some((fontFile) => path45.resolve(fontFile) === normalized);
|
|
16667
17251
|
});
|
|
16668
17252
|
}
|
|
16669
17253
|
async installWatcher() {
|
|
@@ -16684,6 +17268,11 @@ ${cssText}`).toString(36);
|
|
|
16684
17268
|
if (rawKinds.size === 0)
|
|
16685
17269
|
return;
|
|
16686
17270
|
const generation = ++this.#generation;
|
|
17271
|
+
const autoImport = await this.#autoImportSync.syncForBatch(batch.files);
|
|
17272
|
+
for (const error of autoImport.errors)
|
|
17273
|
+
this.#logger.error(error);
|
|
17274
|
+
if (autoImport.changedFiles.length > 0)
|
|
17275
|
+
this.#logger.verbose(`[auto-import] inserted imports into ${autoImport.changedFiles.length} file(s)`);
|
|
16687
17276
|
const indexSync = await this.#generatedIndexSync.syncForBatch(batch.files);
|
|
16688
17277
|
const { files, kinds, expandedBatch, event, hasSyncErrors } = prepareDevWatchBatch({
|
|
16689
17278
|
generation,
|
|
@@ -16711,14 +17300,18 @@ ${cssText}`).toString(36);
|
|
|
16711
17300
|
}
|
|
16712
17301
|
if (indexSync.changedFiles.length > 0)
|
|
16713
17302
|
this.#sendBuildStatus("barrel", { generation, ok: true, files });
|
|
16714
|
-
|
|
17303
|
+
const rebuildClient = devPlan.actions.includes("rebuild-client");
|
|
17304
|
+
if (kinds.includes("code") && !rebuildClient) {
|
|
17305
|
+
this.#logger.verbose(`client rebuild skipped; devPlan actions=${devPlan.actions.join(",") || "(none)"}`);
|
|
17306
|
+
}
|
|
17307
|
+
if (kinds.includes("code") && rebuildClient && await this.batchMayChangePageKeys(appDir, expandedBatch)) {
|
|
16715
17308
|
const started = Date.now();
|
|
16716
17309
|
await this.#app.getPageKeys({ refresh: true });
|
|
16717
17310
|
this.#logger.verbose(`pageKeys updated, app pageKeys are refreshed (${Date.now() - started}ms)`);
|
|
16718
|
-
} else if (kinds.includes("code") && this.batchTouchesPagesTree(appDir, expandedBatch)) {
|
|
17311
|
+
} else if (kinds.includes("code") && rebuildClient && this.batchTouchesPagesTree(appDir, expandedBatch)) {
|
|
16719
17312
|
this.#logger.verbose("pageKeys refresh skipped; changed page source cannot add/remove a route key");
|
|
16720
17313
|
}
|
|
16721
|
-
if (kinds.includes("code") && this.#shouldRebuildCsr()) {
|
|
17314
|
+
if (kinds.includes("code") && rebuildClient && this.#shouldRebuildCsr()) {
|
|
16722
17315
|
try {
|
|
16723
17316
|
const started = Date.now();
|
|
16724
17317
|
await new CsrArtifactBuilder(this.#app).build();
|
|
@@ -16729,11 +17322,11 @@ ${cssText}`).toString(36);
|
|
|
16729
17322
|
this.#logger.error(`csr-rebundle failed: ${message}`);
|
|
16730
17323
|
this.#sendBuildStatus("csr", { generation, ok: false, files, message });
|
|
16731
17324
|
}
|
|
16732
|
-
} else if (kinds.includes("code")) {
|
|
17325
|
+
} else if (kinds.includes("code") && rebuildClient) {
|
|
16733
17326
|
this.#logger.verbose(`csr-rebundle skipped; set AKAN_DEV_CSR_REBUILD=1 to enable per-save CSR rebuilds`);
|
|
16734
17327
|
}
|
|
16735
17328
|
process.send?.(event);
|
|
16736
|
-
if (kinds.includes("code")) {
|
|
17329
|
+
if (kinds.includes("code") && rebuildClient) {
|
|
16737
17330
|
try {
|
|
16738
17331
|
const started = Date.now();
|
|
16739
17332
|
const next = await new PagesBundleBuilder(this.#app).build();
|
|
@@ -16768,6 +17361,10 @@ ${cssText}`).toString(36);
|
|
|
16768
17361
|
return;
|
|
16769
17362
|
}
|
|
16770
17363
|
});
|
|
17364
|
+
process.on("disconnect", () => {
|
|
17365
|
+
this.#logger.warn("host IPC channel closed; exiting builder");
|
|
17366
|
+
process.exit(0);
|
|
17367
|
+
});
|
|
16771
17368
|
if (this.#watch)
|
|
16772
17369
|
await this.installWatcher();
|
|
16773
17370
|
process.send?.({ type: "builder-ready" });
|