@akanjs/cli 3.0.0-alpha.85 → 3.0.0-alpha.86
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-gp3kwz7x.js → abstractCompactor-pwc6d6yk.js} +1 -2
- package/{agent.command-dzys24ee.js → agent.command-180hh0ye.js} +5 -7
- package/{application.command-m96rteme.js → application.command-v8dywdqh.js} +6 -8
- package/{applicationBuildRunner-d95dswfy.js → applicationBuildRunner-27wyznpv.js} +5 -6
- package/{applicationReleasePackager-3cnjss29.js → applicationReleasePackager-ktjt0erc.js} +1 -1
- package/buildBatch.proc.js +3 -5
- package/{capacitorApp-zrj7q1z4.js → capacitorApp-kwa67kzs.js} +2 -4
- package/{cloud.command-eng6hqd4.js → cloud.command-12k4wy4x.js} +10 -12
- package/{context.command-s96e60h6.js → context.command-dk2m2sjx.js} +13 -15
- package/{guideline.command-0raa8ng7.js → guideline.command-w6ddv13r.js} +3 -5
- package/guidelines/conventions/conventions.instruction.md +0 -9
- package/incrementalBuilder.proc.js +2 -4
- package/{index-ktnvnp7h.js → index-1kzsn94d.js} +1 -1
- package/{index-rna7cj75.js → index-5n0hf8r9.js} +3 -3
- package/{index-vfwdwq5c.js → index-5y7qba1c.js} +2 -2
- package/{index-fqwtcy9j.js → index-6c3ex9qw.js} +6 -6
- package/{index-ctphds8v.js → index-9wtbw98m.js} +5 -2
- package/{index-yagad3ht.js → index-a6c5pc4p.js} +9 -9
- package/{index-cnfawb2y.js → index-a8h184wr.js} +2 -2
- package/{index-1q83gs77.js → index-b2nt0w0k.js} +1 -1
- package/{index-nr8w8h7y.js → index-cd5x18qh.js} +4 -4
- package/{index-ktkm3ht3.js → index-dq6wq1tv.js} +10 -10
- package/{index-n0x82fhs.js → index-ft1sfjz0.js} +1 -1
- package/{index-q2xqmbcq.js → index-gz0c482j.js} +8 -8
- package/{index-y429w5m5.js → index-j9vnq8tr.js} +3 -3
- package/{index-c6rfvayh.js → index-k1n0h7dk.js} +472 -73
- package/{index-azkj85kx.js → index-k86zc21w.js} +7 -7
- package/{index-sc7s8927.js → index-m9c7k0gm.js} +1 -1
- package/{index-aknp5f6x.js → index-qcracvc9.js} +3 -3
- package/{index-md3wv29p.js → index-saheq2bs.js} +1 -1
- package/{index-nf4zam3r.js → index-v0s24t8j.js} +3 -3
- package/{index-mr9b7nkd.js → index-wet2ytnr.js} +1 -1
- package/{index-zp8y6zbb.js → index-xxe90kqy.js} +2 -2
- package/{index-7vvqsanf.js → index-z3c9mmw4.js} +1 -1
- package/index.js +19 -21
- package/{library.command-9cv75y0z.js → library.command-wpedct6c.js} +3 -5
- package/{localRegistry.command-csgtnbb1.js → localRegistry.command-3cew8f75.js} +9 -11
- package/{module.command-jafd05sa.js → module.command-8n4kct3e.js} +6 -8
- package/{package.command-1kmswspp.js → package.command-fcbd0b1d.js} +3 -5
- package/package.json +2 -2
- package/{page.command-p186hd45.js → page.command-x4379grq.js} +3 -5
- package/{primitive.command-a5w19jdg.js → primitive.command-8etmnqhq.js} +7 -9
- package/{quality.command-gcxmxqss.js → quality.command-hfx7z8yr.js} +2 -4
- package/{repair.command-z642bc2h.js → repair.command-j0fs5qkz.js} +5 -7
- package/{scalar.command-9hgcdztr.js → scalar.command-2emk89eh.js} +5 -7
- package/{subspace.command-9x4nhzn2.js → subspace.command-nr32nm35.js} +3 -5
- package/templates/workspaceRoot/.gitignore.template +1 -2
- package/templates/workspaceRoot/.husky/pre-commit.template +1 -6
- package/templates/workspaceRoot/.vscode/settings.json.template +1 -1
- package/{workflow.command-camcqd0s.js → workflow.command-cvpmzwjg.js} +10 -12
- package/{workspace.command-n1nvp28s.js → workspace.command-rqnms515.js} +50 -91
- package/index-5es51p0n.js +0 -66
- package/index-7nr23j55.js +0 -344
|
@@ -1,17 +1,74 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
getRootBoundarySegments,
|
|
4
|
-
isRootBoundarySegments
|
|
5
|
-
} from "./index-7nr23j55.js";
|
|
6
2
|
import {
|
|
7
3
|
FileSys
|
|
8
4
|
} from "./index-ayy5ecax.js";
|
|
9
5
|
import {
|
|
10
6
|
getDirname2
|
|
11
7
|
} from "./index-6wwzs1bc.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
+
}
|
|
15
72
|
|
|
16
73
|
// pkgs/@akanjs/devkit/executors.ts
|
|
17
74
|
import {
|
|
@@ -23,14 +80,14 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
23
80
|
import {
|
|
24
81
|
copyFile,
|
|
25
82
|
cp as cpEntry,
|
|
26
|
-
mkdir,
|
|
83
|
+
mkdir as mkdir2,
|
|
27
84
|
readdir as readDirEntries,
|
|
28
85
|
realpath,
|
|
29
86
|
rm as rm2,
|
|
30
87
|
stat,
|
|
31
88
|
symlink
|
|
32
89
|
} from "fs/promises";
|
|
33
|
-
import
|
|
90
|
+
import path7 from "path";
|
|
34
91
|
import { pathToFileURL } from "url";
|
|
35
92
|
import {
|
|
36
93
|
capitalize,
|
|
@@ -712,10 +769,352 @@ var decreaseBuildNum = async (app) => {
|
|
|
712
769
|
const akanConfigContent = akanConfig.replace(`buildNum: ${appConfig.mobile.buildNum}`, `buildNum: ${appConfig.mobile.buildNum - 1}`);
|
|
713
770
|
fs.writeFileSync(akanConfigPath, akanConfigContent);
|
|
714
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
|
+
|
|
715
1114
|
// pkgs/@akanjs/devkit/linter.ts
|
|
716
1115
|
import { spawn } from "child_process";
|
|
717
1116
|
import { existsSync, readFileSync } from "fs";
|
|
718
|
-
import
|
|
1117
|
+
import path4 from "path";
|
|
719
1118
|
import chalk from "chalk";
|
|
720
1119
|
var parseBiomeReport = (output) => {
|
|
721
1120
|
for (let start = output.indexOf("{");start !== -1; start = output.indexOf("{", start + 1)) {
|
|
@@ -772,13 +1171,13 @@ class Linter {
|
|
|
772
1171
|
#biomeBin;
|
|
773
1172
|
constructor(cwdPath) {
|
|
774
1173
|
this.lintRoot = this.#findBiomeRootPath(cwdPath);
|
|
775
|
-
this.configPath = Linter.#configPathIn(this.lintRoot) ??
|
|
776
|
-
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");
|
|
777
1176
|
this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
|
|
778
1177
|
}
|
|
779
1178
|
static #configPathIn(dir) {
|
|
780
1179
|
for (const fileName of BIOME_CONFIG_FILES) {
|
|
781
|
-
const configPath =
|
|
1180
|
+
const configPath = path4.join(dir, fileName);
|
|
782
1181
|
if (existsSync(configPath))
|
|
783
1182
|
return configPath;
|
|
784
1183
|
}
|
|
@@ -787,19 +1186,19 @@ class Linter {
|
|
|
787
1186
|
#findBiomeRootPath(dir) {
|
|
788
1187
|
if (Linter.#configPathIn(dir))
|
|
789
1188
|
return dir;
|
|
790
|
-
const parentDir =
|
|
1189
|
+
const parentDir = path4.dirname(dir);
|
|
791
1190
|
if (parentDir === dir)
|
|
792
1191
|
throw new Error(`biome.json not found from ${dir}`);
|
|
793
1192
|
return this.#findBiomeRootPath(parentDir);
|
|
794
1193
|
}
|
|
795
1194
|
#toBiomePath(filePath) {
|
|
796
|
-
const relativePath =
|
|
797
|
-
if (!relativePath.startsWith("..") && !
|
|
1195
|
+
const relativePath = path4.relative(this.lintRoot, filePath);
|
|
1196
|
+
if (!relativePath.startsWith("..") && !path4.isAbsolute(relativePath))
|
|
798
1197
|
return relativePath;
|
|
799
1198
|
return filePath;
|
|
800
1199
|
}
|
|
801
1200
|
#resolveFilePath(filePath) {
|
|
802
|
-
return
|
|
1201
|
+
return path4.isAbsolute(filePath) ? filePath : path4.join(this.lintRoot, filePath);
|
|
803
1202
|
}
|
|
804
1203
|
async#runBiome(args, input) {
|
|
805
1204
|
return await new Promise((resolve, reject) => {
|
|
@@ -824,7 +1223,7 @@ class Linter {
|
|
|
824
1223
|
const diagnosticPath = diagnostic.location?.path;
|
|
825
1224
|
if (!diagnosticPath)
|
|
826
1225
|
return fallbackFilePath;
|
|
827
|
-
return
|
|
1226
|
+
return path4.isAbsolute(diagnosticPath) ? diagnosticPath : path4.join(this.lintRoot, diagnosticPath);
|
|
828
1227
|
}
|
|
829
1228
|
#createLintMessage(diagnostic) {
|
|
830
1229
|
const start = diagnostic.location?.start;
|
|
@@ -1054,7 +1453,7 @@ ${errorText}, ${warningText} found`];
|
|
|
1054
1453
|
|
|
1055
1454
|
// pkgs/@akanjs/devkit/repoIdentity.ts
|
|
1056
1455
|
import { execFileSync } from "child_process";
|
|
1057
|
-
import
|
|
1456
|
+
import path5 from "path";
|
|
1058
1457
|
var resolved = new Map;
|
|
1059
1458
|
var readRemoteName = (workspaceRoot) => {
|
|
1060
1459
|
try {
|
|
@@ -1072,14 +1471,14 @@ var resolveRepoName = (workspaceRoot) => {
|
|
|
1072
1471
|
const cached = resolved.get(workspaceRoot);
|
|
1073
1472
|
if (cached)
|
|
1074
1473
|
return cached;
|
|
1075
|
-
const repoName = readRemoteName(workspaceRoot) ??
|
|
1474
|
+
const repoName = readRemoteName(workspaceRoot) ?? path5.basename(workspaceRoot);
|
|
1076
1475
|
resolved.set(workspaceRoot, repoName);
|
|
1077
1476
|
return repoName;
|
|
1078
1477
|
};
|
|
1079
1478
|
|
|
1080
1479
|
// pkgs/@akanjs/devkit/scanInfo.ts
|
|
1081
1480
|
import { rm } from "fs/promises";
|
|
1082
|
-
import
|
|
1481
|
+
import path6 from "path";
|
|
1083
1482
|
|
|
1084
1483
|
// pkgs/@akanjs/devkit/workspaceLayout.ts
|
|
1085
1484
|
var appRootAllowedFiles = new Set([
|
|
@@ -1185,14 +1584,14 @@ var moduleUiFileTypes = {
|
|
|
1185
1584
|
var testFilePattern = /\.(test|spec)\.(ts|tsx)$/;
|
|
1186
1585
|
var createDependencyScanner = async (exec) => (await import("./dependencyScanner-c64m6fxp.js")).TypeScriptDependencyScanner.from(exec);
|
|
1187
1586
|
var isAllowedTestFile = (filename) => testFilePattern.test(filename);
|
|
1188
|
-
var getScanPath = (exec, relativePath) =>
|
|
1587
|
+
var getScanPath = (exec, relativePath) => path6.posix.join(`${exec.type}s`, exec.name, relativePath.split(path6.sep).join("/"));
|
|
1189
1588
|
async function clearGeneratedRootCapacitorConfigs(exec) {
|
|
1190
1589
|
if (exec.type !== "app")
|
|
1191
1590
|
return;
|
|
1192
1591
|
await Promise.all(generatedRootCapacitorConfigFiles.map((filename) => rm(exec.getPath(filename), { force: true })));
|
|
1193
1592
|
}
|
|
1194
1593
|
var getModuleNameFromPath = (kind, modulePath) => {
|
|
1195
|
-
const dirname =
|
|
1594
|
+
const dirname = path6.basename(modulePath);
|
|
1196
1595
|
return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
|
|
1197
1596
|
};
|
|
1198
1597
|
async function assertScanConvention(exec, libRoot) {
|
|
@@ -1214,18 +1613,18 @@ async function assertScanConvention(exec, libRoot) {
|
|
|
1214
1613
|
for (const { relativePath, reason } of await exec.getPageConventionViolations())
|
|
1215
1614
|
addViolation(relativePath, reason);
|
|
1216
1615
|
libRoot.files.filter((filename) => !isAllowedLibFacetRootFile(filename)).forEach((filename) => {
|
|
1217
|
-
addViolation(
|
|
1616
|
+
addViolation(path6.join("lib", filename), "unsupported lib facet root file");
|
|
1218
1617
|
});
|
|
1219
1618
|
libRoot.dirs.filter((dirname) => dirname.startsWith("__") && !internalLibDirs.has(dirname)).forEach((dirname) => {
|
|
1220
|
-
addViolation(
|
|
1619
|
+
addViolation(path6.join("lib", dirname), "unsupported internal lib folder");
|
|
1221
1620
|
});
|
|
1222
1621
|
const databaseDirs = libRoot.dirs.filter((dirname) => !dirname.startsWith("_"));
|
|
1223
1622
|
const serviceDirs = libRoot.dirs.filter((dirname) => dirname.startsWith("_") && !dirname.startsWith("__"));
|
|
1224
1623
|
const scalarDirs = await exec.readdir("lib/__scalar");
|
|
1225
1624
|
await Promise.all([
|
|
1226
|
-
...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database",
|
|
1227
|
-
...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service",
|
|
1228
|
-
...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)))
|
|
1229
1628
|
]);
|
|
1230
1629
|
if (violations.length > 0) {
|
|
1231
1630
|
throw new Error(`[scan-convention]
|
|
@@ -1237,11 +1636,11 @@ async function validateModuleFiles(exec, violations, kind, modulePath) {
|
|
|
1237
1636
|
const { files, dirs } = await exec.getFilesAndDirs(modulePath);
|
|
1238
1637
|
const moduleName = getModuleNameFromPath(kind, modulePath);
|
|
1239
1638
|
dirs.forEach((dirname) => {
|
|
1240
|
-
violations.push(`${getScanPath(exec,
|
|
1639
|
+
violations.push(`${getScanPath(exec, path6.join(modulePath, dirname))}: unsupported module folder`);
|
|
1241
1640
|
});
|
|
1242
1641
|
const uiModuleName = moduleName[0].toUpperCase() + moduleName.slice(1);
|
|
1243
1642
|
files.forEach((filename) => {
|
|
1244
|
-
const filePath =
|
|
1643
|
+
const filePath = path6.join(modulePath, filename);
|
|
1245
1644
|
if (filename === "index.ts" || filename === "index.tsx" || isAllowedTestFile(filename))
|
|
1246
1645
|
return;
|
|
1247
1646
|
if (filename === `${moduleName}.abstract.md`)
|
|
@@ -1321,7 +1720,7 @@ class ScanInfo {
|
|
|
1321
1720
|
});
|
|
1322
1721
|
await Promise.all([
|
|
1323
1722
|
...databaseDirs.map(async (name) => {
|
|
1324
|
-
const filenames = await exec.readdir(
|
|
1723
|
+
const filenames = await exec.readdir(path6.join("lib", name));
|
|
1325
1724
|
filenames.forEach((filename) => {
|
|
1326
1725
|
if (filename.endsWith(".constant.ts"))
|
|
1327
1726
|
files.constant.databases.push(name);
|
|
@@ -1349,7 +1748,7 @@ class ScanInfo {
|
|
|
1349
1748
|
}),
|
|
1350
1749
|
...serviceDirs.map(async (dirname) => {
|
|
1351
1750
|
const name = dirname.slice(1);
|
|
1352
|
-
const filenames = await exec.readdir(
|
|
1751
|
+
const filenames = await exec.readdir(path6.join("lib", dirname));
|
|
1353
1752
|
filenames.forEach((filename) => {
|
|
1354
1753
|
if (filename.endsWith(".dictionary.ts"))
|
|
1355
1754
|
files.dictionary.services.push(name);
|
|
@@ -1372,7 +1771,7 @@ class ScanInfo {
|
|
|
1372
1771
|
});
|
|
1373
1772
|
}),
|
|
1374
1773
|
...scalarDirs.map(async (name) => {
|
|
1375
|
-
const filenames = await exec.readdir(
|
|
1774
|
+
const filenames = await exec.readdir(path6.join("lib/__scalar", name));
|
|
1376
1775
|
filenames.forEach((filename) => {
|
|
1377
1776
|
if (filename.endsWith(".constant.ts"))
|
|
1378
1777
|
files.constant.scalars.push(name);
|
|
@@ -1398,7 +1797,7 @@ class ScanInfo {
|
|
|
1398
1797
|
name: exec.name,
|
|
1399
1798
|
type: exec.type,
|
|
1400
1799
|
repoName: exec.workspace.repoName,
|
|
1401
|
-
serveDomain: WorkspaceExecutor.getBaseDevEnv(
|
|
1800
|
+
serveDomain: WorkspaceExecutor.getBaseDevEnv(path6.join(exec.workspace.workspaceRoot, ".env")).serveDomain,
|
|
1402
1801
|
files,
|
|
1403
1802
|
libDeps,
|
|
1404
1803
|
pkgDeps,
|
|
@@ -1946,10 +2345,10 @@ class Executor {
|
|
|
1946
2345
|
});
|
|
1947
2346
|
}
|
|
1948
2347
|
getPath(filePath) {
|
|
1949
|
-
if (
|
|
2348
|
+
if (path7.isAbsolute(filePath))
|
|
1950
2349
|
return filePath;
|
|
1951
2350
|
if (filePath.startsWith("."))
|
|
1952
|
-
return
|
|
2351
|
+
return path7.join(this.cwdPath, filePath);
|
|
1953
2352
|
const baseParts = this.cwdPath.split(/[\\/]/).filter(Boolean);
|
|
1954
2353
|
const targetParts = filePath.split(/[\\/]/).filter(Boolean);
|
|
1955
2354
|
let overlapLength = 0;
|
|
@@ -1963,12 +2362,12 @@ class Executor {
|
|
|
1963
2362
|
if (isOverlap)
|
|
1964
2363
|
overlapLength = i;
|
|
1965
2364
|
}
|
|
1966
|
-
return
|
|
2365
|
+
return path7.join(this.cwdPath, ...targetParts.slice(overlapLength));
|
|
1967
2366
|
}
|
|
1968
2367
|
async mkdir(dirPath) {
|
|
1969
2368
|
const writePath = this.getPath(dirPath);
|
|
1970
2369
|
if (!await FileSys.dirExists(writePath))
|
|
1971
|
-
await
|
|
2370
|
+
await mkdir2(writePath, { recursive: true });
|
|
1972
2371
|
this.logger.verbose(`Make directory ${writePath}`);
|
|
1973
2372
|
return this;
|
|
1974
2373
|
}
|
|
@@ -2006,7 +2405,7 @@ class Executor {
|
|
|
2006
2405
|
return this;
|
|
2007
2406
|
}
|
|
2008
2407
|
async removeDir(dirPath) {
|
|
2009
|
-
const readPath =
|
|
2408
|
+
const readPath = path7.join(this.getPath(dirPath), ".");
|
|
2010
2409
|
if (await FileSys.entryExists(readPath))
|
|
2011
2410
|
await rm2(readPath, { recursive: true, force: true });
|
|
2012
2411
|
this.logger.verbose(`Remove directory ${readPath}`);
|
|
@@ -2014,9 +2413,9 @@ class Executor {
|
|
|
2014
2413
|
}
|
|
2015
2414
|
async writeFile(filePath, content, { overwrite = true, silent = false } = {}) {
|
|
2016
2415
|
const writePath = this.getPath(filePath);
|
|
2017
|
-
const dir =
|
|
2416
|
+
const dir = path7.dirname(writePath);
|
|
2018
2417
|
if (!await FileSys.dirExists(dir))
|
|
2019
|
-
await
|
|
2418
|
+
await mkdir2(dir, { recursive: true });
|
|
2020
2419
|
let contentStr = typeof content === "string" ? content : `${JSON.stringify(content, null, 2)}
|
|
2021
2420
|
`;
|
|
2022
2421
|
if (await FileSys.fileExists(writePath)) {
|
|
@@ -2040,7 +2439,7 @@ class Executor {
|
|
|
2040
2439
|
await this.writeFile(filePath, content);
|
|
2041
2440
|
}
|
|
2042
2441
|
async getLocalFile(targetPath) {
|
|
2043
|
-
const filePath =
|
|
2442
|
+
const filePath = path7.isAbsolute(targetPath) ? targetPath : targetPath.replace(this.cwdPath, "");
|
|
2044
2443
|
const content = await this.readFile(filePath);
|
|
2045
2444
|
return { filePath, content };
|
|
2046
2445
|
}
|
|
@@ -2059,7 +2458,7 @@ class Executor {
|
|
|
2059
2458
|
return;
|
|
2060
2459
|
const isDirectory = (await stat(src)).isDirectory();
|
|
2061
2460
|
if (!await FileSys.exists(dest) && isDirectory)
|
|
2062
|
-
await
|
|
2461
|
+
await mkdir2(dest, { recursive: true });
|
|
2063
2462
|
if (dereference)
|
|
2064
2463
|
await cpEntry(src, dest, { recursive: isDirectory, dereference: true, force: true });
|
|
2065
2464
|
else
|
|
@@ -2137,9 +2536,9 @@ class Executor {
|
|
|
2137
2536
|
const result = await getContent.default(scanInfo ?? null, dict, options);
|
|
2138
2537
|
if (result === null)
|
|
2139
2538
|
return null;
|
|
2140
|
-
const filename = typeof result === "object" ? result.filename :
|
|
2539
|
+
const filename = typeof result === "object" ? result.filename : path7.basename(targetPath).replace(".js", ".ts");
|
|
2141
2540
|
const content = typeof result === "object" ? result.content : result;
|
|
2142
|
-
const dirname =
|
|
2541
|
+
const dirname = path7.dirname(targetPath);
|
|
2143
2542
|
const convertedTargetPath = Object.entries(dict).reduce((path, [key, value]) => path.replace(new RegExp(`__${key}__`, "g"), value), `${dirname}/${filename}`);
|
|
2144
2543
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2145
2544
|
return this.writeFile(convertedTargetPath, content, { overwrite });
|
|
@@ -2151,12 +2550,12 @@ class Executor {
|
|
|
2151
2550
|
return this.writeFile(convertedTargetPath, convertedContent, {
|
|
2152
2551
|
overwrite
|
|
2153
2552
|
});
|
|
2154
|
-
} else if (staticTemplateFileExtensions.has(
|
|
2553
|
+
} else if (staticTemplateFileExtensions.has(path7.extname(targetPath).toLowerCase())) {
|
|
2155
2554
|
const convertedTargetPath = Object.entries(dict).reduce((path, [key, value]) => path.replace(new RegExp(`__${key}__`, "g"), value), targetPath);
|
|
2156
2555
|
const writePath = this.getPath(convertedTargetPath);
|
|
2157
|
-
const dirname =
|
|
2556
|
+
const dirname = path7.dirname(writePath);
|
|
2158
2557
|
if (!await FileSys.dirExists(dirname))
|
|
2159
|
-
await
|
|
2558
|
+
await mkdir2(dirname, { recursive: true });
|
|
2160
2559
|
await copyFile(templatePath, writePath);
|
|
2161
2560
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2162
2561
|
return { filePath: writePath, content: "" };
|
|
@@ -2175,10 +2574,10 @@ class Executor {
|
|
|
2175
2574
|
const templatePath = `${templateRoot}${template ? `/${template}` : ""}`;
|
|
2176
2575
|
const prefixTemplatePath = templatePath;
|
|
2177
2576
|
if ((await stat(prefixTemplatePath)).isFile()) {
|
|
2178
|
-
const filename =
|
|
2577
|
+
const filename = path7.basename(prefixTemplatePath);
|
|
2179
2578
|
const fileContent = await this.#applyTemplateFile({
|
|
2180
2579
|
templatePath: prefixTemplatePath,
|
|
2181
|
-
targetPath:
|
|
2580
|
+
targetPath: path7.join(basePath, filename),
|
|
2182
2581
|
scanInfo,
|
|
2183
2582
|
overwrite
|
|
2184
2583
|
}, dict, options);
|
|
@@ -2186,19 +2585,19 @@ class Executor {
|
|
|
2186
2585
|
} else {
|
|
2187
2586
|
const subdirs = await readDirEntries(templatePath);
|
|
2188
2587
|
const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
|
|
2189
|
-
const subpath =
|
|
2588
|
+
const subpath = path7.join(templatePath, subdir);
|
|
2190
2589
|
if ((await stat(subpath)).isFile()) {
|
|
2191
2590
|
const fileContent = await this.#applyTemplateFile({
|
|
2192
2591
|
templatePath: subpath,
|
|
2193
|
-
targetPath:
|
|
2592
|
+
targetPath: path7.join(basePath, subdir),
|
|
2194
2593
|
scanInfo,
|
|
2195
2594
|
overwrite
|
|
2196
2595
|
}, dict, options);
|
|
2197
2596
|
return fileContent ? [fileContent] : [];
|
|
2198
2597
|
} else
|
|
2199
2598
|
return await this._applyTemplate({
|
|
2200
|
-
basePath:
|
|
2201
|
-
template:
|
|
2599
|
+
basePath: path7.join(basePath, subdir),
|
|
2600
|
+
template: path7.join(template, subdir),
|
|
2202
2601
|
scanInfo,
|
|
2203
2602
|
dict,
|
|
2204
2603
|
overwrite,
|
|
@@ -2210,8 +2609,8 @@ class Executor {
|
|
|
2210
2609
|
}
|
|
2211
2610
|
async#resolveTemplateRoot() {
|
|
2212
2611
|
const candidates = [
|
|
2213
|
-
|
|
2214
|
-
|
|
2612
|
+
path7.resolve(getDirname2(import.meta.url), "templates"),
|
|
2613
|
+
path7.resolve(getDirname2(import.meta.url), "../cli/templates")
|
|
2215
2614
|
];
|
|
2216
2615
|
for (const candidate of candidates) {
|
|
2217
2616
|
if (await FileSys.dirExists(candidate))
|
|
@@ -2283,11 +2682,11 @@ class Executor {
|
|
|
2283
2682
|
async#resolveTypecheckWorkerEntry() {
|
|
2284
2683
|
const dirname = getDirname2(import.meta.url);
|
|
2285
2684
|
const candidates = [
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
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")
|
|
2291
2690
|
];
|
|
2292
2691
|
for (const candidate of candidates)
|
|
2293
2692
|
if (await Bun.file(candidate).exists())
|
|
@@ -2414,7 +2813,7 @@ class WorkspaceExecutor extends Executor {
|
|
|
2414
2813
|
await Promise.all(dirs.map(async (dir) => {
|
|
2415
2814
|
if (dir.includes("_") || AVOID_DIRS.includes(dir))
|
|
2416
2815
|
return;
|
|
2417
|
-
const dirPath =
|
|
2816
|
+
const dirPath = path7.join(dirname, dir);
|
|
2418
2817
|
if ((await stat(dirPath)).isDirectory()) {
|
|
2419
2818
|
results.push(`${prefix}${dir}`);
|
|
2420
2819
|
if (maxDepth > 0)
|
|
@@ -2449,9 +2848,9 @@ class WorkspaceExecutor extends Executor {
|
|
|
2449
2848
|
await Promise.all(dirs.map(async (dir) => {
|
|
2450
2849
|
if (AVOID_DIRS.includes(dir))
|
|
2451
2850
|
return;
|
|
2452
|
-
const dirPath =
|
|
2851
|
+
const dirPath = path7.join(dirname, dir);
|
|
2453
2852
|
if (await FileSys.dirExists(dirPath)) {
|
|
2454
|
-
const hasTargetFile = await FileSys.fileExists(
|
|
2853
|
+
const hasTargetFile = await FileSys.fileExists(path7.join(dirPath, targetFilename));
|
|
2455
2854
|
if (hasTargetFile)
|
|
2456
2855
|
results.push(`${prefix}${dir}`);
|
|
2457
2856
|
if (maxDepth > 0)
|
|
@@ -2525,7 +2924,7 @@ class SysExecutor extends Executor {
|
|
|
2525
2924
|
return [];
|
|
2526
2925
|
const violations = [];
|
|
2527
2926
|
for (const entry of await this.getAllFiles("**/*", { cwd: this.getPath("page") })) {
|
|
2528
|
-
const relativePath = entry.split(
|
|
2927
|
+
const relativePath = entry.split(path7.sep).join("/");
|
|
2529
2928
|
const reason = getPageSourceFileViolation(relativePath);
|
|
2530
2929
|
if (reason)
|
|
2531
2930
|
violations.push({ relativePath: `page/${relativePath}`, reason });
|
|
@@ -2634,7 +3033,7 @@ class SysExecutor extends Executor {
|
|
|
2634
3033
|
await this.setPackageJson(libPkgJsonWithDeps);
|
|
2635
3034
|
}
|
|
2636
3035
|
async getLocalFile(targetPath) {
|
|
2637
|
-
const filePath =
|
|
3036
|
+
const filePath = path7.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
|
|
2638
3037
|
const content = await this.workspace.readFile(filePath);
|
|
2639
3038
|
return { filePath, content };
|
|
2640
3039
|
}
|
|
@@ -2853,11 +3252,11 @@ class AppExecutor extends SysExecutor {
|
|
|
2853
3252
|
absolute: false,
|
|
2854
3253
|
onlyFiles: true
|
|
2855
3254
|
})) {
|
|
2856
|
-
const segments = rel.split(
|
|
3255
|
+
const segments = rel.split(path7.sep);
|
|
2857
3256
|
if (segments.some((s) => s === "node_modules"))
|
|
2858
3257
|
continue;
|
|
2859
3258
|
const posix = `${root.keyPrefix}${segments.join("/")}`;
|
|
2860
|
-
const absPath =
|
|
3259
|
+
const absPath = path7.join(root.dir, ...segments);
|
|
2861
3260
|
validatePageSourceFile(posix, { filePath: absPath });
|
|
2862
3261
|
if (!isRouteSourceFile(posix))
|
|
2863
3262
|
continue;
|
|
@@ -2996,12 +3395,12 @@ class AppExecutor extends SysExecutor {
|
|
|
2996
3395
|
static async#linkLibAsset(targetPath, linkPath) {
|
|
2997
3396
|
const isWindows = process.platform === "win32";
|
|
2998
3397
|
try {
|
|
2999
|
-
const target = isWindows ? targetPath :
|
|
3398
|
+
const target = isWindows ? targetPath : path7.relative(path7.dirname(linkPath), targetPath);
|
|
3000
3399
|
await symlink(target, linkPath, isWindows ? "junction" : "dir");
|
|
3001
3400
|
} catch (error) {
|
|
3002
3401
|
if (!isWindows)
|
|
3003
3402
|
throw error;
|
|
3004
|
-
await
|
|
3403
|
+
await mkdir2(linkPath, { recursive: true });
|
|
3005
3404
|
await cpEntry(targetPath, linkPath, { recursive: true, dereference: true, force: true });
|
|
3006
3405
|
}
|
|
3007
3406
|
}
|
|
@@ -3038,7 +3437,7 @@ class AppExecutor extends SysExecutor {
|
|
|
3038
3437
|
await this.writeFile(rel, content, opts);
|
|
3039
3438
|
},
|
|
3040
3439
|
readEnvClient: async () => {
|
|
3041
|
-
const envClientPath =
|
|
3440
|
+
const envClientPath = path7.join(this.cwdPath, "env", "env.client.ts");
|
|
3042
3441
|
if (!await FileSys.fileExists(envClientPath))
|
|
3043
3442
|
return null;
|
|
3044
3443
|
try {
|
|
@@ -3148,7 +3547,7 @@ class PkgExecutor extends Executor {
|
|
|
3148
3547
|
return rootVersion;
|
|
3149
3548
|
try {
|
|
3150
3549
|
const packageJsonPath = `pkgs/${dep}/package.json`;
|
|
3151
|
-
if (!await Bun.file(
|
|
3550
|
+
if (!await Bun.file(path7.join(this.workspace.workspaceRoot, packageJsonPath)).exists())
|
|
3152
3551
|
return;
|
|
3153
3552
|
const packageJson = await this.workspace.readJson(packageJsonPath);
|
|
3154
3553
|
if (packageJson.name === dep)
|
|
@@ -3249,4 +3648,4 @@ class ModuleExecutor extends Executor {
|
|
|
3249
3648
|
}
|
|
3250
3649
|
}
|
|
3251
3650
|
|
|
3252
|
-
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 };
|