lecodes-cli 2.4.7 → 2.4.9
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 +874 -644
- package/package.json +8 -8
- 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 +98 -83
- package/src/compile/projectCompile.ts +23 -5
- package/src/compile/sceneCompile.ts +3 -2
- 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.9",
|
|
68
68
|
dependencies: {
|
|
69
69
|
"@letary/chisel": "^0.15.0",
|
|
70
70
|
jimp: "^1.6.1",
|
|
@@ -89,7 +89,7 @@ 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.9",
|
|
93
93
|
"lecodes-3d-editor": "^0.9.0",
|
|
94
94
|
"lecodes-assets": "^0.2.1",
|
|
95
95
|
"heic-decode": "^2.1.0",
|
|
@@ -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.9";
|
|
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) => {
|
|
@@ -880,13 +880,7 @@ var init_resourceSlots = __esm(() => {
|
|
|
880
880
|
"map",
|
|
881
881
|
"shader",
|
|
882
882
|
"build",
|
|
883
|
-
"data"
|
|
884
|
-
"light",
|
|
885
|
-
"aux",
|
|
886
|
-
"direct",
|
|
887
|
-
"indirect",
|
|
888
|
-
"probes",
|
|
889
|
-
"volume"
|
|
883
|
+
"data"
|
|
890
884
|
]
|
|
891
885
|
};
|
|
892
886
|
});
|
|
@@ -1146,6 +1140,520 @@ var init_assetMacro = __esm(() => {
|
|
|
1146
1140
|
SET_TARGET = /\.\s*([A-Za-z_$][\w$]*)\s*$/;
|
|
1147
1141
|
});
|
|
1148
1142
|
|
|
1143
|
+
// ../../sdk/src/compile/assetIconMacro.ts
|
|
1144
|
+
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) => {
|
|
1145
|
+
const quote = src[start];
|
|
1146
|
+
const n = src.length;
|
|
1147
|
+
let i = start + 1;
|
|
1148
|
+
while (i < n) {
|
|
1149
|
+
const c = src[i];
|
|
1150
|
+
if (c === "\\") {
|
|
1151
|
+
i += 2;
|
|
1152
|
+
continue;
|
|
1153
|
+
}
|
|
1154
|
+
if (quote === "`" && c === "$" && src[i + 1] === "{") {
|
|
1155
|
+
i = skipBraces(src, i + 1);
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1158
|
+
if (c === quote)
|
|
1159
|
+
return i + 1;
|
|
1160
|
+
i++;
|
|
1161
|
+
}
|
|
1162
|
+
return n;
|
|
1163
|
+
}, skipBraces = (src, open) => {
|
|
1164
|
+
const n = src.length;
|
|
1165
|
+
let depth = 0;
|
|
1166
|
+
let i = open;
|
|
1167
|
+
while (i < n) {
|
|
1168
|
+
const c = src[i];
|
|
1169
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1170
|
+
i = skipString(src, i);
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
if (c === "{")
|
|
1174
|
+
depth++;
|
|
1175
|
+
else if (c === "}") {
|
|
1176
|
+
depth--;
|
|
1177
|
+
if (depth === 0)
|
|
1178
|
+
return i + 1;
|
|
1179
|
+
}
|
|
1180
|
+
i++;
|
|
1181
|
+
}
|
|
1182
|
+
return n;
|
|
1183
|
+
}, matchParen = (src, open) => {
|
|
1184
|
+
const n = src.length;
|
|
1185
|
+
let depth = 0;
|
|
1186
|
+
let i = open;
|
|
1187
|
+
while (i < n) {
|
|
1188
|
+
const c = src[i];
|
|
1189
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1190
|
+
i = skipString(src, i);
|
|
1191
|
+
continue;
|
|
1192
|
+
}
|
|
1193
|
+
if (c === "/" && src[i + 1] === "/") {
|
|
1194
|
+
i += 2;
|
|
1195
|
+
while (i < n && src[i] !== `
|
|
1196
|
+
`)
|
|
1197
|
+
i++;
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
if (c === "/" && src[i + 1] === "*") {
|
|
1201
|
+
i += 2;
|
|
1202
|
+
while (i < n && !(src[i] === "*" && src[i + 1] === "/"))
|
|
1203
|
+
i++;
|
|
1204
|
+
i += 2;
|
|
1205
|
+
continue;
|
|
1206
|
+
}
|
|
1207
|
+
if (c === "(")
|
|
1208
|
+
depth++;
|
|
1209
|
+
else if (c === ")") {
|
|
1210
|
+
depth--;
|
|
1211
|
+
if (depth === 0)
|
|
1212
|
+
return i;
|
|
1213
|
+
}
|
|
1214
|
+
i++;
|
|
1215
|
+
}
|
|
1216
|
+
return -1;
|
|
1217
|
+
}, splitTopLevel = (text, delim) => {
|
|
1218
|
+
const parts = [];
|
|
1219
|
+
const n = text.length;
|
|
1220
|
+
let depth = 0;
|
|
1221
|
+
let last = 0;
|
|
1222
|
+
let i = 0;
|
|
1223
|
+
while (i < n) {
|
|
1224
|
+
const c = text[i];
|
|
1225
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1226
|
+
i = skipString(text, i);
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
if (c === "(" || c === "[" || c === "{")
|
|
1230
|
+
depth++;
|
|
1231
|
+
else if (c === ")" || c === "]" || c === "}")
|
|
1232
|
+
depth = Math.max(0, depth - 1);
|
|
1233
|
+
else if (depth === 0 && c === delim) {
|
|
1234
|
+
parts.push(text.slice(last, i));
|
|
1235
|
+
last = i + 1;
|
|
1236
|
+
}
|
|
1237
|
+
i++;
|
|
1238
|
+
}
|
|
1239
|
+
parts.push(text.slice(last));
|
|
1240
|
+
return parts;
|
|
1241
|
+
}, stringLiteralValue = (text) => {
|
|
1242
|
+
const t = text.trim();
|
|
1243
|
+
if (t.length < 2)
|
|
1244
|
+
return null;
|
|
1245
|
+
const q = t[0];
|
|
1246
|
+
if (q !== '"' && q !== "'" && q !== "`" || t[t.length - 1] !== q)
|
|
1247
|
+
return null;
|
|
1248
|
+
const inner = t.slice(1, -1);
|
|
1249
|
+
if (q === "`" && inner.includes("${"))
|
|
1250
|
+
return null;
|
|
1251
|
+
if (inner.includes(q) && !inner.includes("\\" + q))
|
|
1252
|
+
return null;
|
|
1253
|
+
return inner.replace(/\\(.)/g, "$1");
|
|
1254
|
+
}, scanAssetIconCalls = (source) => {
|
|
1255
|
+
const calls = [];
|
|
1256
|
+
const n = source.length;
|
|
1257
|
+
let i = 0;
|
|
1258
|
+
while (i < n) {
|
|
1259
|
+
const c = source[i];
|
|
1260
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
1261
|
+
i = skipString(source, i);
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
if (c === "/" && source[i + 1] === "/") {
|
|
1265
|
+
i += 2;
|
|
1266
|
+
while (i < n && source[i] !== `
|
|
1267
|
+
`)
|
|
1268
|
+
i++;
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
if (c === "/" && source[i + 1] === "*") {
|
|
1272
|
+
i += 2;
|
|
1273
|
+
while (i < n && !(source[i] === "*" && source[i + 1] === "/"))
|
|
1274
|
+
i++;
|
|
1275
|
+
i += 2;
|
|
1276
|
+
continue;
|
|
1277
|
+
}
|
|
1278
|
+
if (isIdentStart(c)) {
|
|
1279
|
+
let j = i + 1;
|
|
1280
|
+
while (j < n && isIdentPart(source[j]))
|
|
1281
|
+
j++;
|
|
1282
|
+
if (source.slice(i, j) === "assetIcon" && prevNonSpace(source, i) !== ".") {
|
|
1283
|
+
const call = parseCall(source, i, j);
|
|
1284
|
+
if (call) {
|
|
1285
|
+
calls.push(call);
|
|
1286
|
+
i = call.end;
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
i = j;
|
|
1291
|
+
continue;
|
|
1292
|
+
}
|
|
1293
|
+
i++;
|
|
1294
|
+
}
|
|
1295
|
+
return calls;
|
|
1296
|
+
}, prevNonSpace = (src, i) => {
|
|
1297
|
+
let k = i - 1;
|
|
1298
|
+
while (k >= 0 && /\s/.test(src[k]))
|
|
1299
|
+
k--;
|
|
1300
|
+
return k >= 0 ? src[k] : "";
|
|
1301
|
+
}, parseCall = (src, start, identEnd) => {
|
|
1302
|
+
const n = src.length;
|
|
1303
|
+
let i = identEnd;
|
|
1304
|
+
while (i < n && /\s/.test(src[i]))
|
|
1305
|
+
i++;
|
|
1306
|
+
if (src[i] !== "(")
|
|
1307
|
+
return null;
|
|
1308
|
+
const close = matchParen(src, i);
|
|
1309
|
+
if (close === -1)
|
|
1310
|
+
return null;
|
|
1311
|
+
const call = { start, end: close + 1, id: "", pack: "", name: "" };
|
|
1312
|
+
const args = splitTopLevel(src.slice(i + 1, close), ",");
|
|
1313
|
+
const id = stringLiteralValue(args[0] ?? "");
|
|
1314
|
+
if (id === null) {
|
|
1315
|
+
call.error = `assetIcon(...) needs a string-literal id like "lucide:bell" (got \`${(args[0] ?? "").trim() || "()"}\`).`;
|
|
1316
|
+
return call;
|
|
1317
|
+
}
|
|
1318
|
+
const m = ICON_ID.exec(id);
|
|
1319
|
+
if (!m) {
|
|
1320
|
+
call.error = `assetIcon("${id}"): id must be "pack:name", lowercase [a-z0-9-] (e.g. "lucide:bell").`;
|
|
1321
|
+
return call;
|
|
1322
|
+
}
|
|
1323
|
+
call.id = id;
|
|
1324
|
+
call.pack = m[1];
|
|
1325
|
+
call.name = m[2];
|
|
1326
|
+
const optsText = args[1]?.trim();
|
|
1327
|
+
if (optsText) {
|
|
1328
|
+
const color = extractColor(optsText);
|
|
1329
|
+
if (color.error) {
|
|
1330
|
+
call.error = color.error;
|
|
1331
|
+
return call;
|
|
1332
|
+
}
|
|
1333
|
+
if (color.bake !== undefined)
|
|
1334
|
+
call.bake = color.bake;
|
|
1335
|
+
else if (color.tint !== undefined)
|
|
1336
|
+
call.tint = color.tint;
|
|
1337
|
+
}
|
|
1338
|
+
return call;
|
|
1339
|
+
}, extractColor = (optsText) => {
|
|
1340
|
+
if (!optsText.startsWith("{") || !optsText.endsWith("}")) {
|
|
1341
|
+
return { error: `assetIcon(id, opts): opts must be an object literal like { color: "#5b8cff" }.` };
|
|
1342
|
+
}
|
|
1343
|
+
for (const prop of splitTopLevel(optsText.slice(1, -1), ",")) {
|
|
1344
|
+
const kv = splitTopLevel(prop, ":");
|
|
1345
|
+
if (kv.length < 2)
|
|
1346
|
+
continue;
|
|
1347
|
+
const key = kv[0].trim().replace(/^["'`]|["'`]$/g, "");
|
|
1348
|
+
if (key !== "color")
|
|
1349
|
+
continue;
|
|
1350
|
+
const raw = kv.slice(1).join(":").trim();
|
|
1351
|
+
if (!raw)
|
|
1352
|
+
continue;
|
|
1353
|
+
const literal = stringLiteralValue(raw);
|
|
1354
|
+
return literal !== null ? { bake: literal } : { tint: raw };
|
|
1355
|
+
}
|
|
1356
|
+
return {};
|
|
1357
|
+
}, rewriteAssetIcons = (source, calls, svgById) => {
|
|
1358
|
+
let out = source;
|
|
1359
|
+
for (const call of [...calls].sort((a, b) => b.start - a.start)) {
|
|
1360
|
+
const svg = svgById.get(call.id);
|
|
1361
|
+
if (svg === undefined)
|
|
1362
|
+
continue;
|
|
1363
|
+
out = out.slice(0, call.start) + iconExpr(svg, call) + out.slice(call.end);
|
|
1364
|
+
}
|
|
1365
|
+
return out;
|
|
1366
|
+
}, iconExpr = (svg, call) => {
|
|
1367
|
+
const body = call.bake ? svg.split("currentColor").join(call.bake) : svg;
|
|
1368
|
+
const src = `SvgSource(\`${escapeTemplate(body)}\`)`;
|
|
1369
|
+
return call.tint ? `Object.assign(${src}, { tintColor: (${call.tint}) })` : src;
|
|
1370
|
+
}, escapeTemplate = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${"), applyAssetIconMacro = async (entries, resolveSvgs) => {
|
|
1371
|
+
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);
|
|
1372
|
+
if (scanned.length === 0)
|
|
1373
|
+
return [];
|
|
1374
|
+
const errors = scanned.flatMap((s) => s.calls.filter((c) => c.error).map((c) => c.error));
|
|
1375
|
+
if (errors.length)
|
|
1376
|
+
throw new Error([...new Set(errors)].join(`
|
|
1377
|
+
`));
|
|
1378
|
+
const ids = [...new Set(scanned.flatMap((s) => s.calls.map((c) => c.id)))];
|
|
1379
|
+
const svgById = await resolveSvgs(ids);
|
|
1380
|
+
const missing = ids.filter((id) => !svgById.has(id));
|
|
1381
|
+
if (missing.length)
|
|
1382
|
+
throw new Error(`assetIcon: could not resolve icon(s): ${missing.join(", ")}.`);
|
|
1383
|
+
for (const { entry, calls } of scanned)
|
|
1384
|
+
entry.text = rewriteAssetIcons(entry.text, calls, svgById);
|
|
1385
|
+
return ids;
|
|
1386
|
+
}, buildIconsHeaderValue = (ids) => [...new Set(ids.map((id) => id.split(":")[0]))].sort().join(";"), editDistance = (a, b, cap) => {
|
|
1387
|
+
if (Math.abs(a.length - b.length) > cap)
|
|
1388
|
+
return cap + 1;
|
|
1389
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
1390
|
+
for (let i = 1;i <= a.length; i++) {
|
|
1391
|
+
const cur = [i];
|
|
1392
|
+
let rowMin = i;
|
|
1393
|
+
for (let j = 1;j <= b.length; j++) {
|
|
1394
|
+
cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
1395
|
+
if (cur[j] < rowMin)
|
|
1396
|
+
rowMin = cur[j];
|
|
1397
|
+
}
|
|
1398
|
+
if (rowMin > cap)
|
|
1399
|
+
return cap + 1;
|
|
1400
|
+
prev = cur;
|
|
1401
|
+
}
|
|
1402
|
+
return prev[b.length];
|
|
1403
|
+
}, suggestIconNames = (want, icons) => {
|
|
1404
|
+
const wantParts = new Set(want.split("-").filter(Boolean));
|
|
1405
|
+
const scored = [];
|
|
1406
|
+
for (const [name, info] of Object.entries(icons)) {
|
|
1407
|
+
const lenDiff = Math.abs(name.length - want.length) / 100;
|
|
1408
|
+
let rank;
|
|
1409
|
+
if (name.includes(want) || want.includes(name))
|
|
1410
|
+
rank = lenDiff;
|
|
1411
|
+
else {
|
|
1412
|
+
const d = editDistance(want, name, 2);
|
|
1413
|
+
if (d <= 2)
|
|
1414
|
+
rank = 1 + d;
|
|
1415
|
+
else if (info.kw?.some((k) => wantParts.has(k)))
|
|
1416
|
+
rank = 4 + lenDiff;
|
|
1417
|
+
else
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1420
|
+
scored.push({ name, rank });
|
|
1421
|
+
}
|
|
1422
|
+
return scored.sort((a, b) => a.rank - b.rank || (a.name < b.name ? -1 : 1)).slice(0, 5).map((s) => s.name);
|
|
1423
|
+
}, iconNotFoundError = async (pack, name, read, registry) => {
|
|
1424
|
+
const metaRaw = await read(`${pack}/meta.json`);
|
|
1425
|
+
if (metaRaw !== null) {
|
|
1426
|
+
let icons = {};
|
|
1427
|
+
try {
|
|
1428
|
+
icons = JSON.parse(metaRaw).icons ?? {};
|
|
1429
|
+
} catch {}
|
|
1430
|
+
const similar = suggestIconNames(name, icons);
|
|
1431
|
+
const hint = similar.length ? ` Did you mean ${similar.map((s) => `"${pack}:${s}"`).join(", ")}?` : ` No similar name in the "${pack}" pack either.`;
|
|
1432
|
+
return new Error(`assetIcon: icon "${pack}:${name}" not found.${hint}`);
|
|
1433
|
+
}
|
|
1434
|
+
const licRaw = await read("licenses.json");
|
|
1435
|
+
if (licRaw !== null) {
|
|
1436
|
+
try {
|
|
1437
|
+
const packs = Object.keys(JSON.parse(licRaw)).sort();
|
|
1438
|
+
return new Error(`assetIcon: unknown icon pack "${pack}" (in "${pack}:${name}"). Available packs: ${packs.join(", ")}.`);
|
|
1439
|
+
} catch {}
|
|
1440
|
+
}
|
|
1441
|
+
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 });
|
|
1442
|
+
}, VENDORED_ICON_PATH, collectVendoredIcons = (entries) => {
|
|
1443
|
+
const map = new Map;
|
|
1444
|
+
for (const e of entries) {
|
|
1445
|
+
if (e.type !== "text" || typeof e.text !== "string")
|
|
1446
|
+
continue;
|
|
1447
|
+
const m = VENDORED_ICON_PATH.exec(e.path);
|
|
1448
|
+
if (m)
|
|
1449
|
+
map.set(`${m[1]}:${m[2]}`, e.text);
|
|
1450
|
+
}
|
|
1451
|
+
return map;
|
|
1452
|
+
};
|
|
1453
|
+
var init_assetIconMacro = __esm(() => {
|
|
1454
|
+
ICON_ID = /^([a-z0-9]+(?:-[a-z0-9]+)*):([a-z0-9]+(?:-[a-z0-9]+)*)$/;
|
|
1455
|
+
VENDORED_ICON_PATH = /(?:^|\/)assets\/icons\/([a-z0-9]+(?:-[a-z0-9]+)*)\/([a-z0-9]+(?:-[a-z0-9]+)*)\.svg$/;
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
// ../../sdk/src/compile/bakeMacro.ts
|
|
1459
|
+
var BAKE_CALL, DECLARES_BAKE, DEFINITION_TAIL, hasBakeMacro = (src) => src.includes("bake"), stringLiteralValue2 = (text) => {
|
|
1460
|
+
const t = text.trim();
|
|
1461
|
+
if (t.length < 2)
|
|
1462
|
+
return null;
|
|
1463
|
+
const q = t[0];
|
|
1464
|
+
if (q !== '"' && q !== "'" && q !== "`" || t[t.length - 1] !== q)
|
|
1465
|
+
return null;
|
|
1466
|
+
const inner = t.slice(1, -1);
|
|
1467
|
+
if (q === "`" && inner.includes("${"))
|
|
1468
|
+
return null;
|
|
1469
|
+
if (/[\r\n]/.test(inner))
|
|
1470
|
+
return null;
|
|
1471
|
+
for (let i = 0;i < inner.length; i++) {
|
|
1472
|
+
if (inner[i] === "\\") {
|
|
1473
|
+
i++;
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
if (inner[i] === q)
|
|
1477
|
+
return null;
|
|
1478
|
+
}
|
|
1479
|
+
return inner.replace(/\\(.)/g, "$1");
|
|
1480
|
+
}, closeOf = (mask, open) => {
|
|
1481
|
+
let depth = 0;
|
|
1482
|
+
for (let i = open;i < mask.length; i++) {
|
|
1483
|
+
const c = mask[i];
|
|
1484
|
+
if (c === "(" || c === "[" || c === "{")
|
|
1485
|
+
depth++;
|
|
1486
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
1487
|
+
depth--;
|
|
1488
|
+
if (depth === 0)
|
|
1489
|
+
return i;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return -1;
|
|
1493
|
+
}, argSpans = (mask, open, close) => {
|
|
1494
|
+
const spans = [];
|
|
1495
|
+
let depth = 0;
|
|
1496
|
+
let start = open + 1;
|
|
1497
|
+
for (let i = open + 1;i < close; i++) {
|
|
1498
|
+
const c = mask[i];
|
|
1499
|
+
if (c === "(" || c === "[" || c === "{")
|
|
1500
|
+
depth++;
|
|
1501
|
+
else if (c === ")" || c === "]" || c === "}")
|
|
1502
|
+
depth--;
|
|
1503
|
+
else if (c === "," && depth === 0) {
|
|
1504
|
+
spans.push([start, i]);
|
|
1505
|
+
start = i + 1;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
spans.push([start, close]);
|
|
1509
|
+
return spans;
|
|
1510
|
+
}, newlines = (s) => {
|
|
1511
|
+
let n = 0;
|
|
1512
|
+
for (let i = 0;i < s.length; i++)
|
|
1513
|
+
if (s[i] === `
|
|
1514
|
+
`)
|
|
1515
|
+
n++;
|
|
1516
|
+
return n;
|
|
1517
|
+
}, stringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === "string") ? v : null, readManifest2 = (json) => {
|
|
1518
|
+
if (!json || typeof json !== "object")
|
|
1519
|
+
return null;
|
|
1520
|
+
const m = json;
|
|
1521
|
+
const light = stringArray(m.light), aux = stringArray(m.aux);
|
|
1522
|
+
if (!light || !aux)
|
|
1523
|
+
return null;
|
|
1524
|
+
const file = (v) => typeof v === "string" && v !== "" ? v : v && typeof v === "object" && typeof v.file === "string" ? v.file : undefined;
|
|
1525
|
+
return {
|
|
1526
|
+
light,
|
|
1527
|
+
aux,
|
|
1528
|
+
direct: stringArray(m.direct) ?? undefined,
|
|
1529
|
+
indirect: stringArray(m.indirect) ?? undefined,
|
|
1530
|
+
probes: file(m.probes),
|
|
1531
|
+
volume: file(m.volume),
|
|
1532
|
+
uv1: file(m.uv1)
|
|
1533
|
+
};
|
|
1534
|
+
}, expandBakeMacros = async (src, filePath, exists, read) => {
|
|
1535
|
+
if (!hasBakeMacro(src))
|
|
1536
|
+
return { src, bakes: [] };
|
|
1537
|
+
const strings = [];
|
|
1538
|
+
const mask = maskNonCode(src, (s, e) => {
|
|
1539
|
+
strings.push([s, e]);
|
|
1540
|
+
});
|
|
1541
|
+
if (DECLARES_BAKE.test(mask))
|
|
1542
|
+
return { src, bakes: [] };
|
|
1543
|
+
const stringsIn = ([a, b]) => strings.filter(([s, e]) => s >= a && e <= b);
|
|
1544
|
+
const blankArg = (span) => mask.slice(span[0], span[1]).trim() === "" && stringsIn(span).length === 0;
|
|
1545
|
+
const literalOf = (span) => {
|
|
1546
|
+
const inside = stringsIn(span);
|
|
1547
|
+
if (inside.length === 1 && mask.slice(span[0], span[1]).trim() === "")
|
|
1548
|
+
return src.slice(inside[0][0], inside[0][1]);
|
|
1549
|
+
return src.slice(span[0], span[1]).trim();
|
|
1550
|
+
};
|
|
1551
|
+
const dir = filePath.slice(0, filePath.lastIndexOf("/"));
|
|
1552
|
+
const at = (index) => `${filePath.replace(/^\//, "")}:${newlines(src.slice(0, index)) + 1}`;
|
|
1553
|
+
const bakes = [];
|
|
1554
|
+
const parts = [];
|
|
1555
|
+
let done = 0;
|
|
1556
|
+
for (const m of mask.matchAll(BAKE_CALL)) {
|
|
1557
|
+
const start = m.index ?? 0;
|
|
1558
|
+
if (start < done)
|
|
1559
|
+
continue;
|
|
1560
|
+
const open = start + m[0].length - 1;
|
|
1561
|
+
const close = closeOf(mask, open);
|
|
1562
|
+
if (close < 0)
|
|
1563
|
+
throw new Error(`bake(): unclosed call (${at(start)})`);
|
|
1564
|
+
const spans = argSpans(mask, open, close);
|
|
1565
|
+
const pathText = literalOf(spans[0]);
|
|
1566
|
+
const written = stringLiteralValue2(pathText);
|
|
1567
|
+
if (written === null && DEFINITION_TAIL.test(mask.slice(close + 1, close + 160)))
|
|
1568
|
+
continue;
|
|
1569
|
+
if (written === null)
|
|
1570
|
+
throw new Error(`bake() expects a string-literal path like bake('./assets/lightmap/level.bake'), found \`${pathText || "()"}\` (${at(start)})`);
|
|
1571
|
+
if (!/\.bake$/i.test(written))
|
|
1572
|
+
throw new Error(`bake('${written}'): the path names a .bake file — what \`lecodes lightmap bake\` writes (${at(start)})`);
|
|
1573
|
+
if (spans.slice(2).some((s) => !blankArg(s)))
|
|
1574
|
+
throw new Error(`bake('${written}'): one path and one options object at most (${at(start)})`);
|
|
1575
|
+
let options = null;
|
|
1576
|
+
if (spans.length > 1 && !blankArg(spans[1])) {
|
|
1577
|
+
const [a, b] = spans[1];
|
|
1578
|
+
const code = mask.slice(a, b);
|
|
1579
|
+
const lead = a + (code.length - code.trimStart().length);
|
|
1580
|
+
const tail = b - (code.length - code.trimEnd().length);
|
|
1581
|
+
if (mask[lead] !== "{" || closeOf(mask, lead) !== tail - 1) {
|
|
1582
|
+
throw new Error(`bake('${written}', options): options must be an object literal like { emissiveBake: false } (${at(start)})`);
|
|
1583
|
+
}
|
|
1584
|
+
options = [lead, tail];
|
|
1585
|
+
}
|
|
1586
|
+
const relative = written.startsWith("./") || written.startsWith("../");
|
|
1587
|
+
const rooted = written.startsWith("/");
|
|
1588
|
+
const candidates = rooted ? [normalizePath(written)] : relative ? [normalizePath(`${dir}/${written}`), normalizePath(written)] : [normalizePath(written), normalizePath(`${dir}/${written}`)];
|
|
1589
|
+
const found = candidates.find(exists);
|
|
1590
|
+
const target = found ?? candidates[0];
|
|
1591
|
+
const ref = { path: target.slice(1), exists: found !== undefined, line: newlines(src.slice(0, start)) + 1, written, missing: [] };
|
|
1592
|
+
let manifest = null;
|
|
1593
|
+
if (found !== undefined) {
|
|
1594
|
+
const body = read ? await read(found) : null;
|
|
1595
|
+
if (body === null)
|
|
1596
|
+
ref.unread = true;
|
|
1597
|
+
else {
|
|
1598
|
+
let json;
|
|
1599
|
+
try {
|
|
1600
|
+
json = JSON.parse(body.replace(/^\uFEFF/, ""));
|
|
1601
|
+
} catch (e) {
|
|
1602
|
+
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)})`);
|
|
1603
|
+
}
|
|
1604
|
+
manifest = readManifest2(json);
|
|
1605
|
+
if (!manifest)
|
|
1606
|
+
throw new Error(`bake('${written}'): ${ref.path} is not a bake manifest (no light / aux pages) — rebake with \`lecodes lightmap bake\` (${at(start)})`);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
const bakeDir = target.slice(0, target.lastIndexOf("/"));
|
|
1610
|
+
const ref1 = (name) => {
|
|
1611
|
+
const p = normalizePath(`${bakeDir}/${name}`);
|
|
1612
|
+
if (!exists(p) && !ref.missing.includes(p))
|
|
1613
|
+
ref.missing.push(p);
|
|
1614
|
+
return `asset(${JSON.stringify(p)})`;
|
|
1615
|
+
};
|
|
1616
|
+
const list = (names) => `[${names.map(ref1).join(", ")}]`;
|
|
1617
|
+
const fields = [`path: \`${escapeTemplate(ref.path)}\``];
|
|
1618
|
+
if (manifest) {
|
|
1619
|
+
fields.unshift(`data: asset(${JSON.stringify(target)})`);
|
|
1620
|
+
fields.push(`light: ${list(manifest.light)}`, `aux: ${list(manifest.aux)}`);
|
|
1621
|
+
if (manifest.direct)
|
|
1622
|
+
fields.push(`direct: ${list(manifest.direct)}`);
|
|
1623
|
+
if (manifest.indirect)
|
|
1624
|
+
fields.push(`indirect: ${list(manifest.indirect)}`);
|
|
1625
|
+
if (manifest.probes)
|
|
1626
|
+
fields.push(`probes: ${ref1(manifest.probes)}`);
|
|
1627
|
+
if (manifest.volume)
|
|
1628
|
+
fields.push(`volume: ${ref1(manifest.volume)}`);
|
|
1629
|
+
if (manifest.uv1)
|
|
1630
|
+
fields.push(`uv1: ${ref1(manifest.uv1)}`);
|
|
1631
|
+
} else {
|
|
1632
|
+
fields.unshift("data: null");
|
|
1633
|
+
fields.push("light: []", "aux: []");
|
|
1634
|
+
}
|
|
1635
|
+
const head = `{ ${fields.join(", ")}`;
|
|
1636
|
+
const expansion = options ? `${head}, ${`
|
|
1637
|
+
`.repeat(newlines(src.slice(start, options[0])))}...${src.slice(options[0], options[1])}${`
|
|
1638
|
+
`.repeat(newlines(src.slice(options[1], close + 1)))} }` : `${head}${`
|
|
1639
|
+
`.repeat(newlines(src.slice(start, close + 1)))} }`;
|
|
1640
|
+
parts.push(src.slice(done, start), expansion);
|
|
1641
|
+
done = close + 1;
|
|
1642
|
+
bakes.push(ref);
|
|
1643
|
+
}
|
|
1644
|
+
if (bakes.length === 0)
|
|
1645
|
+
return { src, bakes };
|
|
1646
|
+
parts.push(src.slice(done));
|
|
1647
|
+
return { src: parts.join(""), bakes };
|
|
1648
|
+
};
|
|
1649
|
+
var init_bakeMacro = __esm(() => {
|
|
1650
|
+
init_assetMacro();
|
|
1651
|
+
init_assetIconMacro();
|
|
1652
|
+
BAKE_CALL = /(?<![.\w$])bake\s*\(/g;
|
|
1653
|
+
DECLARES_BAKE = /\b(?:function|const|let|var|class)\s+bake\b|\bimport\s+(?:\{[^}]*\bbake\b[^}]*\}|bake)\s+from\b/;
|
|
1654
|
+
DEFINITION_TAIL = /^\s*(?::[^;{}=()\n]*)?(?:\{|=>)/;
|
|
1655
|
+
});
|
|
1656
|
+
|
|
1149
1657
|
// ../../sdk/src/compile/detectEntry.ts
|
|
1150
1658
|
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
1659
|
const parts = [];
|
|
@@ -1242,7 +1750,7 @@ var HEAD_RE, hasAspectExtends = (src) => /\bextends\s+(?:Aspect|System)\s*</.tes
|
|
|
1242
1750
|
for (;i < src.length && angle > 0; i++) {
|
|
1243
1751
|
const c = src[i];
|
|
1244
1752
|
if (c === '"' || c === "'" || c === "`") {
|
|
1245
|
-
i =
|
|
1753
|
+
i = skipString2(src, i) - 1;
|
|
1246
1754
|
continue;
|
|
1247
1755
|
}
|
|
1248
1756
|
if (c === "=" && src[i + 1] === ">") {
|
|
@@ -1269,7 +1777,7 @@ var HEAD_RE, hasAspectExtends = (src) => /\bextends\s+(?:Aspect|System)\s*</.tes
|
|
|
1269
1777
|
return -1;
|
|
1270
1778
|
}
|
|
1271
1779
|
return -1;
|
|
1272
|
-
},
|
|
1780
|
+
}, skipString2 = (src, at) => {
|
|
1273
1781
|
const q = src[at];
|
|
1274
1782
|
let i = at + 1;
|
|
1275
1783
|
for (;i < src.length; i++) {
|
|
@@ -1646,11 +2154,13 @@ var resolveInject = () => {
|
|
|
1646
2154
|
if (missing.length > 0)
|
|
1647
2155
|
throw new Error(missing.join(`
|
|
1648
2156
|
`));
|
|
1649
|
-
}, bundleProjectChisel = async (entrypoint, files, format, sourcemap, minifyOverride, editor, libraries, inject = CLIENT_INJECT) => {
|
|
2157
|
+
}, bundleProjectChisel = async (entrypoint, files, format, sourcemap, minifyOverride, editor, libraries, inject = CLIENT_INJECT, readResource) => {
|
|
1650
2158
|
const entry = normalize2(entrypoint);
|
|
1651
2159
|
const slugs = new Set(Object.keys(libraries ?? {}));
|
|
2160
|
+
const rootKeys = new Map(Object.keys(files).map((k) => [normalize2(k), k]));
|
|
1652
2161
|
const projFiles = {};
|
|
1653
2162
|
const assetRefs = [];
|
|
2163
|
+
const bakeRefs = [];
|
|
1654
2164
|
const scanSources = {};
|
|
1655
2165
|
for (const [k, v] of Object.entries(files)) {
|
|
1656
2166
|
const path = normalize2(k);
|
|
@@ -1659,6 +2169,12 @@ var resolveInject = () => {
|
|
|
1659
2169
|
if (hasImportStatement(src))
|
|
1660
2170
|
src = rewriteLibraryImports(src, slugs);
|
|
1661
2171
|
scanSources[path] = src;
|
|
2172
|
+
if (hasBakeMacro(src)) {
|
|
2173
|
+
const expanded = await expandBakeMacros(src, path, (rootPath) => rootKeys.has(rootPath), readResource);
|
|
2174
|
+
for (const ref of expanded.bakes)
|
|
2175
|
+
bakeRefs.push({ file: path, ref });
|
|
2176
|
+
src = expanded.src;
|
|
2177
|
+
}
|
|
1662
2178
|
const macros = hasAssetMacro(src) ? collectAssetMacros(src, path) : [];
|
|
1663
2179
|
const paths = collectPathLiterals(src, path, (rootPath) => files[rootPath] !== undefined, macros);
|
|
1664
2180
|
const found = macros.concat(paths).sort((a, b) => a.index - b.index);
|
|
@@ -1692,8 +2208,22 @@ var resolveInject = () => {
|
|
|
1692
2208
|
projFiles[path] = src;
|
|
1693
2209
|
}
|
|
1694
2210
|
}
|
|
1695
|
-
|
|
2211
|
+
const bakes = [];
|
|
2212
|
+
const notes = [];
|
|
2213
|
+
if (assetRefs.length > 0 || bakeRefs.length > 0) {
|
|
1696
2214
|
const reachable = reachableFrom(entry, scanSources);
|
|
2215
|
+
const reached = bakeRefs.filter(({ file }) => reachable.has(file));
|
|
2216
|
+
const incomplete = reached.filter(({ ref }) => ref.missing.length > 0);
|
|
2217
|
+
if (incomplete.length > 0) {
|
|
2218
|
+
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(`
|
|
2219
|
+
`));
|
|
2220
|
+
}
|
|
2221
|
+
for (const { file, ref } of reached) {
|
|
2222
|
+
if (!bakes.some((b) => b.path === ref.path))
|
|
2223
|
+
bakes.push({ path: ref.path, exists: ref.exists });
|
|
2224
|
+
if (ref.unread)
|
|
2225
|
+
notes.push(`${file.replace(/^\//, "")}:${ref.line}: bake('${ref.written}'): this compile cannot read ${ref.path} — the level runs unbaked`);
|
|
2226
|
+
}
|
|
1697
2227
|
assertAssetsExist(assetRefs.filter(({ file }) => reachable.has(file)), projFiles);
|
|
1698
2228
|
}
|
|
1699
2229
|
const sdkFiles = collectSdkFiles(resolveSdkSrc());
|
|
@@ -1727,13 +2257,14 @@ var resolveInject = () => {
|
|
|
1727
2257
|
throw new Error(`chisel: ${parsed.error}`);
|
|
1728
2258
|
if (parsed.code == null)
|
|
1729
2259
|
throw new Error("chisel produced no code");
|
|
1730
|
-
const diagnostics = parsed.diagnostics ?? [];
|
|
2260
|
+
const diagnostics = [...notes, ...parsed.diagnostics ?? []];
|
|
1731
2261
|
for (const d of diagnostics)
|
|
1732
2262
|
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);
|
|
2263
|
+
return { code: parsed.code, map: parsed.map ?? null, diagnostics, bakes };
|
|
2264
|
+
}, bundleProjectWithMap = async (entrypoint, files, format = "esm", minify, editor, libraries, sourcemap = true, inject, readResource) => bundleProjectChisel(entrypoint, files, format, sourcemap, minify, editor, libraries, inject, readResource);
|
|
1735
2265
|
var init_bundler = __esm(() => {
|
|
1736
2266
|
init_assetMacro();
|
|
2267
|
+
init_bakeMacro();
|
|
1737
2268
|
init_detectEntry();
|
|
1738
2269
|
init_aspectMacro();
|
|
1739
2270
|
init_libraryImports();
|
|
@@ -170839,6 +171370,18 @@ var init_shaderSchema = __esm(() => {
|
|
|
170839
171370
|
COLOR_NAME = /colou?r|tint|albedo|emissive|glare|glow/i;
|
|
170840
171371
|
});
|
|
170841
171372
|
|
|
171373
|
+
// ../../sdk/src/compile/sourcemap.ts
|
|
171374
|
+
var offsetSourceMap = (mapJson, lines) => {
|
|
171375
|
+
if (lines <= 0)
|
|
171376
|
+
return mapJson;
|
|
171377
|
+
const map = JSON.parse(mapJson);
|
|
171378
|
+
map.mappings = ";".repeat(lines) + map.mappings;
|
|
171379
|
+
return JSON.stringify(map);
|
|
171380
|
+
}, inlineSourceMapComment = (mapJson) => {
|
|
171381
|
+
const b64 = Buffer.from(mapJson, "utf8").toString("base64");
|
|
171382
|
+
return `//# lecodesMap=data:application/json;charset=utf-8;base64,${b64}`;
|
|
171383
|
+
};
|
|
171384
|
+
|
|
170842
171385
|
// ../../sdk/src/compile/header.ts
|
|
170843
171386
|
var ENGINE_SIGNALS, buildHeader = (name, code, opts = {}) => {
|
|
170844
171387
|
let header = `// sdk: ${SDK_VERSION}
|
|
@@ -170904,333 +171447,6 @@ var init_header = __esm(() => {
|
|
|
170904
171447
|
];
|
|
170905
171448
|
});
|
|
170906
171449
|
|
|
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
171450
|
// ../../sdk/src/compile/compileProject.ts
|
|
171235
171451
|
var localAssetBase = (path) => path.split(/[\\/]/).pop() ?? path, localAssetNames = (entries) => {
|
|
171236
171452
|
const seen = new Map;
|
|
@@ -171328,7 +171544,7 @@ var localAssetBase = (path) => path.split(/[\\/]/).pop() ?? path, localAssetName
|
|
|
171328
171544
|
throw new Error("Couldn't find an entrypoint (no .ts/.js project file — name yours main.ts). Pass entryOverride.");
|
|
171329
171545
|
}
|
|
171330
171546
|
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);
|
|
171547
|
+
const { code, map, bakes } = await bundleProjectWithMap(entry, files, opts.format ?? "esm", opts.minify, opts.editor, opts.libraries, opts.sourcemap ?? true, undefined, opts.readResource);
|
|
171332
171548
|
const plugins = opts.plugins ?? pluginsOfAppJson(entries);
|
|
171333
171549
|
if (map && opts.onWarning) {
|
|
171334
171550
|
const missing = pluginsOfBundle(map).filter((id) => !plugins.includes(id));
|
|
@@ -171337,14 +171553,10 @@ var localAssetBase = (path) => path.split(/[\\/]/).pop() ?? path, localAssetName
|
|
|
171337
171553
|
}
|
|
171338
171554
|
}
|
|
171339
171555
|
if (opts.header === false)
|
|
171340
|
-
return { code, map, entry };
|
|
171556
|
+
return { code, map, entry, bakes };
|
|
171341
171557
|
const header = buildHeader(opts.name, code, { icon: opts.icon, fonts: opts.fontsHeader, icons: opts.iconsHeader, plugins });
|
|
171342
171558
|
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;
|
|
171559
|
+
return { code: header + code, map: map ? offsetSourceMap(map, headerLines) : null, entry, bakes };
|
|
171348
171560
|
};
|
|
171349
171561
|
var init_compileProject = __esm(() => {
|
|
171350
171562
|
init_bundler();
|
|
@@ -171811,7 +172023,7 @@ var FONT_ID, CODE_FILE, DECLARES_FONT, isIdentStart2 = (c) => c >= "A" && c <= "
|
|
|
171811
172023
|
}
|
|
171812
172024
|
parts.push(text.slice(last));
|
|
171813
172025
|
return parts;
|
|
171814
|
-
},
|
|
172026
|
+
}, stringLiteralValue3 = (text) => {
|
|
171815
172027
|
const t = text.trim();
|
|
171816
172028
|
if (t.length < 2)
|
|
171817
172029
|
return null;
|
|
@@ -171883,7 +172095,7 @@ var FONT_ID, CODE_FILE, DECLARES_FONT, isIdentStart2 = (c) => c >= "A" && c <= "
|
|
|
171883
172095
|
return null;
|
|
171884
172096
|
const call = { start, end: close + 1, arg: "", kind: "registry" };
|
|
171885
172097
|
const args = splitTopLevel2(src.slice(i + 1, close), ",");
|
|
171886
|
-
const arg =
|
|
172098
|
+
const arg = stringLiteralValue3(args[0] ?? "");
|
|
171887
172099
|
if (arg === null) {
|
|
171888
172100
|
call.error = `font(...) needs a string-literal argument — a registry id ("manrope") or a project path ("./fonts/Brand.ttf"). Got \`${(args[0] ?? "").trim() || "()"}\`.`;
|
|
171889
172101
|
return call;
|
|
@@ -172138,7 +172350,7 @@ var init_compile = __esm(() => {
|
|
|
172138
172350
|
});
|
|
172139
172351
|
|
|
172140
172352
|
// src/compile/projectCompile.ts
|
|
172141
|
-
import { existsSync as existsSync6 } from "node:fs";
|
|
172353
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
|
|
172142
172354
|
import { createRequire as createRequire4 } from "node:module";
|
|
172143
172355
|
import { dirname as dirname6, join as join7 } from "node:path";
|
|
172144
172356
|
var resolveSdkInject = () => {
|
|
@@ -172162,22 +172374,39 @@ var resolveSdkInject = () => {
|
|
|
172162
172374
|
if (!entry || roots.length < 2 || roots.includes(ENTRY_CONVENTION))
|
|
172163
172375
|
return null;
|
|
172164
172376
|
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
|
-
|
|
172377
|
+
}, resourceReader = (entries) => {
|
|
172378
|
+
const byRoot = new Map(entries.map((e) => ["/" + e.path.replace(/\\/g, "/").replace(/^[./]+/, ""), e]));
|
|
172379
|
+
return (rootPath) => {
|
|
172380
|
+
const e = byRoot.get(rootPath);
|
|
172381
|
+
if (e?.text !== undefined)
|
|
172382
|
+
return e.text;
|
|
172383
|
+
try {
|
|
172384
|
+
return e?.absPath ? readFileSync5(e.absPath, "utf8") : null;
|
|
172385
|
+
} catch {
|
|
172386
|
+
return null;
|
|
172387
|
+
}
|
|
172388
|
+
};
|
|
172389
|
+
}, compileProjectBundle = async (opts) => {
|
|
172390
|
+
const { code, map, bakes } = await compileProjectWithMap({
|
|
172391
|
+
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 })),
|
|
172392
|
+
readResource: resourceReader(opts.entries),
|
|
172393
|
+
name: opts.name,
|
|
172394
|
+
publicUrl: opts.publicUrl,
|
|
172395
|
+
entryOverride: opts.entryOverride,
|
|
172396
|
+
header: opts.header,
|
|
172397
|
+
fontsHeader: opts.fontsHeader,
|
|
172398
|
+
iconsHeader: opts.iconsHeader,
|
|
172399
|
+
format: opts.format,
|
|
172400
|
+
localAssets: opts.localAssets,
|
|
172401
|
+
minify: opts.minify,
|
|
172402
|
+
sourcemap: opts.sourcemap,
|
|
172403
|
+
editor: opts.editor,
|
|
172404
|
+
onWarning: opts.onWarning,
|
|
172405
|
+
serverUrl: opts.serverUrl
|
|
172406
|
+
});
|
|
172407
|
+
return { js: map ? `${code}
|
|
172408
|
+
${inlineSourceMapComment(map)}` : code, bakes };
|
|
172409
|
+
}, compileProject2 = async (opts) => (await compileProjectBundle(opts)).js, hasServerFiles = (entries) => entries.some((e) => e.type === "text" && isServerPath(e.path)), findTypescript = async (root) => {
|
|
172181
172410
|
const api = (mod) => mod?.createProgram ? mod : mod?.default?.createProgram ? mod.default : null;
|
|
172182
172411
|
const from = (at) => {
|
|
172183
172412
|
try {
|
|
@@ -172397,7 +172626,7 @@ var init_paths = __esm(() => {
|
|
|
172397
172626
|
});
|
|
172398
172627
|
|
|
172399
172628
|
// src/project/ignore.ts
|
|
172400
|
-
import { existsSync as existsSync9, readFileSync as
|
|
172629
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
|
|
172401
172630
|
import { join as join10 } from "node:path";
|
|
172402
172631
|
var BUILTIN_PATTERNS, DEFAULT_IGNORE_FILE = `# Files matched here are NOT pushed to LeCodes.
|
|
172403
172632
|
# Only untracked files are affected — assets already in the project stay tracked
|
|
@@ -172482,7 +172711,7 @@ design/comments/
|
|
|
172482
172711
|
const file = join10(root, ".lecodesignore");
|
|
172483
172712
|
if (existsSync9(file)) {
|
|
172484
172713
|
try {
|
|
172485
|
-
lines.push(...
|
|
172714
|
+
lines.push(...readFileSync8(file, "utf8").split(/\r?\n/));
|
|
172486
172715
|
} catch {}
|
|
172487
172716
|
}
|
|
172488
172717
|
const rules = lines.map(compile).filter((r) => r !== null);
|
|
@@ -172510,7 +172739,7 @@ dist/
|
|
|
172510
172739
|
writeFileSync3(file, DEFAULT_GITIGNORE);
|
|
172511
172740
|
return "created";
|
|
172512
172741
|
}
|
|
172513
|
-
const text =
|
|
172742
|
+
const text = readFileSync8(file, "utf8");
|
|
172514
172743
|
const covered = text.split(/\r?\n/).some((l) => /^\/?\.lecodes\/?\s*$/.test(l.trim()));
|
|
172515
172744
|
if (covered)
|
|
172516
172745
|
return null;
|
|
@@ -172528,7 +172757,7 @@ var init_ignore = __esm(() => {
|
|
|
172528
172757
|
});
|
|
172529
172758
|
|
|
172530
172759
|
// src/project/localFiles.ts
|
|
172531
|
-
import { existsSync as existsSync10, readdirSync as readdirSync3, readFileSync as
|
|
172760
|
+
import { existsSync as existsSync10, readdirSync as readdirSync3, readFileSync as readFileSync9 } from "node:fs";
|
|
172532
172761
|
import { basename, dirname as dirname7, join as join11, relative as relative3 } from "node:path";
|
|
172533
172762
|
var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
172534
172763
|
const i = name.lastIndexOf(".");
|
|
@@ -172547,7 +172776,7 @@ var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
|
172547
172776
|
continue;
|
|
172548
172777
|
let folder;
|
|
172549
172778
|
try {
|
|
172550
|
-
folder = JSON.parse(
|
|
172779
|
+
folder = JSON.parse(readFileSync9(file.absPath, "utf8").replace(/^\uFEFF/, "")).web?.static;
|
|
172551
172780
|
} catch {
|
|
172552
172781
|
continue;
|
|
172553
172782
|
}
|
|
@@ -172595,7 +172824,7 @@ var SKIP_DIRS, SKIP_FILES, TEXT_EXTS, ext = (name) => {
|
|
|
172595
172824
|
ignored.push(key);
|
|
172596
172825
|
continue;
|
|
172597
172826
|
}
|
|
172598
|
-
found.push({ path: key, absPath: abs, sha: sha256(
|
|
172827
|
+
found.push({ path: key, absPath: abs, sha: sha256(readFileSync9(abs)) });
|
|
172599
172828
|
}
|
|
172600
172829
|
}
|
|
172601
172830
|
};
|
|
@@ -172676,7 +172905,7 @@ var init_localFiles = __esm(() => {
|
|
|
172676
172905
|
|
|
172677
172906
|
// src/compile/fonts.ts
|
|
172678
172907
|
import { createHash as createHash2 } from "node:crypto";
|
|
172679
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as
|
|
172908
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "node:fs";
|
|
172680
172909
|
import { dirname as dirname9, join as join13 } from "node:path";
|
|
172681
172910
|
var applyProjectFonts = async (entries, opts) => {
|
|
172682
172911
|
const registry = (opts.registry ?? fontRegistryBase()).replace(/\/+$/, "");
|
|
@@ -172688,7 +172917,7 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172688
172917
|
const entry = byPath().get(entryPath);
|
|
172689
172918
|
const abs = entry?.absPath ?? join13(opts.root, entryPath);
|
|
172690
172919
|
try {
|
|
172691
|
-
return new Uint8Array(
|
|
172920
|
+
return new Uint8Array(readFileSync12(abs));
|
|
172692
172921
|
} catch {
|
|
172693
172922
|
return null;
|
|
172694
172923
|
}
|
|
@@ -172720,13 +172949,13 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172720
172949
|
return res.ok ? new Uint8Array(await res.arrayBuffer()) : null;
|
|
172721
172950
|
}
|
|
172722
172951
|
try {
|
|
172723
|
-
return new Uint8Array(
|
|
172952
|
+
return new Uint8Array(readFileSync12(join13(registry, rel)));
|
|
172724
172953
|
} catch {
|
|
172725
172954
|
return null;
|
|
172726
172955
|
}
|
|
172727
172956
|
}, readLock = (path) => {
|
|
172728
172957
|
try {
|
|
172729
|
-
const lock = JSON.parse(
|
|
172958
|
+
const lock = JSON.parse(readFileSync12(path, "utf8"));
|
|
172730
172959
|
if (lock && typeof lock === "object" && lock.faces && lock.families)
|
|
172731
172960
|
return lock;
|
|
172732
172961
|
} catch {}
|
|
@@ -172758,7 +172987,7 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
172758
172987
|
`);
|
|
172759
172988
|
}, writeIfChanged = (path, text) => {
|
|
172760
172989
|
try {
|
|
172761
|
-
if (
|
|
172990
|
+
if (readFileSync12(path, "utf8") === text)
|
|
172762
172991
|
return;
|
|
172763
172992
|
} catch {}
|
|
172764
172993
|
writeFileSync5(path, text);
|
|
@@ -172789,7 +173018,7 @@ var init_fonts = __esm(() => {
|
|
|
172789
173018
|
|
|
172790
173019
|
// src/compile/assetIcons.ts
|
|
172791
173020
|
import { createHash as createHash5 } from "node:crypto";
|
|
172792
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as
|
|
173021
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
172793
173022
|
import { homedir as homedir4 } from "node:os";
|
|
172794
173023
|
import { dirname as dirname10, join as join17 } from "node:path";
|
|
172795
173024
|
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 +173031,13 @@ var DEFAULT_REGISTRY, isHttp2 = (s) => /^https?:/i.test(s), sha122 = (s) => crea
|
|
|
172802
173031
|
}
|
|
172803
173032
|
}
|
|
172804
173033
|
try {
|
|
172805
|
-
return
|
|
173034
|
+
return readFileSync15(join17(registry, rel), "utf8");
|
|
172806
173035
|
} catch {
|
|
172807
173036
|
return null;
|
|
172808
173037
|
}
|
|
172809
173038
|
}, safeRead = (path) => {
|
|
172810
173039
|
try {
|
|
172811
|
-
return
|
|
173040
|
+
return readFileSync15(path, "utf8");
|
|
172812
173041
|
} catch {
|
|
172813
173042
|
return null;
|
|
172814
173043
|
}
|
|
@@ -172830,7 +173059,7 @@ var DEFAULT_REGISTRY, isHttp2 = (s) => /^https?:/i.test(s), sha122 = (s) => crea
|
|
|
172830
173059
|
return JSON.parse(raw);
|
|
172831
173060
|
}, readLock2 = (path) => {
|
|
172832
173061
|
try {
|
|
172833
|
-
const lock = JSON.parse(
|
|
173062
|
+
const lock = JSON.parse(readFileSync15(path, "utf8"));
|
|
172834
173063
|
if (lock && typeof lock === "object" && lock.icons && lock.packs)
|
|
172835
173064
|
return lock;
|
|
172836
173065
|
} catch {}
|
|
@@ -172937,11 +173166,11 @@ var init_assetIcons = __esm(() => {
|
|
|
172937
173166
|
// src/platform/config.ts
|
|
172938
173167
|
import { homedir as homedir5 } from "node:os";
|
|
172939
173168
|
import { join as join18 } from "node:path";
|
|
172940
|
-
import { mkdirSync as mkdirSync8, readFileSync as
|
|
173169
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
|
|
172941
173170
|
var DEFAULT_API = "https://le.codes", CONFIG_DIR, CONFIG_FILE, loadConfig = () => {
|
|
172942
173171
|
let stored = {};
|
|
172943
173172
|
try {
|
|
172944
|
-
stored = JSON.parse(
|
|
173173
|
+
stored = JSON.parse(readFileSync16(CONFIG_FILE, "utf8"));
|
|
172945
173174
|
} catch {}
|
|
172946
173175
|
return {
|
|
172947
173176
|
apiUrl: process.env.LECODES_API ?? stored.apiUrl,
|
|
@@ -206398,7 +206627,7 @@ var init_esm29 = __esm(() => {
|
|
|
206398
206627
|
|
|
206399
206628
|
// src/project/types.ts
|
|
206400
206629
|
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
|
|
206630
|
+
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
206631
|
import { createRequire as createRequire5 } from "node:module";
|
|
206403
206632
|
var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
206404
206633
|
if (!existsSync27(dir))
|
|
@@ -206427,7 +206656,7 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
206427
206656
|
const dest = join29(typesDir, path);
|
|
206428
206657
|
if (!before.has(path))
|
|
206429
206658
|
stats.added++;
|
|
206430
|
-
else if (
|
|
206659
|
+
else if (readFileSync25(dest, "utf8") !== text)
|
|
206431
206660
|
stats.updated++;
|
|
206432
206661
|
else
|
|
206433
206662
|
continue;
|
|
@@ -206446,7 +206675,7 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
206446
206675
|
const typesDir = join29(root, LECODES_DIR, "types");
|
|
206447
206676
|
const bundle = {};
|
|
206448
206677
|
for (const path of listBundleFiles(typesDir))
|
|
206449
|
-
bundle[path] =
|
|
206678
|
+
bundle[path] = readFileSync25(join29(typesDir, path), "utf8");
|
|
206450
206679
|
return bundle;
|
|
206451
206680
|
}, materializeTypes = async (root, apiUrl) => writeTypeBundle(root, await getTypes(apiUrl)), readLocalTypeBundle = () => {
|
|
206452
206681
|
const fromPackage = (() => {
|
|
@@ -206464,7 +206693,7 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
206464
206693
|
for (const path of candidates) {
|
|
206465
206694
|
if (existsSync27(path)) {
|
|
206466
206695
|
try {
|
|
206467
|
-
return JSON.parse(
|
|
206696
|
+
return JSON.parse(readFileSync25(path, "utf8"));
|
|
206468
206697
|
} catch {}
|
|
206469
206698
|
}
|
|
206470
206699
|
}
|
|
@@ -206502,7 +206731,7 @@ var init_types4 = __esm(() => {
|
|
|
206502
206731
|
});
|
|
206503
206732
|
|
|
206504
206733
|
// src/compile/designCompile.ts
|
|
206505
|
-
import { readFileSync as
|
|
206734
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
206506
206735
|
var LOCAL_ASSET_SCHEME = "lecodesfile://", compileDesignScreen = async (opts) => {
|
|
206507
206736
|
const { root, manifest, designDir, designKey, screenId, state } = opts;
|
|
206508
206737
|
const entries = [];
|
|
@@ -206519,7 +206748,7 @@ var LOCAL_ASSET_SCHEME = "lecodesfile://", compileDesignScreen = async (opts) =>
|
|
|
206519
206748
|
} else if (type === "shader") {
|
|
206520
206749
|
entries.push({ path: file.path, type, shaders: [] });
|
|
206521
206750
|
} else {
|
|
206522
|
-
entries.push({ path: file.path, type, text:
|
|
206751
|
+
entries.push({ path: file.path, type, text: readFileSync26(file.absPath, "utf8") });
|
|
206523
206752
|
}
|
|
206524
206753
|
}
|
|
206525
206754
|
const invoke = state !== undefined ? `screen(${JSON.stringify(state)})` : "screen()";
|
|
@@ -206641,11 +206870,11 @@ var init_browserAuth = __esm(() => {
|
|
|
206641
206870
|
});
|
|
206642
206871
|
|
|
206643
206872
|
// src/project/designMeta.ts
|
|
206644
|
-
import { readFileSync as
|
|
206873
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
206645
206874
|
import { join as join31 } from "node:path";
|
|
206646
206875
|
var PHONE_SIZE, readMetaFrames = (designDir) => {
|
|
206647
206876
|
try {
|
|
206648
|
-
const meta = JSON.parse(
|
|
206877
|
+
const meta = JSON.parse(readFileSync27(join31(designDir, "meta.json"), "utf8"));
|
|
206649
206878
|
const d = meta?.defaultSize;
|
|
206650
206879
|
const valid = Array.isArray(d) && d.length === 2 && d.every((n) => typeof n === "number" && Number.isFinite(n) && n >= 64 && n <= 8192);
|
|
206651
206880
|
return {
|
|
@@ -206996,7 +207225,7 @@ var init_comments = __esm(() => {
|
|
|
206996
207225
|
});
|
|
206997
207226
|
|
|
206998
207227
|
// src/commands/design/snapshot.ts
|
|
206999
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync20, readdirSync as readdirSync15, readFileSync as
|
|
207228
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync20, readdirSync as readdirSync15, readFileSync as readFileSync28, writeFileSync as writeFileSync22 } from "node:fs";
|
|
207000
207229
|
import { join as join33 } from "node:path";
|
|
207001
207230
|
var listScreens = (designDir) => {
|
|
207002
207231
|
const dir = join33(designDir, "screens");
|
|
@@ -207068,7 +207297,7 @@ var init_snapshot = __esm(() => {
|
|
|
207068
207297
|
const [width, height] = frames.screens[id]?.size ?? frames.defaultSize;
|
|
207069
207298
|
let plan = [{ state: undefined, bases: [id] }];
|
|
207070
207299
|
if (discover) {
|
|
207071
|
-
const { states, canonical } = discover(
|
|
207300
|
+
const { states, canonical } = discover(readFileSync28(join33(ctx.designDir, "screens", `${id}.ts`), "utf8"));
|
|
207072
207301
|
if (stateFlag !== undefined) {
|
|
207073
207302
|
if (!states.includes(stateFlag)) {
|
|
207074
207303
|
if (args.length === 1)
|
|
@@ -207598,7 +207827,7 @@ var init_templates2 = __esm(() => {
|
|
|
207598
207827
|
});
|
|
207599
207828
|
|
|
207600
207829
|
// src/commands/design/index.ts
|
|
207601
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync21, readFileSync as
|
|
207830
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync21, readFileSync as readFileSync29, writeFileSync as writeFileSync23 } from "node:fs";
|
|
207602
207831
|
import { join as join34 } from "node:path";
|
|
207603
207832
|
var firstLine = (body, max = 64) => {
|
|
207604
207833
|
const line = body.split(`
|
|
@@ -207673,7 +207902,7 @@ var firstLine = (body, max = 64) => {
|
|
|
207673
207902
|
let config = {};
|
|
207674
207903
|
if (existsSync33(path)) {
|
|
207675
207904
|
try {
|
|
207676
|
-
config = JSON.parse(
|
|
207905
|
+
config = JSON.parse(readFileSync29(path, "utf8"));
|
|
207677
207906
|
} catch {
|
|
207678
207907
|
warnErr(".mcp.json exists but isn't valid JSON — left it untouched. Add the lecodes-design server by hand.");
|
|
207679
207908
|
return;
|
|
@@ -207753,7 +207982,7 @@ var init_design = __esm(() => {
|
|
|
207753
207982
|
}
|
|
207754
207983
|
const ignorePath = join34(ctx.root, ".lecodesignore");
|
|
207755
207984
|
const ignoreLines = [`${ctx.dirName}/.snapshots/`, `${ctx.dirName}/comments/`];
|
|
207756
|
-
const current = existsSync33(ignorePath) ?
|
|
207985
|
+
const current = existsSync33(ignorePath) ? readFileSync29(ignorePath, "utf8") : "";
|
|
207757
207986
|
const present = new Set(current.split(/\r?\n/));
|
|
207758
207987
|
const missing = ignoreLines.filter((line) => !present.has(line));
|
|
207759
207988
|
if (missing.length) {
|
|
@@ -227112,17 +227341,17 @@ import { delimiter as delimiter3, dirname as dirname31, join as join63 } from "n
|
|
|
227112
227341
|
// src/commands/app/index.ts
|
|
227113
227342
|
init_manifest();
|
|
227114
227343
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
227115
|
-
import { cpSync as cpSync4, existsSync as existsSync25, mkdirSync as mkdirSync16, readFileSync as
|
|
227344
|
+
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
227345
|
import { homedir as homedir10 } from "node:os";
|
|
227117
227346
|
import { basename as basename10, dirname as dirname17, join as join27, resolve as resolve14 } from "node:path";
|
|
227118
227347
|
|
|
227119
227348
|
// src/plugin/manifest.ts
|
|
227120
|
-
import { existsSync as existsSync8, readFileSync as
|
|
227349
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7, statSync as statSync2 } from "node:fs";
|
|
227121
227350
|
import { isAbsolute as isAbsolute2, join as join9 } from "node:path";
|
|
227122
227351
|
|
|
227123
227352
|
// src/plugin/firstParty.ts
|
|
227124
227353
|
init_projectCompile();
|
|
227125
|
-
import { existsSync as existsSync7, readFileSync as
|
|
227354
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync2 } from "node:fs";
|
|
227126
227355
|
import { join as join8 } from "node:path";
|
|
227127
227356
|
var ID = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
227128
227357
|
var firstPartyContractFile = (id) => {
|
|
@@ -227137,7 +227366,7 @@ var firstPartyIds = () => {
|
|
|
227137
227366
|
const gen = join8(sdkSourceDir, "plugins", "gen");
|
|
227138
227367
|
return existsSync7(gen) ? readdirSync2(gen).filter((id) => existsSync7(join8(gen, id, "contract.d.ts"))).sort() : [];
|
|
227139
227368
|
};
|
|
227140
|
-
var firstPartyContractText = (file) =>
|
|
227369
|
+
var firstPartyContractText = (file) => readFileSync6(file, "utf8").replace(/from "(?:\.\.\/)+plugin"/g, `from "lecodes-sdk/plugin"`);
|
|
227141
227370
|
|
|
227142
227371
|
// src/plugin/manifest.ts
|
|
227143
227372
|
var MANIFEST_FILE = "lecodes-plugin.json";
|
|
@@ -227174,11 +227403,11 @@ var isFolder = (path) => existsSync8(path) && statSync2(path).isDirectory();
|
|
|
227174
227403
|
var pascal = (id) => id.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
227175
227404
|
var XCFRAMEWORK = ".xcframework";
|
|
227176
227405
|
var binaryName = (path) => path.split(/[\\/]/).pop().slice(0, -XCFRAMEWORK.length);
|
|
227177
|
-
var
|
|
227406
|
+
var readManifest3 = (dir, id) => {
|
|
227178
227407
|
const file = join9(dir, MANIFEST_FILE);
|
|
227179
227408
|
let raw;
|
|
227180
227409
|
try {
|
|
227181
|
-
raw = JSON.parse(
|
|
227410
|
+
raw = JSON.parse(readFileSync7(file, "utf8").replace(/^/, ""));
|
|
227182
227411
|
} catch (e) {
|
|
227183
227412
|
throw new ManifestError(file, [`not JSON: ${e instanceof Error ? e.message : String(e)}`]);
|
|
227184
227413
|
}
|
|
@@ -227346,7 +227575,7 @@ var readManifest2 = (dir, id) => {
|
|
|
227346
227575
|
throw new ManifestError(file, problems);
|
|
227347
227576
|
return raw;
|
|
227348
227577
|
};
|
|
227349
|
-
var readManifestIfAny = (dir, id) => existsSync8(join9(dir, MANIFEST_FILE)) ?
|
|
227578
|
+
var readManifestIfAny = (dir, id) => existsSync8(join9(dir, MANIFEST_FILE)) ? readManifest3(dir, id) : null;
|
|
227350
227579
|
|
|
227351
227580
|
// src/commands/compile.ts
|
|
227352
227581
|
init_api();
|
|
@@ -227357,7 +227586,7 @@ import { basename as basename6, resolve as resolve6 } from "node:path";
|
|
|
227357
227586
|
// src/compile/collect.ts
|
|
227358
227587
|
init_localFiles();
|
|
227359
227588
|
init_ignore();
|
|
227360
|
-
import { readFileSync as
|
|
227589
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
227361
227590
|
|
|
227362
227591
|
// src/project/materialize.ts
|
|
227363
227592
|
init_api();
|
|
@@ -227430,7 +227659,7 @@ var collectEntries = (root, manifest, project, opts = {}) => {
|
|
|
227430
227659
|
warnings.push(`No compiled shader for ${file.path} — push it to compile the shader.`);
|
|
227431
227660
|
entries.push({ path: file.path, type, shaders, absPath: file.absPath });
|
|
227432
227661
|
} else {
|
|
227433
|
-
entries.push({ path: file.path, type, text:
|
|
227662
|
+
entries.push({ path: file.path, type, text: readFileSync10(file.absPath, "utf8") });
|
|
227434
227663
|
}
|
|
227435
227664
|
}
|
|
227436
227665
|
return { entries, warnings };
|
|
@@ -227439,11 +227668,11 @@ var collectEntries = (root, manifest, project, opts = {}) => {
|
|
|
227439
227668
|
// src/compile/collectLocal.ts
|
|
227440
227669
|
init_localFiles();
|
|
227441
227670
|
init_ignore();
|
|
227442
|
-
import { readFileSync as
|
|
227671
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
227443
227672
|
import { basename as basename2 } from "node:path";
|
|
227444
227673
|
var isHalfManifest = (abs) => {
|
|
227445
227674
|
try {
|
|
227446
|
-
return typeof JSON.parse(
|
|
227675
|
+
return typeof JSON.parse(readFileSync11(abs, "utf8").replace(/^/, "")).implements === "string";
|
|
227447
227676
|
} catch {
|
|
227448
227677
|
return false;
|
|
227449
227678
|
}
|
|
@@ -227465,7 +227694,7 @@ var collectLocalEntries = (root, manifest, assetBase, opts = {}) => {
|
|
|
227465
227694
|
}
|
|
227466
227695
|
entries.push({ path: file.path, type, shaders: [], absPath: file.absPath });
|
|
227467
227696
|
} else {
|
|
227468
|
-
entries.push({ path: file.path, type, text:
|
|
227697
|
+
entries.push({ path: file.path, type, text: readFileSync11(file.absPath, "utf8") });
|
|
227469
227698
|
}
|
|
227470
227699
|
}
|
|
227471
227700
|
return { entries, warnings };
|
|
@@ -227479,7 +227708,7 @@ init_fonts();
|
|
|
227479
227708
|
init_compile();
|
|
227480
227709
|
import { execFile } from "node:child_process";
|
|
227481
227710
|
import { createHash as createHash4, randomBytes } from "node:crypto";
|
|
227482
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as
|
|
227711
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync14, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync7 } from "node:fs";
|
|
227483
227712
|
import { tmpdir } from "node:os";
|
|
227484
227713
|
import { basename as basename3, join as join16 } from "node:path";
|
|
227485
227714
|
|
|
@@ -227491,14 +227720,14 @@ import { join as join15, resolve as resolve4 } from "node:path";
|
|
|
227491
227720
|
// src/hosts/releases.ts
|
|
227492
227721
|
init_cli();
|
|
227493
227722
|
import { createHash as createHash3 } from "node:crypto";
|
|
227494
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync5, mkdtempSync, readFileSync as
|
|
227723
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, mkdtempSync, readFileSync as readFileSync13, renameSync, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
227495
227724
|
import { join as join14 } from "node:path";
|
|
227496
227725
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
227497
227726
|
var MANIFEST_URL = "https://storage.yandexcloud.net/le-codes/releases/versions.json";
|
|
227498
227727
|
var ARTIFACT_STAMP = ".lecodes-artifact.json";
|
|
227499
227728
|
var cachedArtifactSha = (dir) => {
|
|
227500
227729
|
try {
|
|
227501
|
-
return JSON.parse(
|
|
227730
|
+
return JSON.parse(readFileSync13(join14(dir, ARTIFACT_STAMP), "utf8")).sha256 ?? null;
|
|
227502
227731
|
} catch {
|
|
227503
227732
|
return null;
|
|
227504
227733
|
}
|
|
@@ -227729,7 +227958,7 @@ var applyLocalShaders = async (entries, opts) => {
|
|
|
227729
227958
|
mkdirSync6(cacheDir, { recursive: true });
|
|
227730
227959
|
const artifacts = [];
|
|
227731
227960
|
for (const entry of shaderEntries) {
|
|
227732
|
-
const text =
|
|
227961
|
+
const text = readFileSync14(entry.absPath, "utf8");
|
|
227733
227962
|
const hash = shaderHash(text, matcId);
|
|
227734
227963
|
const family = artifactFamily();
|
|
227735
227964
|
const artifact = (platform) => `${hash}_${platform}.filamat`;
|
|
@@ -227787,7 +228016,7 @@ init_config();
|
|
|
227787
228016
|
init_ignore();
|
|
227788
228017
|
init_cli();
|
|
227789
228018
|
import { execFileSync } from "node:child_process";
|
|
227790
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync5, readFileSync as
|
|
228019
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync5, readFileSync as readFileSync17, statSync as statSync4, writeFileSync as writeFileSync10 } from "node:fs";
|
|
227791
228020
|
import { homedir as homedir6 } from "node:os";
|
|
227792
228021
|
import { basename as basename4, dirname as dirname11, join as join19, resolve as resolve5 } from "node:path";
|
|
227793
228022
|
init_compile();
|
|
@@ -228036,7 +228265,7 @@ var readJson2 = (path) => {
|
|
|
228036
228265
|
if (!existsSync16(path))
|
|
228037
228266
|
return null;
|
|
228038
228267
|
try {
|
|
228039
|
-
return JSON.parse(
|
|
228268
|
+
return JSON.parse(readFileSync17(path, "utf8").replace(/^\uFEFF/, ""));
|
|
228040
228269
|
} catch {
|
|
228041
228270
|
throw new CliError(`Invalid JSON in ${path}`);
|
|
228042
228271
|
}
|
|
@@ -228068,7 +228297,7 @@ ${tail}`);
|
|
|
228068
228297
|
};
|
|
228069
228298
|
var ensureShellIgnored = (root, dir) => {
|
|
228070
228299
|
const ignorePath = join19(root, ".lecodesignore");
|
|
228071
|
-
const ignore = existsSync16(ignorePath) ?
|
|
228300
|
+
const ignore = existsSync16(ignorePath) ? readFileSync17(ignorePath, "utf8") : DEFAULT_IGNORE_FILE;
|
|
228072
228301
|
if (new RegExp(`^${dir}\\/$`, "m").test(ignore))
|
|
228073
228302
|
return;
|
|
228074
228303
|
const comment = ignore.includes("# Native app shells") ? "" : "# Native app shells — generated by `lecodes app init`, never pushed to LeCodes.\n";
|
|
@@ -228201,7 +228430,7 @@ var localPlugin = (root, id, spec) => {
|
|
|
228201
228430
|
if (!existsSync16(dir) || !statSync4(dir).isDirectory())
|
|
228202
228431
|
throw new CliError(`Plugin "${id}": ${spec} is not a folder (${dir})`);
|
|
228203
228432
|
const folder = basename4(dir);
|
|
228204
|
-
const manifest =
|
|
228433
|
+
const manifest = readManifest3(dir, folder);
|
|
228205
228434
|
if (manifest.implements ? manifest.implements !== id : folder !== id) {
|
|
228206
228435
|
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
228436
|
}
|
|
@@ -228212,7 +228441,7 @@ var localPluginKey = (root, spec) => {
|
|
|
228212
228441
|
const dir = resolve5(root, spec.startsWith("file:") ? spec.slice("file:".length) : spec);
|
|
228213
228442
|
if (!existsSync16(join19(dir, "lecodes-plugin.json")))
|
|
228214
228443
|
return basename4(dir);
|
|
228215
|
-
return
|
|
228444
|
+
return readManifest3(dir, basename4(dir)).implements ?? basename4(dir);
|
|
228216
228445
|
};
|
|
228217
228446
|
function resolvePlugin(id, entry, lock, platform, opts) {
|
|
228218
228447
|
const spec = pluginSpecOf(entry, platform);
|
|
@@ -228244,7 +228473,7 @@ function resolvePlugin(id, entry, lock, platform, opts) {
|
|
|
228244
228473
|
const dir = subdir ? join19(checkout.dir, subdir) : checkout.dir;
|
|
228245
228474
|
if (!existsSync16(join19(dir, "lecodes-plugin.json")))
|
|
228246
228475
|
throw new CliError(`Plugin "${id}": no lecodes-plugin.json in ${dir}`);
|
|
228247
|
-
const manifest =
|
|
228476
|
+
const manifest = readManifest3(dir, id);
|
|
228248
228477
|
fillManifestDefaults(manifest, id);
|
|
228249
228478
|
if (!manifest[platform]) {
|
|
228250
228479
|
if (opts?.optional)
|
|
@@ -228435,7 +228664,7 @@ var buildBundle = async (bundle, opts = {}) => {
|
|
|
228435
228664
|
warnErr(ambiguous);
|
|
228436
228665
|
}
|
|
228437
228666
|
const serverUrl = await opts.backend?.start(entries, (w) => warnings.push(w));
|
|
228438
|
-
const js = await
|
|
228667
|
+
const { js, bakes } = await compileProjectBundle({
|
|
228439
228668
|
entries,
|
|
228440
228669
|
name,
|
|
228441
228670
|
publicUrl,
|
|
@@ -228456,7 +228685,7 @@ var buildBundle = async (bundle, opts = {}) => {
|
|
|
228456
228685
|
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
228686
|
for (const artifact of stagedShaders)
|
|
228458
228687
|
resources.push({ path: artifact.name, name: artifact.name, absPath: artifact.absPath, remote: false, shader: true });
|
|
228459
|
-
return { js, resources };
|
|
228688
|
+
return { js, resources, bakes: bakes.map((b) => ({ path: b.path, absPath: resolve6(root, b.path), exists: b.exists })) };
|
|
228460
228689
|
};
|
|
228461
228690
|
|
|
228462
228691
|
// src/commands/app/index.ts
|
|
@@ -229431,13 +229660,13 @@ init_compile();
|
|
|
229431
229660
|
init_manifest();
|
|
229432
229661
|
import { execFileSync as execFileSync2, spawn, spawnSync as spawnSync5 } from "node:child_process";
|
|
229433
229662
|
import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
|
|
229434
|
-
import { chmodSync, cpSync, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as
|
|
229663
|
+
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
229664
|
import { homedir as homedir8 } from "node:os";
|
|
229436
229665
|
import { basename as basename7, dirname as dirname15, join as join23, relative as relative4, resolve as resolve10 } from "node:path";
|
|
229437
229666
|
init_cli();
|
|
229438
229667
|
|
|
229439
229668
|
// src/project/env.ts
|
|
229440
|
-
import { appendFileSync, existsSync as existsSync17, readFileSync as
|
|
229669
|
+
import { appendFileSync, existsSync as existsSync17, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "node:fs";
|
|
229441
229670
|
import { homedir as homedir7 } from "node:os";
|
|
229442
229671
|
import { dirname as dirname12, join as join20, resolve as resolve7 } from "node:path";
|
|
229443
229672
|
var KEY_RE = /^(LECODES|CREATOR)_[A-Z0-9_]+$/;
|
|
@@ -229505,7 +229734,7 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
229505
229734
|
const file = join20(root, ".env");
|
|
229506
229735
|
if (!existsSync17(file))
|
|
229507
229736
|
return [];
|
|
229508
|
-
const added = applyDotEnv(parseDotEnv(
|
|
229737
|
+
const added = applyDotEnv(parseDotEnv(readFileSync18(file, "utf8")), root, process.env);
|
|
229509
229738
|
for (const [k, v] of Object.entries(added))
|
|
229510
229739
|
process.env[k] = v;
|
|
229511
229740
|
return Object.keys(added);
|
|
@@ -229516,7 +229745,7 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
229516
229745
|
var upsertDotEnv = (root, entries) => {
|
|
229517
229746
|
const touched = [];
|
|
229518
229747
|
const envPath = join20(root, ".env");
|
|
229519
|
-
let content = existsSync17(envPath) ?
|
|
229748
|
+
let content = existsSync17(envPath) ? readFileSync18(envPath, "utf8") : "";
|
|
229520
229749
|
for (const [key, value] of Object.entries(entries)) {
|
|
229521
229750
|
const line = `${key}=${value}`;
|
|
229522
229751
|
const re = new RegExp(`^(?:export\\s+)?${key}\\s*=.*$`, "m");
|
|
@@ -229531,7 +229760,7 @@ var upsertDotEnv = (root, entries) => {
|
|
|
229531
229760
|
writeFileSync12(envPath, content);
|
|
229532
229761
|
touched.push(".env");
|
|
229533
229762
|
const ignorePath = join20(root, ".gitignore");
|
|
229534
|
-
const ignore = existsSync17(ignorePath) ?
|
|
229763
|
+
const ignore = existsSync17(ignorePath) ? readFileSync18(ignorePath, "utf8") : "";
|
|
229535
229764
|
if (!ignore.split(`
|
|
229536
229765
|
`).some((l) => l.trim() === ".env")) {
|
|
229537
229766
|
appendFileSync(ignorePath, `${!ignore || ignore.endsWith(`
|
|
@@ -229544,7 +229773,7 @@ var upsertDotEnv = (root, entries) => {
|
|
|
229544
229773
|
};
|
|
229545
229774
|
|
|
229546
229775
|
// src/commands/app/icon.ts
|
|
229547
|
-
import { existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as
|
|
229776
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "node:fs";
|
|
229548
229777
|
import { dirname as dirname13, join as join21, resolve as resolve8 } from "node:path";
|
|
229549
229778
|
|
|
229550
229779
|
// ../../sdk/src/canvas/gen/cssColor.ts
|
|
@@ -230088,7 +230317,7 @@ var restampManifestIcon = (androidDir) => {
|
|
|
230088
230317
|
const path = join21(androidDir, "app", "src", "main", "AndroidManifest.xml");
|
|
230089
230318
|
if (!existsSync19(path))
|
|
230090
230319
|
return;
|
|
230091
|
-
const content =
|
|
230320
|
+
const content = readFileSync19(path, "utf8");
|
|
230092
230321
|
if (content.includes(`android:icon="@mipmap/ic_launcher"`))
|
|
230093
230322
|
return;
|
|
230094
230323
|
if (!/android:icon="[^"]*"/.test(content)) {
|
|
@@ -230100,7 +230329,7 @@ var restampManifestIcon = (androidDir) => {
|
|
|
230100
230329
|
};
|
|
230101
230330
|
|
|
230102
230331
|
// src/commands/app/splash.ts
|
|
230103
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as
|
|
230332
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync20, rmSync as rmSync3, writeFileSync as writeFileSync14 } from "node:fs";
|
|
230104
230333
|
import { dirname as dirname14, join as join22, resolve as resolve9 } from "node:path";
|
|
230105
230334
|
init_cli();
|
|
230106
230335
|
|
|
@@ -230978,7 +231207,7 @@ var androidSplashThemeHint = (androidDir) => {
|
|
|
230978
231207
|
const path = join22(androidDir, "app", "src", "main", "res", "values", "themes.xml");
|
|
230979
231208
|
if (!existsSync20(path))
|
|
230980
231209
|
return null;
|
|
230981
|
-
const xml =
|
|
231210
|
+
const xml = readFileSync20(path, "utf8");
|
|
230982
231211
|
const style = /<style\b[^>]*\bname="Theme\.LeCodesApp"[^>]*?(?:\/>|>([\s\S]*?)<\/style>)/.exec(xml);
|
|
230983
231212
|
if (!style) {
|
|
230984
231213
|
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 +231575,13 @@ if "%OS%"=="Windows_NT" endlocal
|
|
|
231346
231575
|
// src/commands/app/play.ts
|
|
231347
231576
|
init_cli();
|
|
231348
231577
|
import { sign } from "node:crypto";
|
|
231349
|
-
import { readFileSync as
|
|
231578
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
231350
231579
|
var SCOPE = "https://www.googleapis.com/auth/androidpublisher";
|
|
231351
231580
|
var apiBase = () => process.env.LECODES_PLAY_API_URL ?? "https://androidpublisher.googleapis.com";
|
|
231352
231581
|
var readServiceAccount = (path) => {
|
|
231353
231582
|
let key;
|
|
231354
231583
|
try {
|
|
231355
|
-
key = JSON.parse(
|
|
231584
|
+
key = JSON.parse(readFileSync21(path, "utf8"));
|
|
231356
231585
|
} catch {
|
|
231357
231586
|
throw new CliError(`${path} is not a JSON key file.`);
|
|
231358
231587
|
}
|
|
@@ -231432,7 +231661,7 @@ var shellSdkVersionAndroid = (androidDir) => {
|
|
|
231432
231661
|
const path = join23(androidDir, "lecodes-runtime", "build.gradle.kts");
|
|
231433
231662
|
if (!existsSync21(path))
|
|
231434
231663
|
return null;
|
|
231435
|
-
const m = /io\.letary:lecodes-sdk(?:-(?:core|2d|3d))?:(\d+\.\d+\.\d+)@aar/.exec(
|
|
231664
|
+
const m = /io\.letary:lecodes-sdk(?:-(?:core|2d|3d))?:(\d+\.\d+\.\d+)@aar/.exec(readFileSync22(path, "utf8"));
|
|
231436
231665
|
return m ? m[1] : null;
|
|
231437
231666
|
};
|
|
231438
231667
|
var GRADLE_WRAPPER_JAR_URL = "https://raw.githubusercontent.com/gradle/gradle/v8.13.0/gradle/wrapper/gradle-wrapper.jar";
|
|
@@ -231440,7 +231669,7 @@ var GRADLE_WRAPPER_JAR_SHA256 = "81a82aaea5abcc8ff68b3dfcb58b3c3c429378efd98e743
|
|
|
231440
231669
|
var ensureGradleWrapperJar = async () => {
|
|
231441
231670
|
const cached = join23(homedir8(), ".lecodes", "gradle-wrapper", GRADLE_VERSION, "gradle-wrapper.jar");
|
|
231442
231671
|
if (existsSync21(cached))
|
|
231443
|
-
return new Uint8Array(
|
|
231672
|
+
return new Uint8Array(readFileSync22(cached));
|
|
231444
231673
|
try {
|
|
231445
231674
|
const res = await fetch(GRADLE_WRAPPER_JAR_URL);
|
|
231446
231675
|
if (!res.ok)
|
|
@@ -231571,7 +231800,7 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
231571
231800
|
resources = prior.resources;
|
|
231572
231801
|
} else {
|
|
231573
231802
|
resources = await compileShell(join23(assetsDir, "app.js"), { remotePatterns });
|
|
231574
|
-
bundleJs =
|
|
231803
|
+
bundleJs = readFileSync22(join23(assetsDir, "app.js"), "utf8");
|
|
231575
231804
|
}
|
|
231576
231805
|
const requestedVariant = config.android?.variant ?? "auto";
|
|
231577
231806
|
if (requestedVariant !== "auto" && !ANDROID_SDK_VARIANTS.includes(requestedVariant)) {
|
|
@@ -231716,7 +231945,7 @@ var restampManifestBlock = (androidDir, tag, block, what, missing, after = []) =
|
|
|
231716
231945
|
const path = join23(androidDir, "app", "src", "main", "AndroidManifest.xml");
|
|
231717
231946
|
if (!existsSync21(path))
|
|
231718
231947
|
return;
|
|
231719
|
-
const content =
|
|
231948
|
+
const content = readFileSync22(path, "utf8");
|
|
231720
231949
|
const tagged = new RegExp(`\\n[ \\t]*<!-- lecodes:${tag}[\\s\\S]*?<!-- \\/lecodes:${tag} -->`);
|
|
231721
231950
|
let next;
|
|
231722
231951
|
if (tagged.test(content))
|
|
@@ -231745,7 +231974,7 @@ var restampAppBuildGradle = (androidDir, config, gradlePlugins) => {
|
|
|
231745
231974
|
warn("android/app/build.gradle.kts is missing — run `lecodes app init android` on a clean tree to regenerate the shell.");
|
|
231746
231975
|
return;
|
|
231747
231976
|
}
|
|
231748
|
-
let content =
|
|
231977
|
+
let content = readFileSync22(path, "utf8");
|
|
231749
231978
|
const before = content;
|
|
231750
231979
|
const versionName = config.version ?? "1.0.0";
|
|
231751
231980
|
const versionCode = config.android?.versionCode ?? 1;
|
|
@@ -231958,7 +232187,7 @@ var uploadAndroid = async (flags) => {
|
|
|
231958
232187
|
const token = await serviceAccountToken(key);
|
|
231959
232188
|
const { versionCode } = await uploadToPlay(token, {
|
|
231960
232189
|
packageName,
|
|
231961
|
-
aab:
|
|
232190
|
+
aab: readFileSync22(aabPath),
|
|
231962
232191
|
track: flags.track,
|
|
231963
232192
|
status: flags.draft ? "draft" : "completed"
|
|
231964
232193
|
});
|
|
@@ -231987,7 +232216,7 @@ var ANDROID_SIGNING_ENV = {
|
|
|
231987
232216
|
};
|
|
231988
232217
|
var readProperties = (path) => {
|
|
231989
232218
|
const out = {};
|
|
231990
|
-
for (const raw of
|
|
232219
|
+
for (const raw of readFileSync22(path, "utf8").split(/\r?\n/)) {
|
|
231991
232220
|
const line = raw.trim();
|
|
231992
232221
|
if (!line || line.startsWith("#") || line.startsWith("!"))
|
|
231993
232222
|
continue;
|
|
@@ -232087,7 +232316,7 @@ var writeSigningConfig = (root, config, storeFile, alias, storePassword, keyPass
|
|
|
232087
232316
|
const rel = relative4(root, storeFile);
|
|
232088
232317
|
if (rel && !rel.startsWith("..") && !rel.includes(":") && !rel.replace(/\\/g, "/").startsWith("android/")) {
|
|
232089
232318
|
const ignorePath = join23(root, ".gitignore");
|
|
232090
|
-
const ignore = existsSync21(ignorePath) ?
|
|
232319
|
+
const ignore = existsSync21(ignorePath) ? readFileSync22(ignorePath, "utf8") : "";
|
|
232091
232320
|
if (!ignore.split(`
|
|
232092
232321
|
`).some((l) => l.trim() === "*.keystore")) {
|
|
232093
232322
|
writeFileSync15(ignorePath, ignore + (!ignore || ignore.endsWith(`
|
|
@@ -232325,10 +232554,10 @@ var doctorAndroidChecks = async (root, config, check) => {
|
|
|
232325
232554
|
}
|
|
232326
232555
|
if (config.update) {
|
|
232327
232556
|
const manifest = join23(androidDir, "lecodes-runtime", "src", "main", "AndroidManifest.xml");
|
|
232328
|
-
check(existsSync21(manifest) &&
|
|
232557
|
+
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
232558
|
const appSrc = join23(androidDir, "app", "src", "main", "java");
|
|
232330
232559
|
const kt = existsSync21(appSrc) ? readdirSync6(appSrc, { recursive: true }).map(String).filter((f) => f.endsWith(".kt")) : [];
|
|
232331
|
-
const sources = kt.map((f) =>
|
|
232560
|
+
const sources = kt.map((f) => readFileSync22(join23(appSrc, f), "utf8"));
|
|
232332
232561
|
const boots = sources.some((src) => src.includes("LeCodesShell.boot"));
|
|
232333
232562
|
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
232563
|
const waits = sources.some((src) => /LeCodesShell\.boot\(\s*engine\s*,\s*activity\b/.test(src));
|
|
@@ -232348,7 +232577,7 @@ var doctorAndroidChecks = async (root, config, check) => {
|
|
|
232348
232577
|
}
|
|
232349
232578
|
check(!!findKeytool(), "keytool", "install a JDK or set JAVA_HOME (`lecodes app keystore …` needs it)", false);
|
|
232350
232579
|
const appGradle = join23(androidDir, "app", "build.gradle.kts");
|
|
232351
|
-
const gradleText = existsSync21(appGradle) ?
|
|
232580
|
+
const gradleText = existsSync21(appGradle) ? readFileSync22(appGradle, "utf8") : "";
|
|
232352
232581
|
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
232582
|
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
232583
|
if (Object.keys(config.plugins ?? {}).includes("push")) {
|
|
@@ -232363,7 +232592,7 @@ import { basename as basename9, dirname as dirname16, join as join26, resolve as
|
|
|
232363
232592
|
|
|
232364
232593
|
// src/hosts/desktopRenderer.ts
|
|
232365
232594
|
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
|
|
232595
|
+
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
232596
|
import { homedir as homedir9, tmpdir as tmpdir2 } from "node:os";
|
|
232368
232597
|
import { delimiter, join as join24, resolve as resolve11 } from "node:path";
|
|
232369
232598
|
init_cli();
|
|
@@ -232508,7 +232737,7 @@ var installedDesktopVersions = () => {
|
|
|
232508
232737
|
};
|
|
232509
232738
|
var selectedDesktopVersion = () => {
|
|
232510
232739
|
try {
|
|
232511
|
-
const saved = JSON.parse(
|
|
232740
|
+
const saved = JSON.parse(readFileSync23(currentFile(), "utf8")).version;
|
|
232512
232741
|
if (saved && /^\d+\.\d+\.\d+/.test(saved) && semverNewer(DESKTOP_RENDERER_VERSION, saved) > 0)
|
|
232513
232742
|
return saved;
|
|
232514
232743
|
} catch {}
|
|
@@ -233630,7 +233859,7 @@ var shellSdkVersion = (iosDir) => {
|
|
|
233630
233859
|
const path = join27(iosDir, "LeCodesRuntime", "Package.swift");
|
|
233631
233860
|
if (!existsSync25(path))
|
|
233632
233861
|
return null;
|
|
233633
|
-
const m = /lecodes-ios-sdk\.git",\s*(?:exact|from):\s*"(\d+\.\d+\.\d+)(?:-(?:core|2d|3d))?"/.exec(
|
|
233862
|
+
const m = /lecodes-ios-sdk\.git",\s*(?:exact|from):\s*"(\d+\.\d+\.\d+)(?:-(?:core|2d|3d))?"/.exec(readFileSync24(path, "utf8"));
|
|
233634
233863
|
return m && VERSION_RE.test(m[1]) ? m[1] : null;
|
|
233635
233864
|
};
|
|
233636
233865
|
var IOS_SDK_OPTS = { repo: SDK_REPO, minVersion: SDK_MIN_VERSION, configKey: "ios.sdk" };
|
|
@@ -233836,7 +234065,7 @@ var syncIos = async (root, config) => {
|
|
|
233836
234065
|
rmSync8(resourcesDir, { recursive: true, force: true });
|
|
233837
234066
|
mkdirSync16(resourcesDir, { recursive: true });
|
|
233838
234067
|
const resources = await compileShell(join27(resourcesDir, "app.js"), { remotePatterns });
|
|
233839
|
-
const bundleJs =
|
|
234068
|
+
const bundleJs = readFileSync24(join27(resourcesDir, "app.js"), "utf8");
|
|
233840
234069
|
const { variant, why } = resolveVariant(requestedVariant, bundleJs);
|
|
233841
234070
|
log(`${c.green("variant")} ${variant}${requestedVariant === "auto" ? ` (auto: ${why})` : " (forced by ios.variant)"}`);
|
|
233842
234071
|
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 +234131,7 @@ var syncIos = async (root, config) => {
|
|
|
233902
234131
|
if (pluginSpecs.length > 0 || existsSync25(lockPath))
|
|
233903
234132
|
writeJson(lockPath, { plugins: newLock });
|
|
233904
234133
|
const pbxPath = join27(iosDir, "App.xcodeproj", "project.pbxproj");
|
|
233905
|
-
let pbx =
|
|
234134
|
+
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
234135
|
const mergedEntitlements = {};
|
|
233907
234136
|
const appLinks = appLinksOf(config);
|
|
233908
234137
|
if (appLinks.length) {
|
|
@@ -234194,8 +234423,8 @@ var doctorIosChecks = async (root, config, check) => {
|
|
|
234194
234423
|
const validVariant = requestedVariant === "auto" || SDK_VARIANTS.includes(requestedVariant);
|
|
234195
234424
|
check(validVariant, `ios.variant "${requestedVariant}"`, `use "auto" or one of ${SDK_VARIANTS.join(", ")}`);
|
|
234196
234425
|
if (existsSync25(bundle) && validVariant) {
|
|
234197
|
-
const { variant } = resolveVariant(requestedVariant,
|
|
234198
|
-
const pkg =
|
|
234426
|
+
const { variant } = resolveVariant(requestedVariant, readFileSync24(bundle, "utf8"));
|
|
234427
|
+
const pkg = readFileSync24(join27(root, "ios", "LeCodesRuntime", "Package.swift"), "utf8");
|
|
234199
234428
|
const tag = /lecodes-ios-sdk\.git",\s*exact:\s*"([^"]+)"/.exec(pkg)?.[1] ?? "";
|
|
234200
234429
|
const tagVariant = /-(core|2d|3d)$/.exec(tag)?.[1] ?? "full";
|
|
234201
234430
|
check(tagVariant === variant, `SDK variant ${variant}`, "run `lecodes app sync`");
|
|
@@ -234217,25 +234446,25 @@ var doctorIosChecks = async (root, config, check) => {
|
|
|
234217
234446
|
const inSync = wanted.every((id) => lock[id]) && Object.keys(lock).every((id) => wanted.includes(id));
|
|
234218
234447
|
check(wanted.length === 0 || inSync, "Plugins synced", "run `lecodes app sync`");
|
|
234219
234448
|
const pbxFile = join27(root, "ios", "App.xcodeproj", "project.pbxproj");
|
|
234220
|
-
if (existsSync25(pbxFile) &&
|
|
234449
|
+
if (existsSync25(pbxFile) && readFileSync24(pbxFile, "utf8").includes("CODE_SIGN_ENTITLEMENTS")) {
|
|
234221
234450
|
check(existsSync25(join27(root, "ios", "App", "App.entitlements")), "App/App.entitlements present", "run `lecodes app sync`");
|
|
234222
234451
|
}
|
|
234223
234452
|
if (wanted.includes("push")) {
|
|
234224
234453
|
const runtimeSwift = join27(root, "ios", "LeCodesRuntime", "Sources", "LeCodesRuntime", "LeCodesRuntime.swift");
|
|
234225
|
-
const baked = existsSync25(runtimeSwift) &&
|
|
234454
|
+
const baked = existsSync25(runtimeSwift) && readFileSync24(runtimeSwift, "utf8").includes("bootProjectUuid");
|
|
234226
234455
|
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
234456
|
}
|
|
234228
234457
|
if (config.update) {
|
|
234229
|
-
const plist =
|
|
234458
|
+
const plist = readFileSync24(join27(root, "ios", "App", "Info.plist"), "utf8");
|
|
234230
234459
|
check(plist.includes("<key>LeCodesUpdateURL</key>"), "OTA update URL in Info.plist", "run `lecodes app sync`", false);
|
|
234231
234460
|
const appDir = join27(root, "ios", "App");
|
|
234232
|
-
const swift = readdirSync10(appDir).filter((f) => f.endsWith(".swift")).map((f) =>
|
|
234461
|
+
const swift = readdirSync10(appDir).filter((f) => f.endsWith(".swift")).map((f) => readFileSync24(join27(appDir, f), "utf8"));
|
|
234233
234462
|
const launchesViaUpdater = swift.some((t) => t.includes("LeCodesAppViewController") || t.includes("LeCodesUpdater.activeBundle"));
|
|
234234
234463
|
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
234464
|
}
|
|
234236
234465
|
{
|
|
234237
234466
|
const vc = join27(root, "ios", "App", "ViewController.swift");
|
|
234238
|
-
const is2x = !existsSync25(vc) ||
|
|
234467
|
+
const is2x = !existsSync25(vc) || readFileSync24(vc, "utf8").includes("LeCodesAppViewController");
|
|
234239
234468
|
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
234469
|
}
|
|
234241
234470
|
const asc = readJson2(join27(homedir10(), ".lecodes", "asc.json"));
|
|
@@ -234652,6 +234881,7 @@ lecodes render --sim --script <file> # the WINDOWLESS native host (lecodes-
|
|
|
234652
234881
|
# engines, no GPU, no pixels, no UI hit-test — expect.log /
|
|
234653
234882
|
# expect.paint only; runs on CI and beside an open desktop window
|
|
234654
234883
|
lecodes test # all tests/*.flow.json + design-derived flows; run before "done"
|
|
234884
|
+
bunx -p typescript tsc --noEmit # typecheck against .lecodes/types (the SDK's globals); also before "done"
|
|
234655
234885
|
lecodes test --desktop # the file flows on the NATIVE host (design flows stay headless)
|
|
234656
234886
|
lecodes test --sim # the windowless twin: coordinates + expect.log / expect.paint only
|
|
234657
234887
|
lecodes dev --android --time 12 --png phone.png # the REAL phone over adb (USB): launches the app on
|
|
@@ -234775,9 +235005,9 @@ fetch the docs — they are served as raw markdown for AI tools:
|
|
|
234775
235005
|
with a COOKBOOK: read the matching recipe BEFORE you design the structure.** It has the file
|
|
234776
235006
|
layout, a skeleton per part, how to verify, and the traps already paid for (start with
|
|
234777
235007
|
"Project architecture for a game" for any game bigger than one file).
|
|
234778
|
-
- https://le.codes/
|
|
235008
|
+
- https://le.codes/docs/api/<area>/<page>.md — one reference page as raw markdown
|
|
234779
235009
|
(e.g. \`ui/styling.md\`, \`2d/scene2d.md\`, \`3d/scene.md\`, \`runtime/storage.md\`)
|
|
234780
|
-
- https://le.codes/
|
|
235010
|
+
- https://le.codes/docs/guide/<page>.md — guide pages (project anatomy, CLI, tracks)
|
|
234781
235011
|
- https://le.codes/llms-full.txt — everything in one file (large; prefer per-page)
|
|
234782
235012
|
|
|
234783
235013
|
Always fetch the \`.md\` URLs — the HTML routes are a JS app and return an empty shell.
|
|
@@ -235575,7 +235805,7 @@ var desktop_default = defineCommand({
|
|
|
235575
235805
|
|
|
235576
235806
|
// src/commands/dev.ts
|
|
235577
235807
|
init_manifest();
|
|
235578
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as
|
|
235808
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as readFileSync33, writeFileSync as writeFileSync25 } from "node:fs";
|
|
235579
235809
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
235580
235810
|
import { networkInterfaces } from "node:os";
|
|
235581
235811
|
import { basename as basename15, join as join43 } from "node:path";
|
|
@@ -235583,7 +235813,7 @@ import { basename as basename15, join as join43 } from "node:path";
|
|
|
235583
235813
|
// src/dev/devServer.ts
|
|
235584
235814
|
init_localFiles();
|
|
235585
235815
|
import { createHash as createHash8 } from "node:crypto";
|
|
235586
|
-
import { createReadStream as createReadStream2, readFileSync as
|
|
235816
|
+
import { createReadStream as createReadStream2, readFileSync as readFileSync31, statSync as statSync11 } from "node:fs";
|
|
235587
235817
|
import { join as join39 } from "node:path";
|
|
235588
235818
|
import { Readable as Readable3 } from "node:stream";
|
|
235589
235819
|
init_projectCompile();
|
|
@@ -235718,7 +235948,7 @@ init_paths();
|
|
|
235718
235948
|
// src/web/halves.ts
|
|
235719
235949
|
init_compile();
|
|
235720
235950
|
init_cli();
|
|
235721
|
-
import { cpSync as cpSync5, existsSync as existsSync34, readFileSync as
|
|
235951
|
+
import { cpSync as cpSync5, existsSync as existsSync34, readFileSync as readFileSync30 } from "node:fs";
|
|
235722
235952
|
import { join as join38, sep as sep4 } from "node:path";
|
|
235723
235953
|
var halfModule = (half) => `plugins/${half.folder}/index.js`;
|
|
235724
235954
|
var asCliError = (e) => new CliError(e instanceof Error ? e.message : String(e));
|
|
@@ -235729,7 +235959,7 @@ var projectHalves = (root) => {
|
|
|
235729
235959
|
const folder = dir.split(sep4).pop();
|
|
235730
235960
|
let web;
|
|
235731
235961
|
try {
|
|
235732
|
-
web = webHalfManifestOf(
|
|
235962
|
+
web = webHalfManifestOf(readFileSync30(join38(dir, MANIFEST_FILE), "utf8"), folder, id);
|
|
235733
235963
|
} catch (e) {
|
|
235734
235964
|
throw asCliError(e);
|
|
235735
235965
|
}
|
|
@@ -235870,7 +236100,7 @@ var startDevServer = async (options) => {
|
|
|
235870
236100
|
const liteTable = () => {
|
|
235871
236101
|
let plugins = {};
|
|
235872
236102
|
try {
|
|
235873
|
-
plugins = JSON.parse(
|
|
236103
|
+
plugins = JSON.parse(readFileSync31(join39(lite, "plugins.json"), "utf8")).plugins ?? {};
|
|
235874
236104
|
} catch {}
|
|
235875
236105
|
const table = { ...plugins };
|
|
235876
236106
|
for (const { half, hash } of halves) {
|
|
@@ -236361,7 +236591,7 @@ var androidCrashLines = (session) => {
|
|
|
236361
236591
|
|
|
236362
236592
|
// src/dev/iosDev.ts
|
|
236363
236593
|
init_cli();
|
|
236364
|
-
import { existsSync as existsSync37, readdirSync as readdirSync17, readFileSync as
|
|
236594
|
+
import { existsSync as existsSync37, readdirSync as readdirSync17, readFileSync as readFileSync32, statSync as statSync13, unlinkSync } from "node:fs";
|
|
236365
236595
|
import { homedir as homedir12 } from "node:os";
|
|
236366
236596
|
import { join as join42 } from "node:path";
|
|
236367
236597
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
@@ -236394,7 +236624,7 @@ var listDevices2 = () => {
|
|
|
236394
236624
|
if (!ok || !existsSync37(tmp))
|
|
236395
236625
|
return [];
|
|
236396
236626
|
try {
|
|
236397
|
-
const json = JSON.parse(
|
|
236627
|
+
const json = JSON.parse(readFileSync32(tmp, "utf8"));
|
|
236398
236628
|
return (json.result?.devices ?? []).map((d) => ({
|
|
236399
236629
|
udid: d.identifier,
|
|
236400
236630
|
name: d.deviceProperties?.name ?? d.identifier,
|
|
@@ -236441,7 +236671,7 @@ var deviceHasApp = (udid, bundleId) => {
|
|
|
236441
236671
|
if (!ok || !existsSync37(tmp))
|
|
236442
236672
|
return false;
|
|
236443
236673
|
try {
|
|
236444
|
-
const json = JSON.parse(
|
|
236674
|
+
const json = JSON.parse(readFileSync32(tmp, "utf8"));
|
|
236445
236675
|
return (json.result?.apps ?? []).some((a) => a.bundleIdentifier === bundleId);
|
|
236446
236676
|
} catch {
|
|
236447
236677
|
return false;
|
|
@@ -236481,7 +236711,7 @@ var launchOnIos = (opts) => {
|
|
|
236481
236711
|
if (!start.ok)
|
|
236482
236712
|
throw new CliError(`Could not launch ${bundleId} on ${target.name}: ${start.out}`);
|
|
236483
236713
|
try {
|
|
236484
|
-
const json = JSON.parse(
|
|
236714
|
+
const json = JSON.parse(readFileSync32(tmp, "utf8"));
|
|
236485
236715
|
pid = json.result?.process?.processIdentifier?.toString() ?? null;
|
|
236486
236716
|
} catch {
|
|
236487
236717
|
pid = null;
|
|
@@ -236553,7 +236783,7 @@ var lanCandidates = () => {
|
|
|
236553
236783
|
var loadDevToken = (root) => {
|
|
236554
236784
|
const path = join43(root, LECODES_DIR, "dev.json");
|
|
236555
236785
|
try {
|
|
236556
|
-
const token = JSON.parse(
|
|
236786
|
+
const token = JSON.parse(readFileSync33(path, "utf8")).token;
|
|
236557
236787
|
if (token && /^[a-z0-9]{8,}$/.test(token))
|
|
236558
236788
|
return token;
|
|
236559
236789
|
} catch {}
|
|
@@ -236788,7 +237018,7 @@ init_api();
|
|
|
236788
237018
|
|
|
236789
237019
|
// src/platform/serverDiff.ts
|
|
236790
237020
|
init_localFiles();
|
|
236791
|
-
import { readFileSync as
|
|
237021
|
+
import { readFileSync as readFileSync34 } from "node:fs";
|
|
236792
237022
|
var isTextAsset = (t) => t === "text" || t === "shader" || t === "scene";
|
|
236793
237023
|
var computeServerDiff = (project, scan) => {
|
|
236794
237024
|
const pathById = buildPaths(project.assets);
|
|
@@ -236806,7 +237036,7 @@ var computeServerDiff = (project, scan) => {
|
|
|
236806
237036
|
const local = localByPath.get(path);
|
|
236807
237037
|
if (local && !server2) {
|
|
236808
237038
|
const text = isTextKind(local.kind);
|
|
236809
|
-
entries.push({ path, status: "added", binary: !text, serverText: "", localText: text ?
|
|
237039
|
+
entries.push({ path, status: "added", binary: !text, serverText: "", localText: text ? readFileSync34(local.absPath, "utf8") : undefined });
|
|
236810
237040
|
continue;
|
|
236811
237041
|
}
|
|
236812
237042
|
if (server2 && !local) {
|
|
@@ -236817,12 +237047,12 @@ var computeServerDiff = (project, scan) => {
|
|
|
236817
237047
|
if (server2 && local) {
|
|
236818
237048
|
if (isTextAsset(server2.type)) {
|
|
236819
237049
|
const serverText = server2.text ?? "";
|
|
236820
|
-
const localText =
|
|
237050
|
+
const localText = readFileSync34(local.absPath, "utf8");
|
|
236821
237051
|
if (serverText !== localText)
|
|
236822
237052
|
entries.push({ path, status: "modified", binary: false, serverText, localText });
|
|
236823
237053
|
} else {
|
|
236824
237054
|
const serverSize = server2.file?.size;
|
|
236825
|
-
const localSize = Buffer.byteLength(
|
|
237055
|
+
const localSize = Buffer.byteLength(readFileSync34(local.absPath));
|
|
236826
237056
|
if (serverSize !== undefined && serverSize !== localSize) {
|
|
236827
237057
|
entries.push({ path, status: "modified", binary: true });
|
|
236828
237058
|
}
|
|
@@ -237154,7 +237384,7 @@ var init3 = (dir, forDesktop) => {
|
|
|
237154
237384
|
// src/commands/install.ts
|
|
237155
237385
|
init_cli();
|
|
237156
237386
|
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
|
|
237387
|
+
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
237388
|
import { homedir as homedir13 } from "node:os";
|
|
237159
237389
|
import { basename as basename17, delimiter as delimiter2, dirname as dirname22, join as join45, resolve as resolve21 } from "node:path";
|
|
237160
237390
|
var isWin = process.platform === "win32";
|
|
@@ -237208,7 +237438,7 @@ var appendPathToShellRc = (binDir) => {
|
|
|
237208
237438
|
const { file, name } = shellRc();
|
|
237209
237439
|
const line = `export PATH="${binDir}:$PATH"`;
|
|
237210
237440
|
try {
|
|
237211
|
-
const existing = existsSync40(file) ?
|
|
237441
|
+
const existing = existsSync40(file) ? readFileSync35(file, "utf8") : "";
|
|
237212
237442
|
if (existing.includes(line))
|
|
237213
237443
|
return name;
|
|
237214
237444
|
appendFileSync3(file, `${existing && !existing.endsWith(`
|
|
@@ -237330,9 +237560,9 @@ var install_default = defineCommand({
|
|
|
237330
237560
|
});
|
|
237331
237561
|
|
|
237332
237562
|
// src/commands/lightmap.ts
|
|
237333
|
-
import { closeSync, existsSync as existsSync41, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync4, openSync, readFileSync as
|
|
237563
|
+
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
237564
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
237335
|
-
import { basename as basename18, join as join46, relative as relative7, resolve as resolve22 } from "node:path";
|
|
237565
|
+
import { basename as basename18, dirname as dirname23, join as join46, relative as relative7, resolve as resolve22, sep as sep5 } from "node:path";
|
|
237336
237566
|
import { deflateSync } from "node:zlib";
|
|
237337
237567
|
init_peerInstall();
|
|
237338
237568
|
init_cli();
|
|
@@ -237345,7 +237575,7 @@ var range = (name, value, min, max) => {
|
|
|
237345
237575
|
var readBake = (file) => {
|
|
237346
237576
|
if (!existsSync41(file))
|
|
237347
237577
|
throw new CliError(`No bake at ${file} — run \`lecodes lightmap bake\` first.`);
|
|
237348
|
-
const data = JSON.parse(
|
|
237578
|
+
const data = JSON.parse(readFileSync36(file, "utf8"));
|
|
237349
237579
|
if (data.version !== 4)
|
|
237350
237580
|
throw new CliError(`${file} is not a creator-bake file (version ${String(data.version)}) — rebake.`);
|
|
237351
237581
|
return data;
|
|
@@ -237381,54 +237611,47 @@ var cubePatternsOf = (argv) => {
|
|
|
237381
237611
|
}
|
|
237382
237612
|
return out.filter((p) => p !== "");
|
|
237383
237613
|
};
|
|
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;
|
|
237614
|
+
var stemOf = (path) => basename18(path).replace(/\.bake$/i, "");
|
|
237615
|
+
var pickTarget2 = (bakes, name, entry) => {
|
|
237616
|
+
if (bakes.length === 0)
|
|
237617
|
+
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'))\`).`);
|
|
237618
|
+
const listed = bakes.map((b) => `${stemOf(b.path)} (${b.path})`).join(", ");
|
|
237619
|
+
if (name === undefined) {
|
|
237620
|
+
if (bakes.length > 1)
|
|
237621
|
+
throw new CliError(`${entry} reaches ${bakes.length} bake() calls: ${listed} — pass --name <stem> to pick the level to bake.`);
|
|
237622
|
+
return bakes[0];
|
|
237623
|
+
}
|
|
237624
|
+
const named = bakes.filter((b) => stemOf(b.path) === name);
|
|
237625
|
+
if (named.length === 0)
|
|
237626
|
+
throw new CliError(`--name ${name}: ${entry} reaches no bake() of that stem — it reaches ${listed}.`);
|
|
237627
|
+
if (named.length > 1)
|
|
237628
|
+
throw new CliError(`--name ${name}: two bake() targets share that stem (${named.map((b) => b.path).join(", ")}) — rename one.`);
|
|
237629
|
+
return named[0];
|
|
237413
237630
|
};
|
|
237414
|
-
var
|
|
237415
|
-
const
|
|
237416
|
-
const
|
|
237417
|
-
|
|
237418
|
-
|
|
237419
|
-
|
|
237420
|
-
|
|
237421
|
-
|
|
237422
|
-
|
|
237423
|
-
|
|
237424
|
-
|
|
237425
|
-
|
|
237426
|
-
|
|
237427
|
-
|
|
237428
|
-
|
|
237429
|
-
|
|
237430
|
-
if (
|
|
237431
|
-
|
|
237631
|
+
var findBakes = (root) => {
|
|
237632
|
+
const SKIP = new Set(["node_modules", ".lightmap", ".git", ".lecodes"]);
|
|
237633
|
+
const out = [];
|
|
237634
|
+
const walk = (dir) => {
|
|
237635
|
+
for (const e of readdirSync18(dir, { withFileTypes: true })) {
|
|
237636
|
+
if (e.isDirectory()) {
|
|
237637
|
+
if (!SKIP.has(e.name))
|
|
237638
|
+
walk(join46(dir, e.name));
|
|
237639
|
+
} else if (/\.bake$/i.test(e.name))
|
|
237640
|
+
out.push(relative7(root, join46(dir, e.name)).replace(/\\/g, "/"));
|
|
237641
|
+
}
|
|
237642
|
+
};
|
|
237643
|
+
walk(root);
|
|
237644
|
+
return out.sort();
|
|
237645
|
+
};
|
|
237646
|
+
var bakeFileOf = (root, flag) => {
|
|
237647
|
+
if (flag)
|
|
237648
|
+
return resolve22(root, flag);
|
|
237649
|
+
const found = findBakes(root);
|
|
237650
|
+
if (found.length === 0)
|
|
237651
|
+
throw new CliError("No .bake in the project — run `lecodes lightmap bake` first.");
|
|
237652
|
+
if (found.length > 1)
|
|
237653
|
+
throw new CliError(`The project has ${found.length} bakes (${found.join(", ")}) — pass --bake <file>.`);
|
|
237654
|
+
return resolve22(root, found[0]);
|
|
237432
237655
|
};
|
|
237433
237656
|
var readGlbJson = (file) => {
|
|
237434
237657
|
let fd;
|
|
@@ -237491,25 +237714,27 @@ var unwrapReferenced = async (js, resources, root, texel) => {
|
|
|
237491
237714
|
var bake = defineCommand({
|
|
237492
237715
|
name: "bake",
|
|
237493
237716
|
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.
|
|
237717
|
+
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).
|
|
237718
|
+
|
|
237719
|
+
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
237720
|
|
|
237496
237721
|
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
237722
|
flags: {
|
|
237498
|
-
out: str("
|
|
237499
|
-
name: str("
|
|
237723
|
+
out: str("write the files into this folder instead of next to the level's .bake (a second seed for `lightmap diff`)", { value: "<dir>" }),
|
|
237724
|
+
name: str("bake the level whose bake() names <stem>.bake — when the entry reaches several", { value: "<stem>" }),
|
|
237500
237725
|
...bundleFlags,
|
|
237501
|
-
entry: str("the file that
|
|
237726
|
+
entry: str("the file that opens the level (it reaches the bake() that names the target)", { value: "<file>", default: "main.ts" }),
|
|
237502
237727
|
size: num("atlas page edge (texels)", { default: 4096 }),
|
|
237503
237728
|
texel: num("texel size (m); the bake coarsens only when the pages are full", { default: 0.05 }),
|
|
237504
237729
|
pages: num("atlas pages to fill before the bake coarsens the texel", { default: 4 }),
|
|
237505
237730
|
"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
|
|
237731
|
+
"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 }),
|
|
237732
|
+
"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 }),
|
|
237733
|
+
"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
237734
|
bounces: num("path vertices at most (Russian roulette from the third); 0 = direct light only", { default: 3 }),
|
|
237510
237735
|
"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 (
|
|
237736
|
+
split: bool('also write <stem>-direct[_n].ktx2 / <stem>-indirect[_n].ktx2 — the pages the "direct" / "indirect" views bind (the manifest names them)'),
|
|
237737
|
+
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
237738
|
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
237739
|
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
237740
|
"light-radius": num("lamps: the emitter's radius (m) — soft shadows, no 1/d² singularity", { default: 0.05 }),
|
|
@@ -237523,13 +237748,13 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237523
237748
|
"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
237749
|
"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
237750
|
"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
|
|
237751
|
+
"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 }),
|
|
237752
|
+
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
237753
|
"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
237754
|
"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
237755
|
"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 (
|
|
237756
|
+
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 }),
|
|
237757
|
+
"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
237758
|
"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
237759
|
"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
237760
|
frames: num("host frames to run before giving up — load headroom", { default: 900 }),
|
|
@@ -237540,14 +237765,16 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237540
237765
|
logs: bool("forward the host's output"),
|
|
237541
237766
|
"no-unwrap": bool("leave the referenced GLBs as they are: no lightmap unwrap of those without TEXCOORD_1 (they bake without lightmap uvs)")
|
|
237542
237767
|
},
|
|
237543
|
-
examples: [
|
|
237768
|
+
examples: [
|
|
237769
|
+
"lecodes lightmap bake",
|
|
237770
|
+
"lecodes lightmap bake --dry-run --logs",
|
|
237771
|
+
"lecodes lightmap bake --entry level2.ts --texel 0.04 --debug-dir .lightmap/level2 --logs"
|
|
237772
|
+
],
|
|
237544
237773
|
run: async ({ flags, argv }) => {
|
|
237545
237774
|
const { root } = localProject();
|
|
237546
|
-
const outDir = resolve22(root, flags.out);
|
|
237547
|
-
const stem = flags.name;
|
|
237548
237775
|
const cube = cubePatternsOf(argv);
|
|
237549
|
-
if (!/^[A-Za-z0-9_
|
|
237550
|
-
throw new CliError(`--name wants
|
|
237776
|
+
if (flags.name !== undefined && !/^[A-Za-z0-9_.-]+$/.test(flags.name))
|
|
237777
|
+
throw new CliError(`--name wants the stem of a .bake (its file name without .bake), got "${flags.name}".`);
|
|
237551
237778
|
const entryFile = flags.entry;
|
|
237552
237779
|
if (!existsSync41(resolve22(root, entryFile))) {
|
|
237553
237780
|
throw new CliError(`No ${entryFile} in ${root} — pass --entry <file> (the file that builds the scene and calls Lightmap.load).`);
|
|
@@ -237560,8 +237787,9 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237560
237787
|
if (!["auto", "optix", "oidn"].includes(flags.denoiser))
|
|
237561
237788
|
throw new CliError(`--denoiser wants auto, optix or oidn, got "${flags.denoiser}".`);
|
|
237562
237789
|
const cfg = {
|
|
237563
|
-
|
|
237564
|
-
|
|
237790
|
+
root: root.replace(/\\/g, "/"),
|
|
237791
|
+
...flags.out ? { outDir: resolve22(root, flags.out).replace(/\\/g, "/") } : {},
|
|
237792
|
+
...flags.name !== undefined ? { stem: flags.name } : {},
|
|
237565
237793
|
size: range("size", flags.size, 256, 16384),
|
|
237566
237794
|
texel: range("texel", flags.texel, 0.001, 2),
|
|
237567
237795
|
pages: range("pages", flags.pages, 1, 16),
|
|
@@ -237604,23 +237832,26 @@ Lightmap UVs: the GLBs the app references that have none (TEXCOORD_1) are unwrap
|
|
|
237604
237832
|
const entryText = `globalThis.__lecodesLightmap = ${JSON.stringify(cfg)}
|
|
237605
237833
|
import ${JSON.stringify(importPath)}
|
|
237606
237834
|
`;
|
|
237607
|
-
mkdirSync25(outDir, { recursive: true });
|
|
237608
|
-
ensurePlaceholders(outDir, stem);
|
|
237609
|
-
if (debugDir)
|
|
237610
|
-
mkdirSync25(debugDir, { recursive: true });
|
|
237611
237835
|
const desktopRenderer = "gl";
|
|
237612
|
-
const { js, resources } = await buildBundle(bundleOptions(flags), {
|
|
237836
|
+
const { js, resources, bakes } = await buildBundle(bundleOptions(flags), {
|
|
237613
237837
|
localAssets: true,
|
|
237614
237838
|
desktopRenderer,
|
|
237615
237839
|
extraEntries: [{ path: entryPath, type: "text", text: entryText }],
|
|
237616
237840
|
entryOverride: entryPath
|
|
237617
237841
|
});
|
|
237842
|
+
const target = pickTarget2(bakes, flags.name, entryFile);
|
|
237843
|
+
const stem = stemOf(target.path);
|
|
237844
|
+
const outDir = flags.out ? resolve22(root, flags.out) : dirname23(target.absPath);
|
|
237845
|
+
mkdirSync25(outDir, { recursive: true });
|
|
237846
|
+
if (debugDir)
|
|
237847
|
+
mkdirSync25(debugDir, { recursive: true });
|
|
237848
|
+
note(`Target: ${relative7(root, join46(outDir, `${stem}.bake`)).replace(/\\/g, "/")}${target.exists ? "" : " (the first bake: nothing there yet)"}${flags.out ? " (--out)" : ""}`);
|
|
237618
237849
|
if (!flags["no-unwrap"])
|
|
237619
237850
|
await unwrapReferenced(js, resources, root, cfg.texel);
|
|
237620
237851
|
const scratch = mkdtempSync4(join46(tmpdir4(), "lecodes-lightmap-"));
|
|
237621
237852
|
const outPng = join46(scratch, "frame.png");
|
|
237622
237853
|
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}.*…`);
|
|
237854
|
+
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
237855
|
let output = "";
|
|
237625
237856
|
if (flags["dry-run"])
|
|
237626
237857
|
process.env.CBK_LAYOUT_ONLY = "1";
|
|
@@ -237664,16 +237895,12 @@ import ${JSON.stringify(importPath)}
|
|
|
237664
237895
|
}
|
|
237665
237896
|
if (/\[lightmap\] done/.test(output)) {
|
|
237666
237897
|
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
237898
|
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
237899
|
const probeFiles = data.probes ? ` + ${data.probes.file} (${data.probes.count} probe(s) of ${data.probes.size}² at ${data.probes.spacing} m)` : "";
|
|
237672
237900
|
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`));
|
|
237901
|
+
const uv1File = data.uv1 ? ` + ${data.uv1} (the packed lightmap uv1)` : "";
|
|
237902
|
+
logErr(c.green(`✓ baked → ${relative7(root, outDir).replace(/\\/g, "/") || "."}/${stem}.bake + ${data.light.join(", ")} + ${data.aux.join(", ")}${splitFiles}${probeFiles}${gridFile}${uv1File}`));
|
|
237903
|
+
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
237904
|
if (debugDir)
|
|
237678
237905
|
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
237906
|
return;
|
|
@@ -237693,15 +237920,16 @@ var stats = defineCommand({
|
|
|
237693
237920
|
summary: "The per-instance numbers a .bake carries: mean lux, sun / sky visibility, texels, rect",
|
|
237694
237921
|
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
237922
|
flags: {
|
|
237696
|
-
bake: str("the .bake file", { value: "<file>"
|
|
237923
|
+
bake: str("the .bake file (default: the project's one .bake)", { value: "<file>" }),
|
|
237697
237924
|
key: str("only instances whose key matches this regular expression", { value: "<regex>" }),
|
|
237698
237925
|
sort: str("row order", { value: "<lux|key|texels|sun|sky>", default: "lux" }),
|
|
237699
237926
|
limit: num("rows to print (0 = all)", { default: 60 })
|
|
237700
237927
|
},
|
|
237701
|
-
examples: ["lecodes lightmap stats --
|
|
237928
|
+
examples: ["lecodes lightmap stats --key Wall", "lecodes lightmap stats --bake assets/level2/lightmap/level2.bake --sort sky --limit 0"],
|
|
237702
237929
|
run: ({ flags }) => {
|
|
237703
237930
|
const { root } = localProject();
|
|
237704
|
-
const
|
|
237931
|
+
const bakeFile = bakeFileOf(root, flags.bake);
|
|
237932
|
+
const data = readBake(bakeFile);
|
|
237705
237933
|
const re = flags.key ? new RegExp(flags.key) : null;
|
|
237706
237934
|
let rows = data.instances.filter((i) => i.receiver && (!re || re.test(i.key)));
|
|
237707
237935
|
const sorters = {
|
|
@@ -237718,7 +237946,7 @@ var stats = defineCommand({
|
|
|
237718
237946
|
const total = rows.length;
|
|
237719
237947
|
if (flags.limit > 0)
|
|
237720
237948
|
rows = rows.slice(0, flags.limit);
|
|
237721
|
-
log(`${basename18(
|
|
237949
|
+
log(`${basename18(bakeFile)}: ${data.pages} page(s) of ${data.size}, ${(data.texel * 100).toFixed(2)} cm texels, ${data.texels ?? "?"} texels, lightScale ${data.lightScale}`);
|
|
237722
237950
|
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
237951
|
for (const r of rows) {
|
|
237724
237952
|
const rect = r.rect ? `${r.rect[0]},${r.rect[1]} ${r.rect[2]}x${r.rect[3]}` : "";
|
|
@@ -237733,7 +237961,7 @@ var diff = defineCommand({
|
|
|
237733
237961
|
summary: "The noise of a bake, per instance: two bakes that differ only by --seed, compared texel by texel",
|
|
237734
237962
|
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
237963
|
flags: {
|
|
237736
|
-
bake: str("the first .bake", { value: "<file>"
|
|
237964
|
+
bake: str("the first .bake (default: the project's one .bake)", { value: "<file>" }),
|
|
237737
237965
|
"debug-dir": str("where the first bake kept its PFM layers", { value: "<dir>", default: ".lightmap" }),
|
|
237738
237966
|
bake2: str("the second .bake (another --seed)", { value: "<file>" }),
|
|
237739
237967
|
"debug-dir2": str("where the second bake kept its PFM layers", { value: "<dir>" }),
|
|
@@ -237744,21 +237972,23 @@ var diff = defineCommand({
|
|
|
237744
237972
|
limit: num("rows to print (0 = all)", { default: 40 })
|
|
237745
237973
|
},
|
|
237746
237974
|
examples: [
|
|
237747
|
-
"lecodes lightmap bake --
|
|
237748
|
-
"lecodes lightmap
|
|
237975
|
+
"lecodes lightmap bake --debug-dir .lightmap/seed1 --logs",
|
|
237976
|
+
"lecodes lightmap bake --seed 2 --out .lightmap/seed2/bake --debug-dir .lightmap/seed2 --logs",
|
|
237977
|
+
"lecodes lightmap diff --debug-dir .lightmap/seed1 --bake2 .lightmap/seed2/bake/level.bake --debug-dir2 .lightmap/seed2 --layer bounce"
|
|
237749
237978
|
],
|
|
237750
237979
|
run: ({ flags }) => {
|
|
237751
237980
|
const { root } = localProject();
|
|
237752
237981
|
if (!flags.bake2 || !flags["debug-dir2"])
|
|
237753
237982
|
throw new CliError("--bake2 and --debug-dir2 name the second bake (another --seed).");
|
|
237754
|
-
const
|
|
237983
|
+
const bakeFile = bakeFileOf(root, flags.bake);
|
|
237984
|
+
const a = readBake(bakeFile), b = readBake(resolve22(root, flags.bake2));
|
|
237755
237985
|
if (a.size !== b.size || a.pages !== b.pages)
|
|
237756
237986
|
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
237987
|
const ra = a.instances.filter((i) => i.receiver), rb = b.instances.filter((i) => i.receiver);
|
|
237758
237988
|
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
237989
|
throw new CliError("The bakes list different instances or rects — a diff needs the same scene baked twice with another --seed.");
|
|
237760
237990
|
}
|
|
237761
|
-
const stemA = basename18(
|
|
237991
|
+
const stemA = basename18(bakeFile, ".bake"), stemB = basename18(flags.bake2, ".bake");
|
|
237762
237992
|
const dirA = resolve22(root, flags["debug-dir"]), dirB = resolve22(root, flags["debug-dir2"]);
|
|
237763
237993
|
const layer = flags.layer;
|
|
237764
237994
|
if (!["irradiance", "bounce", "sun", "sky", "lamps"].includes(layer))
|
|
@@ -237831,7 +238061,7 @@ var diff = defineCommand({
|
|
|
237831
238061
|
}
|
|
237832
238062
|
});
|
|
237833
238063
|
var readPfm = (file) => {
|
|
237834
|
-
const buf =
|
|
238064
|
+
const buf = readFileSync36(file);
|
|
237835
238065
|
let o = 0;
|
|
237836
238066
|
const token = () => {
|
|
237837
238067
|
while (o < buf.length && /\s/.test(String.fromCharCode(buf[o])))
|
|
@@ -237911,7 +238141,7 @@ var inspect = defineCommand({
|
|
|
237911
238141
|
summary: "PNGs from a bake's debug layers: whole pages, or one instance's rect enlarged",
|
|
237912
238142
|
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
238143
|
flags: {
|
|
237914
|
-
bake: str("the .bake file", { value: "<file>"
|
|
238144
|
+
bake: str("the .bake file (default: the project's one .bake)", { value: "<file>" }),
|
|
237915
238145
|
"debug-dir": str("where the bake kept its PFM layers", { value: "<dir>", default: ".lightmap" }),
|
|
237916
238146
|
out: str("where the PNGs go", { value: "<dir>", default: ".lightmap/png" }),
|
|
237917
238147
|
key: str("instances whose key matches this regular expression (default: whole pages)", { value: "<regex>" }),
|
|
@@ -237922,10 +238152,10 @@ var inspect = defineCommand({
|
|
|
237922
238152
|
white: num("linear mode: the lux shown as white (0 = log mode)", { default: 0 }),
|
|
237923
238153
|
limit: num("instances to render with --key (0 = all)", { default: 24 })
|
|
237924
238154
|
},
|
|
237925
|
-
examples: ["lecodes lightmap inspect --
|
|
238155
|
+
examples: ["lecodes lightmap inspect --debug-dir .lightmap/level", "lecodes lightmap inspect --key 'Wall_05' --layer irradiance,sun,sky,lamps --scale 6"],
|
|
237926
238156
|
run: ({ flags }) => {
|
|
237927
238157
|
const { root } = localProject();
|
|
237928
|
-
const bakeFile =
|
|
238158
|
+
const bakeFile = bakeFileOf(root, flags.bake);
|
|
237929
238159
|
const data = readBake(bakeFile);
|
|
237930
238160
|
const stem = basename18(bakeFile).replace(/\.bake$/, "");
|
|
237931
238161
|
const dbg = resolve22(root, flags["debug-dir"]);
|
|
@@ -238097,7 +238327,7 @@ init_types4();
|
|
|
238097
238327
|
// src/commands/push.ts
|
|
238098
238328
|
init_cli();
|
|
238099
238329
|
init_api();
|
|
238100
|
-
import { readFileSync as
|
|
238330
|
+
import { readFileSync as readFileSync38 } from "node:fs";
|
|
238101
238331
|
import { basename as basename19 } from "node:path";
|
|
238102
238332
|
init_localFiles();
|
|
238103
238333
|
init_manifest();
|
|
@@ -238106,7 +238336,7 @@ init_manifest();
|
|
|
238106
238336
|
init_cli();
|
|
238107
238337
|
init_api();
|
|
238108
238338
|
init_localFiles();
|
|
238109
|
-
import { existsSync as existsSync42, readFileSync as
|
|
238339
|
+
import { existsSync as existsSync42, readFileSync as readFileSync37 } from "node:fs";
|
|
238110
238340
|
import { resolve as resolve23 } from "node:path";
|
|
238111
238341
|
init_shared();
|
|
238112
238342
|
var compareVersions = (a, b) => {
|
|
@@ -238193,11 +238423,11 @@ var upload2 = defineCommand({
|
|
|
238193
238423
|
const path = resolve23(file);
|
|
238194
238424
|
if (!existsSync42(path))
|
|
238195
238425
|
throw new CliError(`No such file: ${file}`);
|
|
238196
|
-
const code =
|
|
238426
|
+
const code = readFileSync37(path, "utf8");
|
|
238197
238427
|
const sdk = /^\/\/ sdk: (\S+)/m.exec(code)?.[1];
|
|
238198
238428
|
if (!sdk)
|
|
238199
238429
|
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`) ?
|
|
238430
|
+
const map = existsSync42(`${path}.map`) ? readFileSync37(`${path}.map`, "utf8") : null;
|
|
238201
238431
|
const { root, manifest, apiUrl, token } = linkedProject();
|
|
238202
238432
|
if (hasChanges(diffLocal(manifest, scanProject(root, manifest))))
|
|
238203
238433
|
await runPush({ message: flags.message || "Release" });
|
|
@@ -238302,9 +238532,9 @@ var runPush = async (opts) => {
|
|
|
238302
238532
|
if (source)
|
|
238303
238533
|
entry.assetId = source.id;
|
|
238304
238534
|
if (isTextKind(kind))
|
|
238305
|
-
entry.text =
|
|
238535
|
+
entry.text = readFileSync38(file.absPath, "utf8");
|
|
238306
238536
|
else if (!source || source.sha !== file.sha) {
|
|
238307
|
-
const blob = await uploadBlob(apiUrl, token, manifest.uuid, basename19(file.path),
|
|
238537
|
+
const blob = await uploadBlob(apiUrl, token, manifest.uuid, basename19(file.path), readFileSync38(file.absPath));
|
|
238308
238538
|
entry.blobFileId = blob.id;
|
|
238309
238539
|
uploaded++;
|
|
238310
238540
|
}
|
|
@@ -238504,7 +238734,7 @@ var login_default = defineCommand({
|
|
|
238504
238734
|
});
|
|
238505
238735
|
|
|
238506
238736
|
// src/commands/navmesh.ts
|
|
238507
|
-
import { existsSync as existsSync44, mkdirSync as mkdirSync26, mkdtempSync as mkdtempSync5, readdirSync as
|
|
238737
|
+
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
238738
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
238509
238739
|
import { basename as basename21, join as join48, relative as relative8, resolve as resolve25 } from "node:path";
|
|
238510
238740
|
init_cli();
|
|
@@ -239307,7 +239537,7 @@ var guessName = (root) => {
|
|
|
239307
239537
|
continue;
|
|
239308
239538
|
let entries;
|
|
239309
239539
|
try {
|
|
239310
|
-
entries =
|
|
239540
|
+
entries = readdirSync19(dir);
|
|
239311
239541
|
} catch {
|
|
239312
239542
|
continue;
|
|
239313
239543
|
}
|
|
@@ -239315,7 +239545,7 @@ var guessName = (root) => {
|
|
|
239315
239545
|
if (!f.endsWith(".scene.ts"))
|
|
239316
239546
|
continue;
|
|
239317
239547
|
try {
|
|
239318
|
-
if (/\bnavmesh\s*:/.test(
|
|
239548
|
+
if (/\bnavmesh\s*:/.test(readFileSync39(join48(dir, f), "utf8")))
|
|
239319
239549
|
return f.slice(0, -".scene.ts".length);
|
|
239320
239550
|
} catch {}
|
|
239321
239551
|
}
|
|
@@ -239465,7 +239695,7 @@ import ${JSON.stringify(importPath)}
|
|
|
239465
239695
|
const geoPath = join48(outDir, `${name}.navgeo`);
|
|
239466
239696
|
if (!existsSync44(geoPath))
|
|
239467
239697
|
throw new CliError(`The host reported a dump but ${geoPath} is missing.`);
|
|
239468
|
-
const geo = readNgeo(new Uint8Array(
|
|
239698
|
+
const geo = readNgeo(new Uint8Array(readFileSync39(geoPath)));
|
|
239469
239699
|
const params = {
|
|
239470
239700
|
agentRadius: range2("radius", flags.radius, config.agent.radius, 0.05, 10),
|
|
239471
239701
|
agentHeight: range2("height", flags.height, config.agent.height, 0.1, 20),
|
|
@@ -239519,7 +239749,7 @@ import ${JSON.stringify(importPath)}
|
|
|
239519
239749
|
}
|
|
239520
239750
|
if (!flags["keep-geometry"])
|
|
239521
239751
|
unlinkSync2(geoPath);
|
|
239522
|
-
const kb = Math.round(
|
|
239752
|
+
const kb = Math.round(statSync14(navmeshPath).size / 1024);
|
|
239523
239753
|
const b = result.bounds;
|
|
239524
239754
|
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
239755
|
logErr(c.green(`✓ baked → ${relative8(root, navmeshPath).replace(/\\/g, "/")} (${kb} KB)`));
|
|
@@ -239539,9 +239769,9 @@ init_cli();
|
|
|
239539
239769
|
|
|
239540
239770
|
// src/plugin/generate.ts
|
|
239541
239771
|
init_cli();
|
|
239542
|
-
import { existsSync as existsSync45, mkdirSync as mkdirSync27, readFileSync as
|
|
239772
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync27, readFileSync as readFileSync40, readdirSync as readdirSync20, statSync as statSync15, writeFileSync as writeFileSync29 } from "node:fs";
|
|
239543
239773
|
import { createRequire as createRequire7 } from "node:module";
|
|
239544
|
-
import { basename as basename22, join as join49, relative as relative9, resolve as resolve26, sep as
|
|
239774
|
+
import { basename as basename22, join as join49, relative as relative9, resolve as resolve26, sep as sep6 } from "node:path";
|
|
239545
239775
|
|
|
239546
239776
|
// src/plugin/permissions.ts
|
|
239547
239777
|
var PERMISSION_KINDS = ["camera", "microphone", "location", "speech"];
|
|
@@ -242410,10 +242640,10 @@ const wire = {
|
|
|
242410
242640
|
`;
|
|
242411
242641
|
|
|
242412
242642
|
// src/plugin/generate.ts
|
|
242413
|
-
var shown = (from, to) => relative9(from, to).split(
|
|
242643
|
+
var shown = (from, to) => relative9(from, to).split(sep6).join("/");
|
|
242414
242644
|
var implementsOf = (dir) => {
|
|
242415
242645
|
try {
|
|
242416
|
-
const raw = JSON.parse(
|
|
242646
|
+
const raw = JSON.parse(readFileSync40(join49(dir, MANIFEST_FILE), "utf8").replace(/^/, ""));
|
|
242417
242647
|
return typeof raw.implements === "string" ? raw.implements : null;
|
|
242418
242648
|
} catch {
|
|
242419
242649
|
return null;
|
|
@@ -242427,7 +242657,7 @@ var findPlugins = (path) => {
|
|
|
242427
242657
|
const holder = join49(root, "plugins");
|
|
242428
242658
|
if (!existsSync45(holder))
|
|
242429
242659
|
return [];
|
|
242430
|
-
return
|
|
242660
|
+
return readdirSync20(holder).sort().map((id) => ({ id, dir: join49(holder, id) })).filter((p) => statSync15(p.dir).isDirectory() && isPluginDir(p.dir));
|
|
242431
242661
|
};
|
|
242432
242662
|
var loadTypescript = (dir) => {
|
|
242433
242663
|
for (const from of [join49(dir, "package.json"), import.meta.url]) {
|
|
@@ -242444,7 +242674,7 @@ var generatePlugin = (ts, plugin) => {
|
|
|
242444
242674
|
const manifest = readManifestIfAny(plugin.dir, plugin.id);
|
|
242445
242675
|
const implemented = manifest?.implements;
|
|
242446
242676
|
const file = implemented ? firstPartyContractFile(implemented) : join49(plugin.dir, CONTRACT_FILE);
|
|
242447
|
-
const contract = readContract(ts, file, implemented ? firstPartyContractText(file) :
|
|
242677
|
+
const contract = readContract(ts, file, implemented ? firstPartyContractText(file) : readFileSync40(file, "utf8"));
|
|
242448
242678
|
checkPermissions(plugin, contract, manifest);
|
|
242449
242679
|
const id = implemented ?? plugin.id;
|
|
242450
242680
|
const handWritten = existsSync45(join49(plugin.dir, "sdk", `${id}.ts`));
|
|
@@ -242484,7 +242714,7 @@ var checkPermissions = (plugin, contract, manifest) => {
|
|
|
242484
242714
|
if (kinds.length === 0)
|
|
242485
242715
|
return;
|
|
242486
242716
|
const androidManifest = join49(plugin.dir, "android", "src", "main", "AndroidManifest.xml");
|
|
242487
|
-
const androidXml = manifest.android ? existsSync45(androidManifest) ?
|
|
242717
|
+
const androidXml = manifest.android ? existsSync45(androidManifest) ? readFileSync40(androidManifest, "utf8") : "" : null;
|
|
242488
242718
|
const missing = missingDeclarations(kinds, manifest.ios ? manifest.ios.infoPlist ?? {} : null, androidXml === null ? null : usesPermissions(androidXml), androidXml === null ? null : usesFeatures(androidXml));
|
|
242489
242719
|
const problems = [];
|
|
242490
242720
|
if (missing.infoPlist.length)
|
|
@@ -242499,16 +242729,16 @@ var checkPermissions = (plugin, contract, manifest) => {
|
|
|
242499
242729
|
var hostImports = (web) => {
|
|
242500
242730
|
const found = [];
|
|
242501
242731
|
const walk = (dir) => {
|
|
242502
|
-
for (const entry of
|
|
242732
|
+
for (const entry of readdirSync20(dir).sort()) {
|
|
242503
242733
|
const path = join49(dir, entry);
|
|
242504
|
-
if (
|
|
242734
|
+
if (statSync15(path).isDirectory()) {
|
|
242505
242735
|
if (entry !== "node_modules" && entry !== "dist")
|
|
242506
242736
|
walk(path);
|
|
242507
242737
|
continue;
|
|
242508
242738
|
}
|
|
242509
242739
|
if (!/\.(ts|tsx|js|mjs)$/.test(entry))
|
|
242510
242740
|
continue;
|
|
242511
|
-
|
|
242741
|
+
readFileSync40(path, "utf8").split(`
|
|
242512
242742
|
`).forEach((line, i) => {
|
|
242513
242743
|
const m = /(?:from\s+|import\s*\(\s*|import\s+)["'](lecodes-[^"']*)["']/.exec(line);
|
|
242514
242744
|
if (m && !/^\s*\/\//.test(line))
|
|
@@ -242529,8 +242759,8 @@ var kotlinPackage = (android, register) => {
|
|
|
242529
242759
|
}
|
|
242530
242760
|
let dir = root;
|
|
242531
242761
|
while (existsSync45(dir)) {
|
|
242532
|
-
const entries =
|
|
242533
|
-
const dirs = entries.filter((e) =>
|
|
242762
|
+
const entries = readdirSync20(dir).filter((e) => !e.startsWith("."));
|
|
242763
|
+
const dirs = entries.filter((e) => statSync15(join49(dir, e)).isDirectory());
|
|
242534
242764
|
if (dirs.length !== 1 || entries.length !== 1)
|
|
242535
242765
|
break;
|
|
242536
242766
|
dir = join49(dir, dirs[0]);
|
|
@@ -242545,7 +242775,7 @@ var repoSdkPath = (root) => {
|
|
|
242545
242775
|
if (!existsSync45(file))
|
|
242546
242776
|
return DEFAULT_SDK_PATH;
|
|
242547
242777
|
try {
|
|
242548
|
-
const pkg = JSON.parse(
|
|
242778
|
+
const pkg = JSON.parse(readFileSync40(file, "utf8"));
|
|
242549
242779
|
const path = pkg.lecodes?.iosSdkPath;
|
|
242550
242780
|
if (path !== undefined && typeof path !== "string")
|
|
242551
242781
|
throw new PackageError(`package.json lecodes.iosSdkPath: a path, as a string`);
|
|
@@ -242565,7 +242795,7 @@ var generate = (path, opts = {}) => {
|
|
|
242565
242795
|
const report = { plugins: [], repo: { written: [], stale: [], fresh: [] }, failures: [] };
|
|
242566
242796
|
const place = (f, entry) => {
|
|
242567
242797
|
const name = shown(root, f.file) || basename22(f.file);
|
|
242568
|
-
const current = existsSync45(f.file) ?
|
|
242798
|
+
const current = existsSync45(f.file) ? readFileSync40(f.file, "utf8") : null;
|
|
242569
242799
|
if (current === f.text) {
|
|
242570
242800
|
entry.fresh.push(name);
|
|
242571
242801
|
return;
|
|
@@ -243002,7 +243232,7 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
243002
243232
|
};
|
|
243003
243233
|
|
|
243004
243234
|
// src/commands/render.ts
|
|
243005
|
-
import { mkdirSync as mkdirSync30, readFileSync as
|
|
243235
|
+
import { mkdirSync as mkdirSync30, readFileSync as readFileSync42, writeFileSync as writeFileSync32 } from "node:fs";
|
|
243006
243236
|
import { dirname as dirname25, resolve as resolve30 } from "node:path";
|
|
243007
243237
|
|
|
243008
243238
|
// src/compile/headlessBundle.ts
|
|
@@ -243090,7 +243320,7 @@ var compileHeadlessBundle = async (opts = {}) => {
|
|
|
243090
243320
|
init_designMeta();
|
|
243091
243321
|
init_cli();
|
|
243092
243322
|
init_paths();
|
|
243093
|
-
import { existsSync as existsSync47, readFileSync as
|
|
243323
|
+
import { existsSync as existsSync47, readFileSync as readFileSync41, statSync as statSync16 } from "node:fs";
|
|
243094
243324
|
import { isAbsolute as isAbsolute3, join as join51, relative as relative10, resolve as resolve27 } from "node:path";
|
|
243095
243325
|
var SCREEN_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
|
|
243096
243326
|
var SCREEN_ENTRY_PATH = "/.screen-entry.ts";
|
|
@@ -243102,7 +243332,7 @@ var findScreenFile = (root, file, dirFlag) => {
|
|
|
243102
243332
|
candidates.push(join51(root, (dirFlag ?? DEFAULT_DESIGN_DIR).replace(/[/\\]+$/, ""), "screens", file));
|
|
243103
243333
|
}
|
|
243104
243334
|
for (const base of candidates) {
|
|
243105
|
-
if (existsSync47(base) &&
|
|
243335
|
+
if (existsSync47(base) && statSync16(base).isFile())
|
|
243106
243336
|
return base;
|
|
243107
243337
|
for (const ext of SCREEN_EXTS)
|
|
243108
243338
|
if (existsSync47(base + ext))
|
|
@@ -243124,7 +243354,7 @@ var resolveScreenTarget = (root, file, opts = {}) => {
|
|
|
243124
243354
|
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
243355
|
}
|
|
243126
243356
|
const key = toKey(rel);
|
|
243127
|
-
if (!/^\s*export\s+default\b/m.test(
|
|
243357
|
+
if (!/^\s*export\s+default\b/m.test(readFileSync41(abs, "utf8"))) {
|
|
243128
243358
|
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
243359
|
}
|
|
243130
243360
|
const invoke = opts.state !== undefined ? `screen(${JSON.stringify(opts.state)})` : "screen()";
|
|
@@ -243921,7 +244151,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
243921
244151
|
if (typeof value === "string") {
|
|
243922
244152
|
const abs = resolve30(baseDir, value);
|
|
243923
244153
|
try {
|
|
243924
|
-
map = JSON.parse(
|
|
244154
|
+
map = JSON.parse(readFileSync42(abs, "utf8"));
|
|
243925
244155
|
} catch (e) {
|
|
243926
244156
|
throw new CliError(`Can't read fixtures "${value}": ${e instanceof Error ? e.message : String(e)}`);
|
|
243927
244157
|
}
|
|
@@ -243934,7 +244164,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
243934
244164
|
var readScenarioFile = (path) => {
|
|
243935
244165
|
let raw;
|
|
243936
244166
|
try {
|
|
243937
|
-
raw = JSON.parse(
|
|
244167
|
+
raw = JSON.parse(readFileSync42(resolve30(path), "utf8"));
|
|
243938
244168
|
} catch (e) {
|
|
243939
244169
|
throw new CliError(`Can't read scenario "${path}": ${e instanceof Error ? e.message : String(e)}`);
|
|
243940
244170
|
}
|
|
@@ -244279,7 +244509,7 @@ var renderHeadless = async (flags, file) => {
|
|
|
244279
244509
|
|
|
244280
244510
|
// src/commands/scene.ts
|
|
244281
244511
|
init_cli();
|
|
244282
|
-
import { existsSync as existsSync50, readFileSync as
|
|
244512
|
+
import { existsSync as existsSync50, readFileSync as readFileSync44, readdirSync as readdirSync21, statSync as statSync17, writeFileSync as writeFileSync34 } from "node:fs";
|
|
244283
244513
|
import { basename as basename23, dirname as dirname26, join as join54, relative as relative11, resolve as resolve31 } from "node:path";
|
|
244284
244514
|
|
|
244285
244515
|
// src/compile/sceneCompile.ts
|
|
@@ -244288,7 +244518,7 @@ init_ignore();
|
|
|
244288
244518
|
init_cli();
|
|
244289
244519
|
init_projectCompile();
|
|
244290
244520
|
import { createHash as createHash9 } from "node:crypto";
|
|
244291
|
-
import { existsSync as existsSync49, mkdirSync as mkdirSync31, readFileSync as
|
|
244521
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync31, readFileSync as readFileSync43, writeFileSync as writeFileSync33 } from "node:fs";
|
|
244292
244522
|
import { join as join53 } from "node:path";
|
|
244293
244523
|
var TEXT_EXT = /\.(ts|js|json|svg|txt|md)$/i;
|
|
244294
244524
|
var rel = (key) => key.replace(/^\//, "");
|
|
@@ -244300,11 +244530,11 @@ var compileSceneEditor = async (opts) => {
|
|
|
244300
244530
|
for (const file of scan.files) {
|
|
244301
244531
|
const path = "./" + rel(file.path);
|
|
244302
244532
|
if (TEXT_EXT.test(path)) {
|
|
244303
|
-
entries.push({ path, type: "text", text:
|
|
244533
|
+
entries.push({ path, type: "text", text: readFileSync43(file.absPath, "utf8") });
|
|
244304
244534
|
} else if (/\.mat$/i.test(path)) {
|
|
244305
|
-
entries.push({ path, type: "shader", text:
|
|
244535
|
+
entries.push({ path, type: "shader", text: readFileSync43(file.absPath, "utf8"), absPath: file.absPath });
|
|
244306
244536
|
} else {
|
|
244307
|
-
entries.push({ path, type: "resource", fileSrc: "/project/" + rel(file.path) });
|
|
244537
|
+
entries.push({ path, type: "resource", fileSrc: "/project/" + rel(file.path), absPath: file.absPath });
|
|
244308
244538
|
}
|
|
244309
244539
|
}
|
|
244310
244540
|
const shaderEntries = entries.filter((e) => e.type === "shader");
|
|
@@ -244384,7 +244614,7 @@ var getContext2 = (pathArg) => {
|
|
|
244384
244614
|
manifest = null;
|
|
244385
244615
|
if (pathArg) {
|
|
244386
244616
|
const abs = resolve31(process.cwd(), pathArg);
|
|
244387
|
-
if (existsSync50(abs) &&
|
|
244617
|
+
if (existsSync50(abs) && statSync17(abs).isDirectory())
|
|
244388
244618
|
root = abs;
|
|
244389
244619
|
else if (abs.endsWith(".scene.ts") && existsSync50(abs))
|
|
244390
244620
|
root = findAppRoot(dirname26(abs)) ?? dirname26(abs);
|
|
@@ -244409,7 +244639,7 @@ var writeMcpConfig2 = (root, port) => {
|
|
|
244409
244639
|
let config = {};
|
|
244410
244640
|
if (existsSync50(path)) {
|
|
244411
244641
|
try {
|
|
244412
|
-
config = JSON.parse(
|
|
244642
|
+
config = JSON.parse(readFileSync44(path, "utf8"));
|
|
244413
244643
|
} catch {
|
|
244414
244644
|
warnErr(".mcp.json exists but isn't valid JSON — left it untouched. Add the lecodes-scene server by hand.");
|
|
244415
244645
|
return;
|
|
@@ -244428,11 +244658,11 @@ var writeMcpConfig2 = (root, port) => {
|
|
|
244428
244658
|
};
|
|
244429
244659
|
var countScenes = (dir) => {
|
|
244430
244660
|
let n = 0;
|
|
244431
|
-
for (const name of
|
|
244661
|
+
for (const name of readdirSync21(dir)) {
|
|
244432
244662
|
if (name === "node_modules" || name.startsWith("."))
|
|
244433
244663
|
continue;
|
|
244434
244664
|
const full = join54(dir, name);
|
|
244435
|
-
if (
|
|
244665
|
+
if (statSync17(full).isDirectory())
|
|
244436
244666
|
n += countScenes(full);
|
|
244437
244667
|
else if (name.endsWith(".scene.ts"))
|
|
244438
244668
|
n++;
|
|
@@ -244524,7 +244754,7 @@ var serve_default = defineCommand({
|
|
|
244524
244754
|
});
|
|
244525
244755
|
|
|
244526
244756
|
// src/commands/shaders/index.ts
|
|
244527
|
-
import { readFileSync as
|
|
244757
|
+
import { readFileSync as readFileSync46 } from "node:fs";
|
|
244528
244758
|
import { relative as relative13 } from "node:path";
|
|
244529
244759
|
init_cli();
|
|
244530
244760
|
init_shared();
|
|
@@ -244533,7 +244763,7 @@ init_shared();
|
|
|
244533
244763
|
init_compile();
|
|
244534
244764
|
init_distRoot();
|
|
244535
244765
|
init_cli();
|
|
244536
|
-
import { existsSync as existsSync51, mkdirSync as mkdirSync32, readdirSync as
|
|
244766
|
+
import { existsSync as existsSync51, mkdirSync as mkdirSync32, readdirSync as readdirSync22, readFileSync as readFileSync45, writeFileSync as writeFileSync35 } from "node:fs";
|
|
244537
244767
|
import { basename as basename25, join as join55, relative as relative12, resolve as resolve32 } from "node:path";
|
|
244538
244768
|
var engineMaterialsDir = () => {
|
|
244539
244769
|
const candidates = [
|
|
@@ -244549,7 +244779,7 @@ var engineMaterialNames = () => {
|
|
|
244549
244779
|
const dir = engineMaterialsDir();
|
|
244550
244780
|
if (!dir)
|
|
244551
244781
|
return [];
|
|
244552
|
-
return
|
|
244782
|
+
return readdirSync22(dir).filter((f) => f.endsWith(".mat") && !f.startsWith("camera") && f !== "shader360.mat").map((f) => f.slice(0, -4)).sort();
|
|
244553
244783
|
};
|
|
244554
244784
|
var NAME_RE = /^[a-z][a-z0-9_-]*$/i;
|
|
244555
244785
|
var matName = (name) => name.replace(/-/g, "_");
|
|
@@ -244640,7 +244870,7 @@ var writeNewShader = (o) => {
|
|
|
244640
244870
|
const known = engineMaterialNames();
|
|
244641
244871
|
if (!known.includes(ref))
|
|
244642
244872
|
throw new CliError(`no engine material "${ref}". Known: ${known.join(", ")}`);
|
|
244643
|
-
mat = refMat(name, ref,
|
|
244873
|
+
mat = refMat(name, ref, readFileSync45(join55(srcDir, `${ref}.mat`), "utf8"));
|
|
244644
244874
|
} else
|
|
244645
244875
|
mat = starterMat(name);
|
|
244646
244876
|
mkdirSync32(dir, { recursive: true });
|
|
@@ -244672,7 +244902,7 @@ var status2 = async () => {
|
|
|
244672
244902
|
if (matcId === null)
|
|
244673
244903
|
state = c.dim("unknown (matc not downloaded)");
|
|
244674
244904
|
else {
|
|
244675
|
-
const text =
|
|
244905
|
+
const text = readFileSync46(shader.absPath, "utf8");
|
|
244676
244906
|
if (shaderIsCompiled(root, text, matcId))
|
|
244677
244907
|
state = "compiled";
|
|
244678
244908
|
else {
|
|
@@ -244681,7 +244911,7 @@ var status2 = async () => {
|
|
|
244681
244911
|
}
|
|
244682
244912
|
}
|
|
244683
244913
|
log(` ${shader.path.padEnd(width)} ${state}`);
|
|
244684
|
-
const schema = parseShaderSchema(
|
|
244914
|
+
const schema = parseShaderSchema(readFileSync46(shader.absPath, "utf8"));
|
|
244685
244915
|
for (const p of schema.params) {
|
|
244686
244916
|
const range = p.min !== undefined ? ` [${p.min}..${p.max}]` : "";
|
|
244687
244917
|
const def = p.default !== null && p.default !== undefined ? ` = ${JSON.stringify(p.default)}` : "";
|
|
@@ -244722,7 +244952,7 @@ var compileShaders = async (platforms) => {
|
|
|
244722
244952
|
}
|
|
244723
244953
|
const matcExe = await resolveMatcExe();
|
|
244724
244954
|
const matcId = matcIdentity(matcExe);
|
|
244725
|
-
const wasCompiled = new Map(shaders.map((s) => [s.path, shaderIsCompiled(root,
|
|
244955
|
+
const wasCompiled = new Map(shaders.map((s) => [s.path, shaderIsCompiled(root, readFileSync46(s.absPath, "utf8"), matcId)]));
|
|
244726
244956
|
const errors = [];
|
|
244727
244957
|
for (const shader of shaders) {
|
|
244728
244958
|
try {
|
|
@@ -244824,7 +245054,7 @@ var status_default = defineCommand({
|
|
|
244824
245054
|
});
|
|
244825
245055
|
|
|
244826
245056
|
// src/commands/test.ts
|
|
244827
|
-
import { existsSync as existsSync53, mkdirSync as mkdirSync34, readFileSync as
|
|
245057
|
+
import { existsSync as existsSync53, mkdirSync as mkdirSync34, readFileSync as readFileSync47, readdirSync as readdirSync23 } from "node:fs";
|
|
244828
245058
|
import { dirname as dirname28, resolve as resolve33 } from "node:path";
|
|
244829
245059
|
init_manifest();
|
|
244830
245060
|
|
|
@@ -245341,7 +245571,7 @@ var slug = (s) => s.replace(/[^a-zA-Z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").sli
|
|
|
245341
245571
|
var readFlowFile = (abs, displayName) => {
|
|
245342
245572
|
let raw;
|
|
245343
245573
|
try {
|
|
245344
|
-
raw = JSON.parse(
|
|
245574
|
+
raw = JSON.parse(readFileSync47(abs, "utf8"));
|
|
245345
245575
|
} catch (e) {
|
|
245346
245576
|
throw new CliError(`Can't read "${displayName}": ${e instanceof Error ? e.message : String(e)}`);
|
|
245347
245577
|
}
|
|
@@ -245449,7 +245679,7 @@ var runTests = async (args, flags) => {
|
|
|
245449
245679
|
cases.push(readFlowFile(abs, given));
|
|
245450
245680
|
}
|
|
245451
245681
|
} else if (existsSync53(testsDir)) {
|
|
245452
|
-
for (const f of
|
|
245682
|
+
for (const f of readdirSync23(testsDir).filter((f) => f.endsWith(".flow.json")).sort()) {
|
|
245453
245683
|
cases.push(readFlowFile(resolve33(testsDir, f), f));
|
|
245454
245684
|
}
|
|
245455
245685
|
}
|
|
@@ -245467,7 +245697,7 @@ var runTests = async (args, flags) => {
|
|
|
245467
245697
|
if (!desktop && !lite && (wantFlows || flowsOnly) && existsSync53(designMetaPath)) {
|
|
245468
245698
|
let meta;
|
|
245469
245699
|
try {
|
|
245470
|
-
meta = JSON.parse(
|
|
245700
|
+
meta = JSON.parse(readFileSync47(designMetaPath, "utf8"));
|
|
245471
245701
|
} catch (e) {
|
|
245472
245702
|
throw new CliError(`Can't read ${designMetaPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
245473
245703
|
}
|
|
@@ -245540,7 +245770,7 @@ var runTests = async (args, flags) => {
|
|
|
245540
245770
|
script: plan.text,
|
|
245541
245771
|
fixedDtMs: nativeFixedDt
|
|
245542
245772
|
});
|
|
245543
|
-
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ?
|
|
245773
|
+
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ? readFileSync47(path, "utf8") : null);
|
|
245544
245774
|
if (!r.loaded)
|
|
245545
245775
|
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
245776
|
return {
|
|
@@ -245579,7 +245809,7 @@ var runTests = async (args, flags) => {
|
|
|
245579
245809
|
height: flags.height || kase.height || projectViewport?.height || 844,
|
|
245580
245810
|
onConsole
|
|
245581
245811
|
});
|
|
245582
|
-
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ?
|
|
245812
|
+
const r = evaluateDesktopRun(plan, output, (path) => existsSync53(path) ? readFileSync47(path, "utf8") : null);
|
|
245583
245813
|
return {
|
|
245584
245814
|
name: kase.name,
|
|
245585
245815
|
kind: kase.kind,
|
|
@@ -245688,7 +245918,7 @@ var runTests = async (args, flags) => {
|
|
|
245688
245918
|
init_peerInstall();
|
|
245689
245919
|
import { createRequire as createRequire8 } from "node:module";
|
|
245690
245920
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
245691
|
-
import { existsSync as existsSync54, mkdtempSync as mkdtempSync7, readdirSync as
|
|
245921
|
+
import { existsSync as existsSync54, mkdtempSync as mkdtempSync7, readdirSync as readdirSync24, rmSync as rmSync17, statSync as statSync18 } from "node:fs";
|
|
245692
245922
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
245693
245923
|
import { extname, join as join57, relative as relative14, resolve as resolve34 } from "node:path";
|
|
245694
245924
|
init_cli();
|
|
@@ -245746,11 +245976,11 @@ var ktxToPng = (ktx, file, out) => {
|
|
|
245746
245976
|
};
|
|
245747
245977
|
var collect = (dir) => {
|
|
245748
245978
|
const out = [];
|
|
245749
|
-
for (const name of
|
|
245979
|
+
for (const name of readdirSync24(dir)) {
|
|
245750
245980
|
if (name === "node_modules" || name.startsWith("."))
|
|
245751
245981
|
continue;
|
|
245752
245982
|
const full = join57(dir, name);
|
|
245753
|
-
if (
|
|
245983
|
+
if (statSync18(full).isDirectory())
|
|
245754
245984
|
out.push(...collect(full));
|
|
245755
245985
|
else if (IMAGE_EXT.test(name))
|
|
245756
245986
|
out.push(full);
|
|
@@ -245778,7 +246008,7 @@ var thumbs = async (targets, size, force) => {
|
|
|
245778
246008
|
const abs = resolve34(process.cwd(), arg);
|
|
245779
246009
|
if (!existsSync54(abs))
|
|
245780
246010
|
throw new CliError(`No such file or folder: ${arg}`);
|
|
245781
|
-
if (
|
|
246011
|
+
if (statSync18(abs).isDirectory())
|
|
245782
246012
|
files.push(...collect(abs));
|
|
245783
246013
|
else if (IMAGE_EXT.test(abs))
|
|
245784
246014
|
files.push(abs);
|
|
@@ -245855,7 +246085,7 @@ init_peerInstall();
|
|
|
245855
246085
|
init_archives();
|
|
245856
246086
|
init_packageManager();
|
|
245857
246087
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
245858
|
-
import { existsSync as existsSync55, readdirSync as
|
|
246088
|
+
import { existsSync as existsSync55, readdirSync as readdirSync25 } from "node:fs";
|
|
245859
246089
|
import { homedir as homedir14 } from "node:os";
|
|
245860
246090
|
import { dirname as dirname29, join as join58, resolve as resolve36 } from "node:path";
|
|
245861
246091
|
|
|
@@ -246026,7 +246256,7 @@ ${c.bold(name)} ${c.dim(what)}`);
|
|
|
246026
246256
|
return ["skipped", "not inside a project"];
|
|
246027
246257
|
if (flags["no-shells"])
|
|
246028
246258
|
return ["skipped", "--no-shells"];
|
|
246029
|
-
const present = ["ios", "android"].filter((d) => existsSync55(join58(root, d)) &&
|
|
246259
|
+
const present = ["ios", "android"].filter((d) => existsSync55(join58(root, d)) && readdirSync25(join58(root, d)).length > 0);
|
|
246030
246260
|
if (present.length === 0)
|
|
246031
246261
|
return ["skipped", "no ios/ or android/ shell in this project (`lecodes app init ios|android`)"];
|
|
246032
246262
|
await runSubcommand(app_default, "update");
|
|
@@ -246105,7 +246335,7 @@ init_cli();
|
|
|
246105
246335
|
// src/web/build.ts
|
|
246106
246336
|
init_compile();
|
|
246107
246337
|
import { createHash as createHash10 } from "node:crypto";
|
|
246108
|
-
import { copyFileSync as copyFileSync2, cpSync as cpSync7, existsSync as existsSync56, mkdirSync as mkdirSync35, readFileSync as
|
|
246338
|
+
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
246339
|
import { dirname as dirname30, extname as extname2, join as join59, resolve as resolve37 } from "node:path";
|
|
246110
246340
|
init_fonts();
|
|
246111
246341
|
init_assetIcons();
|
|
@@ -246118,9 +246348,9 @@ var normalBase = (base) => {
|
|
|
246118
246348
|
};
|
|
246119
246349
|
var walk = (dir, prefix = "") => {
|
|
246120
246350
|
const out = [];
|
|
246121
|
-
for (const name of
|
|
246351
|
+
for (const name of readdirSync26(dir)) {
|
|
246122
246352
|
const abs = join59(dir, name);
|
|
246123
|
-
const stat =
|
|
246353
|
+
const stat = statSync19(abs);
|
|
246124
246354
|
if (stat.isDirectory())
|
|
246125
246355
|
out.push(...walk(abs, `${prefix}${name}/`));
|
|
246126
246356
|
else
|
|
@@ -246149,7 +246379,7 @@ var buildWeb = async (options) => {
|
|
|
246149
246379
|
for (const entry of entries) {
|
|
246150
246380
|
if (entry.type !== "shader" || !entry.absPath)
|
|
246151
246381
|
continue;
|
|
246152
|
-
const text =
|
|
246382
|
+
const text = readFileSync48(entry.absPath, "utf8");
|
|
246153
246383
|
const hash = createHash10("sha256").update(text).digest("hex").slice(0, 16);
|
|
246154
246384
|
shaders.set(hash, JSON.stringify(buildLiteMaterialArtifact(text)));
|
|
246155
246385
|
entry.shaders = [{ platform: "opengl", src: `shaders/${hash}_opengl.filamat` }];
|
|
@@ -246196,7 +246426,7 @@ var buildWeb = async (options) => {
|
|
|
246196
246426
|
cpSync7(lite, out, { recursive: true });
|
|
246197
246427
|
const table = join59(out, "features.json");
|
|
246198
246428
|
if (existsSync56(table)) {
|
|
246199
|
-
const { features, fonts } = JSON.parse(
|
|
246429
|
+
const { features, fonts } = JSON.parse(readFileSync48(table, "utf8"));
|
|
246200
246430
|
if (config.font === "system")
|
|
246201
246431
|
for (const file of fonts ?? [])
|
|
246202
246432
|
rmSync18(join59(out, file), { force: true });
|
|
@@ -246210,7 +246440,7 @@ var buildWeb = async (options) => {
|
|
|
246210
246440
|
}
|
|
246211
246441
|
const pluginsTable = join59(out, "plugins.json");
|
|
246212
246442
|
if (existsSync56(pluginsTable) || halves.length > 0) {
|
|
246213
|
-
const { plugins } = existsSync56(pluginsTable) ? JSON.parse(
|
|
246443
|
+
const { plugins } = existsSync56(pluginsTable) ? JSON.parse(readFileSync48(pluginsTable, "utf8")) : { plugins: {} };
|
|
246214
246444
|
const kept = {};
|
|
246215
246445
|
for (const id of Object.keys(plugins)) {
|
|
246216
246446
|
if (listed.has(id))
|
|
@@ -246260,7 +246490,7 @@ var buildWeb = async (options) => {
|
|
|
246260
246490
|
writeFileSync37(join59(out, "shaders", `${hash}_webgl-lite.filamat`), artifact);
|
|
246261
246491
|
}
|
|
246262
246492
|
const app = readAppConfigAt(root);
|
|
246263
|
-
let html =
|
|
246493
|
+
let html = readFileSync48(join59(lite, "index.html"), "utf8");
|
|
246264
246494
|
const head = [];
|
|
246265
246495
|
head.push(`<meta name="theme-color" content="${escapeHtml(config.themeColor ?? "#000000")}" />`);
|
|
246266
246496
|
if (app?.icon) {
|
|
@@ -246300,7 +246530,7 @@ var buildWeb = async (options) => {
|
|
|
246300
246530
|
};
|
|
246301
246531
|
|
|
246302
246532
|
// src/web/preview.ts
|
|
246303
|
-
import { createReadStream as createReadStream3, existsSync as existsSync57, statSync as
|
|
246533
|
+
import { createReadStream as createReadStream3, existsSync as existsSync57, statSync as statSync20 } from "node:fs";
|
|
246304
246534
|
import { createServer as createServer4 } from "node:http";
|
|
246305
246535
|
import { join as join60, resolve as resolve38 } from "node:path";
|
|
246306
246536
|
var startPreview = async (dir, port) => {
|
|
@@ -246322,10 +246552,10 @@ var startPreview = async (dir, port) => {
|
|
|
246322
246552
|
return;
|
|
246323
246553
|
}
|
|
246324
246554
|
let file = join60(root, ...parts);
|
|
246325
|
-
if (existsSync57(file) &&
|
|
246555
|
+
if (existsSync57(file) && statSync20(file).isDirectory())
|
|
246326
246556
|
file = join60(file, "index.html");
|
|
246327
246557
|
let status = 200;
|
|
246328
|
-
if (!existsSync57(file) || !
|
|
246558
|
+
if (!existsSync57(file) || !statSync20(file).isFile()) {
|
|
246329
246559
|
if (!fallback || /\.[a-z0-9]+$/i.test(parts[parts.length - 1] ?? "")) {
|
|
246330
246560
|
res.writeHead(404, { "content-type": "text/plain" });
|
|
246331
246561
|
res.end("Not found");
|
|
@@ -246355,7 +246585,7 @@ var startPreview = async (dir, port) => {
|
|
|
246355
246585
|
init_shared();
|
|
246356
246586
|
|
|
246357
246587
|
// src/dev/https.ts
|
|
246358
|
-
import { existsSync as existsSync58, mkdirSync as mkdirSync36, readFileSync as
|
|
246588
|
+
import { existsSync as existsSync58, mkdirSync as mkdirSync36, readFileSync as readFileSync49, writeFileSync as writeFileSync38 } from "node:fs";
|
|
246359
246589
|
import { homedir as homedir15 } from "node:os";
|
|
246360
246590
|
import { join as join61 } from "node:path";
|
|
246361
246591
|
var DIR = () => join61(homedir15(), ".lecodes", "dev-https");
|
|
@@ -246365,12 +246595,12 @@ var devCertificate = async (names, dir = DIR()) => {
|
|
|
246365
246595
|
const files = { cert: join61(dir, "cert.pem"), key: join61(dir, "key.pem"), meta: join61(dir, "names.json") };
|
|
246366
246596
|
let kept = null;
|
|
246367
246597
|
try {
|
|
246368
|
-
kept = JSON.parse(
|
|
246598
|
+
kept = JSON.parse(readFileSync49(files.meta, "utf8"));
|
|
246369
246599
|
} catch {}
|
|
246370
246600
|
const wanted = [...new Set(["localhost", "127.0.0.1", ...names])];
|
|
246371
246601
|
const fresh = kept && Date.now() - kept.made < RENEW_DAYS * 86400000 && wanted.every((n) => kept.names.includes(n));
|
|
246372
246602
|
if (fresh && existsSync58(files.cert) && existsSync58(files.key)) {
|
|
246373
|
-
return { cert:
|
|
246603
|
+
return { cert: readFileSync49(files.cert, "utf8"), key: readFileSync49(files.key, "utf8") };
|
|
246374
246604
|
}
|
|
246375
246605
|
const { generate } = await Promise.resolve().then(() => __toESM(require_selfsigned(), 1));
|
|
246376
246606
|
const all = [...new Set([...kept?.names ?? [], ...wanted])];
|