lecodes-cli 2.4.8 → 2.4.10
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/README.md +2 -3
- package/dist/index.js +1072 -832
- package/package.json +10 -10
- package/runtime/materials/lightmap.mat +4 -0
- package/runtime/materials/lit.mat +27 -0
- package/runtime/sdk-types.json +1 -1
- package/runtime/web/VERSION.json +3 -3
- package/runtime/web/assets/materials-CJzxzdUK.bin +0 -0
- package/runtime/web/assets/materials-world-BNQb0Z1l.bin +0 -0
- package/runtime/web/player.js +3 -3
- package/runtime/web-lite/assets/{index-Bd7pdF7u.js → index-e-m97P8Y.js} +1 -1
- package/runtime/web-lite/assets/{scene3d-DXpVYhGy.js → scene3d-NxtMMpHd.js} +23 -16
- package/runtime/web-lite/features.json +2 -2
- package/runtime/web-lite/lite.js +2 -2
- package/src/commands/compile.ts +13 -4
- package/src/commands/init/templates.ts +3 -2
- package/src/commands/lightmap.ts +101 -83
- package/src/compile/projectCompile.ts +23 -5
- package/src/compile/sceneCompile.ts +3 -2
- package/src/hosts/peerInstall.ts +19 -3
- package/runtime/web/assets/materials-BzTsWTWO.bin +0 -0
- package/runtime/web/assets/materials-world-aKwAWYRd.bin +0 -0
package/dist/index.js
CHANGED
|
@@ -64,7 +64,7 @@ var package_default;
|
|
|
64
64
|
var init_package = __esm(() => {
|
|
65
65
|
package_default = {
|
|
66
66
|
name: "lecodes-cli",
|
|
67
|
-
version: "2.4.
|
|
67
|
+
version: "2.4.10",
|
|
68
68
|
dependencies: {
|
|
69
69
|
"@letary/chisel": "^0.15.0",
|
|
70
70
|
jimp: "^1.6.1",
|
|
@@ -89,9 +89,9 @@ var init_package = __esm(() => {
|
|
|
89
89
|
},
|
|
90
90
|
peerDependencies: {
|
|
91
91
|
"lecodes-design": "^0.11.0",
|
|
92
|
-
"lecodes-headless": "^2.4.
|
|
92
|
+
"lecodes-headless": "^2.4.10",
|
|
93
93
|
"lecodes-3d-editor": "^0.9.0",
|
|
94
|
-
"lecodes-assets": "^
|
|
94
|
+
"lecodes-assets": "^2.4.10",
|
|
95
95
|
"heic-decode": "^2.1.0",
|
|
96
96
|
"marcidb-embedded": "^0.15.0",
|
|
97
97
|
sharp: "^0.35.2",
|
|
@@ -159,7 +159,7 @@ var init_package = __esm(() => {
|
|
|
159
159
|
});
|
|
160
160
|
|
|
161
161
|
// ../../sdk/src/version.ts
|
|
162
|
-
var SDK_VERSION = "2.4.
|
|
162
|
+
var SDK_VERSION = "2.4.10";
|
|
163
163
|
|
|
164
164
|
// src/cli/args.ts
|
|
165
165
|
var isNegativeNumber = (s) => /^-(\d|\.\d)/.test(s), isValue = (s) => !s.startsWith("-") || isNegativeNumber(s), parseArgv = (argv, booleans = new Set) => {
|
|
@@ -651,6 +651,94 @@ var init_peers = __esm(() => {
|
|
|
651
651
|
];
|
|
652
652
|
});
|
|
653
653
|
|
|
654
|
+
// src/hosts/releases.ts
|
|
655
|
+
import { createHash } from "node:crypto";
|
|
656
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, mkdtempSync, readFileSync as readFileSync3, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
657
|
+
import { join as join4 } from "node:path";
|
|
658
|
+
import { spawnSync } from "node:child_process";
|
|
659
|
+
var MANIFEST_URL = "https://storage.yandexcloud.net/le-codes/releases/versions.json", ARTIFACT_STAMP = ".lecodes-artifact.json", cachedArtifactSha = (dir) => {
|
|
660
|
+
try {
|
|
661
|
+
return JSON.parse(readFileSync3(join4(dir, ARTIFACT_STAMP), "utf8")).sha256 ?? null;
|
|
662
|
+
} catch {
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
}, macPlatformKey = () => process.arch === "arm64" ? "macos-arm64" : "macos-x64", semverNewer = (a, b) => {
|
|
666
|
+
const pa = a.split(/[.-]/).map(Number), pb = b.split(/[.-]/).map(Number);
|
|
667
|
+
for (let i = 0;i < 3; i++)
|
|
668
|
+
if ((pb[i] ?? 0) !== (pa[i] ?? 0))
|
|
669
|
+
return (pb[i] ?? 0) - (pa[i] ?? 0);
|
|
670
|
+
return 0;
|
|
671
|
+
}, newestForPlatform = (versions, key) => {
|
|
672
|
+
const carrying = versions.filter((v) => v.files[key]).sort((a, b) => semverNewer(a.version, b.version));
|
|
673
|
+
const newest = carrying[0];
|
|
674
|
+
return newest ? { version: newest.version, file: newest.files[key] } : null;
|
|
675
|
+
}, fetchReleaseProduct = async (product, label) => {
|
|
676
|
+
let manifest;
|
|
677
|
+
try {
|
|
678
|
+
const res = await fetch(MANIFEST_URL);
|
|
679
|
+
if (!res.ok)
|
|
680
|
+
throw new Error(`HTTP ${res.status}`);
|
|
681
|
+
manifest = await res.json();
|
|
682
|
+
} catch (e) {
|
|
683
|
+
throw new CliError(`Can't fetch the release manifest (${MANIFEST_URL}): ${e instanceof Error ? e.message : String(e)}`);
|
|
684
|
+
}
|
|
685
|
+
const entry = manifest.products?.[product];
|
|
686
|
+
if (!entry)
|
|
687
|
+
throw new CliError(`The release manifest has no ${label} product.`);
|
|
688
|
+
return entry;
|
|
689
|
+
}, downloadReleaseArchive = async (file, opts) => {
|
|
690
|
+
let bytes;
|
|
691
|
+
try {
|
|
692
|
+
const res = await fetch(file.url);
|
|
693
|
+
if (!res.ok)
|
|
694
|
+
throw new Error(`HTTP ${res.status}`);
|
|
695
|
+
bytes = Buffer.from(await res.arrayBuffer());
|
|
696
|
+
} catch (e) {
|
|
697
|
+
throw new CliError(`Download failed (${file.url}): ${e instanceof Error ? e.message : String(e)}`);
|
|
698
|
+
}
|
|
699
|
+
const sha = createHash("sha256").update(bytes).digest("hex");
|
|
700
|
+
if (sha !== file.sha256)
|
|
701
|
+
throw new CliError(`Downloaded archive is corrupt (sha256 mismatch) — try again.`);
|
|
702
|
+
mkdirSync2(opts.cacheRoot, { recursive: true });
|
|
703
|
+
const stage = mkdtempSync(join4(opts.cacheRoot, "dl-"));
|
|
704
|
+
try {
|
|
705
|
+
const archiveName = file.url.split("/").pop() ?? "archive";
|
|
706
|
+
const archive = join4(stage, archiveName);
|
|
707
|
+
writeFileSync2(archive, bytes);
|
|
708
|
+
if (opts.extract) {
|
|
709
|
+
opts.extract(archive, stage);
|
|
710
|
+
} else {
|
|
711
|
+
const winTar = join4(process.env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
|
|
712
|
+
const tarExe = process.platform === "win32" && existsSync4(winTar) ? winTar : "tar";
|
|
713
|
+
const tar = spawnSync(tarExe, ["-xf", archiveName], { cwd: stage, stdio: ["ignore", "ignore", "pipe"] });
|
|
714
|
+
if (tar.status !== 0)
|
|
715
|
+
throw new CliError(`Couldn't extract the archive: ${tar.stderr?.toString() ?? "tar failed"}`);
|
|
716
|
+
}
|
|
717
|
+
rmSync(archive);
|
|
718
|
+
const bad = opts.validate(stage);
|
|
719
|
+
if (bad)
|
|
720
|
+
throw new CliError(bad);
|
|
721
|
+
writeFileSync2(join4(stage, ARTIFACT_STAMP), JSON.stringify({ sha256: file.sha256, url: file.url }, null, 2));
|
|
722
|
+
try {
|
|
723
|
+
renameSync(stage, opts.dest);
|
|
724
|
+
} catch {
|
|
725
|
+
let destBad;
|
|
726
|
+
try {
|
|
727
|
+
destBad = opts.validate(opts.dest);
|
|
728
|
+
} catch {
|
|
729
|
+
destBad = "missing";
|
|
730
|
+
}
|
|
731
|
+
if (destBad)
|
|
732
|
+
throw new CliError(`Couldn't move the download into ${opts.dest}.`);
|
|
733
|
+
}
|
|
734
|
+
} finally {
|
|
735
|
+
rmSync(stage, { recursive: true, force: true });
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
var init_releases = __esm(() => {
|
|
739
|
+
init_cli();
|
|
740
|
+
});
|
|
741
|
+
|
|
654
742
|
// src/hosts/archives.ts
|
|
655
743
|
var ARCHIVED_PEERS, BASE = "https://storage.yandexcloud.net/le-codes/releases/packages", packagesBase = () => (process.env.LECODES_PACKAGES_URL || BASE).replace(/\/$/, ""), archiveUrl = (name, version) => `${packagesBase()}/${name}/${name}-${version}.tgz`, numbers = (version) => version.split(/[.-]/).slice(0, 3).map(Number), byVersion = (a, b) => {
|
|
656
744
|
const pa = numbers(a), pb = numbers(b);
|
|
@@ -699,17 +787,17 @@ var init_archives = __esm(() => {
|
|
|
699
787
|
});
|
|
700
788
|
|
|
701
789
|
// src/hosts/packageManager.ts
|
|
702
|
-
import { spawnSync } from "node:child_process";
|
|
790
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
703
791
|
import { homedir as homedir2 } from "node:os";
|
|
704
|
-
import { join as
|
|
792
|
+
import { join as join5, resolve as resolve2, sep } from "node:path";
|
|
705
793
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
706
794
|
var onPath = (cmd) => {
|
|
707
795
|
try {
|
|
708
|
-
return
|
|
796
|
+
return spawnSync2(cmd, ["--version"], { stdio: "ignore", shell: process.platform === "win32" }).status === 0;
|
|
709
797
|
} catch {
|
|
710
798
|
return false;
|
|
711
799
|
}
|
|
712
|
-
}, bunGlobalDir = () =>
|
|
800
|
+
}, bunGlobalDir = () => join5(process.env.BUN_INSTALL ? resolve2(process.env.BUN_INSTALL) : join5(homedir2(), ".bun"), "install", "global"), ownManager = (file = fileURLToPath2(import.meta.url)) => {
|
|
713
801
|
const norm = (p) => process.platform === "win32" ? p.toLowerCase() : p;
|
|
714
802
|
return norm(resolve2(file)).startsWith(norm(bunGlobalDir()) + sep) ? "bun" : "npm";
|
|
715
803
|
}, pickManager = () => {
|
|
@@ -720,12 +808,16 @@ var onPath = (cmd) => {
|
|
|
720
808
|
var init_packageManager = () => {};
|
|
721
809
|
|
|
722
810
|
// src/hosts/peerInstall.ts
|
|
723
|
-
import { spawnSync as
|
|
724
|
-
import { existsSync as
|
|
725
|
-
import { join as
|
|
811
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
812
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
813
|
+
import { join as join6 } from "node:path";
|
|
726
814
|
import { pathToFileURL } from "node:url";
|
|
727
815
|
async function loadPeer(name, subpath, opts) {
|
|
728
816
|
const spec = subpath ? `${name}/${subpath}` : name;
|
|
817
|
+
const byHand = peerVersionGlobal(name, spec);
|
|
818
|
+
if (olderThanCli(name, byHand)) {
|
|
819
|
+
throw new CliError(`${name} ${byHand} (installed by hand) is older than this CLI (${package_default.version}) needs — update it: ${commandLine(ownManager(), installGlobalArgv(ownManager(), [await peerSpec(name)]))}`);
|
|
820
|
+
}
|
|
729
821
|
try {
|
|
730
822
|
return await import(spec);
|
|
731
823
|
} catch (e) {
|
|
@@ -733,18 +825,22 @@ async function loadPeer(name, subpath, opts) {
|
|
|
733
825
|
throw e;
|
|
734
826
|
}
|
|
735
827
|
const dir = peerDirInPrefix(name);
|
|
736
|
-
|
|
828
|
+
const installed = peerVersionPrefix(name);
|
|
829
|
+
const stale = olderThanCli(name, installed);
|
|
830
|
+
if (installed === null || stale) {
|
|
737
831
|
if (opts.install === false)
|
|
738
832
|
return null;
|
|
739
|
-
if (peerVersionGlobal(name, spec) !== null)
|
|
833
|
+
if (installed === null && peerVersionGlobal(name, spec) !== null)
|
|
740
834
|
throw new CliError(`${name} is installed but "${spec}" can't be loaded from it — reinstall it: ${commandLine(ownManager(), installGlobalArgv(ownManager(), [await peerSpec(name)]))}`);
|
|
835
|
+
if (stale)
|
|
836
|
+
note(`${name} ${installed} in ${peersDir()} is older than this CLI (${package_default.version}) — installing the one it needs`);
|
|
741
837
|
await installPeers(companions(name), opts.for);
|
|
742
838
|
}
|
|
743
839
|
return await import(pathToFileURL(resolveEntry(dir, subpath)).href);
|
|
744
840
|
}
|
|
745
841
|
var CANVAS_RANGE_FALLBACK = "^0.1.65", readJson = (path) => {
|
|
746
842
|
try {
|
|
747
|
-
return JSON.parse(
|
|
843
|
+
return JSON.parse(readFileSync4(path, "utf8"));
|
|
748
844
|
} catch {
|
|
749
845
|
return null;
|
|
750
846
|
}
|
|
@@ -753,7 +849,7 @@ var CANVAS_RANGE_FALLBACK = "^0.1.65", readJson = (path) => {
|
|
|
753
849
|
if (archive)
|
|
754
850
|
return archive;
|
|
755
851
|
if (name === "@napi-rs/canvas") {
|
|
756
|
-
const renderer = readJson(
|
|
852
|
+
const renderer = readJson(join6(peerDirInPrefix("lecodes-headless"), "package.json"));
|
|
757
853
|
const range = renderer?.peerDependencies?.["@napi-rs/canvas"] ?? renderer?.optionalDependencies?.["@napi-rs/canvas"] ?? CANVAS_RANGE_FALLBACK;
|
|
758
854
|
return `@napi-rs/canvas@${range}`;
|
|
759
855
|
}
|
|
@@ -761,10 +857,10 @@ var CANVAS_RANGE_FALLBACK = "^0.1.65", readJson = (path) => {
|
|
|
761
857
|
return range ? `${name}@${range}` : `${name}@latest`;
|
|
762
858
|
}, companions = (name) => name === "lecodes-headless" ? ["lecodes-headless", "@napi-rs/canvas"] : name === "sharp" ? ["sharp", "heic-decode"] : [name], manualCommand = (dir, specs) => commandLine(ownManager(), installIntoArgv(ownManager(), dir, specs)), installPeers = async (names, why, opts = {}) => {
|
|
763
859
|
const dir = peersDir();
|
|
764
|
-
|
|
765
|
-
const manifest =
|
|
766
|
-
if (!
|
|
767
|
-
|
|
860
|
+
mkdirSync3(dir, { recursive: true });
|
|
861
|
+
const manifest = join6(dir, "package.json");
|
|
862
|
+
if (!existsSync5(manifest)) {
|
|
863
|
+
writeFileSync3(manifest, JSON.stringify({
|
|
768
864
|
name: "lecodes-peers",
|
|
769
865
|
private: true,
|
|
770
866
|
description: "Optional lecodes-cli peers, installed on first use. Safe to delete — the CLI re-installs what a command needs."
|
|
@@ -792,16 +888,16 @@ var CANVAS_RANGE_FALLBACK = "^0.1.65", readJson = (path) => {
|
|
|
792
888
|
const spec = await peerSpec(name);
|
|
793
889
|
const argv = installIntoArgv(tool, dir, [spec]);
|
|
794
890
|
note(`$ ${tool} ${argv.join(" ")}`);
|
|
795
|
-
const r =
|
|
891
|
+
const r = spawnSync3(tool, argv, { stdio: "inherit", shell: process.platform === "win32", timeout: 10 * 60000 });
|
|
796
892
|
if (r.error)
|
|
797
893
|
throw new CliError(`${tool} could not run: ${r.error.message}`);
|
|
798
894
|
if (r.status !== 0)
|
|
799
895
|
throw new CliError(`${tool} exited with ${r.status ?? "a signal"} while installing ${spec}. By hand: ${manualCommand(dir, [spec])}`);
|
|
800
|
-
if (!
|
|
896
|
+
if (!existsSync5(join6(peerDirInPrefix(name), "package.json")))
|
|
801
897
|
throw new CliError(`${name} did not land in ${dir} — the installer finished but the package is missing`);
|
|
802
898
|
}
|
|
803
899
|
}, resolveEntry = (pkgDir, subpath) => {
|
|
804
|
-
const manifest = readJson(
|
|
900
|
+
const manifest = readJson(join6(pkgDir, "package.json"));
|
|
805
901
|
if (!manifest)
|
|
806
902
|
throw new CliError(`${pkgDir} holds no package.json`);
|
|
807
903
|
const key = subpath ? `./${subpath}` : ".";
|
|
@@ -829,8 +925,8 @@ var CANVAS_RANGE_FALLBACK = "^0.1.65", readJson = (path) => {
|
|
|
829
925
|
rel = typeof manifest.main === "string" ? manifest.main : "index.js";
|
|
830
926
|
if (!rel)
|
|
831
927
|
throw new CliError(`${manifest.name} has no export "${key}"`);
|
|
832
|
-
return
|
|
833
|
-
}, isNotFound = (e, spec) => {
|
|
928
|
+
return join6(pkgDir, rel);
|
|
929
|
+
}, SET_ON_NPM, olderThanCli = (name, version) => SET_ON_NPM.has(name) && version !== null && semverNewer(version, package_default.version) > 0, isNotFound = (e, spec) => {
|
|
834
930
|
const code = e?.code;
|
|
835
931
|
const msg = e instanceof Error ? e.message : String(e);
|
|
836
932
|
return (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND" || /Cannot find (module|package)/i.test(msg)) && msg.includes(spec.split("/")[0]);
|
|
@@ -838,9 +934,11 @@ var CANVAS_RANGE_FALLBACK = "^0.1.65", readJson = (path) => {
|
|
|
838
934
|
var init_peerInstall = __esm(() => {
|
|
839
935
|
init_package();
|
|
840
936
|
init_peers();
|
|
937
|
+
init_releases();
|
|
841
938
|
init_archives();
|
|
842
939
|
init_packageManager();
|
|
843
940
|
init_cli();
|
|
941
|
+
SET_ON_NPM = new Set(["lecodes-assets"]);
|
|
844
942
|
});
|
|
845
943
|
|
|
846
944
|
// ../../sdk/src/compile/resourceSlots.ts
|
|
@@ -880,13 +978,7 @@ var init_resourceSlots = __esm(() => {
|
|
|
880
978
|
"map",
|
|
881
979
|
"shader",
|
|
882
980
|
"build",
|
|
883
|
-
"data"
|
|
884
|
-
"light",
|
|
885
|
-
"aux",
|
|
886
|
-
"direct",
|
|
887
|
-
"indirect",
|
|
888
|
-
"probes",
|
|
889
|
-
"volume"
|
|
981
|
+
"data"
|
|
890
982
|
]
|
|
891
983
|
};
|
|
892
984
|
});
|
|
@@ -1146,6 +1238,520 @@ var init_assetMacro = __esm(() => {
|
|
|
1146
1238
|
SET_TARGET = /\.\s*([A-Za-z_$][\w$]*)\s*$/;
|
|
1147
1239
|
});
|
|
1148
1240
|
|
|
1241
|
+
// ../../sdk/src/compile/assetIconMacro.ts
|
|
1242
|
+
var ICON_ID, isIdentStart = (c) => c >= "A" && c <= "Z" || c >= "a" && c <= "z" || c === "_" || c === "$", isIdentPart = (c) => isIdentStart(c) || c >= "0" && c <= "9", skipString = (src, start) => {
|
|
1243
|
+
const quote = src[start];
|
|
1244
|
+
const n = src.length;
|
|
1245
|
+
let i = start + 1;
|
|
1246
|
+
while (i < n) {
|
|
1247
|
+
const c = src[i];
|
|
1248
|
+
if (c === "\\") {
|
|
1249
|
+
i += 2;
|
|
1250
|
+
continue;
|
|
1251
|
+
}
|
|
1252
|
+
if (quote === "`" && c === "$" && src[i + 1] === "{") {
|
|
1253
|
+
i = skipBraces(src, i + 1);
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
if (c === quote)
|
|
1257
|
+
return i + 1;
|
|
1258
|
+
i++;
|
|
1259
|
+
}
|
|
1260
|
+
return n;
|
|
1261
|
+
}, skipBraces = (src, open) => {
|
|
1262
|
+
const n = src.length;
|
|
1263
|
+
let depth = 0;
|
|
1264
|
+
let i = open;
|
|
1265
|
+
while (i < n) {
|
|
1266
|
+
const c = src[i];
|
|
1267
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1268
|
+
i = skipString(src, i);
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
if (c === "{")
|
|
1272
|
+
depth++;
|
|
1273
|
+
else if (c === "}") {
|
|
1274
|
+
depth--;
|
|
1275
|
+
if (depth === 0)
|
|
1276
|
+
return i + 1;
|
|
1277
|
+
}
|
|
1278
|
+
i++;
|
|
1279
|
+
}
|
|
1280
|
+
return n;
|
|
1281
|
+
}, matchParen = (src, open) => {
|
|
1282
|
+
const n = src.length;
|
|
1283
|
+
let depth = 0;
|
|
1284
|
+
let i = open;
|
|
1285
|
+
while (i < n) {
|
|
1286
|
+
const c = src[i];
|
|
1287
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1288
|
+
i = skipString(src, i);
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
if (c === "/" && src[i + 1] === "/") {
|
|
1292
|
+
i += 2;
|
|
1293
|
+
while (i < n && src[i] !== `
|
|
1294
|
+
`)
|
|
1295
|
+
i++;
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
if (c === "/" && src[i + 1] === "*") {
|
|
1299
|
+
i += 2;
|
|
1300
|
+
while (i < n && !(src[i] === "*" && src[i + 1] === "/"))
|
|
1301
|
+
i++;
|
|
1302
|
+
i += 2;
|
|
1303
|
+
continue;
|
|
1304
|
+
}
|
|
1305
|
+
if (c === "(")
|
|
1306
|
+
depth++;
|
|
1307
|
+
else if (c === ")") {
|
|
1308
|
+
depth--;
|
|
1309
|
+
if (depth === 0)
|
|
1310
|
+
return i;
|
|
1311
|
+
}
|
|
1312
|
+
i++;
|
|
1313
|
+
}
|
|
1314
|
+
return -1;
|
|
1315
|
+
}, splitTopLevel = (text, delim) => {
|
|
1316
|
+
const parts = [];
|
|
1317
|
+
const n = text.length;
|
|
1318
|
+
let depth = 0;
|
|
1319
|
+
let last = 0;
|
|
1320
|
+
let i = 0;
|
|
1321
|
+
while (i < n) {
|
|
1322
|
+
const c = text[i];
|
|
1323
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1324
|
+
i = skipString(text, i);
|
|
1325
|
+
continue;
|
|
1326
|
+
}
|
|
1327
|
+
if (c === "(" || c === "[" || c === "{")
|
|
1328
|
+
depth++;
|
|
1329
|
+
else if (c === ")" || c === "]" || c === "}")
|
|
1330
|
+
depth = Math.max(0, depth - 1);
|
|
1331
|
+
else if (depth === 0 && c === delim) {
|
|
1332
|
+
parts.push(text.slice(last, i));
|
|
1333
|
+
last = i + 1;
|
|
1334
|
+
}
|
|
1335
|
+
i++;
|
|
1336
|
+
}
|
|
1337
|
+
parts.push(text.slice(last));
|
|
1338
|
+
return parts;
|
|
1339
|
+
}, stringLiteralValue = (text) => {
|
|
1340
|
+
const t = text.trim();
|
|
1341
|
+
if (t.length < 2)
|
|
1342
|
+
return null;
|
|
1343
|
+
const q = t[0];
|
|
1344
|
+
if (q !== '"' && q !== "'" && q !== "`" || t[t.length - 1] !== q)
|
|
1345
|
+
return null;
|
|
1346
|
+
const inner = t.slice(1, -1);
|
|
1347
|
+
if (q === "`" && inner.includes("${"))
|
|
1348
|
+
return null;
|
|
1349
|
+
if (inner.includes(q) && !inner.includes("\\" + q))
|
|
1350
|
+
return null;
|
|
1351
|
+
return inner.replace(/\\(.)/g, "$1");
|
|
1352
|
+
}, scanAssetIconCalls = (source) => {
|
|
1353
|
+
const calls = [];
|
|
1354
|
+
const n = source.length;
|
|
1355
|
+
let i = 0;
|
|
1356
|
+
while (i < n) {
|
|
1357
|
+
const c = source[i];
|
|
1358
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1359
|
+
i = skipString(source, i);
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
if (c === "/" && source[i + 1] === "/") {
|
|
1363
|
+
i += 2;
|
|
1364
|
+
while (i < n && source[i] !== `
|
|
1365
|
+
`)
|
|
1366
|
+
i++;
|
|
1367
|
+
continue;
|
|
1368
|
+
}
|
|
1369
|
+
if (c === "/" && source[i + 1] === "*") {
|
|
1370
|
+
i += 2;
|
|
1371
|
+
while (i < n && !(source[i] === "*" && source[i + 1] === "/"))
|
|
1372
|
+
i++;
|
|
1373
|
+
i += 2;
|
|
1374
|
+
continue;
|
|
1375
|
+
}
|
|
1376
|
+
if (isIdentStart(c)) {
|
|
1377
|
+
let j = i + 1;
|
|
1378
|
+
while (j < n && isIdentPart(source[j]))
|
|
1379
|
+
j++;
|
|
1380
|
+
if (source.slice(i, j) === "assetIcon" && prevNonSpace(source, i) !== ".") {
|
|
1381
|
+
const call = parseCall(source, i, j);
|
|
1382
|
+
if (call) {
|
|
1383
|
+
calls.push(call);
|
|
1384
|
+
i = call.end;
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
i = j;
|
|
1389
|
+
continue;
|
|
1390
|
+
}
|
|
1391
|
+
i++;
|
|
1392
|
+
}
|
|
1393
|
+
return calls;
|
|
1394
|
+
}, prevNonSpace = (src, i) => {
|
|
1395
|
+
let k = i - 1;
|
|
1396
|
+
while (k >= 0 && /\s/.test(src[k]))
|
|
1397
|
+
k--;
|
|
1398
|
+
return k >= 0 ? src[k] : "";
|
|
1399
|
+
}, parseCall = (src, start, identEnd) => {
|
|
1400
|
+
const n = src.length;
|
|
1401
|
+
let i = identEnd;
|
|
1402
|
+
while (i < n && /\s/.test(src[i]))
|
|
1403
|
+
i++;
|
|
1404
|
+
if (src[i] !== "(")
|
|
1405
|
+
return null;
|
|
1406
|
+
const close = matchParen(src, i);
|
|
1407
|
+
if (close === -1)
|
|
1408
|
+
return null;
|
|
1409
|
+
const call = { start, end: close + 1, id: "", pack: "", name: "" };
|
|
1410
|
+
const args = splitTopLevel(src.slice(i + 1, close), ",");
|
|
1411
|
+
const id = stringLiteralValue(args[0] ?? "");
|
|
1412
|
+
if (id === null) {
|
|
1413
|
+
call.error = `assetIcon(...) needs a string-literal id like "lucide:bell" (got \`${(args[0] ?? "").trim() || "()"}\`).`;
|
|
1414
|
+
return call;
|
|
1415
|
+
}
|
|
1416
|
+
const m = ICON_ID.exec(id);
|
|
1417
|
+
if (!m) {
|
|
1418
|
+
call.error = `assetIcon("${id}"): id must be "pack:name", lowercase [a-z0-9-] (e.g. "lucide:bell").`;
|
|
1419
|
+
return call;
|
|
1420
|
+
}
|
|
1421
|
+
call.id = id;
|
|
1422
|
+
call.pack = m[1];
|
|
1423
|
+
call.name = m[2];
|
|
1424
|
+
const optsText = args[1]?.trim();
|
|
1425
|
+
if (optsText) {
|
|
1426
|
+
const color = extractColor(optsText);
|
|
1427
|
+
if (color.error) {
|
|
1428
|
+
call.error = color.error;
|
|
1429
|
+
return call;
|
|
1430
|
+
}
|
|
1431
|
+
if (color.bake !== undefined)
|
|
1432
|
+
call.bake = color.bake;
|
|
1433
|
+
else if (color.tint !== undefined)
|
|
1434
|
+
call.tint = color.tint;
|
|
1435
|
+
}
|
|
1436
|
+
return call;
|
|
1437
|
+
}, extractColor = (optsText) => {
|
|
1438
|
+
if (!optsText.startsWith("{") || !optsText.endsWith("}")) {
|
|
1439
|
+
return { error: `assetIcon(id, opts): opts must be an object literal like { color: "#5b8cff" }.` };
|
|
1440
|
+
}
|
|
1441
|
+
for (const prop of splitTopLevel(optsText.slice(1, -1), ",")) {
|
|
1442
|
+
const kv = splitTopLevel(prop, ":");
|
|
1443
|
+
if (kv.length < 2)
|
|
1444
|
+
continue;
|
|
1445
|
+
const key = kv[0].trim().replace(/^["'`]|["'`]$/g, "");
|
|
1446
|
+
if (key !== "color")
|
|
1447
|
+
continue;
|
|
1448
|
+
const raw = kv.slice(1).join(":").trim();
|
|
1449
|
+
if (!raw)
|
|
1450
|
+
continue;
|
|
1451
|
+
const literal = stringLiteralValue(raw);
|
|
1452
|
+
return literal !== null ? { bake: literal } : { tint: raw };
|
|
1453
|
+
}
|
|
1454
|
+
return {};
|
|
1455
|
+
}, rewriteAssetIcons = (source, calls, svgById) => {
|
|
1456
|
+
let out = source;
|
|
1457
|
+
for (const call of [...calls].sort((a, b) => b.start - a.start)) {
|
|
1458
|
+
const svg = svgById.get(call.id);
|
|
1459
|
+
if (svg === undefined)
|
|
1460
|
+
continue;
|
|
1461
|
+
out = out.slice(0, call.start) + iconExpr(svg, call) + out.slice(call.end);
|
|
1462
|
+
}
|
|
1463
|
+
return out;
|
|
1464
|
+
}, iconExpr = (svg, call) => {
|
|
1465
|
+
const body = call.bake ? svg.split("currentColor").join(call.bake) : svg;
|
|
1466
|
+
const src = `SvgSource(\`${escapeTemplate(body)}\`)`;
|
|
1467
|
+
return call.tint ? `Object.assign(${src}, { tintColor: (${call.tint}) })` : src;
|
|
1468
|
+
}, escapeTemplate = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${"), applyAssetIconMacro = async (entries, resolveSvgs) => {
|
|
1469
|
+
const scanned = entries.filter((e) => e.type === "text" && typeof e.text === "string" && e.text.includes("assetIcon")).map((e) => ({ entry: e, calls: scanAssetIconCalls(e.text) })).filter((s) => s.calls.length > 0);
|
|
1470
|
+
if (scanned.length === 0)
|
|
1471
|
+
return [];
|
|
1472
|
+
const errors = scanned.flatMap((s) => s.calls.filter((c) => c.error).map((c) => c.error));
|
|
1473
|
+
if (errors.length)
|
|
1474
|
+
throw new Error([...new Set(errors)].join(`
|
|
1475
|
+
`));
|
|
1476
|
+
const ids = [...new Set(scanned.flatMap((s) => s.calls.map((c) => c.id)))];
|
|
1477
|
+
const svgById = await resolveSvgs(ids);
|
|
1478
|
+
const missing = ids.filter((id) => !svgById.has(id));
|
|
1479
|
+
if (missing.length)
|
|
1480
|
+
throw new Error(`assetIcon: could not resolve icon(s): ${missing.join(", ")}.`);
|
|
1481
|
+
for (const { entry, calls } of scanned)
|
|
1482
|
+
entry.text = rewriteAssetIcons(entry.text, calls, svgById);
|
|
1483
|
+
return ids;
|
|
1484
|
+
}, buildIconsHeaderValue = (ids) => [...new Set(ids.map((id) => id.split(":")[0]))].sort().join(";"), editDistance = (a, b, cap) => {
|
|
1485
|
+
if (Math.abs(a.length - b.length) > cap)
|
|
1486
|
+
return cap + 1;
|
|
1487
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
1488
|
+
for (let i = 1;i <= a.length; i++) {
|
|
1489
|
+
const cur = [i];
|
|
1490
|
+
let rowMin = i;
|
|
1491
|
+
for (let j = 1;j <= b.length; j++) {
|
|
1492
|
+
cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
1493
|
+
if (cur[j] < rowMin)
|
|
1494
|
+
rowMin = cur[j];
|
|
1495
|
+
}
|
|
1496
|
+
if (rowMin > cap)
|
|
1497
|
+
return cap + 1;
|
|
1498
|
+
prev = cur;
|
|
1499
|
+
}
|
|
1500
|
+
return prev[b.length];
|
|
1501
|
+
}, suggestIconNames = (want, icons) => {
|
|
1502
|
+
const wantParts = new Set(want.split("-").filter(Boolean));
|
|
1503
|
+
const scored = [];
|
|
1504
|
+
for (const [name, info] of Object.entries(icons)) {
|
|
1505
|
+
const lenDiff = Math.abs(name.length - want.length) / 100;
|
|
1506
|
+
let rank;
|
|
1507
|
+
if (name.includes(want) || want.includes(name))
|
|
1508
|
+
rank = lenDiff;
|
|
1509
|
+
else {
|
|
1510
|
+
const d = editDistance(want, name, 2);
|
|
1511
|
+
if (d <= 2)
|
|
1512
|
+
rank = 1 + d;
|
|
1513
|
+
else if (info.kw?.some((k) => wantParts.has(k)))
|
|
1514
|
+
rank = 4 + lenDiff;
|
|
1515
|
+
else
|
|
1516
|
+
continue;
|
|
1517
|
+
}
|
|
1518
|
+
scored.push({ name, rank });
|
|
1519
|
+
}
|
|
1520
|
+
return scored.sort((a, b) => a.rank - b.rank || (a.name < b.name ? -1 : 1)).slice(0, 5).map((s) => s.name);
|
|
1521
|
+
}, iconNotFoundError = async (pack, name, read, registry) => {
|
|
1522
|
+
const metaRaw = await read(`${pack}/meta.json`);
|
|
1523
|
+
if (metaRaw !== null) {
|
|
1524
|
+
let icons = {};
|
|
1525
|
+
try {
|
|
1526
|
+
icons = JSON.parse(metaRaw).icons ?? {};
|
|
1527
|
+
} catch {}
|
|
1528
|
+
const similar = suggestIconNames(name, icons);
|
|
1529
|
+
const hint = similar.length ? ` Did you mean ${similar.map((s) => `"${pack}:${s}"`).join(", ")}?` : ` No similar name in the "${pack}" pack either.`;
|
|
1530
|
+
return new Error(`assetIcon: icon "${pack}:${name}" not found.${hint}`);
|
|
1531
|
+
}
|
|
1532
|
+
const licRaw = await read("licenses.json");
|
|
1533
|
+
if (licRaw !== null) {
|
|
1534
|
+
try {
|
|
1535
|
+
const packs = Object.keys(JSON.parse(licRaw)).sort();
|
|
1536
|
+
return new Error(`assetIcon: unknown icon pack "${pack}" (in "${pack}:${name}"). Available packs: ${packs.join(", ")}.`);
|
|
1537
|
+
} catch {}
|
|
1538
|
+
}
|
|
1539
|
+
return Object.assign(new Error(`assetIcon: can't reach the icon registry${registry ? ` (${registry})` : ""} to resolve "${pack}:${name}". ` + `Check your connection, or set LECODES_ICON_REGISTRY.`), { transient: true });
|
|
1540
|
+
}, VENDORED_ICON_PATH, collectVendoredIcons = (entries) => {
|
|
1541
|
+
const map = new Map;
|
|
1542
|
+
for (const e of entries) {
|
|
1543
|
+
if (e.type !== "text" || typeof e.text !== "string")
|
|
1544
|
+
continue;
|
|
1545
|
+
const m = VENDORED_ICON_PATH.exec(e.path);
|
|
1546
|
+
if (m)
|
|
1547
|
+
map.set(`${m[1]}:${m[2]}`, e.text);
|
|
1548
|
+
}
|
|
1549
|
+
return map;
|
|
1550
|
+
};
|
|
1551
|
+
var init_assetIconMacro = __esm(() => {
|
|
1552
|
+
ICON_ID = /^([a-z0-9]+(?:-[a-z0-9]+)*):([a-z0-9]+(?:-[a-z0-9]+)*)$/;
|
|
1553
|
+
VENDORED_ICON_PATH = /(?:^|\/)assets\/icons\/([a-z0-9]+(?:-[a-z0-9]+)*)\/([a-z0-9]+(?:-[a-z0-9]+)*)\.svg$/;
|
|
1554
|
+
});
|
|
1555
|
+
|
|
1556
|
+
// ../../sdk/src/compile/bakeMacro.ts
|
|
1557
|
+
var BAKE_CALL, DECLARES_BAKE, DEFINITION_TAIL, hasBakeMacro = (src) => src.includes("bake"), stringLiteralValue2 = (text) => {
|
|
1558
|
+
const t = text.trim();
|
|
1559
|
+
if (t.length < 2)
|
|
1560
|
+
return null;
|
|
1561
|
+
const q = t[0];
|
|
1562
|
+
if (q !== '"' && q !== "'" && q !== "`" || t[t.length - 1] !== q)
|
|
1563
|
+
return null;
|
|
1564
|
+
const inner = t.slice(1, -1);
|
|
1565
|
+
if (q === "`" && inner.includes("${"))
|
|
1566
|
+
return null;
|
|
1567
|
+
if (/[\r\n]/.test(inner))
|
|
1568
|
+
return null;
|
|
1569
|
+
for (let i = 0;i < inner.length; i++) {
|
|
1570
|
+
if (inner[i] === "\\") {
|
|
1571
|
+
i++;
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
if (inner[i] === q)
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
return inner.replace(/\\(.)/g, "$1");
|
|
1578
|
+
}, closeOf = (mask, open) => {
|
|
1579
|
+
let depth = 0;
|
|
1580
|
+
for (let i = open;i < mask.length; i++) {
|
|
1581
|
+
const c = mask[i];
|
|
1582
|
+
if (c === "(" || c === "[" || c === "{")
|
|
1583
|
+
depth++;
|
|
1584
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
1585
|
+
depth--;
|
|
1586
|
+
if (depth === 0)
|
|
1587
|
+
return i;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return -1;
|
|
1591
|
+
}, argSpans = (mask, open, close) => {
|
|
1592
|
+
const spans = [];
|
|
1593
|
+
let depth = 0;
|
|
1594
|
+
let start = open + 1;
|
|
1595
|
+
for (let i = open + 1;i < close; i++) {
|
|
1596
|
+
const c = mask[i];
|
|
1597
|
+
if (c === "(" || c === "[" || c === "{")
|
|
1598
|
+
depth++;
|
|
1599
|
+
else if (c === ")" || c === "]" || c === "}")
|
|
1600
|
+
depth--;
|
|
1601
|
+
else if (c === "," && depth === 0) {
|
|
1602
|
+
spans.push([start, i]);
|
|
1603
|
+
start = i + 1;
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
spans.push([start, close]);
|
|
1607
|
+
return spans;
|
|
1608
|
+
}, newlines = (s) => {
|
|
1609
|
+
let n = 0;
|
|
1610
|
+
for (let i = 0;i < s.length; i++)
|
|
1611
|
+
if (s[i] === `
|
|
1612
|
+
`)
|
|
1613
|
+
n++;
|
|
1614
|
+
return n;
|
|
1615
|
+
}, stringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === "string") ? v : null, readManifest2 = (json) => {
|
|
1616
|
+
if (!json || typeof json !== "object")
|
|
1617
|
+
return null;
|
|
1618
|
+
const m = json;
|
|
1619
|
+
const light = stringArray(m.light), aux = stringArray(m.aux);
|
|
1620
|
+
if (!light || !aux)
|
|
1621
|
+
return null;
|
|
1622
|
+
const file = (v) => typeof v === "string" && v !== "" ? v : v && typeof v === "object" && typeof v.file === "string" ? v.file : undefined;
|
|
1623
|
+
return {
|
|
1624
|
+
light,
|
|
1625
|
+
aux,
|
|
1626
|
+
direct: stringArray(m.direct) ?? undefined,
|
|
1627
|
+
indirect: stringArray(m.indirect) ?? undefined,
|
|
1628
|
+
probes: file(m.probes),
|
|
1629
|
+
volume: file(m.volume),
|
|
1630
|
+
uv1: file(m.uv1)
|
|
1631
|
+
};
|
|
1632
|
+
}, expandBakeMacros = async (src, filePath, exists, read) => {
|
|
1633
|
+
if (!hasBakeMacro(src))
|
|
1634
|
+
return { src, bakes: [] };
|
|
1635
|
+
const strings = [];
|
|
1636
|
+
const mask = maskNonCode(src, (s, e) => {
|
|
1637
|
+
strings.push([s, e]);
|
|
1638
|
+
});
|
|
1639
|
+
if (DECLARES_BAKE.test(mask))
|
|
1640
|
+
return { src, bakes: [] };
|
|
1641
|
+
const stringsIn = ([a, b]) => strings.filter(([s, e]) => s >= a && e <= b);
|
|
1642
|
+
const blankArg = (span) => mask.slice(span[0], span[1]).trim() === "" && stringsIn(span).length === 0;
|
|
1643
|
+
const literalOf = (span) => {
|
|
1644
|
+
const inside = stringsIn(span);
|
|
1645
|
+
if (inside.length === 1 && mask.slice(span[0], span[1]).trim() === "")
|
|
1646
|
+
return src.slice(inside[0][0], inside[0][1]);
|
|
1647
|
+
return src.slice(span[0], span[1]).trim();
|
|
1648
|
+
};
|
|
1649
|
+
const dir = filePath.slice(0, filePath.lastIndexOf("/"));
|
|
1650
|
+
const at = (index) => `${filePath.replace(/^\//, "")}:${newlines(src.slice(0, index)) + 1}`;
|
|
1651
|
+
const bakes = [];
|
|
1652
|
+
const parts = [];
|
|
1653
|
+
let done = 0;
|
|
1654
|
+
for (const m of mask.matchAll(BAKE_CALL)) {
|
|
1655
|
+
const start = m.index ?? 0;
|
|
1656
|
+
if (start < done)
|
|
1657
|
+
continue;
|
|
1658
|
+
const open = start + m[0].length - 1;
|
|
1659
|
+
const close = closeOf(mask, open);
|
|
1660
|
+
if (close < 0)
|
|
1661
|
+
throw new Error(`bake(): unclosed call (${at(start)})`);
|
|
1662
|
+
const spans = argSpans(mask, open, close);
|
|
1663
|
+
const pathText = literalOf(spans[0]);
|
|
1664
|
+
const written = stringLiteralValue2(pathText);
|
|
1665
|
+
if (written === null && DEFINITION_TAIL.test(mask.slice(close + 1, close + 160)))
|
|
1666
|
+
continue;
|
|
1667
|
+
if (written === null)
|
|
1668
|
+
throw new Error(`bake() expects a string-literal path like bake('./assets/lightmap/level.bake'), found \`${pathText || "()"}\` (${at(start)})`);
|
|
1669
|
+
if (!/\.bake$/i.test(written))
|
|
1670
|
+
throw new Error(`bake('${written}'): the path names a .bake file — what \`lecodes lightmap bake\` writes (${at(start)})`);
|
|
1671
|
+
if (spans.slice(2).some((s) => !blankArg(s)))
|
|
1672
|
+
throw new Error(`bake('${written}'): one path and one options object at most (${at(start)})`);
|
|
1673
|
+
let options = null;
|
|
1674
|
+
if (spans.length > 1 && !blankArg(spans[1])) {
|
|
1675
|
+
const [a, b] = spans[1];
|
|
1676
|
+
const code = mask.slice(a, b);
|
|
1677
|
+
const lead = a + (code.length - code.trimStart().length);
|
|
1678
|
+
const tail = b - (code.length - code.trimEnd().length);
|
|
1679
|
+
if (mask[lead] !== "{" || closeOf(mask, lead) !== tail - 1) {
|
|
1680
|
+
throw new Error(`bake('${written}', options): options must be an object literal like { emissiveBake: false } (${at(start)})`);
|
|
1681
|
+
}
|
|
1682
|
+
options = [lead, tail];
|
|
1683
|
+
}
|
|
1684
|
+
const relative = written.startsWith("./") || written.startsWith("../");
|
|
1685
|
+
const rooted = written.startsWith("/");
|
|
1686
|
+
const candidates = rooted ? [normalizePath(written)] : relative ? [normalizePath(`${dir}/${written}`), normalizePath(written)] : [normalizePath(written), normalizePath(`${dir}/${written}`)];
|
|
1687
|
+
const found = candidates.find(exists);
|
|
1688
|
+
const target = found ?? candidates[0];
|
|
1689
|
+
const ref = { path: target.slice(1), exists: found !== undefined, line: newlines(src.slice(0, start)) + 1, written, missing: [] };
|
|
1690
|
+
let manifest = null;
|
|
1691
|
+
if (found !== undefined) {
|
|
1692
|
+
const body = read ? await read(found) : null;
|
|
1693
|
+
if (body === null)
|
|
1694
|
+
ref.unread = true;
|
|
1695
|
+
else {
|
|
1696
|
+
let json;
|
|
1697
|
+
try {
|
|
1698
|
+
json = JSON.parse(body.replace(/^\uFEFF/, ""));
|
|
1699
|
+
} catch (e) {
|
|
1700
|
+
throw new Error(`bake('${written}'): ${ref.path} is not a bake manifest (${e instanceof Error ? e.message : String(e)}) — rebake with \`lecodes lightmap bake\` (${at(start)})`);
|
|
1701
|
+
}
|
|
1702
|
+
manifest = readManifest2(json);
|
|
1703
|
+
if (!manifest)
|
|
1704
|
+
throw new Error(`bake('${written}'): ${ref.path} is not a bake manifest (no light / aux pages) — rebake with \`lecodes lightmap bake\` (${at(start)})`);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
const bakeDir = target.slice(0, target.lastIndexOf("/"));
|
|
1708
|
+
const ref1 = (name) => {
|
|
1709
|
+
const p = normalizePath(`${bakeDir}/${name}`);
|
|
1710
|
+
if (!exists(p) && !ref.missing.includes(p))
|
|
1711
|
+
ref.missing.push(p);
|
|
1712
|
+
return `asset(${JSON.stringify(p)})`;
|
|
1713
|
+
};
|
|
1714
|
+
const list = (names) => `[${names.map(ref1).join(", ")}]`;
|
|
1715
|
+
const fields = [`path: \`${escapeTemplate(ref.path)}\``];
|
|
1716
|
+
if (manifest) {
|
|
1717
|
+
fields.unshift(`data: asset(${JSON.stringify(target)})`);
|
|
1718
|
+
fields.push(`light: ${list(manifest.light)}`, `aux: ${list(manifest.aux)}`);
|
|
1719
|
+
if (manifest.direct)
|
|
1720
|
+
fields.push(`direct: ${list(manifest.direct)}`);
|
|
1721
|
+
if (manifest.indirect)
|
|
1722
|
+
fields.push(`indirect: ${list(manifest.indirect)}`);
|
|
1723
|
+
if (manifest.probes)
|
|
1724
|
+
fields.push(`probes: ${ref1(manifest.probes)}`);
|
|
1725
|
+
if (manifest.volume)
|
|
1726
|
+
fields.push(`volume: ${ref1(manifest.volume)}`);
|
|
1727
|
+
if (manifest.uv1)
|
|
1728
|
+
fields.push(`uv1: ${ref1(manifest.uv1)}`);
|
|
1729
|
+
} else {
|
|
1730
|
+
fields.unshift("data: null");
|
|
1731
|
+
fields.push("light: []", "aux: []");
|
|
1732
|
+
}
|
|
1733
|
+
const head = `{ ${fields.join(", ")}`;
|
|
1734
|
+
const expansion = options ? `${head}, ${`
|
|
1735
|
+
`.repeat(newlines(src.slice(start, options[0])))}...${src.slice(options[0], options[1])}${`
|
|
1736
|
+
`.repeat(newlines(src.slice(options[1], close + 1)))} }` : `${head}${`
|
|
1737
|
+
`.repeat(newlines(src.slice(start, close + 1)))} }`;
|
|
1738
|
+
parts.push(src.slice(done, start), expansion);
|
|
1739
|
+
done = close + 1;
|
|
1740
|
+
bakes.push(ref);
|
|
1741
|
+
}
|
|
1742
|
+
if (bakes.length === 0)
|
|
1743
|
+
return { src, bakes };
|
|
1744
|
+
parts.push(src.slice(done));
|
|
1745
|
+
return { src: parts.join(""), bakes };
|
|
1746
|
+
};
|
|
1747
|
+
var init_bakeMacro = __esm(() => {
|
|
1748
|
+
init_assetMacro();
|
|
1749
|
+
init_assetIconMacro();
|
|
1750
|
+
BAKE_CALL = /(?<![.\w$])bake\s*\(/g;
|
|
1751
|
+
DECLARES_BAKE = /\b(?:function|const|let|var|class)\s+bake\b|\bimport\s+(?:\{[^}]*\bbake\b[^}]*\}|bake)\s+from\b/;
|
|
1752
|
+
DEFINITION_TAIL = /^\s*(?::[^;{}=()\n]*)?(?:\{|=>)/;
|
|
1753
|
+
});
|
|
1754
|
+
|
|
1149
1755
|
// ../../sdk/src/compile/detectEntry.ts
|
|
1150
1756
|
var ENTRY_CONVENTION = "/main.ts", isCode = (path) => /\.[tj]s$/.test(path) && !path.endsWith(".d.ts"), isNonEntry = (path) => path.endsWith(".editor.ts") || /\.server\.[tj]s$/.test(path) || /^\/design\//.test(path), normalize = (path) => {
|
|
1151
1757
|
const parts = [];
|
|
@@ -1242,7 +1848,7 @@ var HEAD_RE, hasAspectExtends = (src) => /\bextends\s+(?:Aspect|System)\s*</.tes
|
|
|
1242
1848
|
for (;i < src.length && angle > 0; i++) {
|
|
1243
1849
|
const c = src[i];
|
|
1244
1850
|
if (c === '"' || c === "'" || c === "`") {
|
|
1245
|
-
i =
|
|
1851
|
+
i = skipString2(src, i) - 1;
|
|
1246
1852
|
continue;
|
|
1247
1853
|
}
|
|
1248
1854
|
if (c === "=" && src[i + 1] === ">") {
|
|
@@ -1269,7 +1875,7 @@ var HEAD_RE, hasAspectExtends = (src) => /\bextends\s+(?:Aspect|System)\s*</.tes
|
|
|
1269
1875
|
return -1;
|
|
1270
1876
|
}
|
|
1271
1877
|
return -1;
|
|
1272
|
-
},
|
|
1878
|
+
}, skipString2 = (src, at) => {
|
|
1273
1879
|
const q = src[at];
|
|
1274
1880
|
let i = at + 1;
|
|
1275
1881
|
for (;i < src.length; i++) {
|
|
@@ -1533,18 +2139,18 @@ var init_chisel = __esm(() => {
|
|
|
1533
2139
|
});
|
|
1534
2140
|
|
|
1535
2141
|
// ../../sdk/src/compile/bundler.ts
|
|
1536
|
-
import { existsSync as
|
|
1537
|
-
import { spawnSync as
|
|
2142
|
+
import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync5, statSync } from "node:fs";
|
|
2143
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
1538
2144
|
import { createRequire as createRequire3 } from "node:module";
|
|
1539
|
-
import { dirname as dirname4, join as
|
|
2145
|
+
import { dirname as dirname4, join as join7, relative } from "node:path";
|
|
1540
2146
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1541
2147
|
var resolveInject = () => {
|
|
1542
2148
|
const override = process.env.LECODES_SDK_INJECT;
|
|
1543
|
-
if (override &&
|
|
2149
|
+
if (override && existsSync6(override))
|
|
1544
2150
|
return override;
|
|
1545
2151
|
const here = dirname4(fileURLToPath3(import.meta.url));
|
|
1546
|
-
const src =
|
|
1547
|
-
if (
|
|
2152
|
+
const src = join7(here, "..", "inject.ts");
|
|
2153
|
+
if (existsSync6(src))
|
|
1548
2154
|
return src;
|
|
1549
2155
|
throw new Error("sdk: could not locate the inject source (LECODES_SDK_INJECT / src/inject.ts)");
|
|
1550
2156
|
}, normalize2 = (path) => {
|
|
@@ -1560,7 +2166,7 @@ var resolveInject = () => {
|
|
|
1560
2166
|
return "/" + parts.join("/");
|
|
1561
2167
|
}, CHISEL_DEFINE, CHISEL_KEEP, CLIENT_INJECT = "/__sdk/inject.ts", SERVER_INJECT = "/__sdk/server/inject.ts", EDITOR_INJECT = "/__sdk/inject.editor.ts", readInjectSources = () => {
|
|
1562
2168
|
const client = resolveInject();
|
|
1563
|
-
return { client:
|
|
2169
|
+
return { client: readFileSync5(client, "utf8"), server: readFileSync5(join7(dirname4(client), "server", "inject.ts"), "utf8") };
|
|
1564
2170
|
}, resolveSdkSrc = () => {
|
|
1565
2171
|
const inject = resolveInject();
|
|
1566
2172
|
if (!inject.endsWith("inject.ts")) {
|
|
@@ -1574,11 +2180,11 @@ var resolveInject = () => {
|
|
|
1574
2180
|
const out = {};
|
|
1575
2181
|
const walk = (dir) => {
|
|
1576
2182
|
for (const name of readdirSync(dir)) {
|
|
1577
|
-
const p =
|
|
2183
|
+
const p = join7(dir, name);
|
|
1578
2184
|
if (statSync(p).isDirectory())
|
|
1579
2185
|
walk(p);
|
|
1580
2186
|
else if (isSdkSource(p))
|
|
1581
|
-
out["/__sdk/" + relative(sdkSrc, p).split("\\").join("/")] =
|
|
2187
|
+
out["/__sdk/" + relative(sdkSrc, p).split("\\").join("/")] = readFileSync5(p, "utf8");
|
|
1582
2188
|
}
|
|
1583
2189
|
};
|
|
1584
2190
|
walk(sdkSrc);
|
|
@@ -1587,13 +2193,13 @@ var resolveInject = () => {
|
|
|
1587
2193
|
}, resolveChiselBin = () => {
|
|
1588
2194
|
const override = process.env.LECODES_CHISEL_BIN;
|
|
1589
2195
|
if (override) {
|
|
1590
|
-
if (
|
|
2196
|
+
if (existsSync6(override))
|
|
1591
2197
|
return override;
|
|
1592
2198
|
throw new Error(`LECODES_CHISEL_BIN points at a missing file: ${override}`);
|
|
1593
2199
|
}
|
|
1594
2200
|
try {
|
|
1595
2201
|
const bin = createRequire3(import.meta.url)("@letary/chisel").binaryPath();
|
|
1596
|
-
if (bin &&
|
|
2202
|
+
if (bin && existsSync6(bin))
|
|
1597
2203
|
return bin;
|
|
1598
2204
|
} catch {}
|
|
1599
2205
|
throw new Error("chisel binary not found. Install @letary/chisel, or set LECODES_CHISEL_BIN.");
|
|
@@ -1605,7 +2211,7 @@ var resolveInject = () => {
|
|
|
1605
2211
|
return null;
|
|
1606
2212
|
}
|
|
1607
2213
|
const input = JSON.stringify({ scan: true, files });
|
|
1608
|
-
const r =
|
|
2214
|
+
const r = spawnSync4(bin, [], { input, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
|
|
1609
2215
|
if (r.status !== 0 || r.error)
|
|
1610
2216
|
return null;
|
|
1611
2217
|
try {
|
|
@@ -1646,11 +2252,13 @@ var resolveInject = () => {
|
|
|
1646
2252
|
if (missing.length > 0)
|
|
1647
2253
|
throw new Error(missing.join(`
|
|
1648
2254
|
`));
|
|
1649
|
-
}, bundleProjectChisel = async (entrypoint, files, format, sourcemap, minifyOverride, editor, libraries, inject = CLIENT_INJECT) => {
|
|
2255
|
+
}, bundleProjectChisel = async (entrypoint, files, format, sourcemap, minifyOverride, editor, libraries, inject = CLIENT_INJECT, readResource) => {
|
|
1650
2256
|
const entry = normalize2(entrypoint);
|
|
1651
2257
|
const slugs = new Set(Object.keys(libraries ?? {}));
|
|
2258
|
+
const rootKeys = new Map(Object.keys(files).map((k) => [normalize2(k), k]));
|
|
1652
2259
|
const projFiles = {};
|
|
1653
2260
|
const assetRefs = [];
|
|
2261
|
+
const bakeRefs = [];
|
|
1654
2262
|
const scanSources = {};
|
|
1655
2263
|
for (const [k, v] of Object.entries(files)) {
|
|
1656
2264
|
const path = normalize2(k);
|
|
@@ -1659,6 +2267,12 @@ var resolveInject = () => {
|
|
|
1659
2267
|
if (hasImportStatement(src))
|
|
1660
2268
|
src = rewriteLibraryImports(src, slugs);
|
|
1661
2269
|
scanSources[path] = src;
|
|
2270
|
+
if (hasBakeMacro(src)) {
|
|
2271
|
+
const expanded = await expandBakeMacros(src, path, (rootPath) => rootKeys.has(rootPath), readResource);
|
|
2272
|
+
for (const ref of expanded.bakes)
|
|
2273
|
+
bakeRefs.push({ file: path, ref });
|
|
2274
|
+
src = expanded.src;
|
|
2275
|
+
}
|
|
1662
2276
|
const macros = hasAssetMacro(src) ? collectAssetMacros(src, path) : [];
|
|
1663
2277
|
const paths = collectPathLiterals(src, path, (rootPath) => files[rootPath] !== undefined, macros);
|
|
1664
2278
|
const found = macros.concat(paths).sort((a, b) => a.index - b.index);
|
|
@@ -1692,8 +2306,22 @@ var resolveInject = () => {
|
|
|
1692
2306
|
projFiles[path] = src;
|
|
1693
2307
|
}
|
|
1694
2308
|
}
|
|
1695
|
-
|
|
2309
|
+
const bakes = [];
|
|
2310
|
+
const notes = [];
|
|
2311
|
+
if (assetRefs.length > 0 || bakeRefs.length > 0) {
|
|
1696
2312
|
const reachable = reachableFrom(entry, scanSources);
|
|
2313
|
+
const reached = bakeRefs.filter(({ file }) => reachable.has(file));
|
|
2314
|
+
const incomplete = reached.filter(({ ref }) => ref.missing.length > 0);
|
|
2315
|
+
if (incomplete.length > 0) {
|
|
2316
|
+
throw new Error(incomplete.map(({ file, ref }) => `bake('${ref.written}') (${file.replace(/^\//, "")}:${ref.line}): ${ref.path} names files that are not there: ${ref.missing.map((p) => p.replace(/^\//, "")).join(", ")} — rebake with \`lecodes lightmap bake\``).join(`
|
|
2317
|
+
`));
|
|
2318
|
+
}
|
|
2319
|
+
for (const { file, ref } of reached) {
|
|
2320
|
+
if (!bakes.some((b) => b.path === ref.path))
|
|
2321
|
+
bakes.push({ path: ref.path, exists: ref.exists });
|
|
2322
|
+
if (ref.unread)
|
|
2323
|
+
notes.push(`${file.replace(/^\//, "")}:${ref.line}: bake('${ref.written}'): this compile cannot read ${ref.path} — the level runs unbaked`);
|
|
2324
|
+
}
|
|
1697
2325
|
assertAssetsExist(assetRefs.filter(({ file }) => reachable.has(file)), projFiles);
|
|
1698
2326
|
}
|
|
1699
2327
|
const sdkFiles = collectSdkFiles(resolveSdkSrc());
|
|
@@ -1713,7 +2341,7 @@ var resolveInject = () => {
|
|
|
1713
2341
|
vocab: chiselVocab
|
|
1714
2342
|
});
|
|
1715
2343
|
const bin = resolveChiselBin();
|
|
1716
|
-
const r =
|
|
2344
|
+
const r = spawnSync4(bin, [], { input, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
|
|
1717
2345
|
if (r.status === 2 || r.error) {
|
|
1718
2346
|
throw new Error(`chisel failed: ${r.error?.message ?? r.stderr ?? "unknown error"}`);
|
|
1719
2347
|
}
|
|
@@ -1727,13 +2355,14 @@ var resolveInject = () => {
|
|
|
1727
2355
|
throw new Error(`chisel: ${parsed.error}`);
|
|
1728
2356
|
if (parsed.code == null)
|
|
1729
2357
|
throw new Error("chisel produced no code");
|
|
1730
|
-
const diagnostics = parsed.diagnostics ?? [];
|
|
2358
|
+
const diagnostics = [...notes, ...parsed.diagnostics ?? []];
|
|
1731
2359
|
for (const d of diagnostics)
|
|
1732
2360
|
console.warn(`warning: ${d}`);
|
|
1733
|
-
return { code: parsed.code, map: parsed.map ?? null, diagnostics };
|
|
1734
|
-
}, bundleProjectWithMap = async (entrypoint, files, format = "esm", minify, editor, libraries, sourcemap = true, inject) => bundleProjectChisel(entrypoint, files, format, sourcemap, minify, editor, libraries, inject);
|
|
2361
|
+
return { code: parsed.code, map: parsed.map ?? null, diagnostics, bakes };
|
|
2362
|
+
}, bundleProjectWithMap = async (entrypoint, files, format = "esm", minify, editor, libraries, sourcemap = true, inject, readResource) => bundleProjectChisel(entrypoint, files, format, sourcemap, minify, editor, libraries, inject, readResource);
|
|
1735
2363
|
var init_bundler = __esm(() => {
|
|
1736
2364
|
init_assetMacro();
|
|
2365
|
+
init_bakeMacro();
|
|
1737
2366
|
init_detectEntry();
|
|
1738
2367
|
init_aspectMacro();
|
|
1739
2368
|
init_libraryImports();
|
|
@@ -170839,6 +171468,18 @@ var init_shaderSchema = __esm(() => {
|
|
|
170839
171468
|
COLOR_NAME = /colou?r|tint|albedo|emissive|glare|glow/i;
|
|
170840
171469
|
});
|
|
170841
171470
|
|
|
171471
|
+
// ../../sdk/src/compile/sourcemap.ts
|
|
171472
|
+
var offsetSourceMap = (mapJson, lines) => {
|
|
171473
|
+
if (lines <= 0)
|
|
171474
|
+
return mapJson;
|
|
171475
|
+
const map = JSON.parse(mapJson);
|
|
171476
|
+
map.mappings = ";".repeat(lines) + map.mappings;
|
|
171477
|
+
return JSON.stringify(map);
|
|
171478
|
+
}, inlineSourceMapComment = (mapJson) => {
|
|
171479
|
+
const b64 = Buffer.from(mapJson, "utf8").toString("base64");
|
|
171480
|
+
return `//# lecodesMap=data:application/json;charset=utf-8;base64,${b64}`;
|
|
171481
|
+
};
|
|
171482
|
+
|
|
170842
171483
|
// ../../sdk/src/compile/header.ts
|
|
170843
171484
|
var ENGINE_SIGNALS, buildHeader = (name, code, opts = {}) => {
|
|
170844
171485
|
let header = `// sdk: ${SDK_VERSION}
|
|
@@ -170904,333 +171545,6 @@ var init_header = __esm(() => {
|
|
|
170904
171545
|
];
|
|
170905
171546
|
});
|
|
170906
171547
|
|
|
170907
|
-
// ../../sdk/src/compile/sourcemap.ts
|
|
170908
|
-
var offsetSourceMap = (mapJson, lines) => {
|
|
170909
|
-
if (lines <= 0)
|
|
170910
|
-
return mapJson;
|
|
170911
|
-
const map = JSON.parse(mapJson);
|
|
170912
|
-
map.mappings = ";".repeat(lines) + map.mappings;
|
|
170913
|
-
return JSON.stringify(map);
|
|
170914
|
-
}, inlineSourceMapComment = (mapJson) => {
|
|
170915
|
-
const b64 = Buffer.from(mapJson, "utf8").toString("base64");
|
|
170916
|
-
return `//# lecodesMap=data:application/json;charset=utf-8;base64,${b64}`;
|
|
170917
|
-
};
|
|
170918
|
-
|
|
170919
|
-
// ../../sdk/src/compile/assetIconMacro.ts
|
|
170920
|
-
var ICON_ID, isIdentStart = (c) => c >= "A" && c <= "Z" || c >= "a" && c <= "z" || c === "_" || c === "$", isIdentPart = (c) => isIdentStart(c) || c >= "0" && c <= "9", skipString2 = (src, start) => {
|
|
170921
|
-
const quote = src[start];
|
|
170922
|
-
const n = src.length;
|
|
170923
|
-
let i = start + 1;
|
|
170924
|
-
while (i < n) {
|
|
170925
|
-
const c = src[i];
|
|
170926
|
-
if (c === "\\") {
|
|
170927
|
-
i += 2;
|
|
170928
|
-
continue;
|
|
170929
|
-
}
|
|
170930
|
-
if (quote === "`" && c === "$" && src[i + 1] === "{") {
|
|
170931
|
-
i = skipBraces(src, i + 1);
|
|
170932
|
-
continue;
|
|
170933
|
-
}
|
|
170934
|
-
if (c === quote)
|
|
170935
|
-
return i + 1;
|
|
170936
|
-
i++;
|
|
170937
|
-
}
|
|
170938
|
-
return n;
|
|
170939
|
-
}, skipBraces = (src, open) => {
|
|
170940
|
-
const n = src.length;
|
|
170941
|
-
let depth = 0;
|
|
170942
|
-
let i = open;
|
|
170943
|
-
while (i < n) {
|
|
170944
|
-
const c = src[i];
|
|
170945
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
170946
|
-
i = skipString2(src, i);
|
|
170947
|
-
continue;
|
|
170948
|
-
}
|
|
170949
|
-
if (c === "{")
|
|
170950
|
-
depth++;
|
|
170951
|
-
else if (c === "}") {
|
|
170952
|
-
depth--;
|
|
170953
|
-
if (depth === 0)
|
|
170954
|
-
return i + 1;
|
|
170955
|
-
}
|
|
170956
|
-
i++;
|
|
170957
|
-
}
|
|
170958
|
-
return n;
|
|
170959
|
-
}, matchParen = (src, open) => {
|
|
170960
|
-
const n = src.length;
|
|
170961
|
-
let depth = 0;
|
|
170962
|
-
let i = open;
|
|
170963
|
-
while (i < n) {
|
|
170964
|
-
const c = src[i];
|
|
170965
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
170966
|
-
i = skipString2(src, i);
|
|
170967
|
-
continue;
|
|
170968
|
-
}
|
|
170969
|
-
if (c === "/" && src[i + 1] === "/") {
|
|
170970
|
-
i += 2;
|
|
170971
|
-
while (i < n && src[i] !== `
|
|
170972
|
-
`)
|
|
170973
|
-
i++;
|
|
170974
|
-
continue;
|
|
170975
|
-
}
|
|
170976
|
-
if (c === "/" && src[i + 1] === "*") {
|
|
170977
|
-
i += 2;
|
|
170978
|
-
while (i < n && !(src[i] === "*" && src[i + 1] === "/"))
|
|
170979
|
-
i++;
|
|
170980
|
-
i += 2;
|
|
170981
|
-
continue;
|
|
170982
|
-
}
|
|
170983
|
-
if (c === "(")
|
|
170984
|
-
depth++;
|
|
170985
|
-
else if (c === ")") {
|
|
170986
|
-
depth--;
|
|
170987
|
-
if (depth === 0)
|
|
170988
|
-
return i;
|
|
170989
|
-
}
|
|
170990
|
-
i++;
|
|
170991
|
-
}
|
|
170992
|
-
return -1;
|
|
170993
|
-
}, splitTopLevel = (text, delim) => {
|
|
170994
|
-
const parts = [];
|
|
170995
|
-
const n = text.length;
|
|
170996
|
-
let depth = 0;
|
|
170997
|
-
let last = 0;
|
|
170998
|
-
let i = 0;
|
|
170999
|
-
while (i < n) {
|
|
171000
|
-
const c = text[i];
|
|
171001
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
171002
|
-
i = skipString2(text, i);
|
|
171003
|
-
continue;
|
|
171004
|
-
}
|
|
171005
|
-
if (c === "(" || c === "[" || c === "{")
|
|
171006
|
-
depth++;
|
|
171007
|
-
else if (c === ")" || c === "]" || c === "}")
|
|
171008
|
-
depth = Math.max(0, depth - 1);
|
|
171009
|
-
else if (depth === 0 && c === delim) {
|
|
171010
|
-
parts.push(text.slice(last, i));
|
|
171011
|
-
last = i + 1;
|
|
171012
|
-
}
|
|
171013
|
-
i++;
|
|
171014
|
-
}
|
|
171015
|
-
parts.push(text.slice(last));
|
|
171016
|
-
return parts;
|
|
171017
|
-
}, stringLiteralValue = (text) => {
|
|
171018
|
-
const t = text.trim();
|
|
171019
|
-
if (t.length < 2)
|
|
171020
|
-
return null;
|
|
171021
|
-
const q = t[0];
|
|
171022
|
-
if (q !== '"' && q !== "'" && q !== "`" || t[t.length - 1] !== q)
|
|
171023
|
-
return null;
|
|
171024
|
-
const inner = t.slice(1, -1);
|
|
171025
|
-
if (q === "`" && inner.includes("${"))
|
|
171026
|
-
return null;
|
|
171027
|
-
if (inner.includes(q) && !inner.includes("\\" + q))
|
|
171028
|
-
return null;
|
|
171029
|
-
return inner.replace(/\\(.)/g, "$1");
|
|
171030
|
-
}, scanAssetIconCalls = (source) => {
|
|
171031
|
-
const calls = [];
|
|
171032
|
-
const n = source.length;
|
|
171033
|
-
let i = 0;
|
|
171034
|
-
while (i < n) {
|
|
171035
|
-
const c = source[i];
|
|
171036
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
171037
|
-
i = skipString2(source, i);
|
|
171038
|
-
continue;
|
|
171039
|
-
}
|
|
171040
|
-
if (c === "/" && source[i + 1] === "/") {
|
|
171041
|
-
i += 2;
|
|
171042
|
-
while (i < n && source[i] !== `
|
|
171043
|
-
`)
|
|
171044
|
-
i++;
|
|
171045
|
-
continue;
|
|
171046
|
-
}
|
|
171047
|
-
if (c === "/" && source[i + 1] === "*") {
|
|
171048
|
-
i += 2;
|
|
171049
|
-
while (i < n && !(source[i] === "*" && source[i + 1] === "/"))
|
|
171050
|
-
i++;
|
|
171051
|
-
i += 2;
|
|
171052
|
-
continue;
|
|
171053
|
-
}
|
|
171054
|
-
if (isIdentStart(c)) {
|
|
171055
|
-
let j = i + 1;
|
|
171056
|
-
while (j < n && isIdentPart(source[j]))
|
|
171057
|
-
j++;
|
|
171058
|
-
if (source.slice(i, j) === "assetIcon" && prevNonSpace(source, i) !== ".") {
|
|
171059
|
-
const call = parseCall(source, i, j);
|
|
171060
|
-
if (call) {
|
|
171061
|
-
calls.push(call);
|
|
171062
|
-
i = call.end;
|
|
171063
|
-
continue;
|
|
171064
|
-
}
|
|
171065
|
-
}
|
|
171066
|
-
i = j;
|
|
171067
|
-
continue;
|
|
171068
|
-
}
|
|
171069
|
-
i++;
|
|
171070
|
-
}
|
|
171071
|
-
return calls;
|
|
171072
|
-
}, prevNonSpace = (src, i) => {
|
|
171073
|
-
let k = i - 1;
|
|
171074
|
-
while (k >= 0 && /\s/.test(src[k]))
|
|
171075
|
-
k--;
|
|
171076
|
-
return k >= 0 ? src[k] : "";
|
|
171077
|
-
}, parseCall = (src, start, identEnd) => {
|
|
171078
|
-
const n = src.length;
|
|
171079
|
-
let i = identEnd;
|
|
171080
|
-
while (i < n && /\s/.test(src[i]))
|
|
171081
|
-
i++;
|
|
171082
|
-
if (src[i] !== "(")
|
|
171083
|
-
return null;
|
|
171084
|
-
const close = matchParen(src, i);
|
|
171085
|
-
if (close === -1)
|
|
171086
|
-
return null;
|
|
171087
|
-
const call = { start, end: close + 1, id: "", pack: "", name: "" };
|
|
171088
|
-
const args = splitTopLevel(src.slice(i + 1, close), ",");
|
|
171089
|
-
const id = stringLiteralValue(args[0] ?? "");
|
|
171090
|
-
if (id === null) {
|
|
171091
|
-
call.error = `assetIcon(...) needs a string-literal id like "lucide:bell" (got \`${(args[0] ?? "").trim() || "()"}\`).`;
|
|
171092
|
-
return call;
|
|
171093
|
-
}
|
|
171094
|
-
const m = ICON_ID.exec(id);
|
|
171095
|
-
if (!m) {
|
|
171096
|
-
call.error = `assetIcon("${id}"): id must be "pack:name", lowercase [a-z0-9-] (e.g. "lucide:bell").`;
|
|
171097
|
-
return call;
|
|
171098
|
-
}
|
|
171099
|
-
call.id = id;
|
|
171100
|
-
call.pack = m[1];
|
|
171101
|
-
call.name = m[2];
|
|
171102
|
-
const optsText = args[1]?.trim();
|
|
171103
|
-
if (optsText) {
|
|
171104
|
-
const color = extractColor(optsText);
|
|
171105
|
-
if (color.error) {
|
|
171106
|
-
call.error = color.error;
|
|
171107
|
-
return call;
|
|
171108
|
-
}
|
|
171109
|
-
if (color.bake !== undefined)
|
|
171110
|
-
call.bake = color.bake;
|
|
171111
|
-
else if (color.tint !== undefined)
|
|
171112
|
-
call.tint = color.tint;
|
|
171113
|
-
}
|
|
171114
|
-
return call;
|
|
171115
|
-
}, extractColor = (optsText) => {
|
|
171116
|
-
if (!optsText.startsWith("{") || !optsText.endsWith("}")) {
|
|
171117
|
-
return { error: `assetIcon(id, opts): opts must be an object literal like { color: "#5b8cff" }.` };
|
|
171118
|
-
}
|
|
171119
|
-
for (const prop of splitTopLevel(optsText.slice(1, -1), ",")) {
|
|
171120
|
-
const kv = splitTopLevel(prop, ":");
|
|
171121
|
-
if (kv.length < 2)
|
|
171122
|
-
continue;
|
|
171123
|
-
const key = kv[0].trim().replace(/^["'`]|["'`]$/g, "");
|
|
171124
|
-
if (key !== "color")
|
|
171125
|
-
continue;
|
|
171126
|
-
const raw = kv.slice(1).join(":").trim();
|
|
171127
|
-
if (!raw)
|
|
171128
|
-
continue;
|
|
171129
|
-
const literal = stringLiteralValue(raw);
|
|
171130
|
-
return literal !== null ? { bake: literal } : { tint: raw };
|
|
171131
|
-
}
|
|
171132
|
-
return {};
|
|
171133
|
-
}, rewriteAssetIcons = (source, calls, svgById) => {
|
|
171134
|
-
let out = source;
|
|
171135
|
-
for (const call of [...calls].sort((a, b) => b.start - a.start)) {
|
|
171136
|
-
const svg = svgById.get(call.id);
|
|
171137
|
-
if (svg === undefined)
|
|
171138
|
-
continue;
|
|
171139
|
-
out = out.slice(0, call.start) + iconExpr(svg, call) + out.slice(call.end);
|
|
171140
|
-
}
|
|
171141
|
-
return out;
|
|
171142
|
-
}, iconExpr = (svg, call) => {
|
|
171143
|
-
const body = call.bake ? svg.split("currentColor").join(call.bake) : svg;
|
|
171144
|
-
const src = `SvgSource(\`${escapeTemplate(body)}\`)`;
|
|
171145
|
-
return call.tint ? `Object.assign(${src}, { tintColor: (${call.tint}) })` : src;
|
|
171146
|
-
}, escapeTemplate = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${"), applyAssetIconMacro = async (entries, resolveSvgs) => {
|
|
171147
|
-
const scanned = entries.filter((e) => e.type === "text" && typeof e.text === "string" && e.text.includes("assetIcon")).map((e) => ({ entry: e, calls: scanAssetIconCalls(e.text) })).filter((s) => s.calls.length > 0);
|
|
171148
|
-
if (scanned.length === 0)
|
|
171149
|
-
return [];
|
|
171150
|
-
const errors = scanned.flatMap((s) => s.calls.filter((c) => c.error).map((c) => c.error));
|
|
171151
|
-
if (errors.length)
|
|
171152
|
-
throw new Error([...new Set(errors)].join(`
|
|
171153
|
-
`));
|
|
171154
|
-
const ids = [...new Set(scanned.flatMap((s) => s.calls.map((c) => c.id)))];
|
|
171155
|
-
const svgById = await resolveSvgs(ids);
|
|
171156
|
-
const missing = ids.filter((id) => !svgById.has(id));
|
|
171157
|
-
if (missing.length)
|
|
171158
|
-
throw new Error(`assetIcon: could not resolve icon(s): ${missing.join(", ")}.`);
|
|
171159
|
-
for (const { entry, calls } of scanned)
|
|
171160
|
-
entry.text = rewriteAssetIcons(entry.text, calls, svgById);
|
|
171161
|
-
return ids;
|
|
171162
|
-
}, buildIconsHeaderValue = (ids) => [...new Set(ids.map((id) => id.split(":")[0]))].sort().join(";"), editDistance = (a, b, cap) => {
|
|
171163
|
-
if (Math.abs(a.length - b.length) > cap)
|
|
171164
|
-
return cap + 1;
|
|
171165
|
-
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
171166
|
-
for (let i = 1;i <= a.length; i++) {
|
|
171167
|
-
const cur = [i];
|
|
171168
|
-
let rowMin = i;
|
|
171169
|
-
for (let j = 1;j <= b.length; j++) {
|
|
171170
|
-
cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
171171
|
-
if (cur[j] < rowMin)
|
|
171172
|
-
rowMin = cur[j];
|
|
171173
|
-
}
|
|
171174
|
-
if (rowMin > cap)
|
|
171175
|
-
return cap + 1;
|
|
171176
|
-
prev = cur;
|
|
171177
|
-
}
|
|
171178
|
-
return prev[b.length];
|
|
171179
|
-
}, suggestIconNames = (want, icons) => {
|
|
171180
|
-
const wantParts = new Set(want.split("-").filter(Boolean));
|
|
171181
|
-
const scored = [];
|
|
171182
|
-
for (const [name, info] of Object.entries(icons)) {
|
|
171183
|
-
const lenDiff = Math.abs(name.length - want.length) / 100;
|
|
171184
|
-
let rank;
|
|
171185
|
-
if (name.includes(want) || want.includes(name))
|
|
171186
|
-
rank = lenDiff;
|
|
171187
|
-
else {
|
|
171188
|
-
const d = editDistance(want, name, 2);
|
|
171189
|
-
if (d <= 2)
|
|
171190
|
-
rank = 1 + d;
|
|
171191
|
-
else if (info.kw?.some((k) => wantParts.has(k)))
|
|
171192
|
-
rank = 4 + lenDiff;
|
|
171193
|
-
else
|
|
171194
|
-
continue;
|
|
171195
|
-
}
|
|
171196
|
-
scored.push({ name, rank });
|
|
171197
|
-
}
|
|
171198
|
-
return scored.sort((a, b) => a.rank - b.rank || (a.name < b.name ? -1 : 1)).slice(0, 5).map((s) => s.name);
|
|
171199
|
-
}, iconNotFoundError = async (pack, name, read, registry) => {
|
|
171200
|
-
const metaRaw = await read(`${pack}/meta.json`);
|
|
171201
|
-
if (metaRaw !== null) {
|
|
171202
|
-
let icons = {};
|
|
171203
|
-
try {
|
|
171204
|
-
icons = JSON.parse(metaRaw).icons ?? {};
|
|
171205
|
-
} catch {}
|
|
171206
|
-
const similar = suggestIconNames(name, icons);
|
|
171207
|
-
const hint = similar.length ? ` Did you mean ${similar.map((s) => `"${pack}:${s}"`).join(", ")}?` : ` No similar name in the "${pack}" pack either.`;
|
|
171208
|
-
return new Error(`assetIcon: icon "${pack}:${name}" not found.${hint}`);
|
|
171209
|
-
}
|
|
171210
|
-
const licRaw = await read("licenses.json");
|
|
171211
|
-
if (licRaw !== null) {
|
|
171212
|
-
try {
|
|
171213
|
-
const packs = Object.keys(JSON.parse(licRaw)).sort();
|
|
171214
|
-
return new Error(`assetIcon: unknown icon pack "${pack}" (in "${pack}:${name}"). Available packs: ${packs.join(", ")}.`);
|
|
171215
|
-
} catch {}
|
|
171216
|
-
}
|
|
171217
|
-
return Object.assign(new Error(`assetIcon: can't reach the icon registry${registry ? ` (${registry})` : ""} to resolve "${pack}:${name}". ` + `Check your connection, or set LECODES_ICON_REGISTRY.`), { transient: true });
|
|
171218
|
-
}, VENDORED_ICON_PATH, collectVendoredIcons = (entries) => {
|
|
171219
|
-
const map = new Map;
|
|
171220
|
-
for (const e of entries) {
|
|
171221
|
-
if (e.type !== "text" || typeof e.text !== "string")
|
|
171222
|
-
continue;
|
|
171223
|
-
const m = VENDORED_ICON_PATH.exec(e.path);
|
|
171224
|
-
if (m)
|
|
171225
|
-
map.set(`${m[1]}:${m[2]}`, e.text);
|
|
171226
|
-
}
|
|
171227
|
-
return map;
|
|
171228
|
-
};
|
|
171229
|
-
var init_assetIconMacro = __esm(() => {
|
|
171230
|
-
ICON_ID = /^([a-z0-9]+(?:-[a-z0-9]+)*):([a-z0-9]+(?:-[a-z0-9]+)*)$/;
|
|
171231
|
-
VENDORED_ICON_PATH = /(?:^|\/)assets\/icons\/([a-z0-9]+(?:-[a-z0-9]+)*)\/([a-z0-9]+(?:-[a-z0-9]+)*)\.svg$/;
|
|
171232
|
-
});
|
|
171233
|
-
|
|
171234
171548
|
// ../../sdk/src/compile/compileProject.ts
|
|
171235
171549
|
var localAssetBase = (path) => path.split(/[\\/]/).pop() ?? path, localAssetNames = (entries) => {
|
|
171236
171550
|
const seen = new Map;
|
|
@@ -171328,7 +171642,7 @@ var localAssetBase = (path) => path.split(/[\\/]/).pop() ?? path, localAssetName
|
|
|
171328
171642
|
throw new Error("Couldn't find an entrypoint (no .ts/.js project file — name yours main.ts). Pass entryOverride.");
|
|
171329
171643
|
}
|
|
171330
171644
|
const files = entriesToFiles(entries, opts);
|
|
171331
|
-
const { code, map } = await bundleProjectWithMap(entry, files, opts.format ?? "esm", opts.minify, opts.editor, opts.libraries, opts.sourcemap ?? true);
|
|
171645
|
+
const { code, map, bakes } = await bundleProjectWithMap(entry, files, opts.format ?? "esm", opts.minify, opts.editor, opts.libraries, opts.sourcemap ?? true, undefined, opts.readResource);
|
|
171332
171646
|
const plugins = opts.plugins ?? pluginsOfAppJson(entries);
|
|
171333
171647
|
if (map && opts.onWarning) {
|
|
171334
171648
|
const missing = pluginsOfBundle(map).filter((id) => !plugins.includes(id));
|
|
@@ -171337,14 +171651,10 @@ var localAssetBase = (path) => path.split(/[\\/]/).pop() ?? path, localAssetName
|
|
|
171337
171651
|
}
|
|
171338
171652
|
}
|
|
171339
171653
|
if (opts.header === false)
|
|
171340
|
-
return { code, map, entry };
|
|
171654
|
+
return { code, map, entry, bakes };
|
|
171341
171655
|
const header = buildHeader(opts.name, code, { icon: opts.icon, fonts: opts.fontsHeader, icons: opts.iconsHeader, plugins });
|
|
171342
171656
|
const headerLines = (header.match(/\n/g) ?? []).length;
|
|
171343
|
-
return { code: header + code, map: map ? offsetSourceMap(map, headerLines) : null, entry };
|
|
171344
|
-
}, compileProject = async (opts) => {
|
|
171345
|
-
const { code, map } = await compileProjectWithMap(opts);
|
|
171346
|
-
return map ? `${code}
|
|
171347
|
-
${inlineSourceMapComment(map)}` : code;
|
|
171657
|
+
return { code: header + code, map: map ? offsetSourceMap(map, headerLines) : null, entry, bakes };
|
|
171348
171658
|
};
|
|
171349
171659
|
var init_compileProject = __esm(() => {
|
|
171350
171660
|
init_bundler();
|
|
@@ -171811,7 +172121,7 @@ var FONT_ID, CODE_FILE, DECLARES_FONT, isIdentStart2 = (c) => c >= "A" && c <= "
|
|
|
171811
172121
|
}
|
|
171812
172122
|
parts.push(text.slice(last));
|
|
171813
172123
|
return parts;
|
|
171814
|
-
},
|
|
172124
|
+
}, stringLiteralValue3 = (text) => {
|
|
171815
172125
|
const t = text.trim();
|
|
171816
172126
|
if (t.length < 2)
|
|
171817
172127
|
return null;
|
|
@@ -171883,7 +172193,7 @@ var FONT_ID, CODE_FILE, DECLARES_FONT, isIdentStart2 = (c) => c >= "A" && c <= "
|
|
|
171883
172193
|
return null;
|
|
171884
172194
|
const call = { start, end: close + 1, arg: "", kind: "registry" };
|
|
171885
172195
|
const args = splitTopLevel2(src.slice(i + 1, close), ",");
|
|
171886
|
-
const arg =
|
|
172196
|
+
const arg = stringLiteralValue3(args[0] ?? "");
|
|
171887
172197
|
if (arg === null) {
|
|
171888
172198
|
call.error = `font(...) needs a string-literal argument — a registry id ("manrope") or a project path ("./fonts/Brand.ttf"). Got \`${(args[0] ?? "").trim() || "()"}\`.`;
|
|
171889
172199
|
return call;
|
|
@@ -172138,15 +172448,15 @@ var init_compile = __esm(() => {
|
|
|
172138
172448
|
});
|
|
172139
172449
|
|
|
172140
172450
|
// src/compile/projectCompile.ts
|
|
172141
|
-
import { existsSync as
|
|
172451
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
|
|
172142
172452
|
import { createRequire as createRequire4 } from "node:module";
|
|
172143
|
-
import { dirname as dirname6, join as
|
|
172453
|
+
import { dirname as dirname6, join as join8 } from "node:path";
|
|
172144
172454
|
var resolveSdkInject = () => {
|
|
172145
172455
|
try {
|
|
172146
172456
|
return createRequire4(import.meta.url).resolve("lecodes-sdk/inject");
|
|
172147
172457
|
} catch {}
|
|
172148
|
-
const vendored =
|
|
172149
|
-
return
|
|
172458
|
+
const vendored = join8(distRoot, "runtime", "sdk", "inject.ts");
|
|
172459
|
+
return existsSync7(vendored) ? vendored : null;
|
|
172150
172460
|
}, sdkInject, sdkSourceDir, resolveChiselBin2 = () => {
|
|
172151
172461
|
if (process.env.LECODES_CHISEL_BIN)
|
|
172152
172462
|
return process.env.LECODES_CHISEL_BIN;
|
|
@@ -172155,29 +172465,46 @@ var resolveSdkInject = () => {
|
|
|
172155
172465
|
if (fromPkg)
|
|
172156
172466
|
return fromPkg;
|
|
172157
172467
|
} catch {}
|
|
172158
|
-
const local =
|
|
172159
|
-
return
|
|
172468
|
+
const local = join8(dirname6(process.execPath), process.platform === "win32" ? "chisel.exe" : "chisel");
|
|
172469
|
+
return existsSync7(local) ? local : null;
|
|
172160
172470
|
}, chiselBin, ambiguousEntryWarning = (entries) => {
|
|
172161
172471
|
const { entry, roots } = detectEntry(entries, scanModulesChisel);
|
|
172162
172472
|
if (!entry || roots.length < 2 || roots.includes(ENTRY_CONVENTION))
|
|
172163
172473
|
return null;
|
|
172164
172474
|
return `Ambiguous entrypoint: nothing imports ${roots.join(", ")} — picked ${entry}. Rename your entry to main.ts (or pass --entry).`;
|
|
172165
|
-
},
|
|
172166
|
-
|
|
172167
|
-
|
|
172168
|
-
|
|
172169
|
-
|
|
172170
|
-
|
|
172171
|
-
|
|
172172
|
-
|
|
172173
|
-
|
|
172174
|
-
|
|
172175
|
-
|
|
172176
|
-
|
|
172177
|
-
|
|
172178
|
-
|
|
172179
|
-
|
|
172180
|
-
|
|
172475
|
+
}, resourceReader = (entries) => {
|
|
172476
|
+
const byRoot = new Map(entries.map((e) => ["/" + e.path.replace(/\\/g, "/").replace(/^[./]+/, ""), e]));
|
|
172477
|
+
return (rootPath) => {
|
|
172478
|
+
const e = byRoot.get(rootPath);
|
|
172479
|
+
if (e?.text !== undefined)
|
|
172480
|
+
return e.text;
|
|
172481
|
+
try {
|
|
172482
|
+
return e?.absPath ? readFileSync6(e.absPath, "utf8") : null;
|
|
172483
|
+
} catch {
|
|
172484
|
+
return null;
|
|
172485
|
+
}
|
|
172486
|
+
};
|
|
172487
|
+
}, compileProjectBundle = async (opts) => {
|
|
172488
|
+
const { code, map, bakes } = await compileProjectWithMap({
|
|
172489
|
+
entries: opts.entries.map((e) => ({ path: e.path, type: e.type, text: e.text, fileSrc: e.fileSrc, remote: e.remote, shaders: e.shaders, shadersLocal: e.shadersLocal })),
|
|
172490
|
+
readResource: resourceReader(opts.entries),
|
|
172491
|
+
name: opts.name,
|
|
172492
|
+
publicUrl: opts.publicUrl,
|
|
172493
|
+
entryOverride: opts.entryOverride,
|
|
172494
|
+
header: opts.header,
|
|
172495
|
+
fontsHeader: opts.fontsHeader,
|
|
172496
|
+
iconsHeader: opts.iconsHeader,
|
|
172497
|
+
format: opts.format,
|
|
172498
|
+
localAssets: opts.localAssets,
|
|
172499
|
+
minify: opts.minify,
|
|
172500
|
+
sourcemap: opts.sourcemap,
|
|
172501
|
+
editor: opts.editor,
|
|
172502
|
+
onWarning: opts.onWarning,
|
|
172503
|
+
serverUrl: opts.serverUrl
|
|
172504
|
+
});
|
|
172505
|
+
return { js: map ? `${code}
|
|
172506
|
+
${inlineSourceMapComment(map)}` : code, bakes };
|
|
172507
|
+
}, compileProject2 = async (opts) => (await compileProjectBundle(opts)).js, hasServerFiles = (entries) => entries.some((e) => e.type === "text" && isServerPath(e.path)), findTypescript = async (root) => {
|
|
172181
172508
|
const api = (mod) => mod?.createProgram ? mod : mod?.default?.createProgram ? mod.default : null;
|
|
172182
172509
|
const from = (at) => {
|
|
172183
172510
|
try {
|
|
@@ -172188,15 +172515,15 @@ var resolveSdkInject = () => {
|
|
|
172188
172515
|
};
|
|
172189
172516
|
const dir = peerDirInPrefix("typescript");
|
|
172190
172517
|
const peer = () => {
|
|
172191
|
-
if (!
|
|
172518
|
+
if (!existsSync7(join8(dir, "package.json")))
|
|
172192
172519
|
return null;
|
|
172193
172520
|
try {
|
|
172194
|
-
return api(createRequire4(import.meta.url)(
|
|
172521
|
+
return api(createRequire4(import.meta.url)(join8(dir, "lib", "typescript.js")));
|
|
172195
172522
|
} catch {
|
|
172196
172523
|
return null;
|
|
172197
172524
|
}
|
|
172198
172525
|
};
|
|
172199
|
-
const found = from(
|
|
172526
|
+
const found = from(join8(root, "package.json")) ?? from(import.meta.url) ?? peer();
|
|
172200
172527
|
if (found)
|
|
172201
172528
|
return found;
|
|
172202
172529
|
await installPeers(["typescript"], "The project's server code (*.server.ts)");
|
|
@@ -172381,8 +172708,8 @@ var init_assetName = __esm(() => {
|
|
|
172381
172708
|
});
|
|
172382
172709
|
|
|
172383
172710
|
// src/project/paths.ts
|
|
172384
|
-
import { createHash } from "node:crypto";
|
|
172385
|
-
var sha256 = (data) =>
|
|
172711
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
172712
|
+
var sha256 = (data) => createHash2("sha256").update(data).digest("hex"), toKey = (path) => {
|
|
172386
172713
|
const parts = path.replace(/\\/g, "/").split("/").map((p) => p.trim()).filter((p) => p && p !== ".");
|
|
172387
172714
|
if (parts.some((p) => p === ".."))
|
|
172388
172715
|
throw new CliError(`Unsafe path: ${path}`);
|
|
@@ -172397,8 +172724,8 @@ var init_paths = __esm(() => {
|
|
|
172397
172724
|
});
|
|
172398
172725
|
|
|
172399
172726
|
// src/project/ignore.ts
|
|
172400
|
-
import { existsSync as
|
|
172401
|
-
import { join as
|
|
172727
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
|
|
172728
|
+
import { join as join11 } from "node:path";
|
|
172402
172729
|
var BUILTIN_PATTERNS, DEFAULT_IGNORE_FILE = `# Files matched here are NOT pushed to LeCodes.
|
|
172403
172730
|
# Only untracked files are affected — assets already in the project stay tracked
|
|
172404
172731
|
# even if they match a pattern. Built-in defaults (node_modules, _*, *.log, .artifacts)
|
|
@@ -172479,18 +172806,18 @@ design/comments/
|
|
|
172479
172806
|
return (path) => match(path.startsWith("/") ? path : "/" + path, false);
|
|
172480
172807
|
}, loadIgnore = (root) => {
|
|
172481
172808
|
const lines = [...BUILTIN_PATTERNS];
|
|
172482
|
-
const file =
|
|
172483
|
-
if (
|
|
172809
|
+
const file = join11(root, ".lecodesignore");
|
|
172810
|
+
if (existsSync10(file)) {
|
|
172484
172811
|
try {
|
|
172485
|
-
lines.push(...
|
|
172812
|
+
lines.push(...readFileSync9(file, "utf8").split(/\r?\n/));
|
|
172486
172813
|
} catch {}
|
|
172487
172814
|
}
|
|
172488
172815
|
const rules = lines.map(compile).filter((r) => r !== null);
|
|
172489
172816
|
return buildMatcher(rules);
|
|
172490
172817
|
}, writeDefaultIgnore = (root) => {
|
|
172491
|
-
const file =
|
|
172492
|
-
if (!
|
|
172493
|
-
|
|
172818
|
+
const file = join11(root, ".lecodesignore");
|
|
172819
|
+
if (!existsSync10(file))
|
|
172820
|
+
writeFileSync4(file, DEFAULT_IGNORE_FILE);
|
|
172494
172821
|
}, DEFAULT_GITIGNORE = `# LeCodes per-checkout state: generated IDE types + this machine's sync cursor
|
|
172495
172822
|
# (.lecodes/manifest.json). Regenerate with \`lecodes update\` / re-attach with \`lecodes link\`.
|
|
172496
172823
|
.lecodes/
|
|
@@ -172505,19 +172832,19 @@ node_modules/
|
|
|
172505
172832
|
|
|
172506
172833
|
dist/
|
|
172507
172834
|
`, ensureGitignore = (root) => {
|
|
172508
|
-
const file =
|
|
172509
|
-
if (!
|
|
172510
|
-
|
|
172835
|
+
const file = join11(root, ".gitignore");
|
|
172836
|
+
if (!existsSync10(file)) {
|
|
172837
|
+
writeFileSync4(file, DEFAULT_GITIGNORE);
|
|
172511
172838
|
return "created";
|
|
172512
172839
|
}
|
|
172513
|
-
const text =
|
|
172840
|
+
const text = readFileSync9(file, "utf8");
|
|
172514
172841
|
const covered = text.split(/\r?\n/).some((l) => /^\/?\.lecodes\/?\s*$/.test(l.trim()));
|
|
172515
172842
|
if (covered)
|
|
172516
172843
|
return null;
|
|
172517
172844
|
const sep = text.length === 0 || text.endsWith(`
|
|
172518
172845
|
`) ? "" : `
|
|
172519
172846
|
`;
|
|
172520
|
-
|
|
172847
|
+
writeFileSync4(file, `${text}${sep}
|
|
172521
172848
|
# LeCodes per-checkout state (generated types + sync cursor) — not source
|
|
172522
172849
|
.lecodes/
|
|
172523
172850
|
`);
|
|
@@ -172528,8 +172855,8 @@ var init_ignore = __esm(() => {
|
|
|
172528
172855
|
});
|
|
172529
172856
|
|
|
172530
172857
|
// src/project/localFiles.ts
|
|
172531
|
-
import { existsSync as
|
|
172532
|
-
import { basename, dirname as dirname7, join as
|
|
172858
|
+
import { existsSync as existsSync11, readdirSync as readdirSync3, readFileSync as readFileSync10 } from "node:fs";
|
|
172859
|
+
import { basename, dirname as dirname7, join as join12, relative as relative3 } from "node:path";
|
|
172533
172860
|
var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
172534
172861
|
const i = name.lastIndexOf(".");
|
|
172535
172862
|
return i < 0 ? "" : name.slice(i + 1).toLowerCase();
|
|
@@ -172547,14 +172874,14 @@ var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
|
172547
172874
|
continue;
|
|
172548
172875
|
let folder;
|
|
172549
172876
|
try {
|
|
172550
|
-
folder = JSON.parse(
|
|
172877
|
+
folder = JSON.parse(readFileSync10(file.absPath, "utf8").replace(/^\uFEFF/, "")).web?.static;
|
|
172551
172878
|
} catch {
|
|
172552
172879
|
continue;
|
|
172553
172880
|
}
|
|
172554
172881
|
if (typeof folder !== "string" || folder.trim() === "")
|
|
172555
172882
|
continue;
|
|
172556
172883
|
try {
|
|
172557
|
-
folders.push(toKey(relative3(root,
|
|
172884
|
+
folders.push(toKey(relative3(root, join12(dirname7(file.absPath), folder))) + "/");
|
|
172558
172885
|
} catch {}
|
|
172559
172886
|
}
|
|
172560
172887
|
return folders;
|
|
@@ -172575,7 +172902,7 @@ var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
|
172575
172902
|
};
|
|
172576
172903
|
const walk = (dir, parentIgnored) => {
|
|
172577
172904
|
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
172578
|
-
const abs =
|
|
172905
|
+
const abs = join12(dir, entry.name);
|
|
172579
172906
|
const key = toKey(relative3(root, abs));
|
|
172580
172907
|
if (entry.isDirectory()) {
|
|
172581
172908
|
if (SKIP_DIRS.has(entry.name))
|
|
@@ -172595,7 +172922,7 @@ var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
|
172595
172922
|
ignored.push(key);
|
|
172596
172923
|
continue;
|
|
172597
172924
|
}
|
|
172598
|
-
found.push({ path: key, absPath: abs, sha: sha256(
|
|
172925
|
+
found.push({ path: key, absPath: abs, sha: sha256(readFileSync10(abs)) });
|
|
172599
172926
|
}
|
|
172600
172927
|
}
|
|
172601
172928
|
};
|
|
@@ -172607,8 +172934,8 @@ var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
|
172607
172934
|
}));
|
|
172608
172935
|
return { files, dirs, ignored };
|
|
172609
172936
|
}, resolveLocalPath = (root, key) => {
|
|
172610
|
-
const direct =
|
|
172611
|
-
if (
|
|
172937
|
+
const direct = join12(root, key.slice(1));
|
|
172938
|
+
if (existsSync11(direct))
|
|
172612
172939
|
return direct;
|
|
172613
172940
|
let dir = root;
|
|
172614
172941
|
try {
|
|
@@ -172616,7 +172943,7 @@ var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
|
172616
172943
|
const match = readdirSync3(dir).find((entry) => entry === name || sanitizeAssetName2(entry) === name);
|
|
172617
172944
|
if (!match)
|
|
172618
172945
|
return null;
|
|
172619
|
-
dir =
|
|
172946
|
+
dir = join12(dir, match);
|
|
172620
172947
|
}
|
|
172621
172948
|
} catch {
|
|
172622
172949
|
return null;
|
|
@@ -172675,9 +173002,9 @@ var init_localFiles = __esm(() => {
|
|
|
172675
173002
|
});
|
|
172676
173003
|
|
|
172677
173004
|
// src/compile/fonts.ts
|
|
172678
|
-
import { createHash as
|
|
172679
|
-
import { existsSync as
|
|
172680
|
-
import { dirname as dirname9, join as
|
|
173005
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
173006
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "node:fs";
|
|
173007
|
+
import { dirname as dirname9, join as join14 } from "node:path";
|
|
172681
173008
|
var applyProjectFonts = async (entries, opts) => {
|
|
172682
173009
|
const registry = (opts.registry ?? fontRegistryBase()).replace(/\/+$/, "");
|
|
172683
173010
|
const byPath = () => new Map(entries.map((e) => [e.path.replace(/^\//, ""), e]));
|
|
@@ -172686,9 +173013,9 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172686
173013
|
registryBase: registry,
|
|
172687
173014
|
readBytes: (entryPath) => {
|
|
172688
173015
|
const entry = byPath().get(entryPath);
|
|
172689
|
-
const abs = entry?.absPath ??
|
|
173016
|
+
const abs = entry?.absPath ?? join14(opts.root, entryPath);
|
|
172690
173017
|
try {
|
|
172691
|
-
return new Uint8Array(
|
|
173018
|
+
return new Uint8Array(readFileSync13(abs));
|
|
172692
173019
|
} catch {
|
|
172693
173020
|
return null;
|
|
172694
173021
|
}
|
|
@@ -172696,9 +173023,9 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172696
173023
|
vendorFace: opts.mode === "vendor" ? async (face) => {
|
|
172697
173024
|
const vendorDir = opts.vendorDir ?? opts.root;
|
|
172698
173025
|
const rel = `assets/fonts/${face.fileName}`;
|
|
172699
|
-
const abs =
|
|
173026
|
+
const abs = join14(vendorDir, rel);
|
|
172700
173027
|
const entryPath = `${opts.vendorPrefix ?? ""}/${rel}`;
|
|
172701
|
-
if (!
|
|
173028
|
+
if (!existsSync12(abs))
|
|
172702
173029
|
await downloadFace(registry, vendorDir, face, rel, abs);
|
|
172703
173030
|
if (!byPath().has(entryPath.replace(/^\//, ""))) {
|
|
172704
173031
|
entries.push(opts.makeResourceEntry?.(entryPath, abs) ?? { path: entryPath, type: "resource", absPath: abs });
|
|
@@ -172714,19 +173041,19 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172714
173041
|
const fileSrc = byPath().get(path.replace(/^\//, ""))?.fileSrc;
|
|
172715
173042
|
return fileSrc ? (opts.publicUrl ?? "") + fileSrc : null;
|
|
172716
173043
|
}) || undefined;
|
|
172717
|
-
}, isHttp = (s) => /^https?:/i.test(s), sha12 = (b) =>
|
|
173044
|
+
}, isHttp = (s) => /^https?:/i.test(s), sha12 = (b) => createHash3("sha256").update(b).digest("hex").slice(0, 12), registryHome = (registry) => registry.replace(/\/v\d+$/, ""), readRegistry = async (registry, rel) => {
|
|
172718
173045
|
if (isHttp(registry)) {
|
|
172719
173046
|
const res = await fetch(`${registry}/${rel}`);
|
|
172720
173047
|
return res.ok ? new Uint8Array(await res.arrayBuffer()) : null;
|
|
172721
173048
|
}
|
|
172722
173049
|
try {
|
|
172723
|
-
return new Uint8Array(
|
|
173050
|
+
return new Uint8Array(readFileSync13(join14(registry, rel)));
|
|
172724
173051
|
} catch {
|
|
172725
173052
|
return null;
|
|
172726
173053
|
}
|
|
172727
173054
|
}, readLock = (path) => {
|
|
172728
173055
|
try {
|
|
172729
|
-
const lock = JSON.parse(
|
|
173056
|
+
const lock = JSON.parse(readFileSync13(path, "utf8"));
|
|
172730
173057
|
if (lock && typeof lock === "object" && lock.faces && lock.families)
|
|
172731
173058
|
return lock;
|
|
172732
173059
|
} catch {}
|
|
@@ -172758,10 +173085,10 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172758
173085
|
`);
|
|
172759
173086
|
}, writeIfChanged = (path, text) => {
|
|
172760
173087
|
try {
|
|
172761
|
-
if (
|
|
173088
|
+
if (readFileSync13(path, "utf8") === text)
|
|
172762
173089
|
return;
|
|
172763
173090
|
} catch {}
|
|
172764
|
-
|
|
173091
|
+
writeFileSync6(path, text);
|
|
172765
173092
|
}, downloadFace = async (registry, vendorDir, face, rel, abs) => {
|
|
172766
173093
|
const licRaw = await readRegistry(registry, "licenses.json");
|
|
172767
173094
|
if (!licRaw)
|
|
@@ -172773,15 +173100,15 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172773
173100
|
const bytes = await readRegistry(registry, `${face.id}/${face.fileName}`);
|
|
172774
173101
|
if (!bytes)
|
|
172775
173102
|
throw new Error(`font("${face.id}"): face "${face.fileName}" not found in the registry (${registryHome(registry)}).`);
|
|
172776
|
-
|
|
172777
|
-
|
|
172778
|
-
const lockPath =
|
|
173103
|
+
mkdirSync5(dirname9(abs), { recursive: true });
|
|
173104
|
+
writeFileSync6(abs, bytes);
|
|
173105
|
+
const lockPath = join14(vendorDir, "fonts.lock.json");
|
|
172779
173106
|
const lock = readLock(lockPath) ?? { registry, faces: {}, families: {} };
|
|
172780
173107
|
lock.registry = registry;
|
|
172781
173108
|
lock.faces[`${face.id}@${face.weight}${face.italic ? "i" : ""}`] = { id: face.id, family: face.family, weight: face.weight, italic: face.italic, hash: sha12(bytes), spdx: lic.spdx, path: rel };
|
|
172782
173109
|
lock.families[face.id] = lic;
|
|
172783
173110
|
writeIfChanged(lockPath, serializeLock(lock));
|
|
172784
|
-
writeIfChanged(
|
|
173111
|
+
writeIfChanged(join14(vendorDir, "FONT-NOTICES.md"), renderNotices(lock));
|
|
172785
173112
|
};
|
|
172786
173113
|
var init_fonts = __esm(() => {
|
|
172787
173114
|
init_compile();
|
|
@@ -172789,7 +173116,7 @@ var init_fonts = __esm(() => {
|
|
|
172789
173116
|
|
|
172790
173117
|
// src/compile/assetIcons.ts
|
|
172791
173118
|
import { createHash as createHash5 } from "node:crypto";
|
|
172792
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as
|
|
173119
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
172793
173120
|
import { homedir as homedir4 } from "node:os";
|
|
172794
173121
|
import { dirname as dirname10, join as join17 } from "node:path";
|
|
172795
173122
|
var DEFAULT_REGISTRY, isHttp2 = (s) => /^https?:/i.test(s), sha122 = (s) => createHash5("sha256").update(s).digest("hex").slice(0, 12), readText = async (registry, rel) => {
|
|
@@ -172802,13 +173129,13 @@ var DEFAULT_REGISTRY, isHttp2 = (s) => /^https?:/i.test(s), sha122 = (s) => crea
|
|
|
172802
173129
|
}
|
|
172803
173130
|
}
|
|
172804
173131
|
try {
|
|
172805
|
-
return
|
|
173132
|
+
return readFileSync15(join17(registry, rel), "utf8");
|
|
172806
173133
|
} catch {
|
|
172807
173134
|
return null;
|
|
172808
173135
|
}
|
|
172809
173136
|
}, safeRead = (path) => {
|
|
172810
173137
|
try {
|
|
172811
|
-
return
|
|
173138
|
+
return readFileSync15(path, "utf8");
|
|
172812
173139
|
} catch {
|
|
172813
173140
|
return null;
|
|
172814
173141
|
}
|
|
@@ -172830,7 +173157,7 @@ var DEFAULT_REGISTRY, isHttp2 = (s) => /^https?:/i.test(s), sha122 = (s) => crea
|
|
|
172830
173157
|
return JSON.parse(raw);
|
|
172831
173158
|
}, readLock2 = (path) => {
|
|
172832
173159
|
try {
|
|
172833
|
-
const lock = JSON.parse(
|
|
173160
|
+
const lock = JSON.parse(readFileSync15(path, "utf8"));
|
|
172834
173161
|
if (lock && typeof lock === "object" && lock.icons && lock.packs)
|
|
172835
173162
|
return lock;
|
|
172836
173163
|
} catch {}
|
|
@@ -172937,11 +173264,11 @@ var init_assetIcons = __esm(() => {
|
|
|
172937
173264
|
// src/platform/config.ts
|
|
172938
173265
|
import { homedir as homedir5 } from "node:os";
|
|
172939
173266
|
import { join as join18 } from "node:path";
|
|
172940
|
-
import { mkdirSync as mkdirSync8, readFileSync as
|
|
173267
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
|
|
172941
173268
|
var DEFAULT_API = "https://le.codes", CONFIG_DIR, CONFIG_FILE, loadConfig = () => {
|
|
172942
173269
|
let stored = {};
|
|
172943
173270
|
try {
|
|
172944
|
-
stored = JSON.parse(
|
|
173271
|
+
stored = JSON.parse(readFileSync16(CONFIG_FILE, "utf8"));
|
|
172945
173272
|
} catch {}
|
|
172946
173273
|
return {
|
|
172947
173274
|
apiUrl: process.env.LECODES_API ?? stored.apiUrl,
|
|
@@ -206398,7 +206725,7 @@ var init_esm29 = __esm(() => {
|
|
|
206398
206725
|
|
|
206399
206726
|
// src/project/types.ts
|
|
206400
206727
|
import { dirname as dirname18, join as join29, relative as relative5, sep as sep3 } from "node:path";
|
|
206401
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync17, readdirSync as readdirSync12, readFileSync as
|
|
206728
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync17, readdirSync as readdirSync12, readFileSync as readFileSync25, rmSync as rmSync9, statSync as statSync10, writeFileSync as writeFileSync20 } from "node:fs";
|
|
206402
206729
|
import { createRequire as createRequire5 } from "node:module";
|
|
206403
206730
|
var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
206404
206731
|
if (!existsSync27(dir))
|
|
@@ -206427,7 +206754,7 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
206427
206754
|
const dest = join29(typesDir, path);
|
|
206428
206755
|
if (!before.has(path))
|
|
206429
206756
|
stats.added++;
|
|
206430
|
-
else if (
|
|
206757
|
+
else if (readFileSync25(dest, "utf8") !== text)
|
|
206431
206758
|
stats.updated++;
|
|
206432
206759
|
else
|
|
206433
206760
|
continue;
|
|
@@ -206446,7 +206773,7 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
206446
206773
|
const typesDir = join29(root, LECODES_DIR, "types");
|
|
206447
206774
|
const bundle = {};
|
|
206448
206775
|
for (const path of listBundleFiles(typesDir))
|
|
206449
|
-
bundle[path] =
|
|
206776
|
+
bundle[path] = readFileSync25(join29(typesDir, path), "utf8");
|
|
206450
206777
|
return bundle;
|
|
206451
206778
|
}, materializeTypes = async (root, apiUrl) => writeTypeBundle(root, await getTypes(apiUrl)), readLocalTypeBundle = () => {
|
|
206452
206779
|
const fromPackage = (() => {
|
|
@@ -206464,7 +206791,7 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
206464
206791
|
for (const path of candidates) {
|
|
206465
206792
|
if (existsSync27(path)) {
|
|
206466
206793
|
try {
|
|
206467
|
-
return JSON.parse(
|
|
206794
|
+
return JSON.parse(readFileSync25(path, "utf8"));
|
|
206468
206795
|
} catch {}
|
|
206469
206796
|
}
|
|
206470
206797
|
}
|
|
@@ -206502,7 +206829,7 @@ var init_types4 = __esm(() => {
|
|
|
206502
206829
|
});
|
|
206503
206830
|
|
|
206504
206831
|
// src/compile/designCompile.ts
|
|
206505
|
-
import { readFileSync as
|
|
206832
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
206506
206833
|
var LOCAL_ASSET_SCHEME = "lecodesfile://", compileDesignScreen = async (opts) => {
|
|
206507
206834
|
const { root, manifest, designDir, designKey, screenId, state } = opts;
|
|
206508
206835
|
const entries = [];
|
|
@@ -206519,7 +206846,7 @@ var LOCAL_ASSET_SCHEME = "lecodesfile://", compileDesignScreen = async (opts) =>
|
|
|
206519
206846
|
} else if (type === "shader") {
|
|
206520
206847
|
entries.push({ path: file.path, type, shaders: [] });
|
|
206521
206848
|
} else {
|
|
206522
|
-
entries.push({ path: file.path, type, text:
|
|
206849
|
+
entries.push({ path: file.path, type, text: readFileSync26(file.absPath, "utf8") });
|
|
206523
206850
|
}
|
|
206524
206851
|
}
|
|
206525
206852
|
const invoke = state !== undefined ? `screen(${JSON.stringify(state)})` : "screen()";
|
|
@@ -206641,11 +206968,11 @@ var init_browserAuth = __esm(() => {
|
|
|
206641
206968
|
});
|
|
206642
206969
|
|
|
206643
206970
|
// src/project/designMeta.ts
|
|
206644
|
-
import { readFileSync as
|
|
206971
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
206645
206972
|
import { join as join31 } from "node:path";
|
|
206646
206973
|
var PHONE_SIZE, readMetaFrames = (designDir) => {
|
|
206647
206974
|
try {
|
|
206648
|
-
const meta = JSON.parse(
|
|
206975
|
+
const meta = JSON.parse(readFileSync27(join31(designDir, "meta.json"), "utf8"));
|
|
206649
206976
|
const d = meta?.defaultSize;
|
|
206650
206977
|
const valid = Array.isArray(d) && d.length === 2 && d.every((n) => typeof n === "number" && Number.isFinite(n) && n >= 64 && n <= 8192);
|
|
206651
206978
|
return {
|
|
@@ -206996,7 +207323,7 @@ var init_comments = __esm(() => {
|
|
|
206996
207323
|
});
|
|
206997
207324
|
|
|
206998
207325
|
// src/commands/design/snapshot.ts
|
|
206999
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync20, readdirSync as readdirSync15, readFileSync as
|
|
207326
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync20, readdirSync as readdirSync15, readFileSync as readFileSync28, writeFileSync as writeFileSync22 } from "node:fs";
|
|
207000
207327
|
import { join as join33 } from "node:path";
|
|
207001
207328
|
var listScreens = (designDir) => {
|
|
207002
207329
|
const dir = join33(designDir, "screens");
|
|
@@ -207068,7 +207395,7 @@ var init_snapshot = __esm(() => {
|
|
|
207068
207395
|
const [width, height] = frames.screens[id]?.size ?? frames.defaultSize;
|
|
207069
207396
|
let plan = [{ state: undefined, bases: [id] }];
|
|
207070
207397
|
if (discover) {
|
|
207071
|
-
const { states, canonical } = discover(
|
|
207398
|
+
const { states, canonical } = discover(readFileSync28(join33(ctx.designDir, "screens", `${id}.ts`), "utf8"));
|
|
207072
207399
|
if (stateFlag !== undefined) {
|
|
207073
207400
|
if (!states.includes(stateFlag)) {
|
|
207074
207401
|
if (args.length === 1)
|
|
@@ -207598,7 +207925,7 @@ var init_templates2 = __esm(() => {
|
|
|
207598
207925
|
});
|
|
207599
207926
|
|
|
207600
207927
|
// src/commands/design/index.ts
|
|
207601
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync21, readFileSync as
|
|
207928
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync21, readFileSync as readFileSync29, writeFileSync as writeFileSync23 } from "node:fs";
|
|
207602
207929
|
import { join as join34 } from "node:path";
|
|
207603
207930
|
var firstLine = (body, max = 64) => {
|
|
207604
207931
|
const line = body.split(`
|
|
@@ -207673,7 +208000,7 @@ var firstLine = (body, max = 64) => {
|
|
|
207673
208000
|
let config = {};
|
|
207674
208001
|
if (existsSync33(path)) {
|
|
207675
208002
|
try {
|
|
207676
|
-
config = JSON.parse(
|
|
208003
|
+
config = JSON.parse(readFileSync29(path, "utf8"));
|
|
207677
208004
|
} catch {
|
|
207678
208005
|
warnErr(".mcp.json exists but isn't valid JSON — left it untouched. Add the lecodes-design server by hand.");
|
|
207679
208006
|
return;
|
|
@@ -207753,7 +208080,7 @@ var init_design = __esm(() => {
|
|
|
207753
208080
|
}
|
|
207754
208081
|
const ignorePath = join34(ctx.root, ".lecodesignore");
|
|
207755
208082
|
const ignoreLines = [`${ctx.dirName}/.snapshots/`, `${ctx.dirName}/comments/`];
|
|
207756
|
-
const current = existsSync33(ignorePath) ?
|
|
208083
|
+
const current = existsSync33(ignorePath) ? readFileSync29(ignorePath, "utf8") : "";
|
|
207757
208084
|
const present = new Set(current.split(/\r?\n/));
|
|
207758
208085
|
const missing = ignoreLines.filter((line) => !present.has(line));
|
|
207759
208086
|
if (missing.length) {
|
|
@@ -227112,32 +227439,32 @@ import { delimiter as delimiter3, dirname as dirname31, join as join63 } from "n
|
|
|
227112
227439
|
// src/commands/app/index.ts
|
|
227113
227440
|
init_manifest();
|
|
227114
227441
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
227115
|
-
import { cpSync as cpSync4, existsSync as existsSync25, mkdirSync as mkdirSync16, readFileSync as
|
|
227442
|
+
import { cpSync as cpSync4, existsSync as existsSync25, mkdirSync as mkdirSync16, readFileSync as readFileSync24, readdirSync as readdirSync10, rmSync as rmSync8, statSync as statSync9, writeFileSync as writeFileSync19 } from "node:fs";
|
|
227116
227443
|
import { homedir as homedir10 } from "node:os";
|
|
227117
227444
|
import { basename as basename10, dirname as dirname17, join as join27, resolve as resolve14 } from "node:path";
|
|
227118
227445
|
|
|
227119
227446
|
// src/plugin/manifest.ts
|
|
227120
|
-
import { existsSync as
|
|
227121
|
-
import { isAbsolute as isAbsolute2, join as
|
|
227447
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, statSync as statSync2 } from "node:fs";
|
|
227448
|
+
import { isAbsolute as isAbsolute2, join as join10 } from "node:path";
|
|
227122
227449
|
|
|
227123
227450
|
// src/plugin/firstParty.ts
|
|
227124
227451
|
init_projectCompile();
|
|
227125
|
-
import { existsSync as
|
|
227126
|
-
import { join as
|
|
227452
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7, readdirSync as readdirSync2 } from "node:fs";
|
|
227453
|
+
import { join as join9 } from "node:path";
|
|
227127
227454
|
var ID = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
227128
227455
|
var firstPartyContractFile = (id) => {
|
|
227129
227456
|
if (!sdkSourceDir || !ID.test(id))
|
|
227130
227457
|
return null;
|
|
227131
|
-
const file =
|
|
227132
|
-
return
|
|
227458
|
+
const file = join9(sdkSourceDir, "plugins", "gen", id, "contract.d.ts");
|
|
227459
|
+
return existsSync8(file) ? file : null;
|
|
227133
227460
|
};
|
|
227134
227461
|
var firstPartyIds = () => {
|
|
227135
227462
|
if (!sdkSourceDir)
|
|
227136
227463
|
return [];
|
|
227137
|
-
const gen =
|
|
227138
|
-
return
|
|
227464
|
+
const gen = join9(sdkSourceDir, "plugins", "gen");
|
|
227465
|
+
return existsSync8(gen) ? readdirSync2(gen).filter((id) => existsSync8(join9(gen, id, "contract.d.ts"))).sort() : [];
|
|
227139
227466
|
};
|
|
227140
|
-
var firstPartyContractText = (file) =>
|
|
227467
|
+
var firstPartyContractText = (file) => readFileSync7(file, "utf8").replace(/from "(?:\.\.\/)+plugin"/g, `from "lecodes-sdk/plugin"`);
|
|
227141
227468
|
|
|
227142
227469
|
// src/plugin/manifest.ts
|
|
227143
227470
|
var MANIFEST_FILE = "lecodes-plugin.json";
|
|
@@ -227170,15 +227497,15 @@ var BRANCH = {
|
|
|
227170
227497
|
web: new Set(["register", "dependencies", "resources", "static"])
|
|
227171
227498
|
};
|
|
227172
227499
|
var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
227173
|
-
var isFolder = (path) =>
|
|
227500
|
+
var isFolder = (path) => existsSync9(path) && statSync2(path).isDirectory();
|
|
227174
227501
|
var pascal = (id) => id.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
227175
227502
|
var XCFRAMEWORK = ".xcframework";
|
|
227176
227503
|
var binaryName = (path) => path.split(/[\\/]/).pop().slice(0, -XCFRAMEWORK.length);
|
|
227177
|
-
var
|
|
227178
|
-
const file =
|
|
227504
|
+
var readManifest3 = (dir, id) => {
|
|
227505
|
+
const file = join10(dir, MANIFEST_FILE);
|
|
227179
227506
|
let raw;
|
|
227180
227507
|
try {
|
|
227181
|
-
raw = JSON.parse(
|
|
227508
|
+
raw = JSON.parse(readFileSync8(file, "utf8").replace(/^/, ""));
|
|
227182
227509
|
} catch (e) {
|
|
227183
227510
|
throw new ManifestError(file, [`not JSON: ${e instanceof Error ? e.message : String(e)}`]);
|
|
227184
227511
|
}
|
|
@@ -227217,14 +227544,14 @@ var readManifest2 = (dir, id) => {
|
|
|
227217
227544
|
problems.push(`implements: the id of the first-party plugin whose contract the folder implements ("ar")`);
|
|
227218
227545
|
else if (!firstPartyContractFile(impl))
|
|
227219
227546
|
problems.push(`implements: "${impl}" is no first-party plugin of this SDK (${firstPartyIds().join(", ") || "it carries none"})`);
|
|
227220
|
-
if (
|
|
227547
|
+
if (existsSync9(join10(dir, CONTRACT_FILE)))
|
|
227221
227548
|
problems.push(`implements: the folder implements another plugin's contract — it has no ${CONTRACT_FILE} of its own`);
|
|
227222
|
-
if (isFolder(
|
|
227549
|
+
if (isFolder(join10(dir, "sdk")))
|
|
227223
227550
|
problems.push("implements: the folder implements another plugin — its app side is the SDK's, it has no sdk/ of its own");
|
|
227224
227551
|
}
|
|
227225
227552
|
for (const platform of PLATFORMS) {
|
|
227226
227553
|
const branch = raw[platform];
|
|
227227
|
-
const folder = isFolder(
|
|
227554
|
+
const folder = isFolder(join10(dir, platform));
|
|
227228
227555
|
if (branch === undefined) {
|
|
227229
227556
|
problems.push(`${platform}: missing — an object, or null where the plugin has no ${platform} half`);
|
|
227230
227557
|
continue;
|
|
@@ -227255,7 +227582,7 @@ var readManifest2 = (dir, id) => {
|
|
|
227255
227582
|
if (platform === "web" && register !== undefined) {
|
|
227256
227583
|
if (!register.startsWith("web/"))
|
|
227257
227584
|
problems.push(`web.register: "${register}" — a module of the web/ folder`);
|
|
227258
|
-
else if (!
|
|
227585
|
+
else if (!existsSync9(join10(dir, register)))
|
|
227259
227586
|
problems.push(`web.register: ${register} is not there`);
|
|
227260
227587
|
}
|
|
227261
227588
|
}
|
|
@@ -227295,7 +227622,7 @@ var readManifest2 = (dir, id) => {
|
|
|
227295
227622
|
problems.push(`ios.binaries[${i}]: ${path} is in ios/, the half's sources — a binary stands beside them ("binaries/ios/X.xcframework")`);
|
|
227296
227623
|
else if (!/^[A-Za-z_]\w*$/.test(binaryName(path)))
|
|
227297
227624
|
problems.push(`ios.binaries[${i}]: "${path}" — the folder's name is its binary target's: a Swift name before ${XCFRAMEWORK}`);
|
|
227298
|
-
else if (!isFolder(
|
|
227625
|
+
else if (!isFolder(join10(dir, path)))
|
|
227299
227626
|
problems.push(`ios.binaries[${i}]: ${path} is not a folder of the plugin`);
|
|
227300
227627
|
else if (named.has(binaryName(path)))
|
|
227301
227628
|
problems.push(`ios.binaries[${i}]: ${path} is named "${binaryName(path)}" like ${named.get(binaryName(path))} — a name is one binary target`);
|
|
@@ -227336,7 +227663,7 @@ var readManifest2 = (dir, id) => {
|
|
|
227336
227663
|
const segments = typeof folder === "string" ? folder.split(/[\\/]/) : [];
|
|
227337
227664
|
if (typeof folder !== "string" || folder.trim() === "" || isAbsolute2(folder) || segments.some((s) => s === ".." || s === "." || s === "")) {
|
|
227338
227665
|
problems.push(`web.static: a folder of the plugin, by its path in it ("xr-runtime")`);
|
|
227339
|
-
} else if (!isFolder(
|
|
227666
|
+
} else if (!isFolder(join10(dir, folder)))
|
|
227340
227667
|
problems.push(`web.static: ${folder} is not a folder of the plugin`);
|
|
227341
227668
|
else if (folder === "index.js")
|
|
227342
227669
|
problems.push(`web.static: "index.js" is the built module's name`);
|
|
@@ -227346,7 +227673,7 @@ var readManifest2 = (dir, id) => {
|
|
|
227346
227673
|
throw new ManifestError(file, problems);
|
|
227347
227674
|
return raw;
|
|
227348
227675
|
};
|
|
227349
|
-
var readManifestIfAny = (dir, id) =>
|
|
227676
|
+
var readManifestIfAny = (dir, id) => existsSync9(join10(dir, MANIFEST_FILE)) ? readManifest3(dir, id) : null;
|
|
227350
227677
|
|
|
227351
227678
|
// src/commands/compile.ts
|
|
227352
227679
|
init_api();
|
|
@@ -227357,15 +227684,15 @@ import { basename as basename6, resolve as resolve6 } from "node:path";
|
|
|
227357
227684
|
// src/compile/collect.ts
|
|
227358
227685
|
init_localFiles();
|
|
227359
227686
|
init_ignore();
|
|
227360
|
-
import { readFileSync as
|
|
227687
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
227361
227688
|
|
|
227362
227689
|
// src/project/materialize.ts
|
|
227363
227690
|
init_api();
|
|
227364
227691
|
init_paths();
|
|
227365
|
-
import { dirname as dirname8, join as
|
|
227366
|
-
import { mkdirSync as
|
|
227692
|
+
import { dirname as dirname8, join as join13 } from "node:path";
|
|
227693
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
227367
227694
|
var kindOf = (type) => type === "file" ? "resource" : type;
|
|
227368
|
-
var absOf = (root, key) =>
|
|
227695
|
+
var absOf = (root, key) => join13(root, ...key.replace(/^\//, "").split("/"));
|
|
227369
227696
|
var buildPaths = (assets) => {
|
|
227370
227697
|
const pathById = new Map;
|
|
227371
227698
|
for (const asset of assets) {
|
|
@@ -227383,20 +227710,20 @@ var materializeAssets = async (root, project, apiUrl, token, onProgress) => {
|
|
|
227383
227710
|
const key = pathById.get(asset.id);
|
|
227384
227711
|
const abs = absOf(root, key);
|
|
227385
227712
|
if (asset.type === "folder") {
|
|
227386
|
-
|
|
227713
|
+
mkdirSync4(abs, { recursive: true });
|
|
227387
227714
|
continue;
|
|
227388
227715
|
}
|
|
227389
|
-
|
|
227716
|
+
mkdirSync4(dirname8(abs), { recursive: true });
|
|
227390
227717
|
let sha;
|
|
227391
227718
|
if (asset.type === "file") {
|
|
227392
227719
|
if (!asset.file?.src)
|
|
227393
227720
|
continue;
|
|
227394
227721
|
const bytes = await downloadBlob(apiUrl, asset.file.src);
|
|
227395
|
-
|
|
227722
|
+
writeFileSync5(abs, bytes);
|
|
227396
227723
|
sha = sha256(bytes);
|
|
227397
227724
|
} else {
|
|
227398
227725
|
const text = asset.text ?? "";
|
|
227399
|
-
|
|
227726
|
+
writeFileSync5(abs, text);
|
|
227400
227727
|
sha = sha256(text);
|
|
227401
227728
|
}
|
|
227402
227729
|
files[key] = { id: asset.id, type: kindOf(asset.type), sha };
|
|
@@ -227430,7 +227757,7 @@ var collectEntries = (root, manifest, project, opts = {}) => {
|
|
|
227430
227757
|
warnings.push(`No compiled shader for ${file.path} — push it to compile the shader.`);
|
|
227431
227758
|
entries.push({ path: file.path, type, shaders, absPath: file.absPath });
|
|
227432
227759
|
} else {
|
|
227433
|
-
entries.push({ path: file.path, type, text:
|
|
227760
|
+
entries.push({ path: file.path, type, text: readFileSync11(file.absPath, "utf8") });
|
|
227434
227761
|
}
|
|
227435
227762
|
}
|
|
227436
227763
|
return { entries, warnings };
|
|
@@ -227439,11 +227766,11 @@ var collectEntries = (root, manifest, project, opts = {}) => {
|
|
|
227439
227766
|
// src/compile/collectLocal.ts
|
|
227440
227767
|
init_localFiles();
|
|
227441
227768
|
init_ignore();
|
|
227442
|
-
import { readFileSync as
|
|
227769
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
227443
227770
|
import { basename as basename2 } from "node:path";
|
|
227444
227771
|
var isHalfManifest = (abs) => {
|
|
227445
227772
|
try {
|
|
227446
|
-
return typeof JSON.parse(
|
|
227773
|
+
return typeof JSON.parse(readFileSync12(abs, "utf8").replace(/^/, "")).implements === "string";
|
|
227447
227774
|
} catch {
|
|
227448
227775
|
return false;
|
|
227449
227776
|
}
|
|
@@ -227465,7 +227792,7 @@ var collectLocalEntries = (root, manifest, assetBase, opts = {}) => {
|
|
|
227465
227792
|
}
|
|
227466
227793
|
entries.push({ path: file.path, type, shaders: [], absPath: file.absPath });
|
|
227467
227794
|
} else {
|
|
227468
|
-
entries.push({ path: file.path, type, text:
|
|
227795
|
+
entries.push({ path: file.path, type, text: readFileSync12(file.absPath, "utf8") });
|
|
227469
227796
|
}
|
|
227470
227797
|
}
|
|
227471
227798
|
return { entries, warnings };
|
|
@@ -227479,110 +227806,16 @@ init_fonts();
|
|
|
227479
227806
|
init_compile();
|
|
227480
227807
|
import { execFile } from "node:child_process";
|
|
227481
227808
|
import { createHash as createHash4, randomBytes } from "node:crypto";
|
|
227482
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as
|
|
227809
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync14, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync7 } from "node:fs";
|
|
227483
227810
|
import { tmpdir } from "node:os";
|
|
227484
227811
|
import { basename as basename3, join as join16 } from "node:path";
|
|
227485
227812
|
|
|
227486
227813
|
// src/hosts/matcTool.ts
|
|
227814
|
+
init_releases();
|
|
227815
|
+
init_cli();
|
|
227487
227816
|
import { existsSync as existsSync13, readdirSync as readdirSync4 } from "node:fs";
|
|
227488
227817
|
import { homedir as homedir3 } from "node:os";
|
|
227489
227818
|
import { join as join15, resolve as resolve4 } from "node:path";
|
|
227490
|
-
|
|
227491
|
-
// src/hosts/releases.ts
|
|
227492
|
-
init_cli();
|
|
227493
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
227494
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync5, mkdtempSync, readFileSync as readFileSync12, renameSync, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
227495
|
-
import { join as join14 } from "node:path";
|
|
227496
|
-
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
227497
|
-
var MANIFEST_URL = "https://storage.yandexcloud.net/le-codes/releases/versions.json";
|
|
227498
|
-
var ARTIFACT_STAMP = ".lecodes-artifact.json";
|
|
227499
|
-
var cachedArtifactSha = (dir) => {
|
|
227500
|
-
try {
|
|
227501
|
-
return JSON.parse(readFileSync12(join14(dir, ARTIFACT_STAMP), "utf8")).sha256 ?? null;
|
|
227502
|
-
} catch {
|
|
227503
|
-
return null;
|
|
227504
|
-
}
|
|
227505
|
-
};
|
|
227506
|
-
var macPlatformKey = () => process.arch === "arm64" ? "macos-arm64" : "macos-x64";
|
|
227507
|
-
var semverNewer = (a, b) => {
|
|
227508
|
-
const pa = a.split(/[.-]/).map(Number), pb = b.split(/[.-]/).map(Number);
|
|
227509
|
-
for (let i = 0;i < 3; i++)
|
|
227510
|
-
if ((pb[i] ?? 0) !== (pa[i] ?? 0))
|
|
227511
|
-
return (pb[i] ?? 0) - (pa[i] ?? 0);
|
|
227512
|
-
return 0;
|
|
227513
|
-
};
|
|
227514
|
-
var newestForPlatform = (versions, key) => {
|
|
227515
|
-
const carrying = versions.filter((v) => v.files[key]).sort((a, b) => semverNewer(a.version, b.version));
|
|
227516
|
-
const newest = carrying[0];
|
|
227517
|
-
return newest ? { version: newest.version, file: newest.files[key] } : null;
|
|
227518
|
-
};
|
|
227519
|
-
var fetchReleaseProduct = async (product, label) => {
|
|
227520
|
-
let manifest;
|
|
227521
|
-
try {
|
|
227522
|
-
const res = await fetch(MANIFEST_URL);
|
|
227523
|
-
if (!res.ok)
|
|
227524
|
-
throw new Error(`HTTP ${res.status}`);
|
|
227525
|
-
manifest = await res.json();
|
|
227526
|
-
} catch (e) {
|
|
227527
|
-
throw new CliError(`Can't fetch the release manifest (${MANIFEST_URL}): ${e instanceof Error ? e.message : String(e)}`);
|
|
227528
|
-
}
|
|
227529
|
-
const entry = manifest.products?.[product];
|
|
227530
|
-
if (!entry)
|
|
227531
|
-
throw new CliError(`The release manifest has no ${label} product.`);
|
|
227532
|
-
return entry;
|
|
227533
|
-
};
|
|
227534
|
-
var downloadReleaseArchive = async (file, opts) => {
|
|
227535
|
-
let bytes;
|
|
227536
|
-
try {
|
|
227537
|
-
const res = await fetch(file.url);
|
|
227538
|
-
if (!res.ok)
|
|
227539
|
-
throw new Error(`HTTP ${res.status}`);
|
|
227540
|
-
bytes = Buffer.from(await res.arrayBuffer());
|
|
227541
|
-
} catch (e) {
|
|
227542
|
-
throw new CliError(`Download failed (${file.url}): ${e instanceof Error ? e.message : String(e)}`);
|
|
227543
|
-
}
|
|
227544
|
-
const sha = createHash3("sha256").update(bytes).digest("hex");
|
|
227545
|
-
if (sha !== file.sha256)
|
|
227546
|
-
throw new CliError(`Downloaded archive is corrupt (sha256 mismatch) — try again.`);
|
|
227547
|
-
mkdirSync5(opts.cacheRoot, { recursive: true });
|
|
227548
|
-
const stage = mkdtempSync(join14(opts.cacheRoot, "dl-"));
|
|
227549
|
-
try {
|
|
227550
|
-
const archiveName = file.url.split("/").pop() ?? "archive";
|
|
227551
|
-
const archive = join14(stage, archiveName);
|
|
227552
|
-
writeFileSync6(archive, bytes);
|
|
227553
|
-
if (opts.extract) {
|
|
227554
|
-
opts.extract(archive, stage);
|
|
227555
|
-
} else {
|
|
227556
|
-
const winTar = join14(process.env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
|
|
227557
|
-
const tarExe = process.platform === "win32" && existsSync12(winTar) ? winTar : "tar";
|
|
227558
|
-
const tar = spawnSync4(tarExe, ["-xf", archiveName], { cwd: stage, stdio: ["ignore", "ignore", "pipe"] });
|
|
227559
|
-
if (tar.status !== 0)
|
|
227560
|
-
throw new CliError(`Couldn't extract the archive: ${tar.stderr?.toString() ?? "tar failed"}`);
|
|
227561
|
-
}
|
|
227562
|
-
rmSync(archive);
|
|
227563
|
-
const bad = opts.validate(stage);
|
|
227564
|
-
if (bad)
|
|
227565
|
-
throw new CliError(bad);
|
|
227566
|
-
writeFileSync6(join14(stage, ARTIFACT_STAMP), JSON.stringify({ sha256: file.sha256, url: file.url }, null, 2));
|
|
227567
|
-
try {
|
|
227568
|
-
renameSync(stage, opts.dest);
|
|
227569
|
-
} catch {
|
|
227570
|
-
let destBad;
|
|
227571
|
-
try {
|
|
227572
|
-
destBad = opts.validate(opts.dest);
|
|
227573
|
-
} catch {
|
|
227574
|
-
destBad = "missing";
|
|
227575
|
-
}
|
|
227576
|
-
if (destBad)
|
|
227577
|
-
throw new CliError(`Couldn't move the download into ${opts.dest}.`);
|
|
227578
|
-
}
|
|
227579
|
-
} finally {
|
|
227580
|
-
rmSync(stage, { recursive: true, force: true });
|
|
227581
|
-
}
|
|
227582
|
-
};
|
|
227583
|
-
|
|
227584
|
-
// src/hosts/matcTool.ts
|
|
227585
|
-
init_cli();
|
|
227586
227819
|
var matcName = () => process.platform === "win32" ? "matc.exe" : "matc";
|
|
227587
227820
|
var platformKey = () => {
|
|
227588
227821
|
if (process.platform === "win32")
|
|
@@ -227729,7 +227962,7 @@ var applyLocalShaders = async (entries, opts) => {
|
|
|
227729
227962
|
mkdirSync6(cacheDir, { recursive: true });
|
|
227730
227963
|
const artifacts = [];
|
|
227731
227964
|
for (const entry of shaderEntries) {
|
|
227732
|
-
const text =
|
|
227965
|
+
const text = readFileSync14(entry.absPath, "utf8");
|
|
227733
227966
|
const hash = shaderHash(text, matcId);
|
|
227734
227967
|
const family = artifactFamily();
|
|
227735
227968
|
const artifact = (platform) => `${hash}_${platform}.filamat`;
|
|
@@ -227787,7 +228020,7 @@ init_config();
|
|
|
227787
228020
|
init_ignore();
|
|
227788
228021
|
init_cli();
|
|
227789
228022
|
import { execFileSync } from "node:child_process";
|
|
227790
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync5, readFileSync as
|
|
228023
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync5, readFileSync as readFileSync17, statSync as statSync4, writeFileSync as writeFileSync10 } from "node:fs";
|
|
227791
228024
|
import { homedir as homedir6 } from "node:os";
|
|
227792
228025
|
import { basename as basename4, dirname as dirname11, join as join19, resolve as resolve5 } from "node:path";
|
|
227793
228026
|
init_compile();
|
|
@@ -228036,7 +228269,7 @@ var readJson2 = (path) => {
|
|
|
228036
228269
|
if (!existsSync16(path))
|
|
228037
228270
|
return null;
|
|
228038
228271
|
try {
|
|
228039
|
-
return JSON.parse(
|
|
228272
|
+
return JSON.parse(readFileSync17(path, "utf8").replace(/^\uFEFF/, ""));
|
|
228040
228273
|
} catch {
|
|
228041
228274
|
throw new CliError(`Invalid JSON in ${path}`);
|
|
228042
228275
|
}
|
|
@@ -228068,7 +228301,7 @@ ${tail}`);
|
|
|
228068
228301
|
};
|
|
228069
228302
|
var ensureShellIgnored = (root, dir) => {
|
|
228070
228303
|
const ignorePath = join19(root, ".lecodesignore");
|
|
228071
|
-
const ignore = existsSync16(ignorePath) ?
|
|
228304
|
+
const ignore = existsSync16(ignorePath) ? readFileSync17(ignorePath, "utf8") : DEFAULT_IGNORE_FILE;
|
|
228072
228305
|
if (new RegExp(`^${dir}\\/$`, "m").test(ignore))
|
|
228073
228306
|
return;
|
|
228074
228307
|
const comment = ignore.includes("# Native app shells") ? "" : "# Native app shells — generated by `lecodes app init`, never pushed to LeCodes.\n";
|
|
@@ -228201,7 +228434,7 @@ var localPlugin = (root, id, spec) => {
|
|
|
228201
228434
|
if (!existsSync16(dir) || !statSync4(dir).isDirectory())
|
|
228202
228435
|
throw new CliError(`Plugin "${id}": ${spec} is not a folder (${dir})`);
|
|
228203
228436
|
const folder = basename4(dir);
|
|
228204
|
-
const manifest =
|
|
228437
|
+
const manifest = readManifest3(dir, folder);
|
|
228205
228438
|
if (manifest.implements ? manifest.implements !== id : folder !== id) {
|
|
228206
228439
|
throw new CliError(manifest.implements ? `Plugin "${id}": ${spec} implements "${manifest.implements}" — app.json names it under that plugin: "${manifest.implements}": { "<platform>": "${spec}" }` : `Plugin "${id}": ${spec} is the plugin "${folder}" — app.json names a plugin of the project by its folder's name`);
|
|
228207
228440
|
}
|
|
@@ -228212,7 +228445,7 @@ var localPluginKey = (root, spec) => {
|
|
|
228212
228445
|
const dir = resolve5(root, spec.startsWith("file:") ? spec.slice("file:".length) : spec);
|
|
228213
228446
|
if (!existsSync16(join19(dir, "lecodes-plugin.json")))
|
|
228214
228447
|
return basename4(dir);
|
|
228215
|
-
return
|
|
228448
|
+
return readManifest3(dir, basename4(dir)).implements ?? basename4(dir);
|
|
228216
228449
|
};
|
|
228217
228450
|
function resolvePlugin(id, entry, lock, platform, opts) {
|
|
228218
228451
|
const spec = pluginSpecOf(entry, platform);
|
|
@@ -228244,7 +228477,7 @@ function resolvePlugin(id, entry, lock, platform, opts) {
|
|
|
228244
228477
|
const dir = subdir ? join19(checkout.dir, subdir) : checkout.dir;
|
|
228245
228478
|
if (!existsSync16(join19(dir, "lecodes-plugin.json")))
|
|
228246
228479
|
throw new CliError(`Plugin "${id}": no lecodes-plugin.json in ${dir}`);
|
|
228247
|
-
const manifest =
|
|
228480
|
+
const manifest = readManifest3(dir, id);
|
|
228248
228481
|
fillManifestDefaults(manifest, id);
|
|
228249
228482
|
if (!manifest[platform]) {
|
|
228250
228483
|
if (opts?.optional)
|
|
@@ -228435,7 +228668,7 @@ var buildBundle = async (bundle, opts = {}) => {
|
|
|
228435
228668
|
warnErr(ambiguous);
|
|
228436
228669
|
}
|
|
228437
228670
|
const serverUrl = await opts.backend?.start(entries, (w) => warnings.push(w));
|
|
228438
|
-
const js = await
|
|
228671
|
+
const { js, bakes } = await compileProjectBundle({
|
|
228439
228672
|
entries,
|
|
228440
228673
|
name,
|
|
228441
228674
|
publicUrl,
|
|
@@ -228456,7 +228689,7 @@ var buildBundle = async (bundle, opts = {}) => {
|
|
|
228456
228689
|
const resources = entries.filter((e) => e.type === "resource").map((e) => ({ path: e.path.replace(/^\//, ""), name: localNames.get(e.path) ?? e.path.split(/[\\/]/).pop() ?? e.path, absPath: e.absPath, remote: !!e.remote }));
|
|
228457
228690
|
for (const artifact of stagedShaders)
|
|
228458
228691
|
resources.push({ path: artifact.name, name: artifact.name, absPath: artifact.absPath, remote: false, shader: true });
|
|
228459
|
-
return { js, resources };
|
|
228692
|
+
return { js, resources, bakes: bakes.map((b) => ({ path: b.path, absPath: resolve6(root, b.path), exists: b.exists })) };
|
|
228460
228693
|
};
|
|
228461
228694
|
|
|
228462
228695
|
// src/commands/app/index.ts
|
|
@@ -229431,13 +229664,13 @@ init_compile();
|
|
|
229431
229664
|
init_manifest();
|
|
229432
229665
|
import { execFileSync as execFileSync2, spawn, spawnSync as spawnSync5 } from "node:child_process";
|
|
229433
229666
|
import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
|
|
229434
|
-
import { chmodSync, cpSync, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as
|
|
229667
|
+
import { chmodSync, cpSync, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync22, readdirSync as readdirSync6, renameSync as renameSync2, rmSync as rmSync4, statSync as statSync5, writeFileSync as writeFileSync15 } from "node:fs";
|
|
229435
229668
|
import { homedir as homedir8 } from "node:os";
|
|
229436
229669
|
import { basename as basename7, dirname as dirname15, join as join23, relative as relative4, resolve as resolve10 } from "node:path";
|
|
229437
229670
|
init_cli();
|
|
229438
229671
|
|
|
229439
229672
|
// src/project/env.ts
|
|
229440
|
-
import { appendFileSync, existsSync as existsSync17, readFileSync as
|
|
229673
|
+
import { appendFileSync, existsSync as existsSync17, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "node:fs";
|
|
229441
229674
|
import { homedir as homedir7 } from "node:os";
|
|
229442
229675
|
import { dirname as dirname12, join as join20, resolve as resolve7 } from "node:path";
|
|
229443
229676
|
var KEY_RE = /^(LECODES|CREATOR)_[A-Z0-9_]+$/;
|
|
@@ -229505,7 +229738,7 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
229505
229738
|
const file = join20(root, ".env");
|
|
229506
229739
|
if (!existsSync17(file))
|
|
229507
229740
|
return [];
|
|
229508
|
-
const added = applyDotEnv(parseDotEnv(
|
|
229741
|
+
const added = applyDotEnv(parseDotEnv(readFileSync18(file, "utf8")), root, process.env);
|
|
229509
229742
|
for (const [k, v] of Object.entries(added))
|
|
229510
229743
|
process.env[k] = v;
|
|
229511
229744
|
return Object.keys(added);
|
|
@@ -229516,7 +229749,7 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
229516
229749
|
var upsertDotEnv = (root, entries) => {
|
|
229517
229750
|
const touched = [];
|
|
229518
229751
|
const envPath = join20(root, ".env");
|
|
229519
|
-
let content = existsSync17(envPath) ?
|
|
229752
|
+
let content = existsSync17(envPath) ? readFileSync18(envPath, "utf8") : "";
|
|
229520
229753
|
for (const [key, value] of Object.entries(entries)) {
|
|
229521
229754
|
const line = `${key}=${value}`;
|
|
229522
229755
|
const re = new RegExp(`^(?:export\\s+)?${key}\\s*=.*$`, "m");
|
|
@@ -229531,7 +229764,7 @@ var upsertDotEnv = (root, entries) => {
|
|
|
229531
229764
|
writeFileSync12(envPath, content);
|
|
229532
229765
|
touched.push(".env");
|
|
229533
229766
|
const ignorePath = join20(root, ".gitignore");
|
|
229534
|
-
const ignore = existsSync17(ignorePath) ?
|
|
229767
|
+
const ignore = existsSync17(ignorePath) ? readFileSync18(ignorePath, "utf8") : "";
|
|
229535
229768
|
if (!ignore.split(`
|
|
229536
229769
|
`).some((l) => l.trim() === ".env")) {
|
|
229537
229770
|
appendFileSync(ignorePath, `${!ignore || ignore.endsWith(`
|
|
@@ -229544,7 +229777,7 @@ var upsertDotEnv = (root, entries) => {
|
|
|
229544
229777
|
};
|
|
229545
229778
|
|
|
229546
229779
|
// src/commands/app/icon.ts
|
|
229547
|
-
import { existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as
|
|
229780
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "node:fs";
|
|
229548
229781
|
import { dirname as dirname13, join as join21, resolve as resolve8 } from "node:path";
|
|
229549
229782
|
|
|
229550
229783
|
// ../../sdk/src/canvas/gen/cssColor.ts
|
|
@@ -230088,7 +230321,7 @@ var restampManifestIcon = (androidDir) => {
|
|
|
230088
230321
|
const path = join21(androidDir, "app", "src", "main", "AndroidManifest.xml");
|
|
230089
230322
|
if (!existsSync19(path))
|
|
230090
230323
|
return;
|
|
230091
|
-
const content =
|
|
230324
|
+
const content = readFileSync19(path, "utf8");
|
|
230092
230325
|
if (content.includes(`android:icon="@mipmap/ic_launcher"`))
|
|
230093
230326
|
return;
|
|
230094
230327
|
if (!/android:icon="[^"]*"/.test(content)) {
|
|
@@ -230100,7 +230333,7 @@ var restampManifestIcon = (androidDir) => {
|
|
|
230100
230333
|
};
|
|
230101
230334
|
|
|
230102
230335
|
// src/commands/app/splash.ts
|
|
230103
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as
|
|
230336
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync20, rmSync as rmSync3, writeFileSync as writeFileSync14 } from "node:fs";
|
|
230104
230337
|
import { dirname as dirname14, join as join22, resolve as resolve9 } from "node:path";
|
|
230105
230338
|
init_cli();
|
|
230106
230339
|
|
|
@@ -230978,7 +231211,7 @@ var androidSplashThemeHint = (androidDir) => {
|
|
|
230978
231211
|
const path = join22(androidDir, "app", "src", "main", "res", "values", "themes.xml");
|
|
230979
231212
|
if (!existsSync20(path))
|
|
230980
231213
|
return null;
|
|
230981
|
-
const xml =
|
|
231214
|
+
const xml = readFileSync20(path, "utf8");
|
|
230982
231215
|
const style = /<style\b[^>]*\bname="Theme\.LeCodesApp"[^>]*?(?:\/>|>([\s\S]*?)<\/style>)/.exec(xml);
|
|
230983
231216
|
if (!style) {
|
|
230984
231217
|
return /\bparent="Theme\.LeCodesRuntime"/.test(xml) ? null : `app/src/main/res/values/themes.xml: the app's theme needs parent="Theme.LeCodesRuntime" and no android:windowBackground of its own for the splash to show — see "Splash screen" in android/README.md`;
|
|
@@ -231346,13 +231579,13 @@ if "%OS%"=="Windows_NT" endlocal
|
|
|
231346
231579
|
// src/commands/app/play.ts
|
|
231347
231580
|
init_cli();
|
|
231348
231581
|
import { sign } from "node:crypto";
|
|
231349
|
-
import { readFileSync as
|
|
231582
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
231350
231583
|
var SCOPE = "https://www.googleapis.com/auth/androidpublisher";
|
|
231351
231584
|
var apiBase = () => process.env.LECODES_PLAY_API_URL ?? "https://androidpublisher.googleapis.com";
|
|
231352
231585
|
var readServiceAccount = (path) => {
|
|
231353
231586
|
let key;
|
|
231354
231587
|
try {
|
|
231355
|
-
key = JSON.parse(
|
|
231588
|
+
key = JSON.parse(readFileSync21(path, "utf8"));
|
|
231356
231589
|
} catch {
|
|
231357
231590
|
throw new CliError(`${path} is not a JSON key file.`);
|
|
231358
231591
|
}
|
|
@@ -231432,7 +231665,7 @@ var shellSdkVersionAndroid = (androidDir) => {
|
|
|
231432
231665
|
const path = join23(androidDir, "lecodes-runtime", "build.gradle.kts");
|
|
231433
231666
|
if (!existsSync21(path))
|
|
231434
231667
|
return null;
|
|
231435
|
-
const m = /io\.letary:lecodes-sdk(?:-(?:core|2d|3d))?:(\d+\.\d+\.\d+)@aar/.exec(
|
|
231668
|
+
const m = /io\.letary:lecodes-sdk(?:-(?:core|2d|3d))?:(\d+\.\d+\.\d+)@aar/.exec(readFileSync22(path, "utf8"));
|
|
231436
231669
|
return m ? m[1] : null;
|
|
231437
231670
|
};
|
|
231438
231671
|
var GRADLE_WRAPPER_JAR_URL = "https://raw.githubusercontent.com/gradle/gradle/v8.13.0/gradle/wrapper/gradle-wrapper.jar";
|
|
@@ -231440,7 +231673,7 @@ var GRADLE_WRAPPER_JAR_SHA256 = "81a82aaea5abcc8ff68b3dfcb58b3c3c429378efd98e743
|
|
|
231440
231673
|
var ensureGradleWrapperJar = async () => {
|
|
231441
231674
|
const cached = join23(homedir8(), ".lecodes", "gradle-wrapper", GRADLE_VERSION, "gradle-wrapper.jar");
|
|
231442
231675
|
if (existsSync21(cached))
|
|
231443
|
-
return new Uint8Array(
|
|
231676
|
+
return new Uint8Array(readFileSync22(cached));
|
|
231444
231677
|
try {
|
|
231445
231678
|
const res = await fetch(GRADLE_WRAPPER_JAR_URL);
|
|
231446
231679
|
if (!res.ok)
|
|
@@ -231571,7 +231804,7 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
231571
231804
|
resources = prior.resources;
|
|
231572
231805
|
} else {
|
|
231573
231806
|
resources = await compileShell(join23(assetsDir, "app.js"), { remotePatterns });
|
|
231574
|
-
bundleJs =
|
|
231807
|
+
bundleJs = readFileSync22(join23(assetsDir, "app.js"), "utf8");
|
|
231575
231808
|
}
|
|
231576
231809
|
const requestedVariant = config.android?.variant ?? "auto";
|
|
231577
231810
|
if (requestedVariant !== "auto" && !ANDROID_SDK_VARIANTS.includes(requestedVariant)) {
|
|
@@ -231716,7 +231949,7 @@ var restampManifestBlock = (androidDir, tag, block, what, missing, after = []) =
|
|
|
231716
231949
|
const path = join23(androidDir, "app", "src", "main", "AndroidManifest.xml");
|
|
231717
231950
|
if (!existsSync21(path))
|
|
231718
231951
|
return;
|
|
231719
|
-
const content =
|
|
231952
|
+
const content = readFileSync22(path, "utf8");
|
|
231720
231953
|
const tagged = new RegExp(`\\n[ \\t]*<!-- lecodes:${tag}[\\s\\S]*?<!-- \\/lecodes:${tag} -->`);
|
|
231721
231954
|
let next;
|
|
231722
231955
|
if (tagged.test(content))
|
|
@@ -231745,7 +231978,7 @@ var restampAppBuildGradle = (androidDir, config, gradlePlugins) => {
|
|
|
231745
231978
|
warn("android/app/build.gradle.kts is missing — run `lecodes app init android` on a clean tree to regenerate the shell.");
|
|
231746
231979
|
return;
|
|
231747
231980
|
}
|
|
231748
|
-
let content =
|
|
231981
|
+
let content = readFileSync22(path, "utf8");
|
|
231749
231982
|
const before = content;
|
|
231750
231983
|
const versionName = config.version ?? "1.0.0";
|
|
231751
231984
|
const versionCode = config.android?.versionCode ?? 1;
|
|
@@ -231958,7 +232191,7 @@ var uploadAndroid = async (flags) => {
|
|
|
231958
232191
|
const token = await serviceAccountToken(key);
|
|
231959
232192
|
const { versionCode } = await uploadToPlay(token, {
|
|
231960
232193
|
packageName,
|
|
231961
|
-
aab:
|
|
232194
|
+
aab: readFileSync22(aabPath),
|
|
231962
232195
|
track: flags.track,
|
|
231963
232196
|
status: flags.draft ? "draft" : "completed"
|
|
231964
232197
|
});
|
|
@@ -231987,7 +232220,7 @@ var ANDROID_SIGNING_ENV = {
|
|
|
231987
232220
|
};
|
|
231988
232221
|
var readProperties = (path) => {
|
|
231989
232222
|
const out = {};
|
|
231990
|
-
for (const raw of
|
|
232223
|
+
for (const raw of readFileSync22(path, "utf8").split(/\r?\n/)) {
|
|
231991
232224
|
const line = raw.trim();
|
|
231992
232225
|
if (!line || line.startsWith("#") || line.startsWith("!"))
|
|
231993
232226
|
continue;
|
|
@@ -232087,7 +232320,7 @@ var writeSigningConfig = (root, config, storeFile, alias, storePassword, keyPass
|
|
|
232087
232320
|
const rel = relative4(root, storeFile);
|
|
232088
232321
|
if (rel && !rel.startsWith("..") && !rel.includes(":") && !rel.replace(/\\/g, "/").startsWith("android/")) {
|
|
232089
232322
|
const ignorePath = join23(root, ".gitignore");
|
|
232090
|
-
const ignore = existsSync21(ignorePath) ?
|
|
232323
|
+
const ignore = existsSync21(ignorePath) ? readFileSync22(ignorePath, "utf8") : "";
|
|
232091
232324
|
if (!ignore.split(`
|
|
232092
232325
|
`).some((l) => l.trim() === "*.keystore")) {
|
|
232093
232326
|
writeFileSync15(ignorePath, ignore + (!ignore || ignore.endsWith(`
|
|
@@ -232325,10 +232558,10 @@ var doctorAndroidChecks = async (root, config, check) => {
|
|
|
232325
232558
|
}
|
|
232326
232559
|
if (config.update) {
|
|
232327
232560
|
const manifest = join23(androidDir, "lecodes-runtime", "src", "main", "AndroidManifest.xml");
|
|
232328
|
-
check(existsSync21(manifest) &&
|
|
232561
|
+
check(existsSync21(manifest) && readFileSync22(manifest, "utf8").includes("io.letary.lecodes.UPDATE_URL"), "OTA update URL in the runtime manifest", "run `lecodes app sync`", false);
|
|
232329
232562
|
const appSrc = join23(androidDir, "app", "src", "main", "java");
|
|
232330
232563
|
const kt = existsSync21(appSrc) ? readdirSync6(appSrc, { recursive: true }).map(String).filter((f) => f.endsWith(".kt")) : [];
|
|
232331
|
-
const sources = kt.map((f) =>
|
|
232564
|
+
const sources = kt.map((f) => readFileSync22(join23(appSrc, f), "utf8"));
|
|
232332
232565
|
const boots = sources.some((src) => src.includes("LeCodesShell.boot"));
|
|
232333
232566
|
check(boots, "App code launches via the updater (LeCodesShell.boot)", 'no app/src/main/java/**/*.kt calls LeCodesShell.boot(engine, activity) — downloaded updates would never run; see "Over-the-air updates" in android/README.md for the AppViewModel snippet', false);
|
|
232334
232567
|
const waits = sources.some((src) => /LeCodesShell\.boot\(\s*engine\s*,\s*activity\b/.test(src));
|
|
@@ -232348,7 +232581,7 @@ var doctorAndroidChecks = async (root, config, check) => {
|
|
|
232348
232581
|
}
|
|
232349
232582
|
check(!!findKeytool(), "keytool", "install a JDK or set JAVA_HOME (`lecodes app keystore …` needs it)", false);
|
|
232350
232583
|
const appGradle = join23(androidDir, "app", "build.gradle.kts");
|
|
232351
|
-
const gradleText = existsSync21(appGradle) ?
|
|
232584
|
+
const gradleText = existsSync21(appGradle) ? readFileSync22(appGradle, "utf8") : "";
|
|
232352
232585
|
check(gradleText.includes("abiFilters"), "abiFilters in app/build.gradle.kts", 'add `ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }` to defaultConfig — x86_64 devices crash at launch without it', false);
|
|
232353
232586
|
check(["isMinifyEnabled", "isShrinkResources"].every((k) => new RegExp(`${k} = (true|false)`).test(gradleText)), "R8 block in app/build.gradle.kts", 'shell predates R8-by-default — see android/README.md "Building"', false);
|
|
232354
232587
|
if (Object.keys(config.plugins ?? {}).includes("push")) {
|
|
@@ -232362,11 +232595,12 @@ import { cpSync as cpSync3, existsSync as existsSync24, mkdirSync as mkdirSync15
|
|
|
232362
232595
|
import { basename as basename9, dirname as dirname16, join as join26, resolve as resolve13 } from "node:path";
|
|
232363
232596
|
|
|
232364
232597
|
// src/hosts/desktopRenderer.ts
|
|
232598
|
+
init_releases();
|
|
232599
|
+
init_cli();
|
|
232365
232600
|
import { execFileSync as execFileSync3, spawn as spawn2, spawnSync as spawnSync6 } from "node:child_process";
|
|
232366
|
-
import { copyFileSync, existsSync as existsSync22, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync2, readdirSync as readdirSync7, readFileSync as
|
|
232601
|
+
import { copyFileSync, existsSync as existsSync22, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync2, readdirSync as readdirSync7, readFileSync as readFileSync23, rmSync as rmSync5, statSync as statSync6, writeFileSync as writeFileSync16, linkSync } from "node:fs";
|
|
232367
232602
|
import { homedir as homedir9, tmpdir as tmpdir2 } from "node:os";
|
|
232368
232603
|
import { delimiter, join as join24, resolve as resolve11 } from "node:path";
|
|
232369
|
-
init_cli();
|
|
232370
232604
|
|
|
232371
232605
|
// ../../renderers/web-shared/src/sourcemapError.ts
|
|
232372
232606
|
var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -232508,7 +232742,7 @@ var installedDesktopVersions = () => {
|
|
|
232508
232742
|
};
|
|
232509
232743
|
var selectedDesktopVersion = () => {
|
|
232510
232744
|
try {
|
|
232511
|
-
const saved = JSON.parse(
|
|
232745
|
+
const saved = JSON.parse(readFileSync23(currentFile(), "utf8")).version;
|
|
232512
232746
|
if (saved && /^\d+\.\d+\.\d+/.test(saved) && semverNewer(DESKTOP_RENDERER_VERSION, saved) > 0)
|
|
232513
232747
|
return saved;
|
|
232514
232748
|
} catch {}
|
|
@@ -233630,7 +233864,7 @@ var shellSdkVersion = (iosDir) => {
|
|
|
233630
233864
|
const path = join27(iosDir, "LeCodesRuntime", "Package.swift");
|
|
233631
233865
|
if (!existsSync25(path))
|
|
233632
233866
|
return null;
|
|
233633
|
-
const m = /lecodes-ios-sdk\.git",\s*(?:exact|from):\s*"(\d+\.\d+\.\d+)(?:-(?:core|2d|3d))?"/.exec(
|
|
233867
|
+
const m = /lecodes-ios-sdk\.git",\s*(?:exact|from):\s*"(\d+\.\d+\.\d+)(?:-(?:core|2d|3d))?"/.exec(readFileSync24(path, "utf8"));
|
|
233634
233868
|
return m && VERSION_RE.test(m[1]) ? m[1] : null;
|
|
233635
233869
|
};
|
|
233636
233870
|
var IOS_SDK_OPTS = { repo: SDK_REPO, minVersion: SDK_MIN_VERSION, configKey: "ios.sdk" };
|
|
@@ -233836,7 +234070,7 @@ var syncIos = async (root, config) => {
|
|
|
233836
234070
|
rmSync8(resourcesDir, { recursive: true, force: true });
|
|
233837
234071
|
mkdirSync16(resourcesDir, { recursive: true });
|
|
233838
234072
|
const resources = await compileShell(join27(resourcesDir, "app.js"), { remotePatterns });
|
|
233839
|
-
const bundleJs =
|
|
234073
|
+
const bundleJs = readFileSync24(join27(resourcesDir, "app.js"), "utf8");
|
|
233840
234074
|
const { variant, why } = resolveVariant(requestedVariant, bundleJs);
|
|
233841
234075
|
log(`${c.green("variant")} ${variant}${requestedVariant === "auto" ? ` (auto: ${why})` : " (forced by ios.variant)"}`);
|
|
233842
234076
|
const sdkWhy = sdkPin === "latest" ? "latest" : config.ios.sdk ? "pinned by ios.sdk" : "from the shell — set ios.sdk or run `lecodes app update`";
|
|
@@ -233902,7 +234136,7 @@ var syncIos = async (root, config) => {
|
|
|
233902
234136
|
if (pluginSpecs.length > 0 || existsSync25(lockPath))
|
|
233903
234137
|
writeJson(lockPath, { plugins: newLock });
|
|
233904
234138
|
const pbxPath = join27(iosDir, "App.xcodeproj", "project.pbxproj");
|
|
233905
|
-
let pbx =
|
|
234139
|
+
let pbx = readFileSync24(pbxPath, "utf8").replace(/MARKETING_VERSION = [^;]+;/g, `MARKETING_VERSION = ${config.version ?? "1.0.0"};`).replace(/CURRENT_PROJECT_VERSION = [^;]+;/g, `CURRENT_PROJECT_VERSION = ${config.ios.buildNumber ?? 1};`);
|
|
233906
234140
|
const mergedEntitlements = {};
|
|
233907
234141
|
const appLinks = appLinksOf(config);
|
|
233908
234142
|
if (appLinks.length) {
|
|
@@ -234194,8 +234428,8 @@ var doctorIosChecks = async (root, config, check) => {
|
|
|
234194
234428
|
const validVariant = requestedVariant === "auto" || SDK_VARIANTS.includes(requestedVariant);
|
|
234195
234429
|
check(validVariant, `ios.variant "${requestedVariant}"`, `use "auto" or one of ${SDK_VARIANTS.join(", ")}`);
|
|
234196
234430
|
if (existsSync25(bundle) && validVariant) {
|
|
234197
|
-
const { variant } = resolveVariant(requestedVariant,
|
|
234198
|
-
const pkg =
|
|
234431
|
+
const { variant } = resolveVariant(requestedVariant, readFileSync24(bundle, "utf8"));
|
|
234432
|
+
const pkg = readFileSync24(join27(root, "ios", "LeCodesRuntime", "Package.swift"), "utf8");
|
|
234199
234433
|
const tag = /lecodes-ios-sdk\.git",\s*exact:\s*"([^"]+)"/.exec(pkg)?.[1] ?? "";
|
|
234200
234434
|
const tagVariant = /-(core|2d|3d)$/.exec(tag)?.[1] ?? "full";
|
|
234201
234435
|
check(tagVariant === variant, `SDK variant ${variant}`, "run `lecodes app sync`");
|
|
@@ -234217,25 +234451,25 @@ var doctorIosChecks = async (root, config, check) => {
|
|
|
234217
234451
|
const inSync = wanted.every((id) => lock[id]) && Object.keys(lock).every((id) => wanted.includes(id));
|
|
234218
234452
|
check(wanted.length === 0 || inSync, "Plugins synced", "run `lecodes app sync`");
|
|
234219
234453
|
const pbxFile = join27(root, "ios", "App.xcodeproj", "project.pbxproj");
|
|
234220
|
-
if (existsSync25(pbxFile) &&
|
|
234454
|
+
if (existsSync25(pbxFile) && readFileSync24(pbxFile, "utf8").includes("CODE_SIGN_ENTITLEMENTS")) {
|
|
234221
234455
|
check(existsSync25(join27(root, "ios", "App", "App.entitlements")), "App/App.entitlements present", "run `lecodes app sync`");
|
|
234222
234456
|
}
|
|
234223
234457
|
if (wanted.includes("push")) {
|
|
234224
234458
|
const runtimeSwift = join27(root, "ios", "LeCodesRuntime", "Sources", "LeCodesRuntime", "LeCodesRuntime.swift");
|
|
234225
|
-
const baked = existsSync25(runtimeSwift) &&
|
|
234459
|
+
const baked = existsSync25(runtimeSwift) && readFileSync24(runtimeSwift, "utf8").includes("bootProjectUuid");
|
|
234226
234460
|
check(baked, "Push world identity baked", `without it Push.register() rejects "unavailable" — needs a pushed project (uuid), lecodes-ios-sdk ${SDK_IDENTITY_VERSION}+ and \`lecodes app sync\``, false);
|
|
234227
234461
|
}
|
|
234228
234462
|
if (config.update) {
|
|
234229
|
-
const plist =
|
|
234463
|
+
const plist = readFileSync24(join27(root, "ios", "App", "Info.plist"), "utf8");
|
|
234230
234464
|
check(plist.includes("<key>LeCodesUpdateURL</key>"), "OTA update URL in Info.plist", "run `lecodes app sync`", false);
|
|
234231
234465
|
const appDir = join27(root, "ios", "App");
|
|
234232
|
-
const swift = readdirSync10(appDir).filter((f) => f.endsWith(".swift")).map((f) =>
|
|
234466
|
+
const swift = readdirSync10(appDir).filter((f) => f.endsWith(".swift")).map((f) => readFileSync24(join27(appDir, f), "utf8"));
|
|
234233
234467
|
const launchesViaUpdater = swift.some((t) => t.includes("LeCodesAppViewController") || t.includes("LeCodesUpdater.activeBundle"));
|
|
234234
234468
|
check(launchesViaUpdater, "App code launches via the updater", `no App/*.swift subclasses LeCodesAppViewController or calls LeCodesUpdater.activeBundle() — downloaded updates would never run; see "Over-the-air updates" in ios/README.md`, false);
|
|
234235
234469
|
}
|
|
234236
234470
|
{
|
|
234237
234471
|
const vc = join27(root, "ios", "App", "ViewController.swift");
|
|
234238
|
-
const is2x = !existsSync25(vc) ||
|
|
234472
|
+
const is2x = !existsSync25(vc) || readFileSync24(vc, "utf8").includes("LeCodesAppViewController");
|
|
234239
234473
|
check(is2x, "App/ViewController.swift is the 2.x shell (LeCodesAppViewController)", "a 1.x shell's App/*.swift: replace AppDelegate.swift, SceneDelegate.swift and ViewController.swift with the ones `lecodes app init ios` writes today (your own code goes into ViewController.configure(_:))", false);
|
|
234240
234474
|
}
|
|
234241
234475
|
const asc = readJson2(join27(homedir10(), ".lecodes", "asc.json"));
|
|
@@ -234465,10 +234699,11 @@ var app_default = defineCommand({
|
|
|
234465
234699
|
init_cli();
|
|
234466
234700
|
|
|
234467
234701
|
// src/hosts/cmgenTool.ts
|
|
234702
|
+
init_releases();
|
|
234703
|
+
init_cli();
|
|
234468
234704
|
import { existsSync as existsSync26, readdirSync as readdirSync11 } from "node:fs";
|
|
234469
234705
|
import { homedir as homedir11 } from "node:os";
|
|
234470
234706
|
import { join as join28, resolve as resolve15 } from "node:path";
|
|
234471
|
-
init_cli();
|
|
234472
234707
|
var exeName2 = () => process.platform === "win32" ? "cmgen.exe" : "cmgen";
|
|
234473
234708
|
var platformKey3 = () => {
|
|
234474
234709
|
if (process.platform === "win32")
|
|
@@ -234652,6 +234887,7 @@ lecodes render --sim --script <file> # the WINDOWLESS native host (lecodes-
|
|
|
234652
234887
|
# engines, no GPU, no pixels, no UI hit-test — expect.log /
|
|
234653
234888
|
# expect.paint only; runs on CI and beside an open desktop window
|
|
234654
234889
|
lecodes test # all tests/*.flow.json + design-derived flows; run before "done"
|
|
234890
|
+
bunx -p typescript tsc --noEmit # typecheck against .lecodes/types (the SDK's globals); also before "done"
|
|
234655
234891
|
lecodes test --desktop # the file flows on the NATIVE host (design flows stay headless)
|
|
234656
234892
|
lecodes test --sim # the windowless twin: coordinates + expect.log / expect.paint only
|
|
234657
234893
|
lecodes dev --android --time 12 --png phone.png # the REAL phone over adb (USB): launches the app on
|
|
@@ -234775,9 +235011,9 @@ fetch the docs — they are served as raw markdown for AI tools:
|
|
|
234775
235011
|
with a COOKBOOK: read the matching recipe BEFORE you design the structure.** It has the file
|
|
234776
235012
|
layout, a skeleton per part, how to verify, and the traps already paid for (start with
|
|
234777
235013
|
"Project architecture for a game" for any game bigger than one file).
|
|
234778
|
-
- https://le.codes/
|
|
235014
|
+
- https://le.codes/docs/api/<area>/<page>.md — one reference page as raw markdown
|
|
234779
235015
|
(e.g. \`ui/styling.md\`, \`2d/scene2d.md\`, \`3d/scene.md\`, \`runtime/storage.md\`)
|
|
234780
|
-
- https://le.codes/
|
|
235016
|
+
- https://le.codes/docs/guide/<page>.md — guide pages (project anatomy, CLI, tracks)
|
|
234781
235017
|
- https://le.codes/llms-full.txt — everything in one file (large; prefer per-page)
|
|
234782
235018
|
|
|
234783
235019
|
Always fetch the \`.md\` URLs — the HTML routes are a JS app and return an empty shell.
|
|
@@ -235575,7 +235811,7 @@ var desktop_default = defineCommand({
|
|
|
235575
235811
|
|
|
235576
235812
|
// src/commands/dev.ts
|
|
235577
235813
|
init_manifest();
|
|
235578
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as
|
|
235814
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as readFileSync33, writeFileSync as writeFileSync25 } from "node:fs";
|
|
235579
235815
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
235580
235816
|
import { networkInterfaces } from "node:os";
|
|
235581
235817
|
import { basename as basename15, join as join43 } from "node:path";
|
|
@@ -235583,7 +235819,7 @@ import { basename as basename15, join as join43 } from "node:path";
|
|
|
235583
235819
|
// src/dev/devServer.ts
|
|
235584
235820
|
init_localFiles();
|
|
235585
235821
|
import { createHash as createHash8 } from "node:crypto";
|
|
235586
|
-
import { createReadStream as createReadStream2, readFileSync as
|
|
235822
|
+
import { createReadStream as createReadStream2, readFileSync as readFileSync31, statSync as statSync11 } from "node:fs";
|
|
235587
235823
|
import { join as join39 } from "node:path";
|
|
235588
235824
|
import { Readable as Readable3 } from "node:stream";
|
|
235589
235825
|
init_projectCompile();
|
|
@@ -235718,7 +235954,7 @@ init_paths();
|
|
|
235718
235954
|
// src/web/halves.ts
|
|
235719
235955
|
init_compile();
|
|
235720
235956
|
init_cli();
|
|
235721
|
-
import { cpSync as cpSync5, existsSync as existsSync34, readFileSync as
|
|
235957
|
+
import { cpSync as cpSync5, existsSync as existsSync34, readFileSync as readFileSync30 } from "node:fs";
|
|
235722
235958
|
import { join as join38, sep as sep4 } from "node:path";
|
|
235723
235959
|
var halfModule = (half) => `plugins/${half.folder}/index.js`;
|
|
235724
235960
|
var asCliError = (e) => new CliError(e instanceof Error ? e.message : String(e));
|
|
@@ -235729,7 +235965,7 @@ var projectHalves = (root) => {
|
|
|
235729
235965
|
const folder = dir.split(sep4).pop();
|
|
235730
235966
|
let web;
|
|
235731
235967
|
try {
|
|
235732
|
-
web = webHalfManifestOf(
|
|
235968
|
+
web = webHalfManifestOf(readFileSync30(join38(dir, MANIFEST_FILE), "utf8"), folder, id);
|
|
235733
235969
|
} catch (e) {
|
|
235734
235970
|
throw asCliError(e);
|
|
235735
235971
|
}
|
|
@@ -235870,7 +236106,7 @@ var startDevServer = async (options) => {
|
|
|
235870
236106
|
const liteTable = () => {
|
|
235871
236107
|
let plugins = {};
|
|
235872
236108
|
try {
|
|
235873
|
-
plugins = JSON.parse(
|
|
236109
|
+
plugins = JSON.parse(readFileSync31(join39(lite, "plugins.json"), "utf8")).plugins ?? {};
|
|
235874
236110
|
} catch {}
|
|
235875
236111
|
const table = { ...plugins };
|
|
235876
236112
|
for (const { half, hash } of halves) {
|
|
@@ -236361,7 +236597,7 @@ var androidCrashLines = (session) => {
|
|
|
236361
236597
|
|
|
236362
236598
|
// src/dev/iosDev.ts
|
|
236363
236599
|
init_cli();
|
|
236364
|
-
import { existsSync as existsSync37, readdirSync as readdirSync17, readFileSync as
|
|
236600
|
+
import { existsSync as existsSync37, readdirSync as readdirSync17, readFileSync as readFileSync32, statSync as statSync13, unlinkSync } from "node:fs";
|
|
236365
236601
|
import { homedir as homedir12 } from "node:os";
|
|
236366
236602
|
import { join as join42 } from "node:path";
|
|
236367
236603
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
@@ -236394,7 +236630,7 @@ var listDevices2 = () => {
|
|
|
236394
236630
|
if (!ok || !existsSync37(tmp))
|
|
236395
236631
|
return [];
|
|
236396
236632
|
try {
|
|
236397
|
-
const json = JSON.parse(
|
|
236633
|
+
const json = JSON.parse(readFileSync32(tmp, "utf8"));
|
|
236398
236634
|
return (json.result?.devices ?? []).map((d) => ({
|
|
236399
236635
|
udid: d.identifier,
|
|
236400
236636
|
name: d.deviceProperties?.name ?? d.identifier,
|
|
@@ -236441,7 +236677,7 @@ var deviceHasApp = (udid, bundleId) => {
|
|
|
236441
236677
|
if (!ok || !existsSync37(tmp))
|
|
236442
236678
|
return false;
|
|
236443
236679
|
try {
|
|
236444
|
-
const json = JSON.parse(
|
|
236680
|
+
const json = JSON.parse(readFileSync32(tmp, "utf8"));
|
|
236445
236681
|
return (json.result?.apps ?? []).some((a) => a.bundleIdentifier === bundleId);
|
|
236446
236682
|
} catch {
|
|
236447
236683
|
return false;
|
|
@@ -236481,7 +236717,7 @@ var launchOnIos = (opts) => {
|
|
|
236481
236717
|
if (!start.ok)
|
|
236482
236718
|
throw new CliError(`Could not launch ${bundleId} on ${target.name}: ${start.out}`);
|
|
236483
236719
|
try {
|
|
236484
|
-
const json = JSON.parse(
|
|
236720
|
+
const json = JSON.parse(readFileSync32(tmp, "utf8"));
|
|
236485
236721
|
pid = json.result?.process?.processIdentifier?.toString() ?? null;
|
|
236486
236722
|
} catch {
|
|
236487
236723
|
pid = null;
|
|
@@ -236553,7 +236789,7 @@ var lanCandidates = () => {
|
|
|
236553
236789
|
var loadDevToken = (root) => {
|
|
236554
236790
|
const path = join43(root, LECODES_DIR, "dev.json");
|
|
236555
236791
|
try {
|
|
236556
|
-
const token = JSON.parse(
|
|
236792
|
+
const token = JSON.parse(readFileSync33(path, "utf8")).token;
|
|
236557
236793
|
if (token && /^[a-z0-9]{8,}$/.test(token))
|
|
236558
236794
|
return token;
|
|
236559
236795
|
} catch {}
|
|
@@ -236788,7 +237024,7 @@ init_api();
|
|
|
236788
237024
|
|
|
236789
237025
|
// src/platform/serverDiff.ts
|
|
236790
237026
|
init_localFiles();
|
|
236791
|
-
import { readFileSync as
|
|
237027
|
+
import { readFileSync as readFileSync34 } from "node:fs";
|
|
236792
237028
|
var isTextAsset = (t) => t === "text" || t === "shader" || t === "scene";
|
|
236793
237029
|
var computeServerDiff = (project, scan) => {
|
|
236794
237030
|
const pathById = buildPaths(project.assets);
|
|
@@ -236806,7 +237042,7 @@ var computeServerDiff = (project, scan) => {
|
|
|
236806
237042
|
const local = localByPath.get(path);
|
|
236807
237043
|
if (local && !server2) {
|
|
236808
237044
|
const text = isTextKind(local.kind);
|
|
236809
|
-
entries.push({ path, status: "added", binary: !text, serverText: "", localText: text ?
|
|
237045
|
+
entries.push({ path, status: "added", binary: !text, serverText: "", localText: text ? readFileSync34(local.absPath, "utf8") : undefined });
|
|
236810
237046
|
continue;
|
|
236811
237047
|
}
|
|
236812
237048
|
if (server2 && !local) {
|
|
@@ -236817,12 +237053,12 @@ var computeServerDiff = (project, scan) => {
|
|
|
236817
237053
|
if (server2 && local) {
|
|
236818
237054
|
if (isTextAsset(server2.type)) {
|
|
236819
237055
|
const serverText = server2.text ?? "";
|
|
236820
|
-
const localText =
|
|
237056
|
+
const localText = readFileSync34(local.absPath, "utf8");
|
|
236821
237057
|
if (serverText !== localText)
|
|
236822
237058
|
entries.push({ path, status: "modified", binary: false, serverText, localText });
|
|
236823
237059
|
} else {
|
|
236824
237060
|
const serverSize = server2.file?.size;
|
|
236825
|
-
const localSize = Buffer.byteLength(
|
|
237061
|
+
const localSize = Buffer.byteLength(readFileSync34(local.absPath));
|
|
236826
237062
|
if (serverSize !== undefined && serverSize !== localSize) {
|
|
236827
237063
|
entries.push({ path, status: "modified", binary: true });
|
|
236828
237064
|
}
|
|
@@ -237154,7 +237390,7 @@ var init3 = (dir, forDesktop) => {
|
|
|
237154
237390
|
// src/commands/install.ts
|
|
237155
237391
|
init_cli();
|
|
237156
237392
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
237157
|
-
import { appendFileSync as appendFileSync3, chmodSync as chmodSync2, cpSync as cpSync6, existsSync as existsSync40, mkdirSync as mkdirSync24, readFileSync as
|
|
237393
|
+
import { appendFileSync as appendFileSync3, chmodSync as chmodSync2, cpSync as cpSync6, existsSync as existsSync40, mkdirSync as mkdirSync24, readFileSync as readFileSync35, realpathSync as realpathSync2, rmSync as rmSync11, symlinkSync as symlinkSync2 } from "node:fs";
|
|
237158
237394
|
import { homedir as homedir13 } from "node:os";
|
|
237159
237395
|
import { basename as basename17, delimiter as delimiter2, dirname as dirname22, join as join45, resolve as resolve21 } from "node:path";
|
|
237160
237396
|
var isWin = process.platform === "win32";
|
|
@@ -237208,7 +237444,7 @@ var appendPathToShellRc = (binDir) => {
|
|
|
237208
237444
|
const { file, name } = shellRc();
|
|
237209
237445
|
const line = `export PATH="${binDir}:$PATH"`;
|
|
237210
237446
|
try {
|
|
237211
|
-
const existing = existsSync40(file) ?
|
|
237447
|
+
const existing = existsSync40(file) ? readFileSync35(file, "utf8") : "";
|
|
237212
237448
|
if (existing.includes(line))
|
|
237213
237449
|
return name;
|
|
237214
237450
|
appendFileSync3(file, `${existing && !existing.endsWith(`
|
|
@@ -237330,9 +237566,9 @@ var install_default = defineCommand({
|
|
|
237330
237566
|
});
|
|
237331
237567
|
|
|
237332
237568
|
// src/commands/lightmap.ts
|
|
237333
|
-
import { closeSync, existsSync as existsSync41, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync4, openSync, readFileSync as
|
|
237569
|
+
import { closeSync, existsSync as existsSync41, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync4, openSync, readdirSync as readdirSync18, readFileSync as readFileSync36, readSync, rmSync as rmSync12, writeFileSync as writeFileSync27 } from "node:fs";
|
|
237334
237570
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
237335
|
-
import { basename as basename18, join as join46, relative as relative7, resolve as resolve22 } from "node:path";
|
|
237571
|
+
import { basename as basename18, dirname as dirname23, join as join46, relative as relative7, resolve as resolve22, sep as sep5 } from "node:path";
|
|
237336
237572
|
import { deflateSync } from "node:zlib";
|
|
237337
237573
|
init_peerInstall();
|
|
237338
237574
|
init_cli();
|
|
@@ -237345,7 +237581,7 @@ var range = (name, value, min, max) => {
|
|
|
237345
237581
|
var readBake = (file) => {
|
|
237346
237582
|
if (!existsSync41(file))
|
|
237347
237583
|
throw new CliError(`No bake at ${file} — run \`lecodes lightmap bake\` first.`);
|
|
237348
|
-
const data = JSON.parse(
|
|
237584
|
+
const data = JSON.parse(readFileSync36(file, "utf8"));
|
|
237349
237585
|
if (data.version !== 4)
|
|
237350
237586
|
throw new CliError(`${file} is not a creator-bake file (version ${String(data.version)}) — rebake.`);
|
|
237351
237587
|
return data;
|
|
@@ -237381,54 +237617,47 @@ var cubePatternsOf = (argv) => {
|
|
|
237381
237617
|
}
|
|
237382
237618
|
return out.filter((p) => p !== "");
|
|
237383
237619
|
};
|
|
237384
|
-
var
|
|
237385
|
-
|
|
237386
|
-
|
|
237387
|
-
|
|
237388
|
-
const
|
|
237389
|
-
|
|
237390
|
-
|
|
237391
|
-
|
|
237392
|
-
|
|
237393
|
-
|
|
237394
|
-
|
|
237395
|
-
|
|
237396
|
-
|
|
237397
|
-
|
|
237398
|
-
|
|
237399
|
-
|
|
237400
|
-
b.writeUInt32LE(0, o);
|
|
237401
|
-
b.writeUInt32LE(0, o + 4);
|
|
237402
|
-
o += 8;
|
|
237403
|
-
b.writeBigUInt64LE(0n, o);
|
|
237404
|
-
b.writeBigUInt64LE(0n, o + 8);
|
|
237405
|
-
o += 16;
|
|
237406
|
-
b.writeBigUInt64LE(BigInt(dfdOffset + dfdSize), o);
|
|
237407
|
-
b.writeBigUInt64LE(BigInt(raw.length), o + 8);
|
|
237408
|
-
b.writeBigUInt64LE(BigInt(raw.length), o + 16);
|
|
237409
|
-
o += 24;
|
|
237410
|
-
b.writeUInt32LE(dfdSize, o);
|
|
237411
|
-
raw.copy(b, dfdOffset + dfdSize);
|
|
237412
|
-
return b;
|
|
237620
|
+
var stemOf = (path) => basename18(path).replace(/\.bake$/i, "");
|
|
237621
|
+
var pickTarget2 = (bakes, name, entry) => {
|
|
237622
|
+
if (bakes.length === 0)
|
|
237623
|
+
throw new CliError(`${entry} reaches no bake(): the level's scene file says where its bake goes — add \`env: { lightmap: bake('./assets/lightmap/level.bake') }\` (a hand-built scene: \`Lightmap.load(scene, bake('./assets/lightmap/level.bake'))\`).`);
|
|
237624
|
+
const listed = bakes.map((b) => `${stemOf(b.path)} (${b.path})`).join(", ");
|
|
237625
|
+
if (name === undefined) {
|
|
237626
|
+
if (bakes.length > 1)
|
|
237627
|
+
throw new CliError(`${entry} reaches ${bakes.length} bake() calls: ${listed} — pass --name <stem> to pick the level to bake.`);
|
|
237628
|
+
return bakes[0];
|
|
237629
|
+
}
|
|
237630
|
+
const named = bakes.filter((b) => stemOf(b.path) === name);
|
|
237631
|
+
if (named.length === 0)
|
|
237632
|
+
throw new CliError(`--name ${name}: ${entry} reaches no bake() of that stem — it reaches ${listed}.`);
|
|
237633
|
+
if (named.length > 1)
|
|
237634
|
+
throw new CliError(`--name ${name}: two bake() targets share that stem (${named.map((b) => b.path).join(", ")}) — rename one.`);
|
|
237635
|
+
return named[0];
|
|
237413
237636
|
};
|
|
237414
|
-
var
|
|
237415
|
-
const
|
|
237416
|
-
const
|
|
237417
|
-
|
|
237418
|
-
|
|
237419
|
-
|
|
237420
|
-
|
|
237421
|
-
|
|
237422
|
-
|
|
237423
|
-
|
|
237424
|
-
|
|
237425
|
-
|
|
237426
|
-
|
|
237427
|
-
|
|
237428
|
-
|
|
237429
|
-
|
|
237430
|
-
if (
|
|
237431
|
-
|
|
237637
|
+
var findBakes = (root) => {
|
|
237638
|
+
const SKIP = new Set(["node_modules", ".lightmap", ".git", ".lecodes"]);
|
|
237639
|
+
const out = [];
|
|
237640
|
+
const walk = (dir) => {
|
|
237641
|
+
for (const e of readdirSync18(dir, { withFileTypes: true })) {
|
|
237642
|
+
if (e.isDirectory()) {
|
|
237643
|
+
if (!SKIP.has(e.name))
|
|
237644
|
+
walk(join46(dir, e.name));
|
|
237645
|
+
} else if (/\.bake$/i.test(e.name))
|
|
237646
|
+
out.push(relative7(root, join46(dir, e.name)).replace(/\\/g, "/"));
|
|
237647
|
+
}
|
|
237648
|
+
};
|
|
237649
|
+
walk(root);
|
|
237650
|
+
return out.sort();
|
|
237651
|
+
};
|
|
237652
|
+
var bakeFileOf = (root, flag) => {
|
|
237653
|
+
if (flag)
|
|
237654
|
+
return resolve22(root, flag);
|
|
237655
|
+
const found = findBakes(root);
|
|
237656
|
+
if (found.length === 0)
|
|
237657
|
+
throw new CliError("No .bake in the project — run `lecodes lightmap bake` first.");
|
|
237658
|
+
if (found.length > 1)
|
|
237659
|
+
throw new CliError(`The project has ${found.length} bakes (${found.join(", ")}) — pass --bake <file>.`);
|
|
237660
|
+
return resolve22(root, found[0]);
|
|
237432
237661
|
};
|
|
237433
237662
|
var readGlbJson = (file) => {
|
|
237434
237663
|
let fd;
|
|
@@ -237474,6 +237703,9 @@ var unwrapReferenced = async (js, resources, root, texel) => {
|
|
|
237474
237703
|
}
|
|
237475
237704
|
note(`Unwrapping ${raw.length} of the ${glbs.length} GLB(s) the app references — no lightmap uvs; written in place (--no-unwrap skips)…`);
|
|
237476
237705
|
const assets = await loadPeer("lecodes-assets", "cli", { for: "lecodes lightmap bake (lightmap uvs)" });
|
|
237706
|
+
if (typeof assets.unwrapGlbFiles !== "function") {
|
|
237707
|
+
throw new CliError("The lecodes-assets this CLI loaded has no unwrapGlbFiles (it predates the bake's unwrap) — `lecodes update` moves it forward; --no-unwrap bakes the GLBs as they are.");
|
|
237708
|
+
}
|
|
237477
237709
|
const t0 = performance.now();
|
|
237478
237710
|
const rel = (f) => relative7(root, f).replace(/\\/g, "/");
|
|
237479
237711
|
const reports = await assets.unwrapGlbFiles(raw, {
|
|
@@ -237491,25 +237723,27 @@ var unwrapReferenced = async (js, resources, root, texel) => {
|
|
|
237491
237723
|
var bake = defineCommand({
|
|
237492
237724
|
name: "bake",
|
|
237493
237725
|
summary: "Bake the sun, the sky and the lamps into a lux atlas for the level's statics",
|
|
237494
|
-
description: `Runs the app in bake mode in lecodes-bake — the windowless host with the bake built in (no physics, 2D, audio, net or navmesh), downloaded on first use like the desktop host; LECODES_BAKE_EXE points at a local build (hosts/desktop build.ps1 -Bake). The statics are what the app registers with Lightmap.add (a scene file does it for every node no Physics aspect moves), the bake fires at its Lightmap.load call.
|
|
237726
|
+
description: `Runs the app in bake mode in lecodes-bake — the windowless host with the bake built in (no physics, 2D, audio, net or navmesh), downloaded on first use like the desktop host; LECODES_BAKE_EXE points at a local build (hosts/desktop build.ps1 -Bake). The statics are what the app registers with Lightmap.add (a scene file does it for every node no Physics aspect moves), the bake fires at its Lightmap.load call. Needs a GPU with hardware ray tracing (--tracer).
|
|
237727
|
+
|
|
237728
|
+
Where: the level's own bake('<dir>/<stem>.bake') — env: { lightmap: bake('./assets/lightmap/level.bake') } in a scene file, the path relative to that file — names the target; nothing has to exist before the first bake. Writes into <dir>: <stem>.bake (the manifest: it names every file below, and the next compile reads it — nothing to paste into the scene) + <stem>-light[_n].ktx2 (irradiance, BC6H, a page per _n) + <stem>-aux[_n].ktx2 (sky visibility, the directional share and direction of the light) + <stem>-probes.ktx2 (the reflection probes: a cubemap of the level's radiance per probe, prefiltered per roughness; --probe-spacing 0 = none) + <stem>.lgrid (the light grid the movers read; --volume 0 = none) + <stem>-uv1.bin (the packed lightmap uv1 the rects map) + with --split <stem>-direct[_n].ktx2 / <stem>-indirect[_n].ktx2.
|
|
237495
237729
|
|
|
237496
237730
|
Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrapped first, IN PLACE — the same as lecodes assets unwrap, run on just those files; a file that has them is left alone, --no-unwrap skips the step. A whole level in one GLB that wants --groups / --zone is unwrapped by hand first (lecodes assets unwrap --help).`,
|
|
237497
237731
|
flags: {
|
|
237498
|
-
out: str("
|
|
237499
|
-
name: str("
|
|
237732
|
+
out: str("write the files into this folder instead of next to the level's .bake (a second seed for `lightmap diff`)", { value: "<dir>" }),
|
|
237733
|
+
name: str("bake the level whose bake() names <stem>.bake — when the entry reaches several", { value: "<stem>" }),
|
|
237500
237734
|
...bundleFlags,
|
|
237501
|
-
entry: str("the file that
|
|
237735
|
+
entry: str("the file that opens the level (it reaches the bake() that names the target)", { value: "<file>", default: "main.ts" }),
|
|
237502
237736
|
size: num("atlas page edge (texels)", { default: 4096 }),
|
|
237503
237737
|
texel: num("texel size (m); the bake coarsens only when the pages are full", { default: 0.05 }),
|
|
237504
237738
|
pages: num("atlas pages to fill before the bake coarsens the texel", { default: 4 }),
|
|
237505
237739
|
"sun-rays": num("shadow rays into the sun's disc per texel", { default: 64 }),
|
|
237506
|
-
"sky-rays": num("hemisphere rays per texel (the sky's irradiance and visibility). 2048 (2026-09-16): shadow rays are cheap (
|
|
237507
|
-
"light-rays": num("shadow rays per lamp per texel (64: at 32
|
|
237508
|
-
"bounce-rays": num("bounce paths per texel; 0 = direct light only. 128 (2026-09-16): a dark room's floor
|
|
237740
|
+
"sky-rays": num("hemisphere rays per texel (the sky's irradiance and visibility). 2048 (2026-09-16): shadow rays are cheap (an interior level's direct pass: 2 s a page) and a texel deep in a corridor sees the sky through a far window with 1 ray in 256 — every hit was 410 lux", { default: 2048 }),
|
|
237741
|
+
"light-rays": num("shadow rays per lamp per texel (64: at 32 an interior level's lamp layer read 43 % noise between two seeds, the ceilings and doors next to a lamp 48 %)", { default: 64 }),
|
|
237742
|
+
"bounce-rays": num("bounce paths per texel; 0 = direct light only. 128 (2026-09-16): a dark room's floor of an interior level reads 240 % noise at 64, 160 % at 128, 130 % at 256 — the last doubling costs 2x the bake time for little", { default: 128 }),
|
|
237509
237743
|
bounces: num("path vertices at most (Russian roulette from the third); 0 = direct light only", { default: 3 }),
|
|
237510
237744
|
"patch-samples": num("next-event samples per texel over the BRIGHT PATCHES of a first direct pass (sunlit floors, the ceiling around a lamp) — what keeps the bounce in dark rooms from arriving as impulses (every path vertex takes one more); 0 = the cosine paths alone", { default: 64 }),
|
|
237511
|
-
split: bool('also write <
|
|
237512
|
-
denoise: str("the AI denoiser (--denoiser) over: indirect = the bounce alone (
|
|
237745
|
+
split: bool('also write <stem>-direct[_n].ktx2 / <stem>-indirect[_n].ktx2 — the pages the "direct" / "indirect" views bind (the manifest names them)'),
|
|
237746
|
+
denoise: str("the AI denoiser (--denoiser) over: indirect = the bounce alone (an interior level, 2026-09-16: bounce noise 57 % -> 23 % of the mean, per-instance means unchanged), no-sun = + the sky and the lamps (the sky through a small opening: 0..3 hits of 256 rays, a texel is one of four values), all = + the sun (its shadow edges too: a sunlit pillar's mean moved 6 %), none. An interior level, two seeds: no-sun took the sky 1.8 % -> 0.5 %, the lamps 43 % -> 21 %", { value: "<none|indirect|no-sun|all>", default: "no-sun" }),
|
|
237513
237747
|
tracer: str("which GPU API traces: auto = OptiX where an NVIDIA driver with OptiX opens, else Vulkan ray query — any card with hardware ray tracing (RTX, Radeon RX 6000+, Arc) with its driver alone; optix / vulkan by name (the bake fails when it cannot open)", { value: "<auto|optix|vulkan>", default: "auto" }),
|
|
237514
237748
|
denoiser: str("which AI denoiser --denoise runs: auto = OptiX's on an NVIDIA card, else Intel Open Image Denoise (its CUDA / HIP / CPU device, the DLLs next to the host); optix / oidn by name. Independent of --tracer; one that cannot open is a warning and the pages stay as traced", { value: "<auto|optix|oidn>", default: "auto" }),
|
|
237515
237749
|
"light-radius": num("lamps: the emitter's radius (m) — soft shadows, no 1/d² singularity", { default: 0.05 }),
|
|
@@ -237523,13 +237757,13 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237523
237757
|
"probe-indoor": bool("keep only the probes under a roof — those whose open share of the sphere (rays from the point that meet nothing) is at most 15 %, holes in the geometry or not: outdoor statics reflect the sky through their baked sky visibility instead — an environment map without the ground, but no outdoor probe can reach indoors and the atlas shrinks"),
|
|
237524
237758
|
"probe-layout": str("rooms = every indoor point of the grid slides to the middle of its room and the points of one room merge: one probe per room, far from the walls, its box the room (stations every ~8 m along a room over 12 m), outdoor points stay on the grid; grid = everything stays on the grid. Either way the pages carry which probes each block of texels sees (rays at bake time)", { value: "<rooms|grid>", default: "rooms" }),
|
|
237525
237759
|
"min-texels": num("instances smaller than this many ATLAS TEXELS along every axis (x --texel: 12 at 5 cm = 0.6 m) get no place in the atlas: they still cast their baked shadow and bounce, their own light is baked where they stand (six sides, no atlas texels) — cartridges, boxes, pipe elbows, a fire extinguisher: a baked shadow does not read on them and their tight charts are where the seams are. 0 = everything bakes; --dry-run lists what falls under it", { default: 12 }),
|
|
237526
|
-
"thin-texels": num("ROUND AND NARROW objects leave the atlas like --min-texels: an instance none of whose lightmap charts is wider than this many texels across its short side (at --texel) — a railing's tubes, a cable, a pipe run, blinds, a gun barrel. A strip of 1-3 texels around a tube cannot hold the light's change around it and its uv seam shows as a step (
|
|
237527
|
-
cube: str(`BAKE AS CUBES BY NAME: a regular expression (ECMAScript, case-sensitive) searched in every record's key — <node path>@<ordinal>, one record per mesh of a model, so SM_pipe takes every pipe node and @1$ the second mesh of each. A record that matches leaves the atlas like a --min-texels / --thin-texels one, whatever its size or charts: an occluder whose own light is baked where it stands as ambient cubes (in slabs along a long one, --object-slab) — a pipe run, a fence, a prop whose lightmap seams show. Repeat the flag (--cube SM_pipe --cube SM_fence) or join with | in one (--cube "SM_pipe|SM_fence", quoted for the shell); a pattern that starts with - goes as --cube=<regex>. The
|
|
237760
|
+
"thin-texels": num("ROUND AND NARROW objects leave the atlas like --min-texels: an instance none of whose lightmap charts is wider than this many texels across its short side (at --texel) — a railing's tubes, a cable, a pipe run, blinds, a gun barrel. A strip of 1-3 texels around a tube cannot hold the light's change around it and its uv seam shows as a step (a railing: two texels 5 mm apart on the seam, one lit, one shadowed); the ambient cube baked where it stands is smooth. A flat object has a wide chart somewhere and stays. 0 = off; --dry-run lists what falls under it", { default: 4 }),
|
|
237761
|
+
cube: str(`BAKE AS CUBES BY NAME: a regular expression (ECMAScript, case-sensitive) searched in every record's key — <node path>@<ordinal>, one record per mesh of a model, so SM_pipe takes every pipe node and @1$ the second mesh of each. A record that matches leaves the atlas like a --min-texels / --thin-texels one, whatever its size or charts: an occluder whose own light is baked where it stands as ambient cubes (in slabs along a long one, --object-slab) — a pipe run, a fence, a prop whose lightmap seams show. Repeat the flag (--cube SM_pipe --cube SM_fence) or join with | in one (--cube "SM_pipe|SM_fence", quoted for the shell); a pattern that starts with - goes as --cube=<regex>. The level's bake() option cube adds its own patterns, a node's lightmap: 'cube' marks one node by hand; --dry-run lists what matches`, { value: "<regex>" }),
|
|
237528
237762
|
"object-slab": num("A LONG object the atlas left out (--min-texels, --thin-texels, --cube) takes its light in SLABS of this many metres along the longest axis of its bounds — round(length / this) ambient cubes, 16 at most — a 6 m pipe run, a railing along a wall: one end under a lamp, the other in the dark, where one cube gave all of it the mean. The shader blends the two slabs around each pixel along that axis. 0 = one cube an object", { value: "<m>", default: 1 }),
|
|
237529
237763
|
"emissive-nits": num("EMISSIVE SURFACES LIGHT THE LEVEL: cd/m² of emission 1.0 (emissive factor x strength x map) — every lit region of an emissive surface (a panel drawn in a ceiling's texture, a screen, a sign) bakes as a rectangle lamp. Default: what the level's camera makes of 1.0, 1.2 x 2^EV100, so a panel lights as brightly as it looks. 0 = emissive surfaces light nothing"),
|
|
237530
237764
|
"detail-texels": num("A SMALL SURFACE GETS A FINER TEXEL: an instance whose surface is under this many atlas texels (area / texel²) is laid out denser by sqrt(this / its texels), 3x at most — a pipe of 1 m is ~300 texels at 5 cm, its charts a few texels wide and every chart edge a step; at 2000 it bakes at ~2 cm. 0 = off", { default: 2000 }),
|
|
237531
|
-
volume: num("THE LIGHT GRID for movers: the cell size in metres (0.75 of it tall) — per cell in free space the baked ambient light (sky, lamps, every bounce; not the direct sun, which stays real-time on movers), links between cells a ray connects so nothing blends through a wall; written as <
|
|
237532
|
-
"probe-box": str("only grid cells whose centre lies inside this world box get a probe: x0,y0,z0,x1,y1,z1 in metres — keeps probes off a roof top the player never sees (
|
|
237765
|
+
volume: num("THE LIGHT GRID for movers: the cell size in metres (0.75 of it tall) — per cell in free space the baked ambient light (sky, lamps, every bounce; not the direct sun, which stays real-time on movers), links between cells a ray connects so nothing blends through a wall; written as <stem>.lgrid. 0 = none", { default: 1 }),
|
|
237766
|
+
"probe-box": str("only grid cells whose centre lies inside this world box get a probe: x0,y0,z0,x1,y1,z1 in metres — keeps probes off a roof top the player never sees (79 probes above a ceiling with holes where the fixtures were bled the sky onto the walls of a level). Default: the receivers' bounds", { value: "<x0,y0,z0,x1,y1,z1>" }),
|
|
237533
237767
|
"debug-dir": str("keep the float layers per page (PFM) here for `lightmap inspect` — gigabytes per level; a `.lightmap/` dir inside the project is skipped by the compile scan, anywhere else must be outside the project", { value: "<dir>" }),
|
|
237534
237768
|
"dry-run": bool("only the atlas LAYOUT: pages, texel size, the largest rects — no tracing, nothing written (seconds, not minutes; the host still loads the level)"),
|
|
237535
237769
|
frames: num("host frames to run before giving up — load headroom", { default: 900 }),
|
|
@@ -237540,14 +237774,16 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237540
237774
|
logs: bool("forward the host's output"),
|
|
237541
237775
|
"no-unwrap": bool("leave the referenced GLBs as they are: no lightmap unwrap of those without TEXCOORD_1 (they bake without lightmap uvs)")
|
|
237542
237776
|
},
|
|
237543
|
-
examples: [
|
|
237777
|
+
examples: [
|
|
237778
|
+
"lecodes lightmap bake",
|
|
237779
|
+
"lecodes lightmap bake --dry-run --logs",
|
|
237780
|
+
"lecodes lightmap bake --entry level2.ts --texel 0.04 --debug-dir .lightmap/level2 --logs"
|
|
237781
|
+
],
|
|
237544
237782
|
run: async ({ flags, argv }) => {
|
|
237545
237783
|
const { root } = localProject();
|
|
237546
|
-
const outDir = resolve22(root, flags.out);
|
|
237547
|
-
const stem = flags.name;
|
|
237548
237784
|
const cube = cubePatternsOf(argv);
|
|
237549
|
-
if (!/^[A-Za-z0-9_
|
|
237550
|
-
throw new CliError(`--name wants
|
|
237785
|
+
if (flags.name !== undefined && !/^[A-Za-z0-9_.-]+$/.test(flags.name))
|
|
237786
|
+
throw new CliError(`--name wants the stem of a .bake (its file name without .bake), got "${flags.name}".`);
|
|
237551
237787
|
const entryFile = flags.entry;
|
|
237552
237788
|
if (!existsSync41(resolve22(root, entryFile))) {
|
|
237553
237789
|
throw new CliError(`No ${entryFile} in ${root} — pass --entry <file> (the file that builds the scene and calls Lightmap.load).`);
|
|
@@ -237560,8 +237796,9 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237560
237796
|
if (!["auto", "optix", "oidn"].includes(flags.denoiser))
|
|
237561
237797
|
throw new CliError(`--denoiser wants auto, optix or oidn, got "${flags.denoiser}".`);
|
|
237562
237798
|
const cfg = {
|
|
237563
|
-
|
|
237564
|
-
|
|
237799
|
+
root: root.replace(/\\/g, "/"),
|
|
237800
|
+
...flags.out ? { outDir: resolve22(root, flags.out).replace(/\\/g, "/") } : {},
|
|
237801
|
+
...flags.name !== undefined ? { stem: flags.name } : {},
|
|
237565
237802
|
size: range("size", flags.size, 256, 16384),
|
|
237566
237803
|
texel: range("texel", flags.texel, 0.001, 2),
|
|
237567
237804
|
pages: range("pages", flags.pages, 1, 16),
|
|
@@ -237604,23 +237841,26 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237604
237841
|
const entryText = `globalThis.__lecodesLightmap = ${JSON.stringify(cfg)}
|
|
237605
237842
|
import ${JSON.stringify(importPath)}
|
|
237606
237843
|
`;
|
|
237607
|
-
mkdirSync25(outDir, { recursive: true });
|
|
237608
|
-
ensurePlaceholders(outDir, stem);
|
|
237609
|
-
if (debugDir)
|
|
237610
|
-
mkdirSync25(debugDir, { recursive: true });
|
|
237611
237844
|
const desktopRenderer = "gl";
|
|
237612
|
-
const { js, resources } = await buildBundle(bundleOptions(flags), {
|
|
237845
|
+
const { js, resources, bakes } = await buildBundle(bundleOptions(flags), {
|
|
237613
237846
|
localAssets: true,
|
|
237614
237847
|
desktopRenderer,
|
|
237615
237848
|
extraEntries: [{ path: entryPath, type: "text", text: entryText }],
|
|
237616
237849
|
entryOverride: entryPath
|
|
237617
237850
|
});
|
|
237851
|
+
const target = pickTarget2(bakes, flags.name, entryFile);
|
|
237852
|
+
const stem = stemOf(target.path);
|
|
237853
|
+
const outDir = flags.out ? resolve22(root, flags.out) : dirname23(target.absPath);
|
|
237854
|
+
mkdirSync25(outDir, { recursive: true });
|
|
237855
|
+
if (debugDir)
|
|
237856
|
+
mkdirSync25(debugDir, { recursive: true });
|
|
237857
|
+
note(`Target: ${relative7(root, join46(outDir, `${stem}.bake`)).replace(/\\/g, "/")}${target.exists ? "" : " (the first bake: nothing there yet)"}${flags.out ? " (--out)" : ""}`);
|
|
237618
237858
|
if (!flags["no-unwrap"])
|
|
237619
237859
|
await unwrapReferenced(js, resources, root, cfg.texel);
|
|
237620
237860
|
const scratch = mkdtempSync4(join46(tmpdir4(), "lecodes-lightmap-"));
|
|
237621
237861
|
const outPng = join46(scratch, "frame.png");
|
|
237622
237862
|
const bounce = cfg.bounceRays > 0 && cfg.bounces > 0 ? `, ${cfg.bounceRays} bounce paths of ${cfg.bounces}${cfg.patchSamples > 0 ? ` + ${cfg.patchSamples} patch samples` : ""}${cfg.denoise !== "none" ? `, denoised (${cfg.denoise})` : ", raw"}` : ", no bounce";
|
|
237623
|
-
note(`Baking up to ${cfg.pages} × ${cfg.size}² at ${(cfg.texel * 100).toFixed(1)} cm texels (${cfg.sunRays} sun + ${cfg.skyRays} sky + ${cfg.lightRays} lamp rays${bounce}) → ${relative7(root, outDir) || "."}/${stem}.*…`);
|
|
237863
|
+
note(`Baking up to ${cfg.pages} × ${cfg.size}² at ${(cfg.texel * 100).toFixed(1)} cm texels (${cfg.sunRays} sun + ${cfg.skyRays} sky + ${cfg.lightRays} lamp rays${bounce}) → ${relative7(root, outDir).split(sep5).join("/") || "."}/${stem}.*…`);
|
|
237624
237864
|
let output = "";
|
|
237625
237865
|
if (flags["dry-run"])
|
|
237626
237866
|
process.env.CBK_LAYOUT_ONLY = "1";
|
|
@@ -237664,16 +237904,12 @@ import ${JSON.stringify(importPath)}
|
|
|
237664
237904
|
}
|
|
237665
237905
|
if (/\[lightmap\] done/.test(output)) {
|
|
237666
237906
|
const data = readBake(join46(outDir, `${stem}.bake`));
|
|
237667
|
-
const rel = (f) => relative7(root, join46(outDir, f)).replace(/\\/g, "/");
|
|
237668
|
-
const assets = (files) => files.length === 1 ? `asset('<rel>/${rel(files[0])}')` : `[${files.map((f) => `asset('<rel>/${rel(f)}')`).join(", ")}]`;
|
|
237669
237907
|
const splitFiles = data.direct && data.indirect ? ` + ${data.direct.join(", ")} + ${data.indirect.join(", ")}` : "";
|
|
237670
|
-
const splitDef = data.direct && data.indirect ? `, direct: ${assets(data.direct)}, indirect: ${assets(data.indirect)}` : "";
|
|
237671
237908
|
const probeFiles = data.probes ? ` + ${data.probes.file} (${data.probes.count} probe(s) of ${data.probes.size}² at ${data.probes.spacing} m)` : "";
|
|
237672
237909
|
const gridFile = data.volume ? ` + ${data.volume.file} (light grid ${data.volume.n.join(" x ")}, ${data.volume.valid} cell(s) in free space)` : "";
|
|
237673
|
-
const
|
|
237674
|
-
|
|
237675
|
-
logErr(c.
|
|
237676
|
-
logErr(c.dim(` scene file: env.lightmap: { data: asset('<rel>/${rel(`${stem}.bake`)}'), light: ${assets(data.light)}, aux: ${assets(data.aux)}${splitDef}${probeDef} } — asset() paths are relative to the scene file`));
|
|
237910
|
+
const uv1File = data.uv1 ? ` + ${data.uv1} (the packed lightmap uv1)` : "";
|
|
237911
|
+
logErr(c.green(`✓ baked → ${relative7(root, outDir).replace(/\\/g, "/") || "."}/${stem}.bake + ${data.light.join(", ")} + ${data.aux.join(", ")}${splitFiles}${probeFiles}${gridFile}${uv1File}`));
|
|
237912
|
+
logErr(c.dim(flags.out ? ` written to --out: the level's bake() still reads ${target.path}` : ` the manifest names them: the next compile of ${entryFile} stages them (bake('…') in the scene reads it)`));
|
|
237677
237913
|
if (debugDir)
|
|
237678
237914
|
logErr(c.dim(` debug layers: ${relative7(root, debugDir)} (lecodes lightmap inspect --bake ${relative7(root, join46(outDir, `${stem}.bake`)).replace(/\\/g, "/")} --debug-dir ${relative7(root, debugDir).replace(/\\/g, "/")})`));
|
|
237679
237915
|
return;
|
|
@@ -237693,15 +237929,16 @@ var stats = defineCommand({
|
|
|
237693
237929
|
summary: "The per-instance numbers a .bake carries: mean lux, sun / sky visibility, texels, rect",
|
|
237694
237930
|
description: "Reads the .bake alone (no debug layers needed). One row per receiver, sorted by mean lux unless --sort says otherwise; --key filters by a regular expression over the keys.",
|
|
237695
237931
|
flags: {
|
|
237696
|
-
bake: str("the .bake file", { value: "<file>"
|
|
237932
|
+
bake: str("the .bake file (default: the project's one .bake)", { value: "<file>" }),
|
|
237697
237933
|
key: str("only instances whose key matches this regular expression", { value: "<regex>" }),
|
|
237698
237934
|
sort: str("row order", { value: "<lux|key|texels|sun|sky>", default: "lux" }),
|
|
237699
237935
|
limit: num("rows to print (0 = all)", { default: 60 })
|
|
237700
237936
|
},
|
|
237701
|
-
examples: ["lecodes lightmap stats --
|
|
237937
|
+
examples: ["lecodes lightmap stats --key Wall", "lecodes lightmap stats --bake assets/level2/lightmap/level2.bake --sort sky --limit 0"],
|
|
237702
237938
|
run: ({ flags }) => {
|
|
237703
237939
|
const { root } = localProject();
|
|
237704
|
-
const
|
|
237940
|
+
const bakeFile = bakeFileOf(root, flags.bake);
|
|
237941
|
+
const data = readBake(bakeFile);
|
|
237705
237942
|
const re = flags.key ? new RegExp(flags.key) : null;
|
|
237706
237943
|
let rows = data.instances.filter((i) => i.receiver && (!re || re.test(i.key)));
|
|
237707
237944
|
const sorters = {
|
|
@@ -237718,7 +237955,7 @@ var stats = defineCommand({
|
|
|
237718
237955
|
const total = rows.length;
|
|
237719
237956
|
if (flags.limit > 0)
|
|
237720
237957
|
rows = rows.slice(0, flags.limit);
|
|
237721
|
-
log(`${basename18(
|
|
237958
|
+
log(`${basename18(bakeFile)}: ${data.pages} page(s) of ${data.size}, ${(data.texel * 100).toFixed(2)} cm texels, ${data.texels ?? "?"} texels, lightScale ${data.lightScale}`);
|
|
237722
237959
|
log(`${"key".padEnd(48)} ${"page".padStart(4)} ${"rect".padStart(20)} ${"texels".padStart(8)} ${"lux".padStart(9)} ${"sun".padStart(6)} ${"sky".padStart(6)} ${"dir".padStart(6)}`);
|
|
237723
237960
|
for (const r of rows) {
|
|
237724
237961
|
const rect = r.rect ? `${r.rect[0]},${r.rect[1]} ${r.rect[2]}x${r.rect[3]}` : "";
|
|
@@ -237733,7 +237970,7 @@ var diff = defineCommand({
|
|
|
237733
237970
|
summary: "The noise of a bake, per instance: two bakes that differ only by --seed, compared texel by texel",
|
|
237734
237971
|
description: "Bake the level twice with different --seed (and --out / --debug-dir, so the second does not overwrite the first — a `.lightmap/` dir inside the project is skipped by the compile scan). Both must share the layout (same instances, rects and pages — a seed changes nothing else). Per instance: the mean of the layer, the noise as the RMS of (a − b) / √2 over the mean, in %, and the share of texels that differ by more than half their mean. Sorted by noise unless --sort says otherwise.",
|
|
237735
237972
|
flags: {
|
|
237736
|
-
bake: str("the first .bake", { value: "<file>"
|
|
237973
|
+
bake: str("the first .bake (default: the project's one .bake)", { value: "<file>" }),
|
|
237737
237974
|
"debug-dir": str("where the first bake kept its PFM layers", { value: "<dir>", default: ".lightmap" }),
|
|
237738
237975
|
bake2: str("the second .bake (another --seed)", { value: "<file>" }),
|
|
237739
237976
|
"debug-dir2": str("where the second bake kept its PFM layers", { value: "<dir>" }),
|
|
@@ -237744,21 +237981,23 @@ var diff = defineCommand({
|
|
|
237744
237981
|
limit: num("rows to print (0 = all)", { default: 40 })
|
|
237745
237982
|
},
|
|
237746
237983
|
examples: [
|
|
237747
|
-
"lecodes lightmap bake --
|
|
237748
|
-
"lecodes lightmap
|
|
237984
|
+
"lecodes lightmap bake --debug-dir .lightmap/seed1 --logs",
|
|
237985
|
+
"lecodes lightmap bake --seed 2 --out .lightmap/seed2/bake --debug-dir .lightmap/seed2 --logs",
|
|
237986
|
+
"lecodes lightmap diff --debug-dir .lightmap/seed1 --bake2 .lightmap/seed2/bake/level.bake --debug-dir2 .lightmap/seed2 --layer bounce"
|
|
237749
237987
|
],
|
|
237750
237988
|
run: ({ flags }) => {
|
|
237751
237989
|
const { root } = localProject();
|
|
237752
237990
|
if (!flags.bake2 || !flags["debug-dir2"])
|
|
237753
237991
|
throw new CliError("--bake2 and --debug-dir2 name the second bake (another --seed).");
|
|
237754
|
-
const
|
|
237992
|
+
const bakeFile = bakeFileOf(root, flags.bake);
|
|
237993
|
+
const a = readBake(bakeFile), b = readBake(resolve22(root, flags.bake2));
|
|
237755
237994
|
if (a.size !== b.size || a.pages !== b.pages)
|
|
237756
237995
|
throw new CliError(`The bakes differ in layout (${a.pages} × ${a.size} vs ${b.pages} × ${b.size}) — a diff needs the same scene baked twice with another --seed.`);
|
|
237757
237996
|
const ra = a.instances.filter((i) => i.receiver), rb = b.instances.filter((i) => i.receiver);
|
|
237758
237997
|
if (ra.length !== rb.length || ra.some((i, k) => i.key !== rb[k].key || i.page !== rb[k].page || String(i.rect) !== String(rb[k].rect))) {
|
|
237759
237998
|
throw new CliError("The bakes list different instances or rects — a diff needs the same scene baked twice with another --seed.");
|
|
237760
237999
|
}
|
|
237761
|
-
const stemA = basename18(
|
|
238000
|
+
const stemA = basename18(bakeFile, ".bake"), stemB = basename18(flags.bake2, ".bake");
|
|
237762
238001
|
const dirA = resolve22(root, flags["debug-dir"]), dirB = resolve22(root, flags["debug-dir2"]);
|
|
237763
238002
|
const layer = flags.layer;
|
|
237764
238003
|
if (!["irradiance", "bounce", "sun", "sky", "lamps"].includes(layer))
|
|
@@ -237831,7 +238070,7 @@ var diff = defineCommand({
|
|
|
237831
238070
|
}
|
|
237832
238071
|
});
|
|
237833
238072
|
var readPfm = (file) => {
|
|
237834
|
-
const buf =
|
|
238073
|
+
const buf = readFileSync36(file);
|
|
237835
238074
|
let o = 0;
|
|
237836
238075
|
const token = () => {
|
|
237837
238076
|
while (o < buf.length && /\s/.test(String.fromCharCode(buf[o])))
|
|
@@ -237911,7 +238150,7 @@ var inspect = defineCommand({
|
|
|
237911
238150
|
summary: "PNGs from a bake's debug layers: whole pages, or one instance's rect enlarged",
|
|
237912
238151
|
description: "Reads the PFM float layers `bake --debug-dir` kept next to the .bake's rects. Without --key: one PNG per page and layer with every rect outlined. With --key: the matching instances' rects (plus a margin) enlarged by --scale, one PNG per instance and layer. Lux layers are shown as log10 over --lux-range (or linear over --white); vectors as x0.5+0.5.",
|
|
237913
238152
|
flags: {
|
|
237914
|
-
bake: str("the .bake file", { value: "<file>"
|
|
238153
|
+
bake: str("the .bake file (default: the project's one .bake)", { value: "<file>" }),
|
|
237915
238154
|
"debug-dir": str("where the bake kept its PFM layers", { value: "<dir>", default: ".lightmap" }),
|
|
237916
238155
|
out: str("where the PNGs go", { value: "<dir>", default: ".lightmap/png" }),
|
|
237917
238156
|
key: str("instances whose key matches this regular expression (default: whole pages)", { value: "<regex>" }),
|
|
@@ -237922,10 +238161,10 @@ var inspect = defineCommand({
|
|
|
237922
238161
|
white: num("linear mode: the lux shown as white (0 = log mode)", { default: 0 }),
|
|
237923
238162
|
limit: num("instances to render with --key (0 = all)", { default: 24 })
|
|
237924
238163
|
},
|
|
237925
|
-
examples: ["lecodes lightmap inspect --
|
|
238164
|
+
examples: ["lecodes lightmap inspect --debug-dir .lightmap/level", "lecodes lightmap inspect --key 'Wall_05' --layer irradiance,sun,sky,lamps --scale 6"],
|
|
237926
238165
|
run: ({ flags }) => {
|
|
237927
238166
|
const { root } = localProject();
|
|
237928
|
-
const bakeFile =
|
|
238167
|
+
const bakeFile = bakeFileOf(root, flags.bake);
|
|
237929
238168
|
const data = readBake(bakeFile);
|
|
237930
238169
|
const stem = basename18(bakeFile).replace(/\.bake$/, "");
|
|
237931
238170
|
const dbg = resolve22(root, flags["debug-dir"]);
|
|
@@ -238097,7 +238336,7 @@ init_types4();
|
|
|
238097
238336
|
// src/commands/push.ts
|
|
238098
238337
|
init_cli();
|
|
238099
238338
|
init_api();
|
|
238100
|
-
import { readFileSync as
|
|
238339
|
+
import { readFileSync as readFileSync38 } from "node:fs";
|
|
238101
238340
|
import { basename as basename19 } from "node:path";
|
|
238102
238341
|
init_localFiles();
|
|
238103
238342
|
init_manifest();
|
|
@@ -238106,7 +238345,7 @@ init_manifest();
|
|
|
238106
238345
|
init_cli();
|
|
238107
238346
|
init_api();
|
|
238108
238347
|
init_localFiles();
|
|
238109
|
-
import { existsSync as existsSync42, readFileSync as
|
|
238348
|
+
import { existsSync as existsSync42, readFileSync as readFileSync37 } from "node:fs";
|
|
238110
238349
|
import { resolve as resolve23 } from "node:path";
|
|
238111
238350
|
init_shared();
|
|
238112
238351
|
var compareVersions = (a, b) => {
|
|
@@ -238193,11 +238432,11 @@ var upload2 = defineCommand({
|
|
|
238193
238432
|
const path = resolve23(file);
|
|
238194
238433
|
if (!existsSync42(path))
|
|
238195
238434
|
throw new CliError(`No such file: ${file}`);
|
|
238196
|
-
const code =
|
|
238435
|
+
const code = readFileSync37(path, "utf8");
|
|
238197
238436
|
const sdk = /^\/\/ sdk: (\S+)/m.exec(code)?.[1];
|
|
238198
238437
|
if (!sdk)
|
|
238199
238438
|
throw new CliError(`${file} is not a LeCodes bundle: no \`// sdk:\` header line. \`lecodes compile --remote-assets -o app.js\` writes one.`);
|
|
238200
|
-
const map = existsSync42(`${path}.map`) ?
|
|
238439
|
+
const map = existsSync42(`${path}.map`) ? readFileSync37(`${path}.map`, "utf8") : null;
|
|
238201
238440
|
const { root, manifest, apiUrl, token } = linkedProject();
|
|
238202
238441
|
if (hasChanges(diffLocal(manifest, scanProject(root, manifest))))
|
|
238203
238442
|
await runPush({ message: flags.message || "Release" });
|
|
@@ -238302,9 +238541,9 @@ var runPush = async (opts) => {
|
|
|
238302
238541
|
if (source)
|
|
238303
238542
|
entry.assetId = source.id;
|
|
238304
238543
|
if (isTextKind(kind))
|
|
238305
|
-
entry.text =
|
|
238544
|
+
entry.text = readFileSync38(file.absPath, "utf8");
|
|
238306
238545
|
else if (!source || source.sha !== file.sha) {
|
|
238307
|
-
const blob = await uploadBlob(apiUrl, token, manifest.uuid, basename19(file.path),
|
|
238546
|
+
const blob = await uploadBlob(apiUrl, token, manifest.uuid, basename19(file.path), readFileSync38(file.absPath));
|
|
238308
238547
|
entry.blobFileId = blob.id;
|
|
238309
238548
|
uploaded++;
|
|
238310
238549
|
}
|
|
@@ -238504,7 +238743,7 @@ var login_default = defineCommand({
|
|
|
238504
238743
|
});
|
|
238505
238744
|
|
|
238506
238745
|
// src/commands/navmesh.ts
|
|
238507
|
-
import { existsSync as existsSync44, mkdirSync as mkdirSync26, mkdtempSync as mkdtempSync5, readdirSync as
|
|
238746
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync26, mkdtempSync as mkdtempSync5, readdirSync as readdirSync19, readFileSync as readFileSync39, rmSync as rmSync13, statSync as statSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync28 } from "node:fs";
|
|
238508
238747
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
238509
238748
|
import { basename as basename21, join as join48, relative as relative8, resolve as resolve25 } from "node:path";
|
|
238510
238749
|
init_cli();
|
|
@@ -239307,7 +239546,7 @@ var guessName = (root) => {
|
|
|
239307
239546
|
continue;
|
|
239308
239547
|
let entries;
|
|
239309
239548
|
try {
|
|
239310
|
-
entries =
|
|
239549
|
+
entries = readdirSync19(dir);
|
|
239311
239550
|
} catch {
|
|
239312
239551
|
continue;
|
|
239313
239552
|
}
|
|
@@ -239315,7 +239554,7 @@ var guessName = (root) => {
|
|
|
239315
239554
|
if (!f.endsWith(".scene.ts"))
|
|
239316
239555
|
continue;
|
|
239317
239556
|
try {
|
|
239318
|
-
if (/\bnavmesh\s*:/.test(
|
|
239557
|
+
if (/\bnavmesh\s*:/.test(readFileSync39(join48(dir, f), "utf8")))
|
|
239319
239558
|
return f.slice(0, -".scene.ts".length);
|
|
239320
239559
|
} catch {}
|
|
239321
239560
|
}
|
|
@@ -239465,7 +239704,7 @@ import ${JSON.stringify(importPath)}
|
|
|
239465
239704
|
const geoPath = join48(outDir, `${name}.navgeo`);
|
|
239466
239705
|
if (!existsSync44(geoPath))
|
|
239467
239706
|
throw new CliError(`The host reported a dump but ${geoPath} is missing.`);
|
|
239468
|
-
const geo = readNgeo(new Uint8Array(
|
|
239707
|
+
const geo = readNgeo(new Uint8Array(readFileSync39(geoPath)));
|
|
239469
239708
|
const params = {
|
|
239470
239709
|
agentRadius: range2("radius", flags.radius, config.agent.radius, 0.05, 10),
|
|
239471
239710
|
agentHeight: range2("height", flags.height, config.agent.height, 0.1, 20),
|
|
@@ -239519,7 +239758,7 @@ import ${JSON.stringify(importPath)}
|
|
|
239519
239758
|
}
|
|
239520
239759
|
if (!flags["keep-geometry"])
|
|
239521
239760
|
unlinkSync2(geoPath);
|
|
239522
|
-
const kb = Math.round(
|
|
239761
|
+
const kb = Math.round(statSync14(navmeshPath).size / 1024);
|
|
239523
239762
|
const b = result.bounds;
|
|
239524
239763
|
logErr(c.dim(` ${result.tiles} tiles, ${result.polys} polygons, ${(b.max[0] - b.min[0]).toFixed(0)} × ${(b.max[2] - b.min[2]).toFixed(0)} m, ${result.time.toFixed(1)} s`));
|
|
239525
239764
|
logErr(c.green(`✓ baked → ${relative8(root, navmeshPath).replace(/\\/g, "/")} (${kb} KB)`));
|
|
@@ -239539,9 +239778,9 @@ init_cli();
|
|
|
239539
239778
|
|
|
239540
239779
|
// src/plugin/generate.ts
|
|
239541
239780
|
init_cli();
|
|
239542
|
-
import { existsSync as existsSync45, mkdirSync as mkdirSync27, readFileSync as
|
|
239781
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync27, readFileSync as readFileSync40, readdirSync as readdirSync20, statSync as statSync15, writeFileSync as writeFileSync29 } from "node:fs";
|
|
239543
239782
|
import { createRequire as createRequire7 } from "node:module";
|
|
239544
|
-
import { basename as basename22, join as join49, relative as relative9, resolve as resolve26, sep as
|
|
239783
|
+
import { basename as basename22, join as join49, relative as relative9, resolve as resolve26, sep as sep6 } from "node:path";
|
|
239545
239784
|
|
|
239546
239785
|
// src/plugin/permissions.ts
|
|
239547
239786
|
var PERMISSION_KINDS = ["camera", "microphone", "location", "speech"];
|
|
@@ -242410,10 +242649,10 @@ const wire = {
|
|
|
242410
242649
|
`;
|
|
242411
242650
|
|
|
242412
242651
|
// src/plugin/generate.ts
|
|
242413
|
-
var shown = (from, to) => relative9(from, to).split(
|
|
242652
|
+
var shown = (from, to) => relative9(from, to).split(sep6).join("/");
|
|
242414
242653
|
var implementsOf = (dir) => {
|
|
242415
242654
|
try {
|
|
242416
|
-
const raw = JSON.parse(
|
|
242655
|
+
const raw = JSON.parse(readFileSync40(join49(dir, MANIFEST_FILE), "utf8").replace(/^/, ""));
|
|
242417
242656
|
return typeof raw.implements === "string" ? raw.implements : null;
|
|
242418
242657
|
} catch {
|
|
242419
242658
|
return null;
|
|
@@ -242427,7 +242666,7 @@ var findPlugins = (path) => {
|
|
|
242427
242666
|
const holder = join49(root, "plugins");
|
|
242428
242667
|
if (!existsSync45(holder))
|
|
242429
242668
|
return [];
|
|
242430
|
-
return
|
|
242669
|
+
return readdirSync20(holder).sort().map((id) => ({ id, dir: join49(holder, id) })).filter((p) => statSync15(p.dir).isDirectory() && isPluginDir(p.dir));
|
|
242431
242670
|
};
|
|
242432
242671
|
var loadTypescript = (dir) => {
|
|
242433
242672
|
for (const from of [join49(dir, "package.json"), import.meta.url]) {
|
|
@@ -242444,7 +242683,7 @@ var generatePlugin = (ts, plugin) => {
|
|
|
242444
242683
|
const manifest = readManifestIfAny(plugin.dir, plugin.id);
|
|
242445
242684
|
const implemented = manifest?.implements;
|
|
242446
242685
|
const file = implemented ? firstPartyContractFile(implemented) : join49(plugin.dir, CONTRACT_FILE);
|
|
242447
|
-
const contract = readContract(ts, file, implemented ? firstPartyContractText(file) :
|
|
242686
|
+
const contract = readContract(ts, file, implemented ? firstPartyContractText(file) : readFileSync40(file, "utf8"));
|
|
242448
242687
|
checkPermissions(plugin, contract, manifest);
|
|
242449
242688
|
const id = implemented ?? plugin.id;
|
|
242450
242689
|
const handWritten = existsSync45(join49(plugin.dir, "sdk", `${id}.ts`));
|
|
@@ -242484,7 +242723,7 @@ var checkPermissions = (plugin, contract, manifest) => {
|
|
|
242484
242723
|
if (kinds.length === 0)
|
|
242485
242724
|
return;
|
|
242486
242725
|
const androidManifest = join49(plugin.dir, "android", "src", "main", "AndroidManifest.xml");
|
|
242487
|
-
const androidXml = manifest.android ? existsSync45(androidManifest) ?
|
|
242726
|
+
const androidXml = manifest.android ? existsSync45(androidManifest) ? readFileSync40(androidManifest, "utf8") : "" : null;
|
|
242488
242727
|
const missing = missingDeclarations(kinds, manifest.ios ? manifest.ios.infoPlist ?? {} : null, androidXml === null ? null : usesPermissions(androidXml), androidXml === null ? null : usesFeatures(androidXml));
|
|
242489
242728
|
const problems = [];
|
|
242490
242729
|
if (missing.infoPlist.length)
|
|
@@ -242499,16 +242738,16 @@ var checkPermissions = (plugin, contract, manifest) => {
|
|
|
242499
242738
|
var hostImports = (web) => {
|
|
242500
242739
|
const found = [];
|
|
242501
242740
|
const walk = (dir) => {
|
|
242502
|
-
for (const entry of
|
|
242741
|
+
for (const entry of readdirSync20(dir).sort()) {
|
|
242503
242742
|
const path = join49(dir, entry);
|
|
242504
|
-
if (
|
|
242743
|
+
if (statSync15(path).isDirectory()) {
|
|
242505
242744
|
if (entry !== "node_modules" && entry !== "dist")
|
|
242506
242745
|
walk(path);
|
|
242507
242746
|
continue;
|
|
242508
242747
|
}
|
|
242509
242748
|
if (!/\.(ts|tsx|js|mjs)$/.test(entry))
|
|
242510
242749
|
continue;
|
|
242511
|
-
|
|
242750
|
+
readFileSync40(path, "utf8").split(`
|
|
242512
242751
|
`).forEach((line, i) => {
|
|
242513
242752
|
const m = /(?:from\s+|import\s*\(\s*|import\s+)["'](lecodes-[^"']*)["']/.exec(line);
|
|
242514
242753
|
if (m && !/^\s*\/\//.test(line))
|
|
@@ -242529,8 +242768,8 @@ var kotlinPackage = (android, register) => {
|
|
|
242529
242768
|
}
|
|
242530
242769
|
let dir = root;
|
|
242531
242770
|
while (existsSync45(dir)) {
|
|
242532
|
-
const entries =
|
|
242533
|
-
const dirs = entries.filter((e) =>
|
|
242771
|
+
const entries = readdirSync20(dir).filter((e) => !e.startsWith("."));
|
|
242772
|
+
const dirs = entries.filter((e) => statSync15(join49(dir, e)).isDirectory());
|
|
242534
242773
|
if (dirs.length !== 1 || entries.length !== 1)
|
|
242535
242774
|
break;
|
|
242536
242775
|
dir = join49(dir, dirs[0]);
|
|
@@ -242545,7 +242784,7 @@ var repoSdkPath = (root) => {
|
|
|
242545
242784
|
if (!existsSync45(file))
|
|
242546
242785
|
return DEFAULT_SDK_PATH;
|
|
242547
242786
|
try {
|
|
242548
|
-
const pkg = JSON.parse(
|
|
242787
|
+
const pkg = JSON.parse(readFileSync40(file, "utf8"));
|
|
242549
242788
|
const path = pkg.lecodes?.iosSdkPath;
|
|
242550
242789
|
if (path !== undefined && typeof path !== "string")
|
|
242551
242790
|
throw new PackageError(`package.json lecodes.iosSdkPath: a path, as a string`);
|
|
@@ -242565,7 +242804,7 @@ var generate = (path, opts = {}) => {
|
|
|
242565
242804
|
const report = { plugins: [], repo: { written: [], stale: [], fresh: [] }, failures: [] };
|
|
242566
242805
|
const place = (f, entry) => {
|
|
242567
242806
|
const name = shown(root, f.file) || basename22(f.file);
|
|
242568
|
-
const current = existsSync45(f.file) ?
|
|
242807
|
+
const current = existsSync45(f.file) ? readFileSync40(f.file, "utf8") : null;
|
|
242569
242808
|
if (current === f.text) {
|
|
242570
242809
|
entry.fresh.push(name);
|
|
242571
242810
|
return;
|
|
@@ -243002,7 +243241,7 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
243002
243241
|
};
|
|
243003
243242
|
|
|
243004
243243
|
// src/commands/render.ts
|
|
243005
|
-
import { mkdirSync as mkdirSync30, readFileSync as
|
|
243244
|
+
import { mkdirSync as mkdirSync30, readFileSync as readFileSync42, writeFileSync as writeFileSync32 } from "node:fs";
|
|
243006
243245
|
import { dirname as dirname25, resolve as resolve30 } from "node:path";
|
|
243007
243246
|
|
|
243008
243247
|
// src/compile/headlessBundle.ts
|
|
@@ -243090,7 +243329,7 @@ var compileHeadlessBundle = async (opts = {}) => {
|
|
|
243090
243329
|
init_designMeta();
|
|
243091
243330
|
init_cli();
|
|
243092
243331
|
init_paths();
|
|
243093
|
-
import { existsSync as existsSync47, readFileSync as
|
|
243332
|
+
import { existsSync as existsSync47, readFileSync as readFileSync41, statSync as statSync16 } from "node:fs";
|
|
243094
243333
|
import { isAbsolute as isAbsolute3, join as join51, relative as relative10, resolve as resolve27 } from "node:path";
|
|
243095
243334
|
var SCREEN_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
|
|
243096
243335
|
var SCREEN_ENTRY_PATH = "/.screen-entry.ts";
|
|
@@ -243102,7 +243341,7 @@ var findScreenFile = (root, file, dirFlag) => {
|
|
|
243102
243341
|
candidates.push(join51(root, (dirFlag ?? DEFAULT_DESIGN_DIR).replace(/[/\\]+$/, ""), "screens", file));
|
|
243103
243342
|
}
|
|
243104
243343
|
for (const base of candidates) {
|
|
243105
|
-
if (existsSync47(base) &&
|
|
243344
|
+
if (existsSync47(base) && statSync16(base).isFile())
|
|
243106
243345
|
return base;
|
|
243107
243346
|
for (const ext of SCREEN_EXTS)
|
|
243108
243347
|
if (existsSync47(base + ext))
|
|
@@ -243124,7 +243363,7 @@ var resolveScreenTarget = (root, file, opts = {}) => {
|
|
|
243124
243363
|
throw new CliError(`"${file}" is outside the project (${root}) — a screen renders as part of its project, so its ` + `imports and asset() files resolve from the same tree.`);
|
|
243125
243364
|
}
|
|
243126
243365
|
const key = toKey(rel);
|
|
243127
|
-
if (!/^\s*export\s+default\b/m.test(
|
|
243366
|
+
if (!/^\s*export\s+default\b/m.test(readFileSync41(abs, "utf8"))) {
|
|
243128
243367
|
throw new CliError(`${key.slice(1)} has no default export. A screen file ends with ` + `\`export default UIScreen([...])\` — or \`export default (state) => UIScreen([...])\` for screen states.`);
|
|
243129
243368
|
}
|
|
243130
243369
|
const invoke = opts.state !== undefined ? `screen(${JSON.stringify(opts.state)})` : "screen()";
|
|
@@ -243921,7 +244160,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
243921
244160
|
if (typeof value === "string") {
|
|
243922
244161
|
const abs = resolve30(baseDir, value);
|
|
243923
244162
|
try {
|
|
243924
|
-
map = JSON.parse(
|
|
244163
|
+
map = JSON.parse(readFileSync42(abs, "utf8"));
|
|
243925
244164
|
} catch (e) {
|
|
243926
244165
|
throw new CliError(`Can't read fixtures "${value}": ${e instanceof Error ? e.message : String(e)}`);
|
|
243927
244166
|
}
|
|
@@ -243934,7 +244173,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
243934
244173
|
var readScenarioFile = (path) => {
|
|
243935
244174
|
let raw;
|
|
243936
244175
|
try {
|
|
243937
|
-
raw = JSON.parse(
|
|
244176
|
+
raw = JSON.parse(readFileSync42(resolve30(path), "utf8"));
|
|
243938
244177
|
} catch (e) {
|
|
243939
244178
|
throw new CliError(`Can't read scenario "${path}": ${e instanceof Error ? e.message : String(e)}`);
|
|
243940
244179
|
}
|
|
@@ -244279,7 +244518,7 @@ var renderHeadless = async (flags, file) => {
|
|
|
244279
244518
|
|
|
244280
244519
|
// src/commands/scene.ts
|
|
244281
244520
|
init_cli();
|
|
244282
|
-
import { existsSync as existsSync50, readFileSync as
|
|
244521
|
+
import { existsSync as existsSync50, readFileSync as readFileSync44, readdirSync as readdirSync21, statSync as statSync17, writeFileSync as writeFileSync34 } from "node:fs";
|
|
244283
244522
|
import { basename as basename23, dirname as dirname26, join as join54, relative as relative11, resolve as resolve31 } from "node:path";
|
|
244284
244523
|
|
|
244285
244524
|
// src/compile/sceneCompile.ts
|
|
@@ -244288,7 +244527,7 @@ init_ignore();
|
|
|
244288
244527
|
init_cli();
|
|
244289
244528
|
init_projectCompile();
|
|
244290
244529
|
import { createHash as createHash9 } from "node:crypto";
|
|
244291
|
-
import { existsSync as existsSync49, mkdirSync as mkdirSync31, readFileSync as
|
|
244530
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync31, readFileSync as readFileSync43, writeFileSync as writeFileSync33 } from "node:fs";
|
|
244292
244531
|
import { join as join53 } from "node:path";
|
|
244293
244532
|
var TEXT_EXT = /\.(ts|js|json|svg|txt|md)$/i;
|
|
244294
244533
|
var rel = (key) => key.replace(/^\//, "");
|
|
@@ -244300,11 +244539,11 @@ var compileSceneEditor = async (opts) => {
|
|
|
244300
244539
|
for (const file of scan.files) {
|
|
244301
244540
|
const path = "./" + rel(file.path);
|
|
244302
244541
|
if (TEXT_EXT.test(path)) {
|
|
244303
|
-
entries.push({ path, type: "text", text:
|
|
244542
|
+
entries.push({ path, type: "text", text: readFileSync43(file.absPath, "utf8") });
|
|
244304
244543
|
} else if (/\.mat$/i.test(path)) {
|
|
244305
|
-
entries.push({ path, type: "shader", text:
|
|
244544
|
+
entries.push({ path, type: "shader", text: readFileSync43(file.absPath, "utf8"), absPath: file.absPath });
|
|
244306
244545
|
} else {
|
|
244307
|
-
entries.push({ path, type: "resource", fileSrc: "/project/" + rel(file.path) });
|
|
244546
|
+
entries.push({ path, type: "resource", fileSrc: "/project/" + rel(file.path), absPath: file.absPath });
|
|
244308
244547
|
}
|
|
244309
244548
|
}
|
|
244310
244549
|
const shaderEntries = entries.filter((e) => e.type === "shader");
|
|
@@ -244384,7 +244623,7 @@ var getContext2 = (pathArg) => {
|
|
|
244384
244623
|
manifest = null;
|
|
244385
244624
|
if (pathArg) {
|
|
244386
244625
|
const abs = resolve31(process.cwd(), pathArg);
|
|
244387
|
-
if (existsSync50(abs) &&
|
|
244626
|
+
if (existsSync50(abs) && statSync17(abs).isDirectory())
|
|
244388
244627
|
root = abs;
|
|
244389
244628
|
else if (abs.endsWith(".scene.ts") && existsSync50(abs))
|
|
244390
244629
|
root = findAppRoot(dirname26(abs)) ?? dirname26(abs);
|
|
@@ -244409,7 +244648,7 @@ var writeMcpConfig2 = (root, port) => {
|
|
|
244409
244648
|
let config = {};
|
|
244410
244649
|
if (existsSync50(path)) {
|
|
244411
244650
|
try {
|
|
244412
|
-
config = JSON.parse(
|
|
244651
|
+
config = JSON.parse(readFileSync44(path, "utf8"));
|
|
244413
244652
|
} catch {
|
|
244414
244653
|
warnErr(".mcp.json exists but isn't valid JSON — left it untouched. Add the lecodes-scene server by hand.");
|
|
244415
244654
|
return;
|
|
@@ -244428,11 +244667,11 @@ var writeMcpConfig2 = (root, port) => {
|
|
|
244428
244667
|
};
|
|
244429
244668
|
var countScenes = (dir) => {
|
|
244430
244669
|
let n = 0;
|
|
244431
|
-
for (const name of
|
|
244670
|
+
for (const name of readdirSync21(dir)) {
|
|
244432
244671
|
if (name === "node_modules" || name.startsWith("."))
|
|
244433
244672
|
continue;
|
|
244434
244673
|
const full = join54(dir, name);
|
|
244435
|
-
if (
|
|
244674
|
+
if (statSync17(full).isDirectory())
|
|
244436
244675
|
n += countScenes(full);
|
|
244437
244676
|
else if (name.endsWith(".scene.ts"))
|
|
244438
244677
|
n++;
|
|
@@ -244524,8 +244763,9 @@ var serve_default = defineCommand({
|
|
|
244524
244763
|
});
|
|
244525
244764
|
|
|
244526
244765
|
// src/commands/shaders/index.ts
|
|
244527
|
-
import { readFileSync as
|
|
244766
|
+
import { readFileSync as readFileSync46 } from "node:fs";
|
|
244528
244767
|
import { relative as relative13 } from "node:path";
|
|
244768
|
+
init_releases();
|
|
244529
244769
|
init_cli();
|
|
244530
244770
|
init_shared();
|
|
244531
244771
|
|
|
@@ -244533,7 +244773,7 @@ init_shared();
|
|
|
244533
244773
|
init_compile();
|
|
244534
244774
|
init_distRoot();
|
|
244535
244775
|
init_cli();
|
|
244536
|
-
import { existsSync as existsSync51, mkdirSync as mkdirSync32, readdirSync as
|
|
244776
|
+
import { existsSync as existsSync51, mkdirSync as mkdirSync32, readdirSync as readdirSync22, readFileSync as readFileSync45, writeFileSync as writeFileSync35 } from "node:fs";
|
|
244537
244777
|
import { basename as basename25, join as join55, relative as relative12, resolve as resolve32 } from "node:path";
|
|
244538
244778
|
var engineMaterialsDir = () => {
|
|
244539
244779
|
const candidates = [
|
|
@@ -244549,7 +244789,7 @@ var engineMaterialNames = () => {
|
|
|
244549
244789
|
const dir = engineMaterialsDir();
|
|
244550
244790
|
if (!dir)
|
|
244551
244791
|
return [];
|
|
244552
|
-
return
|
|
244792
|
+
return readdirSync22(dir).filter((f) => f.endsWith(".mat") && !f.startsWith("camera") && f !== "shader360.mat").map((f) => f.slice(0, -4)).sort();
|
|
244553
244793
|
};
|
|
244554
244794
|
var NAME_RE = /^[a-z][a-z0-9_-]*$/i;
|
|
244555
244795
|
var matName = (name) => name.replace(/-/g, "_");
|
|
@@ -244640,7 +244880,7 @@ var writeNewShader = (o) => {
|
|
|
244640
244880
|
const known = engineMaterialNames();
|
|
244641
244881
|
if (!known.includes(ref))
|
|
244642
244882
|
throw new CliError(`no engine material "${ref}". Known: ${known.join(", ")}`);
|
|
244643
|
-
mat = refMat(name, ref,
|
|
244883
|
+
mat = refMat(name, ref, readFileSync45(join55(srcDir, `${ref}.mat`), "utf8"));
|
|
244644
244884
|
} else
|
|
244645
244885
|
mat = starterMat(name);
|
|
244646
244886
|
mkdirSync32(dir, { recursive: true });
|
|
@@ -244672,7 +244912,7 @@ var status2 = async () => {
|
|
|
244672
244912
|
if (matcId === null)
|
|
244673
244913
|
state = c.dim("unknown (matc not downloaded)");
|
|
244674
244914
|
else {
|
|
244675
|
-
const text =
|
|
244915
|
+
const text = readFileSync46(shader.absPath, "utf8");
|
|
244676
244916
|
if (shaderIsCompiled(root, text, matcId))
|
|
244677
244917
|
state = "compiled";
|
|
244678
244918
|
else {
|
|
@@ -244681,7 +244921,7 @@ var status2 = async () => {
|
|
|
244681
244921
|
}
|
|
244682
244922
|
}
|
|
244683
244923
|
log(` ${shader.path.padEnd(width)} ${state}`);
|
|
244684
|
-
const schema = parseShaderSchema(
|
|
244924
|
+
const schema = parseShaderSchema(readFileSync46(shader.absPath, "utf8"));
|
|
244685
244925
|
for (const p of schema.params) {
|
|
244686
244926
|
const range = p.min !== undefined ? ` [${p.min}..${p.max}]` : "";
|
|
244687
244927
|
const def = p.default !== null && p.default !== undefined ? ` = ${JSON.stringify(p.default)}` : "";
|
|
@@ -244722,7 +244962,7 @@ var compileShaders = async (platforms) => {
|
|
|
244722
244962
|
}
|
|
244723
244963
|
const matcExe = await resolveMatcExe();
|
|
244724
244964
|
const matcId = matcIdentity(matcExe);
|
|
244725
|
-
const wasCompiled = new Map(shaders.map((s) => [s.path, shaderIsCompiled(root,
|
|
244965
|
+
const wasCompiled = new Map(shaders.map((s) => [s.path, shaderIsCompiled(root, readFileSync46(s.absPath, "utf8"), matcId)]));
|
|
244726
244966
|
const errors = [];
|
|
244727
244967
|
for (const shader of shaders) {
|
|
244728
244968
|
try {
|
|
@@ -244824,7 +245064,7 @@ var status_default = defineCommand({
|
|
|
244824
245064
|
});
|
|
244825
245065
|
|
|
244826
245066
|
// src/commands/test.ts
|
|
244827
|
-
import { existsSync as existsSync53, mkdirSync as mkdirSync34, readFileSync as
|
|
245067
|
+
import { existsSync as existsSync53, mkdirSync as mkdirSync34, readFileSync as readFileSync47, readdirSync as readdirSync23 } from "node:fs";
|
|
244828
245068
|
import { dirname as dirname28, resolve as resolve33 } from "node:path";
|
|
244829
245069
|
init_manifest();
|
|
244830
245070
|
|
|
@@ -245341,7 +245581,7 @@ var slug = (s) => s.replace(/[^a-zA-Z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").sli
|
|
|
245341
245581
|
var readFlowFile = (abs, displayName) => {
|
|
245342
245582
|
let raw;
|
|
245343
245583
|
try {
|
|
245344
|
-
raw = JSON.parse(
|
|
245584
|
+
raw = JSON.parse(readFileSync47(abs, "utf8"));
|
|
245345
245585
|
} catch (e) {
|
|
245346
245586
|
throw new CliError(`Can't read "${displayName}": ${e instanceof Error ? e.message : String(e)}`);
|
|
245347
245587
|
}
|
|
@@ -245449,7 +245689,7 @@ var runTests = async (args, flags) => {
|
|
|
245449
245689
|
cases.push(readFlowFile(abs, given));
|
|
245450
245690
|
}
|
|
245451
245691
|
} else if (existsSync53(testsDir)) {
|
|
245452
|
-
for (const f of
|
|
245692
|
+
for (const f of readdirSync23(testsDir).filter((f) => f.endsWith(".flow.json")).sort()) {
|
|
245453
245693
|
cases.push(readFlowFile(resolve33(testsDir, f), f));
|
|
245454
245694
|
}
|
|
245455
245695
|
}
|
|
@@ -245467,7 +245707,7 @@ var runTests = async (args, flags) => {
|
|
|
245467
245707
|
if (!desktop && !lite && (wantFlows || flowsOnly) && existsSync53(designMetaPath)) {
|
|
245468
245708
|
let meta;
|
|
245469
245709
|
try {
|
|
245470
|
-
meta = JSON.parse(
|
|
245710
|
+
meta = JSON.parse(readFileSync47(designMetaPath, "utf8"));
|
|
245471
245711
|
} catch (e) {
|
|
245472
245712
|
throw new CliError(`Can't read ${designMetaPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
245473
245713
|
}
|
|
@@ -245540,7 +245780,7 @@ var runTests = async (args, flags) => {
|
|
|
245540
245780
|
script: plan.text,
|
|
245541
245781
|
fixedDtMs: nativeFixedDt
|
|
245542
245782
|
});
|
|
245543
|
-
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ?
|
|
245783
|
+
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ? readFileSync47(path, "utf8") : null);
|
|
245544
245784
|
if (!r.loaded)
|
|
245545
245785
|
throw new CliError("This desktop host doesn't support scripted input (CREATOR_SCRIPT). Update it: lecodes desktop update (or point LECODES_DESKTOP_EXE at a newer build).");
|
|
245546
245786
|
return {
|
|
@@ -245579,7 +245819,7 @@ var runTests = async (args, flags) => {
|
|
|
245579
245819
|
height: flags.height || kase.height || projectViewport?.height || 844,
|
|
245580
245820
|
onConsole
|
|
245581
245821
|
});
|
|
245582
|
-
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ?
|
|
245822
|
+
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ? readFileSync47(path, "utf8") : null);
|
|
245583
245823
|
return {
|
|
245584
245824
|
name: kase.name,
|
|
245585
245825
|
kind: kase.kind,
|
|
@@ -245688,7 +245928,7 @@ var runTests = async (args, flags) => {
|
|
|
245688
245928
|
init_peerInstall();
|
|
245689
245929
|
import { createRequire as createRequire8 } from "node:module";
|
|
245690
245930
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
245691
|
-
import { existsSync as existsSync54, mkdtempSync as mkdtempSync7, readdirSync as
|
|
245931
|
+
import { existsSync as existsSync54, mkdtempSync as mkdtempSync7, readdirSync as readdirSync24, rmSync as rmSync17, statSync as statSync18 } from "node:fs";
|
|
245692
245932
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
245693
245933
|
import { extname, join as join57, relative as relative14, resolve as resolve34 } from "node:path";
|
|
245694
245934
|
init_cli();
|
|
@@ -245746,11 +245986,11 @@ var ktxToPng = (ktx, file, out) => {
|
|
|
245746
245986
|
};
|
|
245747
245987
|
var collect = (dir) => {
|
|
245748
245988
|
const out = [];
|
|
245749
|
-
for (const name of
|
|
245989
|
+
for (const name of readdirSync24(dir)) {
|
|
245750
245990
|
if (name === "node_modules" || name.startsWith("."))
|
|
245751
245991
|
continue;
|
|
245752
245992
|
const full = join57(dir, name);
|
|
245753
|
-
if (
|
|
245993
|
+
if (statSync18(full).isDirectory())
|
|
245754
245994
|
out.push(...collect(full));
|
|
245755
245995
|
else if (IMAGE_EXT.test(name))
|
|
245756
245996
|
out.push(full);
|
|
@@ -245778,7 +246018,7 @@ var thumbs = async (targets, size, force) => {
|
|
|
245778
246018
|
const abs = resolve34(process.cwd(), arg);
|
|
245779
246019
|
if (!existsSync54(abs))
|
|
245780
246020
|
throw new CliError(`No such file or folder: ${arg}`);
|
|
245781
|
-
if (
|
|
246021
|
+
if (statSync18(abs).isDirectory())
|
|
245782
246022
|
files.push(...collect(abs));
|
|
245783
246023
|
else if (IMAGE_EXT.test(abs))
|
|
245784
246024
|
files.push(abs);
|
|
@@ -245855,7 +246095,7 @@ init_peerInstall();
|
|
|
245855
246095
|
init_archives();
|
|
245856
246096
|
init_packageManager();
|
|
245857
246097
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
245858
|
-
import { existsSync as existsSync55, readdirSync as
|
|
246098
|
+
import { existsSync as existsSync55, readdirSync as readdirSync25 } from "node:fs";
|
|
245859
246099
|
import { homedir as homedir14 } from "node:os";
|
|
245860
246100
|
import { dirname as dirname29, join as join58, resolve as resolve36 } from "node:path";
|
|
245861
246101
|
|
|
@@ -246026,7 +246266,7 @@ ${c.bold(name)} ${c.dim(what)}`);
|
|
|
246026
246266
|
return ["skipped", "not inside a project"];
|
|
246027
246267
|
if (flags["no-shells"])
|
|
246028
246268
|
return ["skipped", "--no-shells"];
|
|
246029
|
-
const present = ["ios", "android"].filter((d) => existsSync55(join58(root, d)) &&
|
|
246269
|
+
const present = ["ios", "android"].filter((d) => existsSync55(join58(root, d)) && readdirSync25(join58(root, d)).length > 0);
|
|
246030
246270
|
if (present.length === 0)
|
|
246031
246271
|
return ["skipped", "no ios/ or android/ shell in this project (`lecodes app init ios|android`)"];
|
|
246032
246272
|
await runSubcommand(app_default, "update");
|
|
@@ -246105,7 +246345,7 @@ init_cli();
|
|
|
246105
246345
|
// src/web/build.ts
|
|
246106
246346
|
init_compile();
|
|
246107
246347
|
import { createHash as createHash10 } from "node:crypto";
|
|
246108
|
-
import { copyFileSync as copyFileSync2, cpSync as cpSync7, existsSync as existsSync56, mkdirSync as mkdirSync35, readFileSync as
|
|
246348
|
+
import { copyFileSync as copyFileSync2, cpSync as cpSync7, existsSync as existsSync56, mkdirSync as mkdirSync35, readFileSync as readFileSync48, readdirSync as readdirSync26, rmSync as rmSync18, statSync as statSync19, writeFileSync as writeFileSync37 } from "node:fs";
|
|
246109
246349
|
import { dirname as dirname30, extname as extname2, join as join59, resolve as resolve37 } from "node:path";
|
|
246110
246350
|
init_fonts();
|
|
246111
246351
|
init_assetIcons();
|
|
@@ -246118,9 +246358,9 @@ var normalBase = (base) => {
|
|
|
246118
246358
|
};
|
|
246119
246359
|
var walk = (dir, prefix = "") => {
|
|
246120
246360
|
const out = [];
|
|
246121
|
-
for (const name of
|
|
246361
|
+
for (const name of readdirSync26(dir)) {
|
|
246122
246362
|
const abs = join59(dir, name);
|
|
246123
|
-
const stat =
|
|
246363
|
+
const stat = statSync19(abs);
|
|
246124
246364
|
if (stat.isDirectory())
|
|
246125
246365
|
out.push(...walk(abs, `${prefix}${name}/`));
|
|
246126
246366
|
else
|
|
@@ -246149,7 +246389,7 @@ var buildWeb = async (options) => {
|
|
|
246149
246389
|
for (const entry of entries) {
|
|
246150
246390
|
if (entry.type !== "shader" || !entry.absPath)
|
|
246151
246391
|
continue;
|
|
246152
|
-
const text =
|
|
246392
|
+
const text = readFileSync48(entry.absPath, "utf8");
|
|
246153
246393
|
const hash = createHash10("sha256").update(text).digest("hex").slice(0, 16);
|
|
246154
246394
|
shaders.set(hash, JSON.stringify(buildLiteMaterialArtifact(text)));
|
|
246155
246395
|
entry.shaders = [{ platform: "opengl", src: `shaders/${hash}_opengl.filamat` }];
|
|
@@ -246196,7 +246436,7 @@ var buildWeb = async (options) => {
|
|
|
246196
246436
|
cpSync7(lite, out, { recursive: true });
|
|
246197
246437
|
const table = join59(out, "features.json");
|
|
246198
246438
|
if (existsSync56(table)) {
|
|
246199
|
-
const { features, fonts } = JSON.parse(
|
|
246439
|
+
const { features, fonts } = JSON.parse(readFileSync48(table, "utf8"));
|
|
246200
246440
|
if (config.font === "system")
|
|
246201
246441
|
for (const file of fonts ?? [])
|
|
246202
246442
|
rmSync18(join59(out, file), { force: true });
|
|
@@ -246210,7 +246450,7 @@ var buildWeb = async (options) => {
|
|
|
246210
246450
|
}
|
|
246211
246451
|
const pluginsTable = join59(out, "plugins.json");
|
|
246212
246452
|
if (existsSync56(pluginsTable) || halves.length > 0) {
|
|
246213
|
-
const { plugins } = existsSync56(pluginsTable) ? JSON.parse(
|
|
246453
|
+
const { plugins } = existsSync56(pluginsTable) ? JSON.parse(readFileSync48(pluginsTable, "utf8")) : { plugins: {} };
|
|
246214
246454
|
const kept = {};
|
|
246215
246455
|
for (const id of Object.keys(plugins)) {
|
|
246216
246456
|
if (listed.has(id))
|
|
@@ -246260,7 +246500,7 @@ var buildWeb = async (options) => {
|
|
|
246260
246500
|
writeFileSync37(join59(out, "shaders", `${hash}_webgl-lite.filamat`), artifact);
|
|
246261
246501
|
}
|
|
246262
246502
|
const app = readAppConfigAt(root);
|
|
246263
|
-
let html =
|
|
246503
|
+
let html = readFileSync48(join59(lite, "index.html"), "utf8");
|
|
246264
246504
|
const head = [];
|
|
246265
246505
|
head.push(`<meta name="theme-color" content="${escapeHtml(config.themeColor ?? "#000000")}" />`);
|
|
246266
246506
|
if (app?.icon) {
|
|
@@ -246300,7 +246540,7 @@ var buildWeb = async (options) => {
|
|
|
246300
246540
|
};
|
|
246301
246541
|
|
|
246302
246542
|
// src/web/preview.ts
|
|
246303
|
-
import { createReadStream as createReadStream3, existsSync as existsSync57, statSync as
|
|
246543
|
+
import { createReadStream as createReadStream3, existsSync as existsSync57, statSync as statSync20 } from "node:fs";
|
|
246304
246544
|
import { createServer as createServer4 } from "node:http";
|
|
246305
246545
|
import { join as join60, resolve as resolve38 } from "node:path";
|
|
246306
246546
|
var startPreview = async (dir, port) => {
|
|
@@ -246322,10 +246562,10 @@ var startPreview = async (dir, port) => {
|
|
|
246322
246562
|
return;
|
|
246323
246563
|
}
|
|
246324
246564
|
let file = join60(root, ...parts);
|
|
246325
|
-
if (existsSync57(file) &&
|
|
246565
|
+
if (existsSync57(file) && statSync20(file).isDirectory())
|
|
246326
246566
|
file = join60(file, "index.html");
|
|
246327
246567
|
let status = 200;
|
|
246328
|
-
if (!existsSync57(file) || !
|
|
246568
|
+
if (!existsSync57(file) || !statSync20(file).isFile()) {
|
|
246329
246569
|
if (!fallback || /\.[a-z0-9]+$/i.test(parts[parts.length - 1] ?? "")) {
|
|
246330
246570
|
res.writeHead(404, { "content-type": "text/plain" });
|
|
246331
246571
|
res.end("Not found");
|
|
@@ -246355,7 +246595,7 @@ var startPreview = async (dir, port) => {
|
|
|
246355
246595
|
init_shared();
|
|
246356
246596
|
|
|
246357
246597
|
// src/dev/https.ts
|
|
246358
|
-
import { existsSync as existsSync58, mkdirSync as mkdirSync36, readFileSync as
|
|
246598
|
+
import { existsSync as existsSync58, mkdirSync as mkdirSync36, readFileSync as readFileSync49, writeFileSync as writeFileSync38 } from "node:fs";
|
|
246359
246599
|
import { homedir as homedir15 } from "node:os";
|
|
246360
246600
|
import { join as join61 } from "node:path";
|
|
246361
246601
|
var DIR = () => join61(homedir15(), ".lecodes", "dev-https");
|
|
@@ -246365,12 +246605,12 @@ var devCertificate = async (names, dir = DIR()) => {
|
|
|
246365
246605
|
const files = { cert: join61(dir, "cert.pem"), key: join61(dir, "key.pem"), meta: join61(dir, "names.json") };
|
|
246366
246606
|
let kept = null;
|
|
246367
246607
|
try {
|
|
246368
|
-
kept = JSON.parse(
|
|
246608
|
+
kept = JSON.parse(readFileSync49(files.meta, "utf8"));
|
|
246369
246609
|
} catch {}
|
|
246370
246610
|
const wanted = [...new Set(["localhost", "127.0.0.1", ...names])];
|
|
246371
246611
|
const fresh = kept && Date.now() - kept.made < RENEW_DAYS * 86400000 && wanted.every((n) => kept.names.includes(n));
|
|
246372
246612
|
if (fresh && existsSync58(files.cert) && existsSync58(files.key)) {
|
|
246373
|
-
return { cert:
|
|
246613
|
+
return { cert: readFileSync49(files.cert, "utf8"), key: readFileSync49(files.key, "utf8") };
|
|
246374
246614
|
}
|
|
246375
246615
|
const { generate } = await Promise.resolve().then(() => __toESM(require_selfsigned(), 1));
|
|
246376
246616
|
const all = [...new Set([...kept?.names ?? [], ...wanted])];
|