@akanjs/cli 3.0.0-alpha.79 → 3.0.0-alpha.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.build-stamp +1 -1
- package/{abstractCompactor-8yjc9sj4.js → abstractCompactor-pwc6d6yk.js} +3 -5
- package/{agent.command-q2rgd8jz.js → agent.command-180hh0ye.js} +11 -14
- package/{application.command-kd5zj0k9.js → application.command-gmcgen9y.js} +29 -34
- package/{applicationBuildRunner-8tqhxjd0.js → applicationBuildRunner-tavpx3fv.js} +9 -12
- package/{applicationReleasePackager-0jf6ejr4.js → applicationReleasePackager-ktjt0erc.js} +6 -7
- package/buildBatch.proc.js +12 -15
- package/capacitorApp-kwa67kzs.js +12 -0
- package/{cloud.command-v60xnfdx.js → cloud.command-gpq7qxrc.js} +15 -21
- package/{context.command-hac3x83c.js → context.command-dk2m2sjx.js} +19 -24
- package/dependencyScanner-c64m6fxp.js +8 -0
- package/{fleet.command-jv24wcae.js → fleet.command-3bkyyd3a.js} +67 -24
- package/getDirname-dr3jz1xg.js +7 -0
- package/{guideline.command-85x1tvjb.js → guideline.command-w6ddv13r.js} +16 -19
- package/incrementalBuilder.proc.js +17 -20
- package/{index-yz8988we.js → index-1kzsn94d.js} +1 -1
- package/{index-dz1q44m8.js → index-3c9n3nt8.js} +21 -21
- package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
- package/{index-dfn0kqj7.js → index-5n0hf8r9.js} +19 -19
- package/{index-w0g7hcr7.js → index-5y7qba1c.js} +19 -19
- package/{index-1577bej2.js → index-6wwzs1bc.js} +2 -2
- package/{index-94hdqqka.js → index-92zztqy1.js} +6 -6
- package/{index-ffrhjdwd.js → index-a8h184wr.js} +7 -7
- package/{index-67546d0j.js → index-ayy5ecax.js} +1 -1
- package/{index-zec5gcx0.js → index-b2nt0w0k.js} +7 -7
- package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
- package/{index-47zynjx7.js → index-cd5x18qh.js} +32 -32
- package/{index-pzsryyjv.js → index-dq6wq1tv.js} +39 -39
- package/{index-psx0z6hb.js → index-ee8z8adx.js} +13 -13
- package/{index-zp0cmfgd.js → index-f7wewj2v.js} +22 -25
- package/{index-1szrbtj9.js → index-ft1sfjz0.js} +20 -23
- package/{index-k7731a4v.js → index-h7yw2z9n.js} +3 -3
- package/{index-egng0kc4.js → index-j9vnq8tr.js} +18 -18
- package/{index-zkrzv21w.js → index-k1n0h7dk.js} +519 -123
- package/{index-pj3hk9kt.js → index-k86zc21w.js} +57 -57
- package/{index-h5sr2nnj.js → index-mfm35dhh.js} +5 -5
- package/{index-qwfwk8be.js → index-qcracvc9.js} +8 -8
- package/{index-6w77v5df.js → index-saheq2bs.js} +4 -4
- package/{index-ta1mk0xh.js → index-v0s24t8j.js} +15 -15
- package/{index-safgeq9a.js → index-wet2ytnr.js} +8 -8
- package/{index-jn9b717k.js → index-xnhf8tr9.js} +1 -1
- package/{index-7605ykh6.js → index-xxe90kqy.js} +6 -6
- package/{index-25qfm3at.js → index-z3c9mmw4.js} +14 -16
- package/index.js +22 -27
- package/{library.command-nvp0wetm.js → library.command-wpedct6c.js} +7 -11
- package/{localRegistry.command-dnefn893.js → localRegistry.command-pjdxa01g.js} +20 -26
- package/{module.command-xs6ded4j.js → module.command-8n4kct3e.js} +13 -17
- package/{package.command-af8sxhff.js → package.command-fcbd0b1d.js} +8 -11
- package/package.json +2 -2
- package/{page.command-gr6rbz17.js → page.command-x4379grq.js} +7 -10
- package/{primitive.command-qjf4mbth.js → primitive.command-8etmnqhq.js} +13 -17
- package/{quality.command-9xhaxzm1.js → quality.command-hfx7z8yr.js} +11 -14
- package/recipeScanner-fpagtgc1.js +11 -0
- package/{repair.command-a2z4d5a0.js → repair.command-j0fs5qkz.js} +12 -15
- package/{routeSourceValidator-7fycdqyv.js → routeSourceValidator-ze6x894c.js} +0 -2
- package/{scalar.command-ax8taqh1.js → scalar.command-2emk89eh.js} +11 -15
- package/templates/workspaceRoot/package.json.template +1 -3
- package/typeChecker-3xgrzc2v.js +7 -0
- package/typecheck.proc.js +4 -5
- package/{workflow.command-gwkw0jae.js → workflow.command-cvpmzwjg.js} +22 -26
- package/{workspace.command-53qpkgzp.js → workspace.command-mbb5s3wx.js} +57 -64
- package/capacitorApp-szqr3cxr.js +0 -62
- package/dependencyScanner-aqg3dkks.js +0 -9
- package/getDirname-ka11hm7e.js +0 -8
- package/index-dp66vwr6.js +0 -348
- package/index-mxvakhsm.js +0 -66
- package/index-yb2wsc7f.js +0 -4
- package/recipeScanner-zrzev25x.js +0 -12
- package/typeChecker-yhs4eht8.js +0 -8
- /package/{index-19nz5chq.js → index-3d9y066c.js} +0 -0
- /package/{index-ynf37b66.js → index-a5vmm6x4.js} +0 -0
- /package/{index-5vy2jzar.js → index-ctphds8v.js} +0 -0
- /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
- /package/{index-scemmfpj.js → index-n68jx79w.js} +0 -0
- /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
- /package/{index-jcm6zr20.js → index-x23688ar.js} +0 -0
|
@@ -1,20 +1,74 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
getRootBoundarySegments,
|
|
4
|
-
isRootBoundarySegments
|
|
5
|
-
} from "./index-dp66vwr6.js";
|
|
6
|
-
import {
|
|
7
|
-
Spinner
|
|
8
|
-
} from "./index-mxvakhsm.js";
|
|
9
|
-
import {
|
|
10
|
-
getDirname
|
|
11
|
-
} from "./index-1577bej2.js";
|
|
12
2
|
import {
|
|
13
3
|
FileSys
|
|
14
|
-
} from "./index-
|
|
4
|
+
} from "./index-ayy5ecax.js";
|
|
15
5
|
import {
|
|
16
|
-
|
|
17
|
-
} from "./index-
|
|
6
|
+
getDirname2
|
|
7
|
+
} from "./index-6wwzs1bc.js";
|
|
8
|
+
|
|
9
|
+
// pkgs/@akanjs/devkit/spinner.ts
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
|
|
12
|
+
class Spinner {
|
|
13
|
+
static padding = 12;
|
|
14
|
+
static oraOptions = { discardStdin: false };
|
|
15
|
+
static canAnimate(stream = process.stderr) {
|
|
16
|
+
return !stream.isTTY || stream.columns > 0;
|
|
17
|
+
}
|
|
18
|
+
spinner;
|
|
19
|
+
stopWatch = null;
|
|
20
|
+
startAt = new Date;
|
|
21
|
+
prefix;
|
|
22
|
+
message;
|
|
23
|
+
enableSpin;
|
|
24
|
+
constructor(message, { prefix = "", indent = 0, enableSpin = true } = {}) {
|
|
25
|
+
Spinner.padding = Math.max(Spinner.padding, prefix.length);
|
|
26
|
+
this.prefix = prefix;
|
|
27
|
+
this.message = message;
|
|
28
|
+
this.spinner = ora({ ...Spinner.oraOptions, text: message });
|
|
29
|
+
this.spinner.prefixText = prefix.padStart(Spinner.padding, " ");
|
|
30
|
+
this.spinner.indent = indent;
|
|
31
|
+
this.enableSpin = enableSpin && Spinner.canAnimate();
|
|
32
|
+
}
|
|
33
|
+
start() {
|
|
34
|
+
this.startAt = new Date;
|
|
35
|
+
if (this.enableSpin) {
|
|
36
|
+
this.spinner.start();
|
|
37
|
+
this.stopWatch = setInterval(() => {
|
|
38
|
+
this.spinner.prefixText = this.prefix.padStart(Spinner.padding, " ");
|
|
39
|
+
this.spinner.text = `${this.message} (${this.#getElapsedTimeStr({ floor: true })})`;
|
|
40
|
+
}, 1000);
|
|
41
|
+
} else
|
|
42
|
+
this.spinner.info();
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
succeed(message) {
|
|
46
|
+
this.spinner.succeed(`${message} (${this.#getElapsedTimeStr()})`);
|
|
47
|
+
this.#reset();
|
|
48
|
+
}
|
|
49
|
+
fail(message) {
|
|
50
|
+
this.spinner.fail(`${message} (${this.#getElapsedTimeStr()})`);
|
|
51
|
+
this.#reset();
|
|
52
|
+
}
|
|
53
|
+
isSpinning() {
|
|
54
|
+
return this.spinner.isSpinning;
|
|
55
|
+
}
|
|
56
|
+
#reset() {
|
|
57
|
+
if (this.stopWatch)
|
|
58
|
+
clearInterval(this.stopWatch);
|
|
59
|
+
this.stopWatch = null;
|
|
60
|
+
}
|
|
61
|
+
#getElapsedTimeStr({ floor = false } = {}) {
|
|
62
|
+
const ms = Date.now() - this.startAt.getTime();
|
|
63
|
+
if (ms < 1000)
|
|
64
|
+
return `${ms}ms`;
|
|
65
|
+
const s = Math.floor(ms / 1000);
|
|
66
|
+
if (s < 60)
|
|
67
|
+
return `${floor ? Math.floor(ms / 1000) : Math.floor(ms / 100) / 10}s`;
|
|
68
|
+
const m = Math.floor(s / 60);
|
|
69
|
+
return `${m}m ${s % 60}s`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
18
72
|
|
|
19
73
|
// pkgs/@akanjs/devkit/executors.ts
|
|
20
74
|
import {
|
|
@@ -26,14 +80,14 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
26
80
|
import {
|
|
27
81
|
copyFile,
|
|
28
82
|
cp as cpEntry,
|
|
29
|
-
mkdir,
|
|
83
|
+
mkdir as mkdir2,
|
|
30
84
|
readdir as readDirEntries,
|
|
31
85
|
realpath,
|
|
32
86
|
rm as rm2,
|
|
33
87
|
stat,
|
|
34
88
|
symlink
|
|
35
89
|
} from "fs/promises";
|
|
36
|
-
import
|
|
90
|
+
import path7 from "path";
|
|
37
91
|
import { pathToFileURL } from "url";
|
|
38
92
|
import {
|
|
39
93
|
capitalize,
|
|
@@ -49,7 +103,7 @@ import chalk2 from "chalk";
|
|
|
49
103
|
|
|
50
104
|
// pkgs/@akanjs/devkit/agentsIndex.ts
|
|
51
105
|
var recipeScannerLoad = null;
|
|
52
|
-
var loadRecipeScanner = () => recipeScannerLoad ??= import("./recipeScanner-
|
|
106
|
+
var loadRecipeScanner = () => recipeScannerLoad ??= import("./recipeScanner-fpagtgc1.js");
|
|
53
107
|
var AGENT_BLOCK_START = "<!-- akan:agent:start -->";
|
|
54
108
|
var AGENT_BLOCK_END = "<!-- akan:agent:end -->";
|
|
55
109
|
var AGENT_VERSION_PREFIX = "<!-- akan:agent:version ";
|
|
@@ -59,9 +113,9 @@ ${block}`;
|
|
|
59
113
|
var extractBlockVersion = (content) => content.match(/<!-- akan:agent:version ([^\s]+) -->/)?.[1] ?? null;
|
|
60
114
|
var readDevkitVersion = async () => {
|
|
61
115
|
const { readFile } = await import("fs/promises");
|
|
62
|
-
const { getDirname
|
|
116
|
+
const { getDirname } = await import("./getDirname-dr3jz1xg.js");
|
|
63
117
|
try {
|
|
64
|
-
const raw = await readFile(`${
|
|
118
|
+
const raw = await readFile(`${getDirname(import.meta.url)}/package.json`, "utf-8");
|
|
65
119
|
return JSON.parse(raw).version ?? null;
|
|
66
120
|
} catch {
|
|
67
121
|
return null;
|
|
@@ -715,10 +769,352 @@ var decreaseBuildNum = async (app) => {
|
|
|
715
769
|
const akanConfigContent = akanConfig.replace(`buildNum: ${appConfig.mobile.buildNum}`, `buildNum: ${appConfig.mobile.buildNum - 1}`);
|
|
716
770
|
fs.writeFileSync(akanConfigPath, akanConfigContent);
|
|
717
771
|
};
|
|
772
|
+
// pkgs/@akanjs/devkit/artifact/implicitRootLayout.ts
|
|
773
|
+
import { mkdir } from "fs/promises";
|
|
774
|
+
import path3 from "path";
|
|
775
|
+
|
|
776
|
+
// pkgs/@akanjs/devkit/transforms/asyncDefaultExportDetector.ts
|
|
777
|
+
import fs2 from "fs";
|
|
778
|
+
import path2 from "path";
|
|
779
|
+
|
|
780
|
+
class AsyncDefaultExportDetector {
|
|
781
|
+
static #typescriptLoad;
|
|
782
|
+
static #loadTypescript() {
|
|
783
|
+
AsyncDefaultExportDetector.#typescriptLoad ??= import("typescript").then((mod) => mod.default ?? mod);
|
|
784
|
+
return AsyncDefaultExportDetector.#typescriptLoad;
|
|
785
|
+
}
|
|
786
|
+
static async detect(moduleAbsPath) {
|
|
787
|
+
try {
|
|
788
|
+
const typescript = await AsyncDefaultExportDetector.#loadTypescript();
|
|
789
|
+
const source = fs2.readFileSync(path2.resolve(moduleAbsPath), "utf8");
|
|
790
|
+
const sourceFile = typescript.createSourceFile(moduleAbsPath, source, typescript.ScriptTarget.Latest, true, AsyncDefaultExportDetector.#scriptKind(typescript, moduleAbsPath));
|
|
791
|
+
return new AsyncDefaultExportDetector(typescript).detectInSourceFile(sourceFile);
|
|
792
|
+
} catch {
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
#ts;
|
|
797
|
+
constructor(typescript) {
|
|
798
|
+
this.#ts = typescript;
|
|
799
|
+
}
|
|
800
|
+
detectInSourceFile(sourceFile) {
|
|
801
|
+
const ts = this.#ts;
|
|
802
|
+
const asyncBindings = new Map;
|
|
803
|
+
let defaultIdentifier = null;
|
|
804
|
+
for (const statement of sourceFile.statements) {
|
|
805
|
+
if (ts.isFunctionDeclaration(statement)) {
|
|
806
|
+
if (this.#hasModifier(statement, ts.SyntaxKind.DefaultKeyword)) {
|
|
807
|
+
return this.#hasModifier(statement, ts.SyntaxKind.AsyncKeyword);
|
|
808
|
+
}
|
|
809
|
+
if (statement.name) {
|
|
810
|
+
asyncBindings.set(statement.name.text, this.#hasModifier(statement, ts.SyntaxKind.AsyncKeyword));
|
|
811
|
+
}
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
if (ts.isVariableStatement(statement)) {
|
|
815
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
816
|
+
if (!ts.isIdentifier(declaration.name))
|
|
817
|
+
continue;
|
|
818
|
+
asyncBindings.set(declaration.name.text, this.#isAsyncFunctionExpression(declaration.initializer));
|
|
819
|
+
}
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
if (ts.isExportAssignment(statement)) {
|
|
823
|
+
if (this.#isAsyncFunctionExpression(statement.expression))
|
|
824
|
+
return true;
|
|
825
|
+
if (ts.isIdentifier(statement.expression))
|
|
826
|
+
defaultIdentifier = statement.expression.text;
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
if (ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
830
|
+
const exportClause = statement.exportClause;
|
|
831
|
+
for (const specifier of exportClause.elements) {
|
|
832
|
+
if (specifier.name.text !== "default")
|
|
833
|
+
continue;
|
|
834
|
+
defaultIdentifier = specifier.propertyName?.text ?? specifier.name.text;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
|
|
839
|
+
}
|
|
840
|
+
#hasModifier(node, kind) {
|
|
841
|
+
const ts = this.#ts;
|
|
842
|
+
return ts.canHaveModifiers(node) && (ts.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
|
|
843
|
+
}
|
|
844
|
+
#isAsyncFunctionExpression(node) {
|
|
845
|
+
const ts = this.#ts;
|
|
846
|
+
return Boolean(node && (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && this.#hasModifier(node, ts.SyntaxKind.AsyncKeyword));
|
|
847
|
+
}
|
|
848
|
+
static #scriptKind(typescript, moduleAbsPath) {
|
|
849
|
+
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? typescript.ScriptKind.TSX : typescript.ScriptKind.TS;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// pkgs/@akanjs/devkit/artifact/implicitRootLayout.ts
|
|
854
|
+
var LAYOUT_KEY_RE = /^\.\/(.+\/)?_layout\.(tsx|ts|jsx|js)$/;
|
|
855
|
+
async function appHasStModule(appCwdPath) {
|
|
856
|
+
return Bun.file(path3.join(appCwdPath, "lib", "st.ts")).exists();
|
|
857
|
+
}
|
|
858
|
+
var IMPLICIT_LAYOUT_DIR = path3.join(".akan", "generated", "root-layouts");
|
|
859
|
+
var IMPLICIT_DICT_DIR = path3.join(".akan", "generated", "dict");
|
|
860
|
+
var IMPLICIT_OVERRIDES_DIR = path3.join(".akan", "generated", "overrides");
|
|
861
|
+
var OVERRIDES_KEY_RE = /^\.\/(.+\/)?_overrides\.(tsx|ts|jsx|js)$/;
|
|
862
|
+
async function writeGeneratedOverridesLayoutFile(opts) {
|
|
863
|
+
const filename = `${opts.key.replace(/^\.\//, "").replace(/[^a-zA-Z0-9]+/g, "_")}.tsx`;
|
|
864
|
+
const absPath = path3.join(path3.resolve(opts.appCwdPath), IMPLICIT_OVERRIDES_DIR, filename);
|
|
865
|
+
const userRel = path3.relative(path3.dirname(absPath), opts.userAbsPath).split(path3.sep).join("/");
|
|
866
|
+
const userSpecifier = userRel.startsWith(".") ? userRel : `./${userRel}`;
|
|
867
|
+
const source = `"use client";
|
|
868
|
+
import { UiOverrideProvider } from "akanjs/ui";
|
|
869
|
+
import { createElement, type ReactNode } from "react";
|
|
870
|
+
import value from ${JSON.stringify(userSpecifier)};
|
|
871
|
+
|
|
872
|
+
export default function AkanUiOverridesLayout({ children }: { children?: ReactNode }) {
|
|
873
|
+
return createElement(UiOverrideProvider, { value }, children);
|
|
874
|
+
}
|
|
875
|
+
`;
|
|
876
|
+
await Bun.write(absPath, source);
|
|
877
|
+
return absPath;
|
|
878
|
+
}
|
|
879
|
+
function getRootBoundarySegments(key) {
|
|
880
|
+
const match = LAYOUT_KEY_RE.exec(key);
|
|
881
|
+
if (!match)
|
|
882
|
+
return null;
|
|
883
|
+
const prefix = match[1]?.replace(/\/$/, "");
|
|
884
|
+
if (!prefix)
|
|
885
|
+
return [];
|
|
886
|
+
return prefix.split("/").filter(Boolean);
|
|
887
|
+
}
|
|
888
|
+
function implicitRootLayoutKey(segments) {
|
|
889
|
+
return `./${[...segments, "__root_layout"].join("/")}.tsx`;
|
|
890
|
+
}
|
|
891
|
+
function implicitRootLayoutAbsPath(appCwdPath, segments) {
|
|
892
|
+
const filename = segments.length ? `${segments.join("__")}__root_layout.tsx` : "__root_layout.tsx";
|
|
893
|
+
return path3.join(path3.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
|
|
894
|
+
}
|
|
895
|
+
function implicitDictionaryMacroAbsPath(appCwdPath) {
|
|
896
|
+
return path3.join(path3.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
897
|
+
}
|
|
898
|
+
function isRootBoundarySegments(segments, basePaths) {
|
|
899
|
+
const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
|
|
900
|
+
if (firstVisibleIndex === -1)
|
|
901
|
+
return segments.length <= 1;
|
|
902
|
+
if (segments.slice(firstVisibleIndex + 1).some((segment) => /^\(.+\)$/.test(segment)))
|
|
903
|
+
return false;
|
|
904
|
+
const visible = segments.slice(firstVisibleIndex);
|
|
905
|
+
const allowedBasePaths = new Set([...basePaths].map((basePath) => basePath.trim()).filter(Boolean));
|
|
906
|
+
return visible.length === 1 && (firstVisibleIndex > 0 || allowedBasePaths.has(visible[0] ?? ""));
|
|
907
|
+
}
|
|
908
|
+
function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
|
|
909
|
+
const boundaries = new Map;
|
|
910
|
+
for (const key of pageKeys) {
|
|
911
|
+
const segments = getRootBoundarySegments(key);
|
|
912
|
+
if (!segments)
|
|
913
|
+
continue;
|
|
914
|
+
if (!isRootBoundarySegments(segments, basePaths))
|
|
915
|
+
continue;
|
|
916
|
+
const id = segments.join("/");
|
|
917
|
+
boundaries.set(id, {
|
|
918
|
+
sourceKey: key,
|
|
919
|
+
sourceAbsPath: path3.resolve(appCwdPath, "page", key.replace(/^\.\//, "")),
|
|
920
|
+
segments
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
const hasExplicitRootBoundary = [...boundaries.values()].some((boundary) => boundary.segments.length === 0);
|
|
924
|
+
if (!hasExplicitRootBoundary && boundaries.size === 0) {
|
|
925
|
+
boundaries.set("", { sourceKey: null, sourceAbsPath: null, segments: [] });
|
|
926
|
+
}
|
|
927
|
+
return [...boundaries.values()].sort((a, b) => a.segments.join("/").localeCompare(b.segments.join("/")));
|
|
928
|
+
}
|
|
929
|
+
function hasAncestorRootBoundary(boundary, boundaries) {
|
|
930
|
+
return boundaries.some((candidate) => candidate !== boundary && candidate.segments.length < boundary.segments.length && candidate.segments.every((segment, index) => boundary.segments[index] === segment));
|
|
931
|
+
}
|
|
932
|
+
function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
|
|
933
|
+
const rootLayoutKey = pageKeys.find((key) => {
|
|
934
|
+
const segments = getRootBoundarySegments(key);
|
|
935
|
+
return segments !== null && segments.length === 0;
|
|
936
|
+
});
|
|
937
|
+
return rootLayoutKey ? path3.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
|
|
938
|
+
}
|
|
939
|
+
function routePrefixForSegments(segments) {
|
|
940
|
+
const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
941
|
+
return visible[0] ?? null;
|
|
942
|
+
}
|
|
943
|
+
async function assertEnvClientConvention(appCwdPath, appName) {
|
|
944
|
+
const envPath = path3.join(appCwdPath, "env", "env.client.ts");
|
|
945
|
+
if (!await Bun.file(envPath).exists()) {
|
|
946
|
+
throw new Error(`[route-convention] app "${appName}" must provide env/env.client.ts exporting "env" for generated System.Provider`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
async function writeGeneratedDictionaryMacroFile(appCwdPath, appName) {
|
|
950
|
+
const absPath = implicitDictionaryMacroAbsPath(appCwdPath);
|
|
951
|
+
await mkdir(path3.dirname(absPath), { recursive: true });
|
|
952
|
+
await Bun.write(absPath, `import { getAllDictionary } from "@apps/${appName}/lib/dict" with { type: "macro" };
|
|
953
|
+
|
|
954
|
+
export const allDictionary = getAllDictionary();
|
|
955
|
+
`);
|
|
956
|
+
return absPath;
|
|
957
|
+
}
|
|
958
|
+
async function writeGeneratedRootLayoutFile(opts) {
|
|
959
|
+
await assertEnvClientConvention(opts.appCwdPath, opts.appName);
|
|
960
|
+
const dictMacroAbsPath = opts.includeSystemProvider ? await writeGeneratedDictionaryMacroFile(opts.appCwdPath, opts.appName) : null;
|
|
961
|
+
const absPath = implicitRootLayoutAbsPath(opts.appCwdPath, opts.boundary.segments);
|
|
962
|
+
await mkdir(path3.dirname(absPath), { recursive: true });
|
|
963
|
+
const dictMacroRel = dictMacroAbsPath ? path3.relative(path3.dirname(absPath), dictMacroAbsPath).split(path3.sep).join("/") : null;
|
|
964
|
+
const dictMacroSpecifier = dictMacroRel ? dictMacroRel.startsWith(".") ? dictMacroRel : `./${dictMacroRel}` : null;
|
|
965
|
+
const sourceRel = opts.boundary.sourceAbsPath ? path3.relative(path3.dirname(absPath), opts.boundary.sourceAbsPath).split(path3.sep).join("/") : null;
|
|
966
|
+
const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
|
|
967
|
+
const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
|
|
968
|
+
const inheritedSourceRel = inheritedSourceAbsPath ? path3.relative(path3.dirname(absPath), inheritedSourceAbsPath).split(path3.sep).join("/") : null;
|
|
969
|
+
const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
|
|
970
|
+
const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
|
|
971
|
+
void st;
|
|
972
|
+
` : `import "@apps/${opts.appName}/client";
|
|
973
|
+
`;
|
|
974
|
+
const inheritedImport = inheritedSourceSpecifier ? `import * as inheritedLayout from ${JSON.stringify(inheritedSourceSpecifier)};
|
|
975
|
+
` : `const inheritedLayout = {};
|
|
976
|
+
`;
|
|
977
|
+
const prefix = routePrefixForSegments(opts.boundary.segments);
|
|
978
|
+
const userImport = sourceSpecifier ? `import UserLayout, * as userLayout from ${JSON.stringify(sourceSpecifier)};
|
|
979
|
+
` : `const UserLayout = ({ children }) => children;
|
|
980
|
+
const userLayout = {};
|
|
981
|
+
`;
|
|
982
|
+
const isAsyncUserLayout = opts.boundary.sourceAbsPath ? await AsyncDefaultExportDetector.detect(opts.boundary.sourceAbsPath) : false;
|
|
983
|
+
const userLayoutElement = "<UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>";
|
|
984
|
+
const layoutSignature = isAsyncUserLayout ? "export default async function GeneratedLayout" : "export default function GeneratedLayout";
|
|
985
|
+
const layoutBinding = isAsyncUserLayout ? ` const layout =
|
|
986
|
+
process.env.AKAN_PUBLIC_RENDER_ENV === "csr"
|
|
987
|
+
? await UserLayout({ params, searchParams, children })
|
|
988
|
+
: ${userLayoutElement};
|
|
989
|
+
` : "";
|
|
990
|
+
const layoutChild = isAsyncUserLayout ? "{layout}" : userLayoutElement;
|
|
991
|
+
const layoutReturn = isAsyncUserLayout ? "layout" : userLayoutElement;
|
|
992
|
+
const source = opts.includeSystemProvider ? `import type { LayoutProps, PageProps } from "akanjs/client";
|
|
993
|
+
import { loadFonts } from "akanjs/client";
|
|
994
|
+
import { System } from "akanjs/ui";
|
|
995
|
+
import { env } from "@apps/${opts.appName}/env/env.client";
|
|
996
|
+
import { allDictionary } from ${JSON.stringify(dictMacroSpecifier)};
|
|
997
|
+
${clientImport}${inheritedImport}${userImport}
|
|
998
|
+
const userFonts = userLayout.fonts ?? inheritedLayout.fonts ?? [];
|
|
999
|
+
const defaultFonts = userFonts.filter((font) => font.default);
|
|
1000
|
+
if (defaultFonts.length > 1) throw new Error("[route-convention] only one default font is allowed per root layout");
|
|
1001
|
+
const defaultFont = defaultFonts[0];
|
|
1002
|
+
const defaultFontClassName = defaultFont ? (defaultFont.className ?? \`font-\${defaultFont.name}\`) : undefined;
|
|
1003
|
+
|
|
1004
|
+
export async function generateHead(props: PageProps) {
|
|
1005
|
+
if (userLayout.generateHead) return userLayout.generateHead(props);
|
|
1006
|
+
if (userLayout.head !== undefined) return userLayout.head;
|
|
1007
|
+
if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
|
|
1008
|
+
return inheritedLayout.head;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
export async function generateMetadata(props: PageProps) {
|
|
1012
|
+
if (userLayout.generateMetadata) return userLayout.generateMetadata(props);
|
|
1013
|
+
if (userLayout.metadata !== undefined) return userLayout.metadata;
|
|
1014
|
+
if (inheritedLayout.generateMetadata) return inheritedLayout.generateMetadata(props);
|
|
1015
|
+
return inheritedLayout.metadata;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
export const NotFound = userLayout.NotFound ?? inheritedLayout.NotFound;
|
|
1019
|
+
export const Error = userLayout.Error ?? inheritedLayout.Error;
|
|
1020
|
+
export const pageConfig = userLayout.pageConfig ?? inheritedLayout.pageConfig;
|
|
1021
|
+
|
|
1022
|
+
${layoutSignature}({ children, params, searchParams }: LayoutProps) {
|
|
1023
|
+
${layoutBinding} return (
|
|
1024
|
+
<System.Provider
|
|
1025
|
+
of={GeneratedLayout as never}
|
|
1026
|
+
appName=${JSON.stringify(opts.appName)}
|
|
1027
|
+
${prefix ? `prefix=${JSON.stringify(prefix)}
|
|
1028
|
+
` : ""}params={params}
|
|
1029
|
+
manifest={userLayout.manifest ?? inheritedLayout.manifest}
|
|
1030
|
+
env={env}
|
|
1031
|
+
theme={userLayout.theme ?? inheritedLayout.theme}
|
|
1032
|
+
fonts={loadFonts(userFonts)}
|
|
1033
|
+
className={defaultFontClassName}
|
|
1034
|
+
gaTrackingId={userLayout.gaTrackingId ?? inheritedLayout.gaTrackingId}
|
|
1035
|
+
layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
|
|
1036
|
+
reconnect={userLayout.reconnect ?? inheritedLayout.reconnect ?? false}
|
|
1037
|
+
wsConnect={userLayout.wsConnect ?? inheritedLayout.wsConnect ?? true}
|
|
1038
|
+
allDictionary={process.env.AKAN_PUBLIC_RENDER_ENV === "ssr" ? allDictionary : undefined}
|
|
1039
|
+
>
|
|
1040
|
+
${layoutChild}
|
|
1041
|
+
</System.Provider>
|
|
1042
|
+
);
|
|
1043
|
+
}
|
|
1044
|
+
` : `import type { LayoutProps, PageProps } from "akanjs/client";
|
|
1045
|
+
${inheritedImport}${userImport}
|
|
1046
|
+
export async function generateHead(props: PageProps) {
|
|
1047
|
+
if (userLayout.generateHead) return userLayout.generateHead(props);
|
|
1048
|
+
if (userLayout.head !== undefined) return userLayout.head;
|
|
1049
|
+
if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
|
|
1050
|
+
return inheritedLayout.head;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
export async function generateMetadata(props: PageProps) {
|
|
1054
|
+
if (userLayout.generateMetadata) return userLayout.generateMetadata(props);
|
|
1055
|
+
if (userLayout.metadata !== undefined) return userLayout.metadata;
|
|
1056
|
+
if (inheritedLayout.generateMetadata) return inheritedLayout.generateMetadata(props);
|
|
1057
|
+
return inheritedLayout.metadata;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
export const NotFound = userLayout.NotFound ?? inheritedLayout.NotFound;
|
|
1061
|
+
export const Error = userLayout.Error ?? inheritedLayout.Error;
|
|
1062
|
+
export const pageConfig = userLayout.pageConfig ?? inheritedLayout.pageConfig;
|
|
1063
|
+
|
|
1064
|
+
${layoutSignature}({ children, params, searchParams }: LayoutProps) {
|
|
1065
|
+
${layoutBinding} return ${layoutReturn};
|
|
1066
|
+
}
|
|
1067
|
+
`;
|
|
1068
|
+
await Bun.write(absPath, source);
|
|
1069
|
+
return absPath;
|
|
1070
|
+
}
|
|
1071
|
+
async function resolveSsrPageEntries(opts) {
|
|
1072
|
+
const absPageDir = path3.resolve(opts.appCwdPath, "page");
|
|
1073
|
+
const hasSt = await appHasStModule(opts.appCwdPath);
|
|
1074
|
+
const basePaths = opts.basePaths ?? [];
|
|
1075
|
+
const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
|
|
1076
|
+
const rootBoundaries = findRootBoundaries(opts.pageKeys, opts.appCwdPath, basePaths);
|
|
1077
|
+
const rootLayoutKeys = new Set(opts.pageKeys.filter((key) => {
|
|
1078
|
+
const segments = getRootBoundarySegments(key);
|
|
1079
|
+
return segments !== null && isRootBoundarySegments(segments, basePaths);
|
|
1080
|
+
}));
|
|
1081
|
+
const base = await Promise.all(opts.pageKeys.filter((key) => !rootLayoutKeys.has(key)).map(async (key) => {
|
|
1082
|
+
const userAbsPath = path3.resolve(absPageDir, key);
|
|
1083
|
+
if (OVERRIDES_KEY_RE.test(key)) {
|
|
1084
|
+
const moduleAbsPath = await writeGeneratedOverridesLayoutFile({
|
|
1085
|
+
appCwdPath: opts.appCwdPath,
|
|
1086
|
+
key,
|
|
1087
|
+
userAbsPath
|
|
1088
|
+
});
|
|
1089
|
+
return { key, moduleAbsPath, seedAbsPaths: [userAbsPath] };
|
|
1090
|
+
}
|
|
1091
|
+
return { key, moduleAbsPath: userAbsPath };
|
|
1092
|
+
}));
|
|
1093
|
+
const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
|
|
1094
|
+
key: implicitRootLayoutKey(boundary.segments),
|
|
1095
|
+
moduleAbsPath: await writeGeneratedRootLayoutFile({
|
|
1096
|
+
appCwdPath: opts.appCwdPath,
|
|
1097
|
+
appName: opts.appName,
|
|
1098
|
+
boundary,
|
|
1099
|
+
rootSourceAbsPath,
|
|
1100
|
+
includeStInit: hasSt && boundary.segments.length === 0,
|
|
1101
|
+
includeSystemProvider: !hasAncestorRootBoundary(boundary, rootBoundaries)
|
|
1102
|
+
}),
|
|
1103
|
+
seedAbsPaths: [...new Set([boundary.sourceAbsPath, rootSourceAbsPath].filter((absPath) => absPath !== null))]
|
|
1104
|
+
})));
|
|
1105
|
+
const entries = [...base, ...generated];
|
|
1106
|
+
entries.sort((a, b) => a.key.localeCompare(b.key));
|
|
1107
|
+
return entries;
|
|
1108
|
+
}
|
|
1109
|
+
async function resolveSsrPageEntriesForApp(app, pageKeys) {
|
|
1110
|
+
const config = await app.getConfig();
|
|
1111
|
+
return resolveSsrPageEntries({ appCwdPath: app.cwdPath, appName: app.name, pageKeys, basePaths: config.basePaths });
|
|
1112
|
+
}
|
|
1113
|
+
|
|
718
1114
|
// pkgs/@akanjs/devkit/linter.ts
|
|
719
1115
|
import { spawn } from "child_process";
|
|
720
1116
|
import { existsSync, readFileSync } from "fs";
|
|
721
|
-
import
|
|
1117
|
+
import path4 from "path";
|
|
722
1118
|
import chalk from "chalk";
|
|
723
1119
|
var parseBiomeReport = (output) => {
|
|
724
1120
|
for (let start = output.indexOf("{");start !== -1; start = output.indexOf("{", start + 1)) {
|
|
@@ -775,13 +1171,13 @@ class Linter {
|
|
|
775
1171
|
#biomeBin;
|
|
776
1172
|
constructor(cwdPath) {
|
|
777
1173
|
this.lintRoot = this.#findBiomeRootPath(cwdPath);
|
|
778
|
-
this.configPath = Linter.#configPathIn(this.lintRoot) ??
|
|
779
|
-
const localBiomeBin =
|
|
1174
|
+
this.configPath = Linter.#configPathIn(this.lintRoot) ?? path4.join(this.lintRoot, "biome.json");
|
|
1175
|
+
const localBiomeBin = path4.join(this.lintRoot, "node_modules/.bin/biome");
|
|
780
1176
|
this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
|
|
781
1177
|
}
|
|
782
1178
|
static #configPathIn(dir) {
|
|
783
1179
|
for (const fileName of BIOME_CONFIG_FILES) {
|
|
784
|
-
const configPath =
|
|
1180
|
+
const configPath = path4.join(dir, fileName);
|
|
785
1181
|
if (existsSync(configPath))
|
|
786
1182
|
return configPath;
|
|
787
1183
|
}
|
|
@@ -790,19 +1186,19 @@ class Linter {
|
|
|
790
1186
|
#findBiomeRootPath(dir) {
|
|
791
1187
|
if (Linter.#configPathIn(dir))
|
|
792
1188
|
return dir;
|
|
793
|
-
const parentDir =
|
|
1189
|
+
const parentDir = path4.dirname(dir);
|
|
794
1190
|
if (parentDir === dir)
|
|
795
1191
|
throw new Error(`biome.json not found from ${dir}`);
|
|
796
1192
|
return this.#findBiomeRootPath(parentDir);
|
|
797
1193
|
}
|
|
798
1194
|
#toBiomePath(filePath) {
|
|
799
|
-
const relativePath =
|
|
800
|
-
if (!relativePath.startsWith("..") && !
|
|
1195
|
+
const relativePath = path4.relative(this.lintRoot, filePath);
|
|
1196
|
+
if (!relativePath.startsWith("..") && !path4.isAbsolute(relativePath))
|
|
801
1197
|
return relativePath;
|
|
802
1198
|
return filePath;
|
|
803
1199
|
}
|
|
804
1200
|
#resolveFilePath(filePath) {
|
|
805
|
-
return
|
|
1201
|
+
return path4.isAbsolute(filePath) ? filePath : path4.join(this.lintRoot, filePath);
|
|
806
1202
|
}
|
|
807
1203
|
async#runBiome(args, input) {
|
|
808
1204
|
return await new Promise((resolve, reject) => {
|
|
@@ -827,7 +1223,7 @@ class Linter {
|
|
|
827
1223
|
const diagnosticPath = diagnostic.location?.path;
|
|
828
1224
|
if (!diagnosticPath)
|
|
829
1225
|
return fallbackFilePath;
|
|
830
|
-
return
|
|
1226
|
+
return path4.isAbsolute(diagnosticPath) ? diagnosticPath : path4.join(this.lintRoot, diagnosticPath);
|
|
831
1227
|
}
|
|
832
1228
|
#createLintMessage(diagnostic) {
|
|
833
1229
|
const start = diagnostic.location?.start;
|
|
@@ -1057,7 +1453,7 @@ ${errorText}, ${warningText} found`];
|
|
|
1057
1453
|
|
|
1058
1454
|
// pkgs/@akanjs/devkit/repoIdentity.ts
|
|
1059
1455
|
import { execFileSync } from "child_process";
|
|
1060
|
-
import
|
|
1456
|
+
import path5 from "path";
|
|
1061
1457
|
var resolved = new Map;
|
|
1062
1458
|
var readRemoteName = (workspaceRoot) => {
|
|
1063
1459
|
try {
|
|
@@ -1075,14 +1471,14 @@ var resolveRepoName = (workspaceRoot) => {
|
|
|
1075
1471
|
const cached = resolved.get(workspaceRoot);
|
|
1076
1472
|
if (cached)
|
|
1077
1473
|
return cached;
|
|
1078
|
-
const repoName = readRemoteName(workspaceRoot) ??
|
|
1474
|
+
const repoName = readRemoteName(workspaceRoot) ?? path5.basename(workspaceRoot);
|
|
1079
1475
|
resolved.set(workspaceRoot, repoName);
|
|
1080
1476
|
return repoName;
|
|
1081
1477
|
};
|
|
1082
1478
|
|
|
1083
1479
|
// pkgs/@akanjs/devkit/scanInfo.ts
|
|
1084
1480
|
import { rm } from "fs/promises";
|
|
1085
|
-
import
|
|
1481
|
+
import path6 from "path";
|
|
1086
1482
|
|
|
1087
1483
|
// pkgs/@akanjs/devkit/workspaceLayout.ts
|
|
1088
1484
|
var appRootAllowedFiles = new Set([
|
|
@@ -1186,16 +1582,16 @@ var moduleUiFileTypes = {
|
|
|
1186
1582
|
scalar: new Set(["Template", "Unit"])
|
|
1187
1583
|
};
|
|
1188
1584
|
var testFilePattern = /\.(test|spec)\.(ts|tsx)$/;
|
|
1189
|
-
var createDependencyScanner = async (exec) => (await import("./dependencyScanner-
|
|
1585
|
+
var createDependencyScanner = async (exec) => (await import("./dependencyScanner-c64m6fxp.js")).TypeScriptDependencyScanner.from(exec);
|
|
1190
1586
|
var isAllowedTestFile = (filename) => testFilePattern.test(filename);
|
|
1191
|
-
var getScanPath = (exec, relativePath) =>
|
|
1587
|
+
var getScanPath = (exec, relativePath) => path6.posix.join(`${exec.type}s`, exec.name, relativePath.split(path6.sep).join("/"));
|
|
1192
1588
|
async function clearGeneratedRootCapacitorConfigs(exec) {
|
|
1193
1589
|
if (exec.type !== "app")
|
|
1194
1590
|
return;
|
|
1195
1591
|
await Promise.all(generatedRootCapacitorConfigFiles.map((filename) => rm(exec.getPath(filename), { force: true })));
|
|
1196
1592
|
}
|
|
1197
1593
|
var getModuleNameFromPath = (kind, modulePath) => {
|
|
1198
|
-
const dirname =
|
|
1594
|
+
const dirname = path6.basename(modulePath);
|
|
1199
1595
|
return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
|
|
1200
1596
|
};
|
|
1201
1597
|
async function assertScanConvention(exec, libRoot) {
|
|
@@ -1217,18 +1613,18 @@ async function assertScanConvention(exec, libRoot) {
|
|
|
1217
1613
|
for (const { relativePath, reason } of await exec.getPageConventionViolations())
|
|
1218
1614
|
addViolation(relativePath, reason);
|
|
1219
1615
|
libRoot.files.filter((filename) => !isAllowedLibFacetRootFile(filename)).forEach((filename) => {
|
|
1220
|
-
addViolation(
|
|
1616
|
+
addViolation(path6.join("lib", filename), "unsupported lib facet root file");
|
|
1221
1617
|
});
|
|
1222
1618
|
libRoot.dirs.filter((dirname) => dirname.startsWith("__") && !internalLibDirs.has(dirname)).forEach((dirname) => {
|
|
1223
|
-
addViolation(
|
|
1619
|
+
addViolation(path6.join("lib", dirname), "unsupported internal lib folder");
|
|
1224
1620
|
});
|
|
1225
1621
|
const databaseDirs = libRoot.dirs.filter((dirname) => !dirname.startsWith("_"));
|
|
1226
1622
|
const serviceDirs = libRoot.dirs.filter((dirname) => dirname.startsWith("_") && !dirname.startsWith("__"));
|
|
1227
1623
|
const scalarDirs = await exec.readdir("lib/__scalar");
|
|
1228
1624
|
await Promise.all([
|
|
1229
|
-
...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database",
|
|
1230
|
-
...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service",
|
|
1231
|
-
...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar",
|
|
1625
|
+
...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path6.join("lib", dirname))),
|
|
1626
|
+
...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path6.join("lib", dirname))),
|
|
1627
|
+
...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path6.join("lib/__scalar", dirname)))
|
|
1232
1628
|
]);
|
|
1233
1629
|
if (violations.length > 0) {
|
|
1234
1630
|
throw new Error(`[scan-convention]
|
|
@@ -1240,11 +1636,11 @@ async function validateModuleFiles(exec, violations, kind, modulePath) {
|
|
|
1240
1636
|
const { files, dirs } = await exec.getFilesAndDirs(modulePath);
|
|
1241
1637
|
const moduleName = getModuleNameFromPath(kind, modulePath);
|
|
1242
1638
|
dirs.forEach((dirname) => {
|
|
1243
|
-
violations.push(`${getScanPath(exec,
|
|
1639
|
+
violations.push(`${getScanPath(exec, path6.join(modulePath, dirname))}: unsupported module folder`);
|
|
1244
1640
|
});
|
|
1245
1641
|
const uiModuleName = moduleName[0].toUpperCase() + moduleName.slice(1);
|
|
1246
1642
|
files.forEach((filename) => {
|
|
1247
|
-
const filePath =
|
|
1643
|
+
const filePath = path6.join(modulePath, filename);
|
|
1248
1644
|
if (filename === "index.ts" || filename === "index.tsx" || isAllowedTestFile(filename))
|
|
1249
1645
|
return;
|
|
1250
1646
|
if (filename === `${moduleName}.abstract.md`)
|
|
@@ -1288,7 +1684,7 @@ class ScanInfo {
|
|
|
1288
1684
|
{ all: new Set, databases: new Set, services: new Set, scalars: new Set }
|
|
1289
1685
|
]));
|
|
1290
1686
|
static async getScanResult(exec) {
|
|
1291
|
-
const [
|
|
1687
|
+
const [akanConfig, scanner, pkgs, libs] = await Promise.all([
|
|
1292
1688
|
exec.getConfig(),
|
|
1293
1689
|
createDependencyScanner(exec),
|
|
1294
1690
|
exec.workspace.getPkgs(),
|
|
@@ -1324,7 +1720,7 @@ class ScanInfo {
|
|
|
1324
1720
|
});
|
|
1325
1721
|
await Promise.all([
|
|
1326
1722
|
...databaseDirs.map(async (name) => {
|
|
1327
|
-
const filenames = await exec.readdir(
|
|
1723
|
+
const filenames = await exec.readdir(path6.join("lib", name));
|
|
1328
1724
|
filenames.forEach((filename) => {
|
|
1329
1725
|
if (filename.endsWith(".constant.ts"))
|
|
1330
1726
|
files.constant.databases.push(name);
|
|
@@ -1352,7 +1748,7 @@ class ScanInfo {
|
|
|
1352
1748
|
}),
|
|
1353
1749
|
...serviceDirs.map(async (dirname) => {
|
|
1354
1750
|
const name = dirname.slice(1);
|
|
1355
|
-
const filenames = await exec.readdir(
|
|
1751
|
+
const filenames = await exec.readdir(path6.join("lib", dirname));
|
|
1356
1752
|
filenames.forEach((filename) => {
|
|
1357
1753
|
if (filename.endsWith(".dictionary.ts"))
|
|
1358
1754
|
files.dictionary.services.push(name);
|
|
@@ -1375,7 +1771,7 @@ class ScanInfo {
|
|
|
1375
1771
|
});
|
|
1376
1772
|
}),
|
|
1377
1773
|
...scalarDirs.map(async (name) => {
|
|
1378
|
-
const filenames = await exec.readdir(
|
|
1774
|
+
const filenames = await exec.readdir(path6.join("lib/__scalar", name));
|
|
1379
1775
|
filenames.forEach((filename) => {
|
|
1380
1776
|
if (filename.endsWith(".constant.ts"))
|
|
1381
1777
|
files.constant.scalars.push(name);
|
|
@@ -1401,7 +1797,7 @@ class ScanInfo {
|
|
|
1401
1797
|
name: exec.name,
|
|
1402
1798
|
type: exec.type,
|
|
1403
1799
|
repoName: exec.workspace.repoName,
|
|
1404
|
-
serveDomain: WorkspaceExecutor.getBaseDevEnv(
|
|
1800
|
+
serveDomain: WorkspaceExecutor.getBaseDevEnv(path6.join(exec.workspace.workspaceRoot, ".env")).serveDomain,
|
|
1405
1801
|
files,
|
|
1406
1802
|
libDeps,
|
|
1407
1803
|
pkgDeps,
|
|
@@ -1409,7 +1805,7 @@ class ScanInfo {
|
|
|
1409
1805
|
devDependencies: npmDevDeps.filter((dep) => !isAkanFrameworkDependency(dep)),
|
|
1410
1806
|
routes
|
|
1411
1807
|
};
|
|
1412
|
-
const scanResult =
|
|
1808
|
+
const scanResult = akanConfig instanceof AkanAppConfig ? { ...common, akanConfig } : { ...common, akanConfig };
|
|
1413
1809
|
return scanResult;
|
|
1414
1810
|
}
|
|
1415
1811
|
constructor(scanResult) {
|
|
@@ -1608,11 +2004,11 @@ class PkgInfo {
|
|
|
1608
2004
|
const [tsconfig, rootPackageJson] = await Promise.all([exec.getTsConfig(), exec.workspace.getPackageJson()]);
|
|
1609
2005
|
const scanner = await createDependencyScanner(exec);
|
|
1610
2006
|
const npmSet = new Set(Object.keys({ ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies }));
|
|
1611
|
-
const pkgPathSet = new Set(Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((
|
|
2007
|
+
const pkgPathSet = new Set(Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((path) => tsconfig.compilerOptions.paths?.[path]?.some((resolve) => resolve.startsWith("pkgs/"))).map((path) => path.replace("/*", "")));
|
|
1612
2008
|
const [npmDepSet, pkgPathDepSet] = await scanner.getImportSets([npmSet, pkgPathSet]);
|
|
1613
|
-
const pkgDeps = [...pkgPathDepSet].map((
|
|
1614
|
-
const pathSplitLength =
|
|
1615
|
-
return (tsconfig.compilerOptions.paths?.[
|
|
2009
|
+
const pkgDeps = [...pkgPathDepSet].map((path) => {
|
|
2010
|
+
const pathSplitLength = path.split("/").length;
|
|
2011
|
+
return (tsconfig.compilerOptions.paths?.[path]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
|
|
1616
2012
|
}).filter((pkg) => pkg !== exec.name);
|
|
1617
2013
|
const pkgScanResult = {
|
|
1618
2014
|
name: exec.name,
|
|
@@ -1949,10 +2345,10 @@ class Executor {
|
|
|
1949
2345
|
});
|
|
1950
2346
|
}
|
|
1951
2347
|
getPath(filePath) {
|
|
1952
|
-
if (
|
|
2348
|
+
if (path7.isAbsolute(filePath))
|
|
1953
2349
|
return filePath;
|
|
1954
2350
|
if (filePath.startsWith("."))
|
|
1955
|
-
return
|
|
2351
|
+
return path7.join(this.cwdPath, filePath);
|
|
1956
2352
|
const baseParts = this.cwdPath.split(/[\\/]/).filter(Boolean);
|
|
1957
2353
|
const targetParts = filePath.split(/[\\/]/).filter(Boolean);
|
|
1958
2354
|
let overlapLength = 0;
|
|
@@ -1966,12 +2362,12 @@ class Executor {
|
|
|
1966
2362
|
if (isOverlap)
|
|
1967
2363
|
overlapLength = i;
|
|
1968
2364
|
}
|
|
1969
|
-
return
|
|
2365
|
+
return path7.join(this.cwdPath, ...targetParts.slice(overlapLength));
|
|
1970
2366
|
}
|
|
1971
2367
|
async mkdir(dirPath) {
|
|
1972
2368
|
const writePath = this.getPath(dirPath);
|
|
1973
2369
|
if (!await FileSys.dirExists(writePath))
|
|
1974
|
-
await
|
|
2370
|
+
await mkdir2(writePath, { recursive: true });
|
|
1975
2371
|
this.logger.verbose(`Make directory ${writePath}`);
|
|
1976
2372
|
return this;
|
|
1977
2373
|
}
|
|
@@ -2009,7 +2405,7 @@ class Executor {
|
|
|
2009
2405
|
return this;
|
|
2010
2406
|
}
|
|
2011
2407
|
async removeDir(dirPath) {
|
|
2012
|
-
const readPath =
|
|
2408
|
+
const readPath = path7.join(this.getPath(dirPath), ".");
|
|
2013
2409
|
if (await FileSys.entryExists(readPath))
|
|
2014
2410
|
await rm2(readPath, { recursive: true, force: true });
|
|
2015
2411
|
this.logger.verbose(`Remove directory ${readPath}`);
|
|
@@ -2017,9 +2413,9 @@ class Executor {
|
|
|
2017
2413
|
}
|
|
2018
2414
|
async writeFile(filePath, content, { overwrite = true, silent = false } = {}) {
|
|
2019
2415
|
const writePath = this.getPath(filePath);
|
|
2020
|
-
const dir =
|
|
2416
|
+
const dir = path7.dirname(writePath);
|
|
2021
2417
|
if (!await FileSys.dirExists(dir))
|
|
2022
|
-
await
|
|
2418
|
+
await mkdir2(dir, { recursive: true });
|
|
2023
2419
|
let contentStr = typeof content === "string" ? content : `${JSON.stringify(content, null, 2)}
|
|
2024
2420
|
`;
|
|
2025
2421
|
if (await FileSys.fileExists(writePath)) {
|
|
@@ -2043,7 +2439,7 @@ class Executor {
|
|
|
2043
2439
|
await this.writeFile(filePath, content);
|
|
2044
2440
|
}
|
|
2045
2441
|
async getLocalFile(targetPath) {
|
|
2046
|
-
const filePath =
|
|
2442
|
+
const filePath = path7.isAbsolute(targetPath) ? targetPath : targetPath.replace(this.cwdPath, "");
|
|
2047
2443
|
const content = await this.readFile(filePath);
|
|
2048
2444
|
return { filePath, content };
|
|
2049
2445
|
}
|
|
@@ -2062,7 +2458,7 @@ class Executor {
|
|
|
2062
2458
|
return;
|
|
2063
2459
|
const isDirectory = (await stat(src)).isDirectory();
|
|
2064
2460
|
if (!await FileSys.exists(dest) && isDirectory)
|
|
2065
|
-
await
|
|
2461
|
+
await mkdir2(dest, { recursive: true });
|
|
2066
2462
|
if (dereference)
|
|
2067
2463
|
await cpEntry(src, dest, { recursive: isDirectory, dereference: true, force: true });
|
|
2068
2464
|
else
|
|
@@ -2140,26 +2536,26 @@ class Executor {
|
|
|
2140
2536
|
const result = await getContent.default(scanInfo ?? null, dict, options);
|
|
2141
2537
|
if (result === null)
|
|
2142
2538
|
return null;
|
|
2143
|
-
const filename = typeof result === "object" ? result.filename :
|
|
2539
|
+
const filename = typeof result === "object" ? result.filename : path7.basename(targetPath).replace(".js", ".ts");
|
|
2144
2540
|
const content = typeof result === "object" ? result.content : result;
|
|
2145
|
-
const dirname =
|
|
2146
|
-
const convertedTargetPath = Object.entries(dict).reduce((
|
|
2541
|
+
const dirname = path7.dirname(targetPath);
|
|
2542
|
+
const convertedTargetPath = Object.entries(dict).reduce((path, [key, value]) => path.replace(new RegExp(`__${key}__`, "g"), value), `${dirname}/${filename}`);
|
|
2147
2543
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2148
2544
|
return this.writeFile(convertedTargetPath, content, { overwrite });
|
|
2149
2545
|
} else if (targetPath.endsWith(".template")) {
|
|
2150
2546
|
const content = await FileSys.readText(templatePath);
|
|
2151
|
-
const convertedTargetPath = Object.entries(dict).reduce((
|
|
2547
|
+
const convertedTargetPath = Object.entries(dict).reduce((path, [key, value]) => path.replace(new RegExp(`__${key}__`, "g"), value), targetPath.slice(0, -9));
|
|
2152
2548
|
const convertedContent = Object.entries(dict).reduce((data, [key, value]) => data.replace(new RegExp(`<%= ${key} %>`, "g"), value), content);
|
|
2153
2549
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2154
2550
|
return this.writeFile(convertedTargetPath, convertedContent, {
|
|
2155
2551
|
overwrite
|
|
2156
2552
|
});
|
|
2157
|
-
} else if (staticTemplateFileExtensions.has(
|
|
2158
|
-
const convertedTargetPath = Object.entries(dict).reduce((
|
|
2553
|
+
} else if (staticTemplateFileExtensions.has(path7.extname(targetPath).toLowerCase())) {
|
|
2554
|
+
const convertedTargetPath = Object.entries(dict).reduce((path, [key, value]) => path.replace(new RegExp(`__${key}__`, "g"), value), targetPath);
|
|
2159
2555
|
const writePath = this.getPath(convertedTargetPath);
|
|
2160
|
-
const dirname =
|
|
2556
|
+
const dirname = path7.dirname(writePath);
|
|
2161
2557
|
if (!await FileSys.dirExists(dirname))
|
|
2162
|
-
await
|
|
2558
|
+
await mkdir2(dirname, { recursive: true });
|
|
2163
2559
|
await copyFile(templatePath, writePath);
|
|
2164
2560
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2165
2561
|
return { filePath: writePath, content: "" };
|
|
@@ -2178,10 +2574,10 @@ class Executor {
|
|
|
2178
2574
|
const templatePath = `${templateRoot}${template ? `/${template}` : ""}`;
|
|
2179
2575
|
const prefixTemplatePath = templatePath;
|
|
2180
2576
|
if ((await stat(prefixTemplatePath)).isFile()) {
|
|
2181
|
-
const filename =
|
|
2577
|
+
const filename = path7.basename(prefixTemplatePath);
|
|
2182
2578
|
const fileContent = await this.#applyTemplateFile({
|
|
2183
2579
|
templatePath: prefixTemplatePath,
|
|
2184
|
-
targetPath:
|
|
2580
|
+
targetPath: path7.join(basePath, filename),
|
|
2185
2581
|
scanInfo,
|
|
2186
2582
|
overwrite
|
|
2187
2583
|
}, dict, options);
|
|
@@ -2189,19 +2585,19 @@ class Executor {
|
|
|
2189
2585
|
} else {
|
|
2190
2586
|
const subdirs = await readDirEntries(templatePath);
|
|
2191
2587
|
const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
|
|
2192
|
-
const subpath =
|
|
2588
|
+
const subpath = path7.join(templatePath, subdir);
|
|
2193
2589
|
if ((await stat(subpath)).isFile()) {
|
|
2194
2590
|
const fileContent = await this.#applyTemplateFile({
|
|
2195
2591
|
templatePath: subpath,
|
|
2196
|
-
targetPath:
|
|
2592
|
+
targetPath: path7.join(basePath, subdir),
|
|
2197
2593
|
scanInfo,
|
|
2198
2594
|
overwrite
|
|
2199
2595
|
}, dict, options);
|
|
2200
2596
|
return fileContent ? [fileContent] : [];
|
|
2201
2597
|
} else
|
|
2202
2598
|
return await this._applyTemplate({
|
|
2203
|
-
basePath:
|
|
2204
|
-
template:
|
|
2599
|
+
basePath: path7.join(basePath, subdir),
|
|
2600
|
+
template: path7.join(template, subdir),
|
|
2205
2601
|
scanInfo,
|
|
2206
2602
|
dict,
|
|
2207
2603
|
overwrite,
|
|
@@ -2213,8 +2609,8 @@ class Executor {
|
|
|
2213
2609
|
}
|
|
2214
2610
|
async#resolveTemplateRoot() {
|
|
2215
2611
|
const candidates = [
|
|
2216
|
-
|
|
2217
|
-
|
|
2612
|
+
path7.resolve(getDirname2(import.meta.url), "templates"),
|
|
2613
|
+
path7.resolve(getDirname2(import.meta.url), "../cli/templates")
|
|
2218
2614
|
];
|
|
2219
2615
|
for (const candidate of candidates) {
|
|
2220
2616
|
if (await FileSys.dirExists(candidate))
|
|
@@ -2244,26 +2640,26 @@ class Executor {
|
|
|
2244
2640
|
}
|
|
2245
2641
|
}
|
|
2246
2642
|
async getTypeChecker() {
|
|
2247
|
-
const { TypeChecker } = await import("./typeChecker-
|
|
2643
|
+
const { TypeChecker } = await import("./typeChecker-3xgrzc2v.js");
|
|
2248
2644
|
this.typeChecker ??= new TypeChecker(this);
|
|
2249
2645
|
return this.typeChecker;
|
|
2250
2646
|
}
|
|
2251
2647
|
async typeCheck(filePath) {
|
|
2252
|
-
const
|
|
2648
|
+
const path = this.getPath(filePath);
|
|
2253
2649
|
const typeChecker = await this.getTypeChecker();
|
|
2254
|
-
const { fileDiagnostics, fileErrors, fileWarnings } = typeChecker.check(
|
|
2650
|
+
const { fileDiagnostics, fileErrors, fileWarnings } = typeChecker.check(path);
|
|
2255
2651
|
const message = typeChecker.formatDiagnostics(fileDiagnostics);
|
|
2256
2652
|
return { fileDiagnostics, fileErrors, fileWarnings, message };
|
|
2257
2653
|
}
|
|
2258
2654
|
async typeCheckAsync(filePath) {
|
|
2259
|
-
const
|
|
2655
|
+
const path = this.getPath(filePath);
|
|
2260
2656
|
const entry = await this.#resolveTypecheckWorkerEntry();
|
|
2261
2657
|
const proc = Bun.spawn([process.execPath, entry], {
|
|
2262
2658
|
cwd: this.cwdPath,
|
|
2263
2659
|
env: {
|
|
2264
2660
|
...process.env,
|
|
2265
2661
|
AKAN_TYPECHECK_CWD: this.cwdPath,
|
|
2266
|
-
AKAN_TYPECHECK_FILE:
|
|
2662
|
+
AKAN_TYPECHECK_FILE: path
|
|
2267
2663
|
},
|
|
2268
2664
|
stdout: "pipe",
|
|
2269
2665
|
stderr: "pipe"
|
|
@@ -2284,13 +2680,13 @@ class Executor {
|
|
|
2284
2680
|
};
|
|
2285
2681
|
}
|
|
2286
2682
|
async#resolveTypecheckWorkerEntry() {
|
|
2287
|
-
const dirname =
|
|
2683
|
+
const dirname = getDirname2(import.meta.url);
|
|
2288
2684
|
const candidates = [
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2685
|
+
path7.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
2686
|
+
path7.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
2687
|
+
path7.join(dirname, "typecheck/typecheck.proc.ts"),
|
|
2688
|
+
path7.join(dirname, "typecheck.proc.js"),
|
|
2689
|
+
path7.join(dirname, "typecheck.proc.ts")
|
|
2294
2690
|
];
|
|
2295
2691
|
for (const candidate of candidates)
|
|
2296
2692
|
if (await Bun.file(candidate).exists())
|
|
@@ -2302,9 +2698,9 @@ class Executor {
|
|
|
2302
2698
|
return this.linter;
|
|
2303
2699
|
}
|
|
2304
2700
|
async lint(filePath, { fix = false, dryRun = false } = {}) {
|
|
2305
|
-
const
|
|
2701
|
+
const path = this.getPath(filePath);
|
|
2306
2702
|
const linter = this.getLinter();
|
|
2307
|
-
const { results, errors, warnings } = await linter.lint(
|
|
2703
|
+
const { results, errors, warnings } = await linter.lint(path, {
|
|
2308
2704
|
fix,
|
|
2309
2705
|
dryRun
|
|
2310
2706
|
});
|
|
@@ -2417,7 +2813,7 @@ class WorkspaceExecutor extends Executor {
|
|
|
2417
2813
|
await Promise.all(dirs.map(async (dir) => {
|
|
2418
2814
|
if (dir.includes("_") || AVOID_DIRS.includes(dir))
|
|
2419
2815
|
return;
|
|
2420
|
-
const dirPath =
|
|
2816
|
+
const dirPath = path7.join(dirname, dir);
|
|
2421
2817
|
if ((await stat(dirPath)).isDirectory()) {
|
|
2422
2818
|
results.push(`${prefix}${dir}`);
|
|
2423
2819
|
if (maxDepth > 0)
|
|
@@ -2452,9 +2848,9 @@ class WorkspaceExecutor extends Executor {
|
|
|
2452
2848
|
await Promise.all(dirs.map(async (dir) => {
|
|
2453
2849
|
if (AVOID_DIRS.includes(dir))
|
|
2454
2850
|
return;
|
|
2455
|
-
const dirPath =
|
|
2851
|
+
const dirPath = path7.join(dirname, dir);
|
|
2456
2852
|
if (await FileSys.dirExists(dirPath)) {
|
|
2457
|
-
const hasTargetFile = await FileSys.fileExists(
|
|
2853
|
+
const hasTargetFile = await FileSys.fileExists(path7.join(dirPath, targetFilename));
|
|
2458
2854
|
if (hasTargetFile)
|
|
2459
2855
|
results.push(`${prefix}${dir}`);
|
|
2460
2856
|
if (maxDepth > 0)
|
|
@@ -2520,15 +2916,15 @@ class SysExecutor extends Executor {
|
|
|
2520
2916
|
return this.#akanConfig;
|
|
2521
2917
|
}
|
|
2522
2918
|
async getModules() {
|
|
2523
|
-
const
|
|
2524
|
-
return await this.workspace.getDirInModule(
|
|
2919
|
+
const path = this.type === "app" ? `apps/${this.name}/lib` : `libs/${this.name}/lib`;
|
|
2920
|
+
return await this.workspace.getDirInModule(path, this.name);
|
|
2525
2921
|
}
|
|
2526
2922
|
async getPageConventionViolations() {
|
|
2527
2923
|
if (!await this.exists("page"))
|
|
2528
2924
|
return [];
|
|
2529
2925
|
const violations = [];
|
|
2530
2926
|
for (const entry of await this.getAllFiles("**/*", { cwd: this.getPath("page") })) {
|
|
2531
|
-
const relativePath = entry.split(
|
|
2927
|
+
const relativePath = entry.split(path7.sep).join("/");
|
|
2532
2928
|
const reason = getPageSourceFileViolation(relativePath);
|
|
2533
2929
|
if (reason)
|
|
2534
2930
|
violations.push({ relativePath: `page/${relativePath}`, reason });
|
|
@@ -2637,7 +3033,7 @@ class SysExecutor extends Executor {
|
|
|
2637
3033
|
await this.setPackageJson(libPkgJsonWithDeps);
|
|
2638
3034
|
}
|
|
2639
3035
|
async getLocalFile(targetPath) {
|
|
2640
|
-
const filePath =
|
|
3036
|
+
const filePath = path7.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
|
|
2641
3037
|
const content = await this.workspace.readFile(filePath);
|
|
2642
3038
|
return { filePath, content };
|
|
2643
3039
|
}
|
|
@@ -2723,7 +3119,7 @@ class SysExecutor extends Executor {
|
|
|
2723
3119
|
class AppExecutor extends SysExecutor {
|
|
2724
3120
|
static #routeSourceValidator = null;
|
|
2725
3121
|
static async#getRouteSourceValidator() {
|
|
2726
|
-
AppExecutor.#routeSourceValidator ??= (await import("./routeSourceValidator-
|
|
3122
|
+
AppExecutor.#routeSourceValidator ??= (await import("./routeSourceValidator-ze6x894c.js")).RouteSourceValidator;
|
|
2727
3123
|
return AppExecutor.#routeSourceValidator;
|
|
2728
3124
|
}
|
|
2729
3125
|
dist;
|
|
@@ -2734,9 +3130,9 @@ class AppExecutor extends SysExecutor {
|
|
|
2734
3130
|
}
|
|
2735
3131
|
static #execs = new Map;
|
|
2736
3132
|
static from(executor, name) {
|
|
2737
|
-
const
|
|
2738
|
-
if (
|
|
2739
|
-
return
|
|
3133
|
+
const exec = AppExecutor.#execs.get(name);
|
|
3134
|
+
if (exec)
|
|
3135
|
+
return exec;
|
|
2740
3136
|
else if (executor instanceof WorkspaceExecutor)
|
|
2741
3137
|
return new AppExecutor({ workspace: executor, name });
|
|
2742
3138
|
else
|
|
@@ -2772,10 +3168,10 @@ class AppExecutor extends SysExecutor {
|
|
|
2772
3168
|
};
|
|
2773
3169
|
}
|
|
2774
3170
|
async prepareCommand(type) {
|
|
2775
|
-
const
|
|
2776
|
-
const databaseMode = process.env.AKAN_DATABASE_MODE ??
|
|
3171
|
+
const akanConfig = await this.getConfig();
|
|
3172
|
+
const databaseMode = process.env.AKAN_DATABASE_MODE ?? akanConfig.defaultDatabaseMode ?? "single";
|
|
2777
3173
|
const routeEnv = {
|
|
2778
|
-
AKAN_PUBLIC_BASE_PATHS: [...
|
|
3174
|
+
AKAN_PUBLIC_BASE_PATHS: [...akanConfig.basePaths].join(","),
|
|
2779
3175
|
AKAN_DATABASE_MODE: databaseMode
|
|
2780
3176
|
};
|
|
2781
3177
|
Object.assign(process.env, routeEnv);
|
|
@@ -2786,12 +3182,12 @@ class AppExecutor extends SysExecutor {
|
|
|
2786
3182
|
await Promise.all([this.dist.mkdir("private"), this.dist.mkdir("public")]);
|
|
2787
3183
|
await Promise.all([
|
|
2788
3184
|
this.cp("private", `${this.dist.cwdPath}/private`, { dereference: true }),
|
|
2789
|
-
...
|
|
3185
|
+
...akanConfig.web.ssr ? [this.cp("public", `${this.dist.cwdPath}/public`, { dereference: true })] : []
|
|
2790
3186
|
]);
|
|
2791
3187
|
} else {
|
|
2792
3188
|
await this.removeDir(".akan");
|
|
2793
|
-
if (!
|
|
2794
|
-
this.logger.verbose(`akan.config.ts disables web.${!
|
|
3189
|
+
if (!akanConfig.web.ssr || !akanConfig.web.csr)
|
|
3190
|
+
this.logger.verbose(`akan.config.ts disables web.${!akanConfig.web.ssr ? "ssr" : "csr"}; \`akan start\` still serves it, \`akan build\` will not`);
|
|
2795
3191
|
}
|
|
2796
3192
|
if (type === "start")
|
|
2797
3193
|
process.env.NODE_ENV = "development";
|
|
@@ -2842,7 +3238,7 @@ class AppExecutor extends SysExecutor {
|
|
|
2842
3238
|
async getPageKeys({ refresh } = {}) {
|
|
2843
3239
|
if (this.#pageKeys && !refresh)
|
|
2844
3240
|
return this.#pageKeys;
|
|
2845
|
-
const
|
|
3241
|
+
const akanConfig = await this.getConfig();
|
|
2846
3242
|
const glob = new Bun.Glob("**/*");
|
|
2847
3243
|
const pageKeys = [];
|
|
2848
3244
|
const owners = new Map;
|
|
@@ -2856,16 +3252,16 @@ class AppExecutor extends SysExecutor {
|
|
|
2856
3252
|
absolute: false,
|
|
2857
3253
|
onlyFiles: true
|
|
2858
3254
|
})) {
|
|
2859
|
-
const segments = rel.split(
|
|
3255
|
+
const segments = rel.split(path7.sep);
|
|
2860
3256
|
if (segments.some((s) => s === "node_modules"))
|
|
2861
3257
|
continue;
|
|
2862
3258
|
const posix = `${root.keyPrefix}${segments.join("/")}`;
|
|
2863
|
-
const absPath =
|
|
3259
|
+
const absPath = path7.join(root.dir, ...segments);
|
|
2864
3260
|
validatePageSourceFile(posix, { filePath: absPath });
|
|
2865
3261
|
if (!isRouteSourceFile(posix))
|
|
2866
3262
|
continue;
|
|
2867
3263
|
const key = `./${posix}`;
|
|
2868
|
-
validateSubRoutePageKey(key,
|
|
3264
|
+
validateSubRoutePageKey(key, akanConfig.basePaths, {
|
|
2869
3265
|
appName: this.name,
|
|
2870
3266
|
filePath: absPath
|
|
2871
3267
|
});
|
|
@@ -2884,7 +3280,7 @@ class AppExecutor extends SysExecutor {
|
|
|
2884
3280
|
if (!owner)
|
|
2885
3281
|
owners.set(routeId, { absPath, fromLib });
|
|
2886
3282
|
const layoutSegments = getRootBoundarySegments(key);
|
|
2887
|
-
const isRootLayout = layoutSegments !== null && isRootBoundarySegments(layoutSegments,
|
|
3283
|
+
const isRootLayout = layoutSegments !== null && isRootBoundarySegments(layoutSegments, akanConfig.basePaths);
|
|
2888
3284
|
const routeSource = await Bun.file(absPath).text();
|
|
2889
3285
|
const validator = await AppExecutor.#getRouteSourceValidator();
|
|
2890
3286
|
if (parsed.kind === "overrides")
|
|
@@ -2915,10 +3311,10 @@ class AppExecutor extends SysExecutor {
|
|
|
2915
3311
|
return pageKeys.filter((key) => !isDevOnly(key));
|
|
2916
3312
|
}
|
|
2917
3313
|
async getPageRoots() {
|
|
2918
|
-
const
|
|
3314
|
+
const akanConfig = await this.getConfig();
|
|
2919
3315
|
const pageDir = `${this.cwdPath}/page`;
|
|
2920
3316
|
const roots = [{ dir: pageDir, realDir: pageDir, keyPrefix: "" }];
|
|
2921
|
-
for (const parent of AppExecutor.#pageLibParents(
|
|
3317
|
+
for (const parent of AppExecutor.#pageLibParents(akanConfig.basePaths)) {
|
|
2922
3318
|
const libsDir = `${pageDir}/${parent}${AppExecutor.#pageLibsDir}`;
|
|
2923
3319
|
const entries = await readDirEntries(libsDir).catch(() => []);
|
|
2924
3320
|
for (const entry of entries.sort()) {
|
|
@@ -2939,9 +3335,9 @@ class AppExecutor extends SysExecutor {
|
|
|
2939
3335
|
return parents.length ? parents : [""];
|
|
2940
3336
|
}
|
|
2941
3337
|
async syncPages(libDeps) {
|
|
2942
|
-
const
|
|
2943
|
-
const parents = AppExecutor.#pageLibParents(
|
|
2944
|
-
const libs = await this.#resolvePageLibs(
|
|
3338
|
+
const akanConfig = await this.getConfig();
|
|
3339
|
+
const parents = AppExecutor.#pageLibParents(akanConfig.basePaths);
|
|
3340
|
+
const libs = await this.#resolvePageLibs(akanConfig.syncPageLibs, libDeps);
|
|
2945
3341
|
const linked = (await Promise.all(parents.map(async (parent) => {
|
|
2946
3342
|
const libsDir = `${this.cwdPath}/page/${parent}${AppExecutor.#pageLibsDir}`;
|
|
2947
3343
|
const entries = await readDirEntries(libsDir).catch(() => []);
|
|
@@ -2999,12 +3395,12 @@ class AppExecutor extends SysExecutor {
|
|
|
2999
3395
|
static async#linkLibAsset(targetPath, linkPath) {
|
|
3000
3396
|
const isWindows = process.platform === "win32";
|
|
3001
3397
|
try {
|
|
3002
|
-
const target = isWindows ? targetPath :
|
|
3398
|
+
const target = isWindows ? targetPath : path7.relative(path7.dirname(linkPath), targetPath);
|
|
3003
3399
|
await symlink(target, linkPath, isWindows ? "junction" : "dir");
|
|
3004
3400
|
} catch (error) {
|
|
3005
3401
|
if (!isWindows)
|
|
3006
3402
|
throw error;
|
|
3007
|
-
await
|
|
3403
|
+
await mkdir2(linkPath, { recursive: true });
|
|
3008
3404
|
await cpEntry(targetPath, linkPath, { recursive: true, dereference: true, force: true });
|
|
3009
3405
|
}
|
|
3010
3406
|
}
|
|
@@ -3041,7 +3437,7 @@ class AppExecutor extends SysExecutor {
|
|
|
3041
3437
|
await this.writeFile(rel, content, opts);
|
|
3042
3438
|
},
|
|
3043
3439
|
readEnvClient: async () => {
|
|
3044
|
-
const envClientPath =
|
|
3440
|
+
const envClientPath = path7.join(this.cwdPath, "env", "env.client.ts");
|
|
3045
3441
|
if (!await FileSys.fileExists(envClientPath))
|
|
3046
3442
|
return null;
|
|
3047
3443
|
try {
|
|
@@ -3100,9 +3496,9 @@ class LibExecutor extends SysExecutor {
|
|
|
3100
3496
|
}
|
|
3101
3497
|
static #execs = new Map;
|
|
3102
3498
|
static from(executor, name) {
|
|
3103
|
-
const
|
|
3104
|
-
if (
|
|
3105
|
-
return
|
|
3499
|
+
const exec = LibExecutor.#execs.get(name);
|
|
3500
|
+
if (exec)
|
|
3501
|
+
return exec;
|
|
3106
3502
|
else if (executor instanceof WorkspaceExecutor)
|
|
3107
3503
|
return new LibExecutor({ workspace: executor, name });
|
|
3108
3504
|
else
|
|
@@ -3151,7 +3547,7 @@ class PkgExecutor extends Executor {
|
|
|
3151
3547
|
return rootVersion;
|
|
3152
3548
|
try {
|
|
3153
3549
|
const packageJsonPath = `pkgs/${dep}/package.json`;
|
|
3154
|
-
if (!await Bun.file(
|
|
3550
|
+
if (!await Bun.file(path7.join(this.workspace.workspaceRoot, packageJsonPath)).exists())
|
|
3155
3551
|
return;
|
|
3156
3552
|
const packageJson = await this.workspace.readJson(packageJsonPath);
|
|
3157
3553
|
if (packageJson.name === dep)
|
|
@@ -3252,4 +3648,4 @@ class ModuleExecutor extends Executor {
|
|
|
3252
3648
|
}
|
|
3253
3649
|
}
|
|
3254
3650
|
|
|
3255
|
-
export { AGENT_BLOCK_START, AGENT_BLOCK_END, stampBlockVersion, extractBlockVersion, readDevkitVersion, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, CLAUDE_COMMENT_RULE, rootAllowedFiles, rootAllowedDirs, isAllowedLibFacetRootFile, isScannedRootEntry, AppInfo, CommandExecutionError, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
|
|
3651
|
+
export { AGENT_BLOCK_START, AGENT_BLOCK_END, stampBlockVersion, extractBlockVersion, readDevkitVersion, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, CLAUDE_COMMENT_RULE, AsyncDefaultExportDetector, resolveSsrPageEntriesForApp, rootAllowedFiles, rootAllowedDirs, isAllowedLibFacetRootFile, isScannedRootEntry, AppInfo, Spinner, CommandExecutionError, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
|