@lucent-lang/lucent 0.0.4
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/app.plugin.js +92 -0
- package/bin/lucent.cjs +16 -0
- package/core/index.cjs +11 -0
- package/dist/bench-CR3E7e2e.js +304 -0
- package/dist/build-CAIrRSYA.js +7 -0
- package/dist/build-check-QozuNJm5.js +92 -0
- package/dist/check-1SCmYlqA.js +7 -0
- package/dist/clean-BVwpbJ5K.js +35 -0
- package/dist/cli.js +406 -0
- package/dist/codes-CIuwXt1S.js +260 -0
- package/dist/compiler.js +4 -0
- package/dist/confirm-BYF5eY3q.js +34 -0
- package/dist/dashboard-B-NzjjaN.js +91 -0
- package/dist/dev-BYWMP7oC.js +221 -0
- package/dist/diagnostic-BM9sXmwl.js +30 -0
- package/dist/diff-BTDo3Sro.js +44 -0
- package/dist/doctor-C0PrfWT6.js +230 -0
- package/dist/doctor-DdR4JnVc.js +30 -0
- package/dist/explain--vV1oaRl.js +35 -0
- package/dist/format-D9fnIMEx.js +53 -0
- package/dist/init-gIabu1S_.js +207 -0
- package/dist/live-steps-BGcWFM9M.js +79 -0
- package/dist/new-module-C2mtb0op.js +66 -0
- package/dist/package-manager-BnxwCySi.js +30 -0
- package/dist/package.json +3 -0
- package/dist/packages-HyskKIsY.js +150 -0
- package/dist/pipeline-CH7-2cxu.js +232 -0
- package/dist/project-D8tEet0k.js +150 -0
- package/dist/sdk-coverage-BoW_3Efd.js +64 -0
- package/dist/sdk-prefetch-mo04JDZV.js +89 -0
- package/dist/sdk-search-Iv4K3-8a.js +124 -0
- package/dist/sdk-show-CkrdlqlP.js +74 -0
- package/dist/sdks-Xoyiy2E4.js +28 -0
- package/dist/src-BD7f1_aZ.js +11493 -0
- package/dist/steps--_h-FFS7.js +24 -0
- package/dist/theme-uv5bc0aK.js +134 -0
- package/dist/tsconfig-S4uyLNzf.js +59 -0
- package/dist/version-bqpIO5sP.js +26 -0
- package/gradle/lucent-classpath.gradle +38 -0
- package/gradle/lucent-classpath.init.gradle +6 -0
- package/gradle/lucent.gradle +24 -0
- package/lib/core.cjs +106 -0
- package/lib/globals.d.ts +36 -0
- package/lib/sdk/android.d.ts +8 -0
- package/lib/sdk/core.d.ts +23 -0
- package/lib/sdk/ios.d.ts +33 -0
- package/lib/sdk/platform.d.ts +8 -0
- package/lib/sdk/thread.d.ts +8 -0
- package/metro/index.cjs +72 -0
- package/metro/index.d.ts +6 -0
- package/metro/transformer.cjs +70 -0
- package/package.json +61 -0
- package/runtime/cpp/lucent/abort.cpp +61 -0
- package/runtime/cpp/lucent/abort.h +54 -0
- package/runtime/cpp/lucent/array.h +442 -0
- package/runtime/cpp/lucent/async.h +236 -0
- package/runtime/cpp/lucent/builtins.cpp +163 -0
- package/runtime/cpp/lucent/bytes.h +129 -0
- package/runtime/cpp/lucent/console.h +17 -0
- package/runtime/cpp/lucent/core.h +129 -0
- package/runtime/cpp/lucent/date.cpp +441 -0
- package/runtime/cpp/lucent/date.h +82 -0
- package/runtime/cpp/lucent/equality.h +87 -0
- package/runtime/cpp/lucent/function.h +61 -0
- package/runtime/cpp/lucent/generator.h +244 -0
- package/runtime/cpp/lucent/helpers.h +226 -0
- package/runtime/cpp/lucent/jserror.cpp +51 -0
- package/runtime/cpp/lucent/jserror.h +66 -0
- package/runtime/cpp/lucent/jsi/convert.cpp +202 -0
- package/runtime/cpp/lucent/jsi/convert.h +612 -0
- package/runtime/cpp/lucent/jsi/host.cpp +322 -0
- package/runtime/cpp/lucent/jsi/host.h +166 -0
- package/runtime/cpp/lucent/json.cpp +243 -0
- package/runtime/cpp/lucent/json.h +164 -0
- package/runtime/cpp/lucent/json_parse.h +138 -0
- package/runtime/cpp/lucent/jsstring.cpp +874 -0
- package/runtime/cpp/lucent/jsstring.h +152 -0
- package/runtime/cpp/lucent/lucent.h +24 -0
- package/runtime/cpp/lucent/map.h +344 -0
- package/runtime/cpp/lucent/native.cpp +76 -0
- package/runtime/cpp/lucent/native.h +116 -0
- package/runtime/cpp/lucent/number.cpp +545 -0
- package/runtime/cpp/lucent/number.h +190 -0
- package/runtime/cpp/lucent/ops.h +165 -0
- package/runtime/cpp/lucent/platform/android.cpp +437 -0
- package/runtime/cpp/lucent/platform/android.h +117 -0
- package/runtime/cpp/lucent/platform/ios.h +297 -0
- package/runtime/cpp/lucent/platform/ios.mm +31 -0
- package/runtime/cpp/lucent/regexp.cpp +440 -0
- package/runtime/cpp/lucent/regexp.h +107 -0
- package/runtime/cpp/lucent/scheduler.cpp +153 -0
- package/runtime/cpp/lucent/scheduler.h +160 -0
- package/runtime/cpp/lucent/unicode_data.inc +4051 -0
- package/runtime/cpp/rn/LucentModule.cpp +35 -0
- package/runtime/cpp/rn/LucentModule.h +37 -0
- package/runtime/cpp/third_party/quickjs/LICENSE +22 -0
- package/runtime/cpp/third_party/quickjs/README.md +11 -0
- package/runtime/cpp/third_party/quickjs/cutils.c +641 -0
- package/runtime/cpp/third_party/quickjs/cutils.h +457 -0
- package/runtime/cpp/third_party/quickjs/libregexp-opcode.h +73 -0
- package/runtime/cpp/third_party/quickjs/libregexp.c +3448 -0
- package/runtime/cpp/third_party/quickjs/libregexp.h +65 -0
- package/runtime/cpp/third_party/quickjs/libunicode-table.h +5206 -0
- package/runtime/cpp/third_party/quickjs/libunicode.c +2124 -0
- package/runtime/cpp/third_party/quickjs/libunicode.h +196 -0
- package/runtime/js/index.d.ts +7 -0
- package/runtime/js/index.js +60 -0
- package/runtime/native/LucentNative.podspec +28 -0
- package/runtime/native/android/CMakeLists.txt +51 -0
- package/runtime/native/android/build.gradle +22 -0
- package/runtime/native/android/include/lucentnative.h +16 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentPackage.java +25 -0
- package/runtime/native/android/src/main/java/dev/lucent/NativeProxy.java +132 -0
- package/runtime/native/ios/LucentRegistration.mm +23 -0
- package/runtime/native/package.json +6 -0
- package/runtime/native/react-native.config.js +19 -0
- package/runtime/test/jsi/harness.cpp +181 -0
- package/schemas/build.schema.json +152 -0
- package/schemas/check.schema.json +74 -0
- package/schemas/doctor.schema.json +40 -0
- package/schemas/lucent.schema.json +43 -0
- package/schemas/sdk-prefetch.schema.json +37 -0
- package/schemas/sdk-search.schema.json +54 -0
- package/ts-plugin/index.d.ts +4 -0
- package/ts-plugin/index.js +99 -0
package/dist/compiler.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { n as Explanations, r as docsUrl, t as Codes } from "./codes-CIuwXt1S.js";
|
|
2
|
+
import { A as formatDiagnostic, C as extractionCount, D as sdkModule, E as sdkAvailable, O as sdkModules, S as cachedModules, T as prefetch, _ as usesPlatforms, a as inputsKey, b as coverage, c as withGradleDependencies, d as coreJsPath, f as coreTypesPath, g as projectFiles, h as platformOf, i as report, k as sdkNames, l as writeNativePackage, m as moduleNameOf, n as compile, o as isUpToDate, p as findLucentFiles, r as compileDirectory, s as runtimeDir, t as checkSources, u as LUCENT_EXTENSION, v as moduleNamespace, w as forgetLoadedSdks, x as podsSearchPaths, y as sdkDts } from "./src-BD7f1_aZ.js";
|
|
3
|
+
import { a as satisfies, i as nativeDependencies, n as lucentPackages, r as lucentVersion } from "./packages-HyskKIsY.js";
|
|
4
|
+
export { Codes, Explanations, LUCENT_EXTENSION, cachedModules, checkSources, compile, compileDirectory, coreJsPath, coreTypesPath, docsUrl, extractionCount, findLucentFiles, forgetLoadedSdks, formatDiagnostic, inputsKey, isUpToDate, lucentPackages, lucentVersion, moduleNameOf, moduleNamespace, nativeDependencies, platformOf, podsSearchPaths, prefetch as prefetchSdk, projectFiles, report, runtimeDir, satisfies, sdkAvailable, coverage as sdkCoverage, sdkDts, sdkModule, sdkModules, sdkNames, usesPlatforms, withGradleDependencies, writeNativePackage };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { t as renderDiff } from "./diff-BTDo3Sro.js";
|
|
2
|
+
import { Box, Static, Text, useInput } from "ink";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/cli/init/confirm.tsx
|
|
6
|
+
function Confirm({ changes, theme, onDone }) {
|
|
7
|
+
const [answers, setAnswers] = useState([]);
|
|
8
|
+
useInput((input, key) => {
|
|
9
|
+
const yes = input === "y" || input === "Y" || key.return;
|
|
10
|
+
if (!yes && !(input === "n" || input === "N") || answers.length >= changes.length) return;
|
|
11
|
+
const next = [...answers, yes];
|
|
12
|
+
setAnswers(next);
|
|
13
|
+
if (next.length === changes.length) onDone(next);
|
|
14
|
+
});
|
|
15
|
+
const current = changes[answers.length];
|
|
16
|
+
const decided = answers.map((yes, i) => ({
|
|
17
|
+
yes,
|
|
18
|
+
change: changes[i]
|
|
19
|
+
}));
|
|
20
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Static, {
|
|
21
|
+
items: decided,
|
|
22
|
+
children: ({ yes, change }, i) => /* @__PURE__ */ jsx(Text, { children: `${yes ? theme.success(theme.symbols.ok) : theme.dim(theme.symbols.off)} ${change.file} ${theme.dim(yes ? change.why : "skipped")}` }, i)
|
|
23
|
+
}), current ? /* @__PURE__ */ jsxs(Box, {
|
|
24
|
+
flexDirection: "column",
|
|
25
|
+
marginTop: 1,
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ jsx(Text, { children: `${theme.bold(current.file)}${current.before === void 0 ? theme.dim(" (new)") : ""} ${theme.dim(current.why)}` }),
|
|
28
|
+
/* @__PURE__ */ jsx(Text, { children: renderDiff(current.before ?? "", current.after, theme) }),
|
|
29
|
+
/* @__PURE__ */ jsx(Text, { children: `Apply? ${theme.dim("(Y/n)")}` })
|
|
30
|
+
]
|
|
31
|
+
}) : null] });
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { Confirm };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { i as table, n as duration, t as codeFrame } from "./format-D9fnIMEx.js";
|
|
2
|
+
import { n as nextText } from "./pipeline-CH7-2cxu.js";
|
|
3
|
+
import { Box, Text, render, useApp, useInput } from "ink";
|
|
4
|
+
import { useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/cli/dev/dashboard.tsx
|
|
7
|
+
const ENTER = "\x1B[?1049h";
|
|
8
|
+
const LEAVE = "\x1B[?1049l\x1B[?25h";
|
|
9
|
+
async function dashboard(options) {
|
|
10
|
+
const stdout = options.stdout ?? process.stdout;
|
|
11
|
+
stdout.write(ENTER);
|
|
12
|
+
const app = render(/* @__PURE__ */ jsx(Dashboard, { ...options }), {
|
|
13
|
+
stdout,
|
|
14
|
+
stdin: options.stdin ?? process.stdin,
|
|
15
|
+
exitOnCtrlC: false,
|
|
16
|
+
patchConsole: false,
|
|
17
|
+
interactive: true
|
|
18
|
+
});
|
|
19
|
+
const restore = () => stdout.write(LEAVE);
|
|
20
|
+
process.once("exit", restore);
|
|
21
|
+
try {
|
|
22
|
+
await app.waitUntilExit();
|
|
23
|
+
} finally {
|
|
24
|
+
options.session.stop();
|
|
25
|
+
process.off("exit", restore);
|
|
26
|
+
restore();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function Dashboard({ session, theme: t, root, open, doctor }) {
|
|
30
|
+
const s = useSyncExternalStore(session.store.subscribe, session.store.get);
|
|
31
|
+
const { exit } = useApp();
|
|
32
|
+
const [selected, setSelected] = useState(0);
|
|
33
|
+
const [checks, setChecks] = useState(void 0);
|
|
34
|
+
const problem = s.problems[Math.min(selected, s.problems.length - 1)];
|
|
35
|
+
useInput((input, key) => {
|
|
36
|
+
if (input === "q" || key.ctrl && input === "c") exit();
|
|
37
|
+
else if (input === "r") session.rebuild();
|
|
38
|
+
else if (input === "c") session.clearCache();
|
|
39
|
+
else if (input === "d") setChecks(checks ? void 0 : doctor());
|
|
40
|
+
else if (input === "o" && problem?.file) open(problem.file, problem.line ?? 1);
|
|
41
|
+
else if (key.upArrow) setSelected((i) => Math.max(0, i - 1));
|
|
42
|
+
else if (key.downArrow) setSelected((i) => Math.min(s.problems.length - 1, i + 1));
|
|
43
|
+
});
|
|
44
|
+
const cell = (state) => state === "ok" ? t.success(t.symbols.on) : state === "error" ? t.error(t.symbols.fail) : state === "building" ? t.progress(t.symbols.off) : " ";
|
|
45
|
+
const last = s.lastBuild;
|
|
46
|
+
const when = s.building ? t.progress(`building${t.symbols.ellipsis}`) : last ? `${last.at.toLocaleTimeString("en-GB")} ${duration(last.ms)}` : "";
|
|
47
|
+
const rows = table([[
|
|
48
|
+
t.dim("MODULE"),
|
|
49
|
+
t.dim("IOS"),
|
|
50
|
+
t.dim("ANDROID"),
|
|
51
|
+
t.dim("LAST BUILD")
|
|
52
|
+
], ...s.modules.map((m) => [
|
|
53
|
+
m.name,
|
|
54
|
+
cell(m.platforms.ios),
|
|
55
|
+
cell(m.platforms.android),
|
|
56
|
+
when
|
|
57
|
+
])], 3);
|
|
58
|
+
const status = last?.fatal ? t.error(`${t.symbols.fail} ${last.fatal}`) : last?.ok && last.next?.rebuild ? t.warn(`next: ${nextText(last.next)}`) : "";
|
|
59
|
+
const rule = (title) => t.dim(`${t.symbols.rule} ${title} ${t.symbols.rule.repeat(Math.max(3, t.terminal.width - title.length - 4))}`);
|
|
60
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
61
|
+
flexDirection: "column",
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ jsx(Text, { children: `${t.brand(t.symbols.brand)} ${t.bold("lucent dev")} ${t.dim(`watching ${s.watching.join(" · ") || root}`)}` }),
|
|
64
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
65
|
+
s.modules.length ? /* @__PURE__ */ jsx(Text, { children: rows.join("\n") }) : /* @__PURE__ */ jsx(Text, { children: t.dim(s.building ? `building${t.symbols.ellipsis}` : "no *.lucent.ts modules yet") }),
|
|
66
|
+
status ? /* @__PURE__ */ jsx(Text, { children: `\n${status}` }) : null,
|
|
67
|
+
s.problems.length ? /* @__PURE__ */ jsxs(Box, {
|
|
68
|
+
flexDirection: "column",
|
|
69
|
+
marginTop: 1,
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ jsx(Text, { children: rule(`problems (${s.problems.length})`) }),
|
|
72
|
+
s.problems.map((d, i) => /* @__PURE__ */ jsx(Text, { children: `${d === problem ? t.brand("›") : " "} ${d.file ? `${d.file}${d.line ? `:${d.line}` : ""} ` : ""}${t.bold(d.code)} ${d.message}` }, i)),
|
|
73
|
+
problem?.fix ? /* @__PURE__ */ jsx(Text, { children: ` ${t.success("fix")} ${problem.fix}` }) : null,
|
|
74
|
+
problem?.source !== void 0 && problem.line ? /* @__PURE__ */ jsx(Text, { children: codeFrame(problem.source, {
|
|
75
|
+
line: problem.line,
|
|
76
|
+
column: problem.column ?? 1,
|
|
77
|
+
length: problem.length ?? 1
|
|
78
|
+
}, t) }) : null
|
|
79
|
+
]
|
|
80
|
+
}) : null,
|
|
81
|
+
checks ? /* @__PURE__ */ jsxs(Box, {
|
|
82
|
+
flexDirection: "column",
|
|
83
|
+
marginTop: 1,
|
|
84
|
+
children: [/* @__PURE__ */ jsx(Text, { children: rule("doctor") }), checks.filter((c) => c.status !== "skip").map((c, i) => /* @__PURE__ */ jsx(Text, { children: `${c.status === "ok" ? t.success(t.symbols.ok) : c.status === "fail" ? t.error(t.symbols.fail) : t.warn(t.symbols.warn)} ${c.label} ${t.dim(c.detail)}${c.fix ? `\n fix: ${c.fix}` : ""}` }, i))]
|
|
85
|
+
}) : null,
|
|
86
|
+
/* @__PURE__ */ jsx(Text, { children: `\n${t.dim("[r] rebuild [c] clear cache [d] doctor [o] open [q] quit")}` })
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
export { dashboard };
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { t as createTheme } from "./theme-uv5bc0aK.js";
|
|
2
|
+
import { n as version } from "./version-bqpIO5sP.js";
|
|
3
|
+
import { h as platformOf, m as moduleNameOf, u as LUCENT_EXTENSION } from "./src-BD7f1_aZ.js";
|
|
4
|
+
import { n as lucentPackages } from "./packages-HyskKIsY.js";
|
|
5
|
+
import { n as nextText, r as plural, t as buildProject } from "./pipeline-CH7-2cxu.js";
|
|
6
|
+
import { t as plainSteps } from "./steps--_h-FFS7.js";
|
|
7
|
+
import { n as systemProbe, t as diagnose } from "./doctor-C0PrfWT6.js";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
//#region src/cli/dev/compact.ts
|
|
12
|
+
function compact(session, out) {
|
|
13
|
+
const t = out.theme;
|
|
14
|
+
let shown;
|
|
15
|
+
return session.store.subscribe(() => {
|
|
16
|
+
const s = session.store.get();
|
|
17
|
+
const last = s.lastBuild;
|
|
18
|
+
if (!last || last === shown || s.building) return;
|
|
19
|
+
shown = last;
|
|
20
|
+
const time = t.dim(`[${last.at.toLocaleTimeString("en-GB")}]`);
|
|
21
|
+
for (const n of s.notices ?? []) out.print(`${time} ${n.level === "ok" ? t.success(t.symbols.ok) : t.warn(t.symbols.warn)} ${n.text}`);
|
|
22
|
+
if (last.fatal) {
|
|
23
|
+
out.error(`${time} ${t.error(t.symbols.fail)} ${last.fatal}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (last.ok) {
|
|
27
|
+
const next = last.next?.rebuild ? ` ${t.dim("·")} ${nextText(last.next)}` : "";
|
|
28
|
+
out.print(`${time} ${t.success(t.symbols.ok)} ${plural(s.modules.length, "module")} ${t.dim(`${last.ms} ms`)}${next}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
out.error(`${time} ${t.error(t.symbols.fail)} ${plural(s.problems.length, "error")}`);
|
|
32
|
+
for (const d of s.problems) {
|
|
33
|
+
const where = d.file ? `${d.file}${d.line ? `:${d.line}:${d.column ?? 1}` : ""} ` : "";
|
|
34
|
+
out.error(` ${where}${t.bold(d.code)} ${d.message}`);
|
|
35
|
+
if (d.fix) out.error(` ${t.dim(`fix: ${d.fix}`)}`);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/cli/dev/session.ts
|
|
41
|
+
function createStore(initial = {
|
|
42
|
+
building: false,
|
|
43
|
+
watching: [],
|
|
44
|
+
modules: [],
|
|
45
|
+
problems: []
|
|
46
|
+
}) {
|
|
47
|
+
let state = initial;
|
|
48
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
49
|
+
return {
|
|
50
|
+
get: () => state,
|
|
51
|
+
set(next) {
|
|
52
|
+
state = next;
|
|
53
|
+
for (const l of [...listeners]) l();
|
|
54
|
+
},
|
|
55
|
+
subscribe(listener) {
|
|
56
|
+
listeners.add(listener);
|
|
57
|
+
return () => listeners.delete(listener);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const DEBOUNCE_MS = 40;
|
|
62
|
+
function startSession(root) {
|
|
63
|
+
const store = createStore();
|
|
64
|
+
const theme = createTheme({
|
|
65
|
+
color: false,
|
|
66
|
+
interactive: false,
|
|
67
|
+
unicode: true,
|
|
68
|
+
links: false,
|
|
69
|
+
width: 80
|
|
70
|
+
});
|
|
71
|
+
let building = false;
|
|
72
|
+
let queued;
|
|
73
|
+
let timer;
|
|
74
|
+
const build = async (force) => {
|
|
75
|
+
if (building) {
|
|
76
|
+
queued = { force: force || !!queued?.force };
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
building = true;
|
|
80
|
+
store.set({
|
|
81
|
+
...store.get(),
|
|
82
|
+
building: true,
|
|
83
|
+
modules: store.get().modules.map((m) => ({
|
|
84
|
+
...m,
|
|
85
|
+
platforms: mapPlatforms(m.platforms, (s) => s === "none" ? s : "building")
|
|
86
|
+
}))
|
|
87
|
+
});
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
89
|
+
const notices = [];
|
|
90
|
+
const at = /* @__PURE__ */ new Date();
|
|
91
|
+
const r = await buildProject(root, {
|
|
92
|
+
mode: "build",
|
|
93
|
+
force
|
|
94
|
+
}, plainSteps(() => {}, theme), (n) => notices.push(n));
|
|
95
|
+
const failing = /* @__PURE__ */ new Map();
|
|
96
|
+
for (const d of r.diagnostics) {
|
|
97
|
+
if (!d.file) continue;
|
|
98
|
+
const name = moduleNameOf(path.resolve(root, d.file));
|
|
99
|
+
const p = platformOf(d.file);
|
|
100
|
+
const set = failing.get(name) ?? /* @__PURE__ */ new Set();
|
|
101
|
+
for (const q of p ? [p] : ["ios", "android"]) set.add(q);
|
|
102
|
+
failing.set(name, set);
|
|
103
|
+
}
|
|
104
|
+
const sources = /* @__PURE__ */ new Map();
|
|
105
|
+
const source = (file) => {
|
|
106
|
+
if (!sources.has(file)) sources.set(file, fs.existsSync(path.resolve(root, file)) ? fs.readFileSync(path.resolve(root, file), "utf8") : void 0);
|
|
107
|
+
return sources.get(file);
|
|
108
|
+
};
|
|
109
|
+
store.set({
|
|
110
|
+
...store.get(),
|
|
111
|
+
building: false,
|
|
112
|
+
modules: r.modules.map((m) => {
|
|
113
|
+
const has = (p) => m.platforms.includes(p) || m.platforms.includes("shared");
|
|
114
|
+
const state = (p) => !has(p) ? "none" : failing.get(m.name)?.has(p) ? "error" : r.ok ? "ok" : "none";
|
|
115
|
+
return {
|
|
116
|
+
name: m.name,
|
|
117
|
+
platforms: {
|
|
118
|
+
ios: state("ios"),
|
|
119
|
+
android: state("android")
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}),
|
|
123
|
+
lastBuild: {
|
|
124
|
+
at,
|
|
125
|
+
ms: r.ms,
|
|
126
|
+
ok: r.ok,
|
|
127
|
+
next: r.ok && !r.upToDate ? r.next : void 0,
|
|
128
|
+
fatal: r.fatal
|
|
129
|
+
},
|
|
130
|
+
problems: r.diagnostics.map((d) => ({
|
|
131
|
+
...d,
|
|
132
|
+
source: d.file ? source(d.file) : void 0
|
|
133
|
+
})),
|
|
134
|
+
notices
|
|
135
|
+
});
|
|
136
|
+
building = false;
|
|
137
|
+
if (queued) {
|
|
138
|
+
const again = queued;
|
|
139
|
+
queued = void 0;
|
|
140
|
+
build(again.force);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const changed = (name) => {
|
|
144
|
+
if (!name || !LUCENT_EXTENSION.test(name) || name.split(path.sep).some((part) => part === "node_modules" || part.startsWith("."))) return;
|
|
145
|
+
clearTimeout(timer);
|
|
146
|
+
timer = setTimeout(() => void build(false), DEBOUNCE_MS);
|
|
147
|
+
};
|
|
148
|
+
let packages = [];
|
|
149
|
+
try {
|
|
150
|
+
packages = lucentPackages(root).map((p) => p.sources).filter((dir) => path.relative(root, dir).startsWith(".."));
|
|
151
|
+
} catch {}
|
|
152
|
+
const watchers = [root, ...packages].map((dir) => fs.watch(dir, { recursive: true }, (_event, name) => changed(name)));
|
|
153
|
+
store.set({
|
|
154
|
+
...store.get(),
|
|
155
|
+
watching: [root, ...packages].map((d) => path.relative(root, d) || ".")
|
|
156
|
+
});
|
|
157
|
+
build(false);
|
|
158
|
+
return {
|
|
159
|
+
store,
|
|
160
|
+
rebuild: () => void build(true),
|
|
161
|
+
clearCache() {
|
|
162
|
+
fs.rmSync(path.join(root, ".lucent/native/manifest.json"), { force: true });
|
|
163
|
+
fs.rmSync(path.join(root, ".lucent/check.json"), { force: true });
|
|
164
|
+
build(true);
|
|
165
|
+
},
|
|
166
|
+
stop() {
|
|
167
|
+
clearTimeout(timer);
|
|
168
|
+
for (const w of watchers) w.close();
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function mapPlatforms(p, f) {
|
|
173
|
+
return {
|
|
174
|
+
ios: f(p.ios),
|
|
175
|
+
android: f(p.android)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/cli/commands/dev.ts
|
|
180
|
+
async function run({ root, flags, out }) {
|
|
181
|
+
const session = startSession(root);
|
|
182
|
+
if (flags.compact || !out.terminal.interactive) {
|
|
183
|
+
compact(session, out);
|
|
184
|
+
await new Promise((resolve) => {
|
|
185
|
+
for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => resolve());
|
|
186
|
+
});
|
|
187
|
+
session.stop();
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
const { dashboard } = await import("./dashboard-B-NzjjaN.js");
|
|
191
|
+
await dashboard({
|
|
192
|
+
session,
|
|
193
|
+
theme: out.theme,
|
|
194
|
+
root,
|
|
195
|
+
open: (file, line) => openInEditor(path.resolve(root, file), line),
|
|
196
|
+
doctor: () => diagnose(root, systemProbe(version()))
|
|
197
|
+
});
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
function openInEditor(file, line) {
|
|
201
|
+
const editor = process.env.VISUAL || process.env.EDITOR || "code";
|
|
202
|
+
const name = path.basename(editor.split(" ")[0]);
|
|
203
|
+
const args = [
|
|
204
|
+
"code",
|
|
205
|
+
"cursor",
|
|
206
|
+
"codium",
|
|
207
|
+
"windsurf",
|
|
208
|
+
"zed",
|
|
209
|
+
"subl"
|
|
210
|
+
].includes(name) ? ["-g", `${file}:${line}`] : name === "idea" || name === "webstorm" ? [
|
|
211
|
+
"--line",
|
|
212
|
+
String(line),
|
|
213
|
+
file
|
|
214
|
+
] : [`+${line}`, file];
|
|
215
|
+
spawn(editor.split(" ")[0], [...editor.split(" ").slice(1), ...args], {
|
|
216
|
+
stdio: "ignore",
|
|
217
|
+
detached: true
|
|
218
|
+
}).unref();
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
export { run };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { r as link, t as codeFrame } from "./format-D9fnIMEx.js";
|
|
2
|
+
//#region src/cli/ui/diagnostic.ts
|
|
3
|
+
function wrap(text, width, indent) {
|
|
4
|
+
const lines = [];
|
|
5
|
+
let line = "";
|
|
6
|
+
for (const word of text.split(" ")) if (line && line.length + 1 + word.length > width) {
|
|
7
|
+
lines.push(line);
|
|
8
|
+
line = word;
|
|
9
|
+
} else line = line ? `${line} ${word}` : word;
|
|
10
|
+
lines.push(line);
|
|
11
|
+
return lines.join(`\n${indent}`);
|
|
12
|
+
}
|
|
13
|
+
function renderDiagnostic(d, source, theme) {
|
|
14
|
+
const width = theme.terminal.width;
|
|
15
|
+
const out = [`${` ${theme.error("error")} ${theme.bold(d.code)} `}${wrap(d.message.split("\n").join(" "), Math.max(20, width - 2 - 6 - d.code.length - 2), " ".repeat(6 + d.code.length + 4))}`];
|
|
16
|
+
if (d.file) {
|
|
17
|
+
out.push("", ` ${theme.dim(d.line ? `${d.file}:${d.line}:${d.column ?? 1}` : d.file)}`);
|
|
18
|
+
if (source !== void 0 && d.line) out.push(codeFrame(source, {
|
|
19
|
+
line: d.line,
|
|
20
|
+
column: d.column ?? 1,
|
|
21
|
+
length: d.length ?? 1
|
|
22
|
+
}, theme));
|
|
23
|
+
}
|
|
24
|
+
if (d.fix || d.docs) out.push("");
|
|
25
|
+
if (d.fix) out.push(` ${theme.success("fix")} ${wrap(d.fix, Math.max(20, width - 7), " ")}`);
|
|
26
|
+
if (d.docs) out.push(` ${theme.progress("docs")} lucent explain ${link(d.code, d.docs, theme.terminal)}`);
|
|
27
|
+
return out.join("\n");
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { renderDiagnostic as t };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/cli/ui/diff.ts
|
|
2
|
+
function diffLines(before, after) {
|
|
3
|
+
const a = before === "" ? [] : before.replace(/\n$/, "").split("\n");
|
|
4
|
+
const b = after.replace(/\n$/, "").split("\n");
|
|
5
|
+
const lcs = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
|
|
6
|
+
for (let i = a.length - 1; i >= 0; i--) for (let j = b.length - 1; j >= 0; j--) lcs[i][j] = a[i] === b[j] ? lcs[i + 1][j + 1] + 1 : Math.max(lcs[i + 1][j], lcs[i][j + 1]);
|
|
7
|
+
const out = [];
|
|
8
|
+
let i = 0;
|
|
9
|
+
let j = 0;
|
|
10
|
+
while (i < a.length || j < b.length) if (i < a.length && j < b.length && a[i] === b[j]) {
|
|
11
|
+
out.push({
|
|
12
|
+
kind: " ",
|
|
13
|
+
text: a[i++]
|
|
14
|
+
});
|
|
15
|
+
j++;
|
|
16
|
+
} else if (i < a.length && (j >= b.length || lcs[i + 1][j] >= lcs[i][j + 1])) out.push({
|
|
17
|
+
kind: "-",
|
|
18
|
+
text: a[i++]
|
|
19
|
+
});
|
|
20
|
+
else out.push({
|
|
21
|
+
kind: "+",
|
|
22
|
+
text: b[j++]
|
|
23
|
+
});
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
function renderDiff(before, after, theme) {
|
|
27
|
+
const lines = diffLines(before, after);
|
|
28
|
+
const near = (k) => lines.slice(Math.max(0, k - 2), k + 3).some((l) => l.kind !== " ");
|
|
29
|
+
const out = [];
|
|
30
|
+
let skipped = false;
|
|
31
|
+
lines.forEach((l, k) => {
|
|
32
|
+
if (l.kind === " " && !near(k)) {
|
|
33
|
+
if (!skipped) out.push(theme.dim(` ${theme.symbols.ellipsis}`));
|
|
34
|
+
skipped = true;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
skipped = false;
|
|
38
|
+
const text = ` ${l.kind} ${l.text}`;
|
|
39
|
+
out.push(l.kind === "+" ? theme.success(text) : l.kind === "-" ? theme.error(text) : theme.dim(text));
|
|
40
|
+
});
|
|
41
|
+
return out.join("\n");
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { renderDiff as t };
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { n as lucentPackages } from "./packages-HyskKIsY.js";
|
|
2
|
+
import { t as packageManagerOf } from "./package-manager-BnxwCySi.js";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
//#region src/cli/doctor.ts
|
|
8
|
+
function systemProbe(cliVersion) {
|
|
9
|
+
return {
|
|
10
|
+
platform: process.platform,
|
|
11
|
+
env: process.env,
|
|
12
|
+
home: os.homedir(),
|
|
13
|
+
nodeVersion: process.version,
|
|
14
|
+
cliVersion,
|
|
15
|
+
run: (cmd, args) => {
|
|
16
|
+
const r = spawnSync(cmd, args, {
|
|
17
|
+
encoding: "utf8",
|
|
18
|
+
timeout: 2e4
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
status: r.error ? null : r.status,
|
|
22
|
+
stdout: r.stdout ?? "",
|
|
23
|
+
stderr: r.stderr ?? ""
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const read = (file) => fs.existsSync(file) ? fs.readFileSync(file, "utf8") : void 0;
|
|
29
|
+
const json = (file) => {
|
|
30
|
+
const text = read(file);
|
|
31
|
+
return text === void 0 ? void 0 : JSON.parse(text);
|
|
32
|
+
};
|
|
33
|
+
function parse(version) {
|
|
34
|
+
return (/(\d+)\.(\d+)(?:\.(\d+))?/.exec(version) ?? []).slice(1, 4).map((n) => Number(n ?? 0));
|
|
35
|
+
}
|
|
36
|
+
function atLeast(version, min) {
|
|
37
|
+
const [a, b] = [parse(version), parse(min)];
|
|
38
|
+
for (let i = 0; i < 3; i++) if ((a[i] ?? 0) !== (b[i] ?? 0)) return (a[i] ?? 0) > (b[i] ?? 0);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
function installed(root, name) {
|
|
42
|
+
for (let dir = root;; dir = path.dirname(dir)) {
|
|
43
|
+
const pkg = json(path.join(dir, "node_modules", name, "package.json"));
|
|
44
|
+
if (pkg?.version) return pkg.version;
|
|
45
|
+
if (path.dirname(dir) === dir) return void 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const ok = (id, label, detail) => ({
|
|
49
|
+
id,
|
|
50
|
+
label,
|
|
51
|
+
status: "ok",
|
|
52
|
+
detail
|
|
53
|
+
});
|
|
54
|
+
const fail = (id, label, detail, fix) => ({
|
|
55
|
+
id,
|
|
56
|
+
label,
|
|
57
|
+
status: "fail",
|
|
58
|
+
detail,
|
|
59
|
+
fix
|
|
60
|
+
});
|
|
61
|
+
const warn = (id, label, detail, fix) => ({
|
|
62
|
+
id,
|
|
63
|
+
label,
|
|
64
|
+
status: "warn",
|
|
65
|
+
detail,
|
|
66
|
+
fix
|
|
67
|
+
});
|
|
68
|
+
const skip = (id, label, detail) => ({
|
|
69
|
+
id,
|
|
70
|
+
label,
|
|
71
|
+
status: "skip",
|
|
72
|
+
detail
|
|
73
|
+
});
|
|
74
|
+
function diagnose(root, probe) {
|
|
75
|
+
const pkg = json(path.join(root, "package.json")) ?? {};
|
|
76
|
+
const expo = "expo" in {
|
|
77
|
+
...pkg.dependencies,
|
|
78
|
+
...pkg.devDependencies
|
|
79
|
+
};
|
|
80
|
+
const mac = probe.platform === "darwin";
|
|
81
|
+
return [
|
|
82
|
+
node(probe),
|
|
83
|
+
packageManager(root),
|
|
84
|
+
reactNative(root),
|
|
85
|
+
expo ? expoSdk(root) : skip("expo", "Expo SDK", "not an Expo app"),
|
|
86
|
+
...mac ? [
|
|
87
|
+
xcode(probe),
|
|
88
|
+
simulator(probe),
|
|
89
|
+
cocoapods(probe)
|
|
90
|
+
] : [skip("xcode", "Xcode", "iOS builds need a Mac")],
|
|
91
|
+
...android(probe),
|
|
92
|
+
jdk(probe),
|
|
93
|
+
gradleTask(root, expo),
|
|
94
|
+
metro(root),
|
|
95
|
+
tsconfig(root),
|
|
96
|
+
sdkCache(probe),
|
|
97
|
+
versions(root, probe)
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
const REQUIREMENTS = {
|
|
101
|
+
node: "22.12",
|
|
102
|
+
reactNative: "0.88",
|
|
103
|
+
expoSdk: 58,
|
|
104
|
+
jdk: {
|
|
105
|
+
min: 17,
|
|
106
|
+
max: 21
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function node(probe) {
|
|
110
|
+
const need = REQUIREMENTS.node;
|
|
111
|
+
return atLeast(probe.nodeVersion, `${need}.0`) ? ok("node", "Node.js", probe.nodeVersion) : fail("node", "Node.js", `${probe.nodeVersion}; Lucent needs ${need} or later`, `install Node.js ${need} or later (nodejs.org, or your version manager)`);
|
|
112
|
+
}
|
|
113
|
+
function packageManager(root) {
|
|
114
|
+
const pm = packageManagerOf(root);
|
|
115
|
+
if (!pm) return warn("package-manager", "Package manager", "no lockfile", "install the app's dependencies (npm install, pnpm install, …)");
|
|
116
|
+
return ok("package-manager", "Package manager", `${pm.name} (${path.relative(root, pm.lockfile)})`);
|
|
117
|
+
}
|
|
118
|
+
function reactNative(root) {
|
|
119
|
+
const v = installed(root, "react-native");
|
|
120
|
+
const need = REQUIREMENTS.reactNative;
|
|
121
|
+
if (!v) return fail("react-native", "React Native", "not installed", `install react-native ${need} or later in the app`);
|
|
122
|
+
return atLeast(v, `${need}.0`) ? ok("react-native", "React Native", v) : fail("react-native", "React Native", `${v}; Lucent needs ${need} or later (the New Architecture's C++ TurboModules)`, `upgrade react-native to ${need} or later`);
|
|
123
|
+
}
|
|
124
|
+
function expoSdk(root) {
|
|
125
|
+
const v = installed(root, "expo");
|
|
126
|
+
if (!v) return fail("expo", "Expo SDK", "expo is a dependency but is not installed", "install the app's dependencies");
|
|
127
|
+
const need = REQUIREMENTS.expoSdk;
|
|
128
|
+
return atLeast(v, `${need}.0.0`) ? ok("expo", "Expo SDK", `${parse(v)[0]} (expo ${v})`) : fail("expo", "Expo SDK", `expo ${v}; Lucent needs SDK ${need} or later`, `upgrade to Expo SDK ${need} (npx expo install expo@^${need})`);
|
|
129
|
+
}
|
|
130
|
+
function xcode(probe) {
|
|
131
|
+
const r = probe.run("xcodebuild", ["-version"]);
|
|
132
|
+
if (r.status !== 0) return fail("xcode", "Xcode", "not found", "install Xcode from the App Store, then: sudo xcode-select -s /Applications/Xcode.app");
|
|
133
|
+
return ok("xcode", "Xcode", r.stdout.split("\n")[0].replace(/^Xcode /, ""));
|
|
134
|
+
}
|
|
135
|
+
function simulator(probe) {
|
|
136
|
+
const r = probe.run("xcrun", [
|
|
137
|
+
"simctl",
|
|
138
|
+
"list",
|
|
139
|
+
"runtimes",
|
|
140
|
+
"--json"
|
|
141
|
+
]);
|
|
142
|
+
const ios = (r.status === 0 ? JSON.parse(r.stdout).runtimes ?? [] : []).filter((rt) => rt.isAvailable !== false && (rt.platform === "iOS" || rt.name.startsWith("iOS")));
|
|
143
|
+
return ios.length ? ok("simulator", "iOS simulator runtime", ios.map((rt) => rt.name).join(", ")) : warn("simulator", "iOS simulator runtime", "none installed", "install one in Xcode: Settings > Components");
|
|
144
|
+
}
|
|
145
|
+
function cocoapods(probe) {
|
|
146
|
+
const r = probe.run("pod", ["--version"]);
|
|
147
|
+
return r.status === 0 ? ok("cocoapods", "CocoaPods", r.stdout.trim()) : fail("cocoapods", "CocoaPods", "not installed", "brew install cocoapods (or: sudo gem install cocoapods)");
|
|
148
|
+
}
|
|
149
|
+
function android(probe) {
|
|
150
|
+
const sdk = [
|
|
151
|
+
probe.env.ANDROID_HOME,
|
|
152
|
+
probe.env.ANDROID_SDK_ROOT,
|
|
153
|
+
path.join(probe.home, probe.platform === "darwin" ? "Library/Android/sdk" : "Android/Sdk")
|
|
154
|
+
].filter((d) => !!d).find((d) => fs.existsSync(path.join(d, "platforms")));
|
|
155
|
+
if (!sdk) return [fail("android-sdk", "Android SDK", "not found", "install Android Studio (or the command-line tools), then set ANDROID_HOME to the SDK (e.g. ~/Library/Android/sdk)"), skip("ndk", "Android NDK", "needs the Android SDK")];
|
|
156
|
+
const platforms = fs.readdirSync(path.join(sdk, "platforms")).filter((p) => /^android-\d+/.test(p)).sort((a, b) => Number(b.slice(8)) - Number(a.slice(8)));
|
|
157
|
+
const sdkCheck = platforms.length ? ok("android-sdk", "Android SDK", `${platforms[0]} at ${sdk.replace(probe.home, "~")}`) : fail("android-sdk", "Android SDK", `no platform installed at ${sdk}`, "install one with Android Studio's SDK Manager, or: sdkmanager 'platforms;android-36'");
|
|
158
|
+
const envSet = probe.env.ANDROID_HOME || probe.env.ANDROID_SDK_ROOT;
|
|
159
|
+
const ndks = fs.existsSync(path.join(sdk, "ndk")) ? fs.readdirSync(path.join(sdk, "ndk")).sort() : [];
|
|
160
|
+
const ndkCheck = ndks.length ? ok("ndk", "Android NDK", ndks.at(-1)) : fail("ndk", "Android NDK", "not installed", "install it with Android Studio's SDK Manager (SDK Tools > NDK), or: sdkmanager 'ndk;27.1.12297006'");
|
|
161
|
+
if (sdkCheck.status === "ok" && !envSet) return [{
|
|
162
|
+
...sdkCheck,
|
|
163
|
+
status: "warn",
|
|
164
|
+
fix: `export ANDROID_HOME=${sdk.replace(probe.home, "$HOME")} (Gradle and adb find the SDK through it)`
|
|
165
|
+
}, ndkCheck];
|
|
166
|
+
return [sdkCheck, ndkCheck];
|
|
167
|
+
}
|
|
168
|
+
function jdk(probe) {
|
|
169
|
+
const r = probe.run("java", ["-version"]);
|
|
170
|
+
const { min, max } = REQUIREMENTS.jdk;
|
|
171
|
+
if (r.status !== 0) return fail("jdk", "JDK", "not found", `install JDK ${min} or ${max} (e.g. brew install --cask zulu@${max}) and set JAVA_HOME`);
|
|
172
|
+
const m = /version "(\d+)(?:\.(\d+))?/.exec(r.stderr + r.stdout);
|
|
173
|
+
const major = m ? Number(m[1] === "1" ? m[2] : m[1]) : 0;
|
|
174
|
+
if (major >= min && major <= max) return ok("jdk", "JDK", String(major));
|
|
175
|
+
return warn("jdk", "JDK", `${major || "unknown version"}; React Native's Gradle build needs ${min} to ${max}`, `set JAVA_HOME to JDK ${min} or ${max} (macOS: export JAVA_HOME=$(/usr/libexec/java_home -v ${max}))`);
|
|
176
|
+
}
|
|
177
|
+
function gradleTask(root, expo) {
|
|
178
|
+
const file = ["android/app/build.gradle", "android/app/build.gradle.kts"].map((f) => path.join(root, f)).find((f) => fs.existsSync(f));
|
|
179
|
+
if (!file) return skip("gradle-task", "Lucent Gradle task", expo ? "no android/ yet (expo prebuild adds it)" : "no android/app/build.gradle");
|
|
180
|
+
const text = read(file);
|
|
181
|
+
return /lucent\.gradle/.test(text) ? ok("gradle-task", "Lucent Gradle task", "applied in android/app") : fail("gradle-task", "Lucent Gradle task", "android/app/build.gradle does not apply it, so Gradle builds may use an old .lucent/native", expo ? "run expo prebuild again (the Lucent config plugin adds it), or lucent init" : "run lucent init");
|
|
182
|
+
}
|
|
183
|
+
function metro(root) {
|
|
184
|
+
const file = [
|
|
185
|
+
"metro.config.js",
|
|
186
|
+
"metro.config.cjs",
|
|
187
|
+
"metro.config.mjs",
|
|
188
|
+
"metro.config.ts"
|
|
189
|
+
].map((f) => path.join(root, f)).find((f) => fs.existsSync(f));
|
|
190
|
+
const fix = "wrap the config: const { withLucent } = require(\"@lucent-lang/lucent/metro\"); module.exports = withLucent(config);";
|
|
191
|
+
if (!file) return fail("metro", "Metro config", "no metro.config.js", fix);
|
|
192
|
+
const text = read(file);
|
|
193
|
+
return /withLucent/.test(text) && /@lucent-lang\/lucent\/metro/.test(text) ? ok("metro", "Metro config", `${path.basename(file)} uses withLucent`) : fail("metro", "Metro config", `${path.basename(file)} does not use withLucent from @lucent-lang/lucent/metro, so Metro bundles *.lucent.ts as TypeScript`, fix);
|
|
194
|
+
}
|
|
195
|
+
function tsconfig(root) {
|
|
196
|
+
const text = read(path.join(root, "tsconfig.json"));
|
|
197
|
+
if (text === void 0) return skip("tsconfig", "tsconfig paths", "no tsconfig.json");
|
|
198
|
+
return text.includes("\"lucent:*\"") ? ok("tsconfig", "tsconfig paths", "lucent:* mapped") : warn("tsconfig", "tsconfig paths", "lucent:* is not mapped, so editors cannot resolve lucent:core or the SDK modules", "run lucent build (or lucent init): it maps lucent:* in tsconfig.json");
|
|
199
|
+
}
|
|
200
|
+
function sdkCache(probe) {
|
|
201
|
+
const dir = probe.env.LUCENT_CACHE_DIR || path.join(probe.env.XDG_CACHE_HOME || path.join(probe.home, ".cache"), "lucent");
|
|
202
|
+
const sdk = path.join(dir, "sdk");
|
|
203
|
+
if (!fs.existsSync(sdk)) return ok("sdk-cache", "SDK cache", `empty (${dir.replace(probe.home, "~")}); lucent sdk prefetch fills it ahead of time`);
|
|
204
|
+
let bytes = 0;
|
|
205
|
+
let modules = 0;
|
|
206
|
+
const walk = (d) => {
|
|
207
|
+
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
208
|
+
const f = path.join(d, e.name);
|
|
209
|
+
if (e.isDirectory()) walk(f);
|
|
210
|
+
else {
|
|
211
|
+
bytes += fs.statSync(f).size;
|
|
212
|
+
if (e.name.endsWith(".json") && !e.name.endsWith(".names.json")) modules++;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
walk(sdk);
|
|
217
|
+
return ok("sdk-cache", "SDK cache", `${modules} modules, ${(bytes / 1e6).toFixed(0)} MB (${dir.replace(probe.home, "~")})`);
|
|
218
|
+
}
|
|
219
|
+
function versions(root, probe) {
|
|
220
|
+
const app = installed(root, "@lucent-lang/lucent");
|
|
221
|
+
if (app && app !== probe.cliVersion) return fail("versions", "Lucent versions", `the app has @lucent-lang/lucent ${app}, this lucent is ${probe.cliVersion}`, "run the app's own lucent (npx lucent …), or install the same version");
|
|
222
|
+
try {
|
|
223
|
+
const packages = lucentPackages(root);
|
|
224
|
+
return ok("versions", "Lucent versions", `${probe.cliVersion}${packages.length ? `; ${packages.length} Lucent package${packages.length === 1 ? "" : "s"} compatible` : ""}`);
|
|
225
|
+
} catch (e) {
|
|
226
|
+
return fail("versions", "Lucent versions", e.message, "update the Lucent package or @lucent-lang/lucent so their versions match");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//#endregion
|
|
230
|
+
export { systemProbe as n, diagnose as t };
|