@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.
Files changed (125) hide show
  1. package/app.plugin.js +92 -0
  2. package/bin/lucent.cjs +16 -0
  3. package/core/index.cjs +11 -0
  4. package/dist/bench-CR3E7e2e.js +304 -0
  5. package/dist/build-CAIrRSYA.js +7 -0
  6. package/dist/build-check-QozuNJm5.js +92 -0
  7. package/dist/check-1SCmYlqA.js +7 -0
  8. package/dist/clean-BVwpbJ5K.js +35 -0
  9. package/dist/cli.js +406 -0
  10. package/dist/codes-CIuwXt1S.js +260 -0
  11. package/dist/compiler.js +4 -0
  12. package/dist/confirm-BYF5eY3q.js +34 -0
  13. package/dist/dashboard-B-NzjjaN.js +91 -0
  14. package/dist/dev-BYWMP7oC.js +221 -0
  15. package/dist/diagnostic-BM9sXmwl.js +30 -0
  16. package/dist/diff-BTDo3Sro.js +44 -0
  17. package/dist/doctor-C0PrfWT6.js +230 -0
  18. package/dist/doctor-DdR4JnVc.js +30 -0
  19. package/dist/explain--vV1oaRl.js +35 -0
  20. package/dist/format-D9fnIMEx.js +53 -0
  21. package/dist/init-gIabu1S_.js +207 -0
  22. package/dist/live-steps-BGcWFM9M.js +79 -0
  23. package/dist/new-module-C2mtb0op.js +66 -0
  24. package/dist/package-manager-BnxwCySi.js +30 -0
  25. package/dist/package.json +3 -0
  26. package/dist/packages-HyskKIsY.js +150 -0
  27. package/dist/pipeline-CH7-2cxu.js +232 -0
  28. package/dist/project-D8tEet0k.js +150 -0
  29. package/dist/sdk-coverage-BoW_3Efd.js +64 -0
  30. package/dist/sdk-prefetch-mo04JDZV.js +89 -0
  31. package/dist/sdk-search-Iv4K3-8a.js +124 -0
  32. package/dist/sdk-show-CkrdlqlP.js +74 -0
  33. package/dist/sdks-Xoyiy2E4.js +28 -0
  34. package/dist/src-BD7f1_aZ.js +11493 -0
  35. package/dist/steps--_h-FFS7.js +24 -0
  36. package/dist/theme-uv5bc0aK.js +134 -0
  37. package/dist/tsconfig-S4uyLNzf.js +59 -0
  38. package/dist/version-bqpIO5sP.js +26 -0
  39. package/gradle/lucent-classpath.gradle +38 -0
  40. package/gradle/lucent-classpath.init.gradle +6 -0
  41. package/gradle/lucent.gradle +24 -0
  42. package/lib/core.cjs +106 -0
  43. package/lib/globals.d.ts +36 -0
  44. package/lib/sdk/android.d.ts +8 -0
  45. package/lib/sdk/core.d.ts +23 -0
  46. package/lib/sdk/ios.d.ts +33 -0
  47. package/lib/sdk/platform.d.ts +8 -0
  48. package/lib/sdk/thread.d.ts +8 -0
  49. package/metro/index.cjs +72 -0
  50. package/metro/index.d.ts +6 -0
  51. package/metro/transformer.cjs +70 -0
  52. package/package.json +61 -0
  53. package/runtime/cpp/lucent/abort.cpp +61 -0
  54. package/runtime/cpp/lucent/abort.h +54 -0
  55. package/runtime/cpp/lucent/array.h +442 -0
  56. package/runtime/cpp/lucent/async.h +236 -0
  57. package/runtime/cpp/lucent/builtins.cpp +163 -0
  58. package/runtime/cpp/lucent/bytes.h +129 -0
  59. package/runtime/cpp/lucent/console.h +17 -0
  60. package/runtime/cpp/lucent/core.h +129 -0
  61. package/runtime/cpp/lucent/date.cpp +441 -0
  62. package/runtime/cpp/lucent/date.h +82 -0
  63. package/runtime/cpp/lucent/equality.h +87 -0
  64. package/runtime/cpp/lucent/function.h +61 -0
  65. package/runtime/cpp/lucent/generator.h +244 -0
  66. package/runtime/cpp/lucent/helpers.h +226 -0
  67. package/runtime/cpp/lucent/jserror.cpp +51 -0
  68. package/runtime/cpp/lucent/jserror.h +66 -0
  69. package/runtime/cpp/lucent/jsi/convert.cpp +202 -0
  70. package/runtime/cpp/lucent/jsi/convert.h +612 -0
  71. package/runtime/cpp/lucent/jsi/host.cpp +322 -0
  72. package/runtime/cpp/lucent/jsi/host.h +166 -0
  73. package/runtime/cpp/lucent/json.cpp +243 -0
  74. package/runtime/cpp/lucent/json.h +164 -0
  75. package/runtime/cpp/lucent/json_parse.h +138 -0
  76. package/runtime/cpp/lucent/jsstring.cpp +874 -0
  77. package/runtime/cpp/lucent/jsstring.h +152 -0
  78. package/runtime/cpp/lucent/lucent.h +24 -0
  79. package/runtime/cpp/lucent/map.h +344 -0
  80. package/runtime/cpp/lucent/native.cpp +76 -0
  81. package/runtime/cpp/lucent/native.h +116 -0
  82. package/runtime/cpp/lucent/number.cpp +545 -0
  83. package/runtime/cpp/lucent/number.h +190 -0
  84. package/runtime/cpp/lucent/ops.h +165 -0
  85. package/runtime/cpp/lucent/platform/android.cpp +437 -0
  86. package/runtime/cpp/lucent/platform/android.h +117 -0
  87. package/runtime/cpp/lucent/platform/ios.h +297 -0
  88. package/runtime/cpp/lucent/platform/ios.mm +31 -0
  89. package/runtime/cpp/lucent/regexp.cpp +440 -0
  90. package/runtime/cpp/lucent/regexp.h +107 -0
  91. package/runtime/cpp/lucent/scheduler.cpp +153 -0
  92. package/runtime/cpp/lucent/scheduler.h +160 -0
  93. package/runtime/cpp/lucent/unicode_data.inc +4051 -0
  94. package/runtime/cpp/rn/LucentModule.cpp +35 -0
  95. package/runtime/cpp/rn/LucentModule.h +37 -0
  96. package/runtime/cpp/third_party/quickjs/LICENSE +22 -0
  97. package/runtime/cpp/third_party/quickjs/README.md +11 -0
  98. package/runtime/cpp/third_party/quickjs/cutils.c +641 -0
  99. package/runtime/cpp/third_party/quickjs/cutils.h +457 -0
  100. package/runtime/cpp/third_party/quickjs/libregexp-opcode.h +73 -0
  101. package/runtime/cpp/third_party/quickjs/libregexp.c +3448 -0
  102. package/runtime/cpp/third_party/quickjs/libregexp.h +65 -0
  103. package/runtime/cpp/third_party/quickjs/libunicode-table.h +5206 -0
  104. package/runtime/cpp/third_party/quickjs/libunicode.c +2124 -0
  105. package/runtime/cpp/third_party/quickjs/libunicode.h +196 -0
  106. package/runtime/js/index.d.ts +7 -0
  107. package/runtime/js/index.js +60 -0
  108. package/runtime/native/LucentNative.podspec +28 -0
  109. package/runtime/native/android/CMakeLists.txt +51 -0
  110. package/runtime/native/android/build.gradle +22 -0
  111. package/runtime/native/android/include/lucentnative.h +16 -0
  112. package/runtime/native/android/src/main/java/dev/lucent/LucentPackage.java +25 -0
  113. package/runtime/native/android/src/main/java/dev/lucent/NativeProxy.java +132 -0
  114. package/runtime/native/ios/LucentRegistration.mm +23 -0
  115. package/runtime/native/package.json +6 -0
  116. package/runtime/native/react-native.config.js +19 -0
  117. package/runtime/test/jsi/harness.cpp +181 -0
  118. package/schemas/build.schema.json +152 -0
  119. package/schemas/check.schema.json +74 -0
  120. package/schemas/doctor.schema.json +40 -0
  121. package/schemas/lucent.schema.json +43 -0
  122. package/schemas/sdk-prefetch.schema.json +37 -0
  123. package/schemas/sdk-search.schema.json +54 -0
  124. package/ts-plugin/index.d.ts +4 -0
  125. package/ts-plugin/index.js +99 -0
@@ -0,0 +1,232 @@
1
+ import { C as extractionCount, D as sdkModule, E as sdkAvailable, _ as usesPlatforms, a as inputsKey, g as projectFiles, h as platformOf, l as writeNativePackage, m as moduleNameOf, n as compile, o as isUpToDate, v as moduleNamespace } from "./src-BD7f1_aZ.js";
2
+ import { i as nativeDependencies, n as lucentPackages } from "./packages-HyskKIsY.js";
3
+ import { a as resolveAndroidDependencies, i as projectSdk, n as mapLucentPaths, o as sdkImports, r as missingInfoPlistKeys, s as writeGradleDependencies, t as backgroundPrefetch } from "./project-D8tEet0k.js";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { createHash } from "node:crypto";
7
+ //#region src/cli/pipeline.ts
8
+ const NONE = {
9
+ rebuild: false,
10
+ podInstall: false,
11
+ reload: false
12
+ };
13
+ async function buildProject(root, options, steps, notify) {
14
+ const t0 = Date.now();
15
+ const build = options.mode === "build";
16
+ let files = [];
17
+ let native;
18
+ const outcome = (o) => ({
19
+ ok: false,
20
+ upToDate: false,
21
+ files,
22
+ modules: moduleSummary(files, void 0),
23
+ diagnostics: [],
24
+ next: NONE,
25
+ ms: Date.now() - t0,
26
+ ...o
27
+ });
28
+ try {
29
+ files = projectFiles(root);
30
+ native = nativeDependencies(lucentPackages(root));
31
+ } catch (e) {
32
+ return outcome({ fatal: e.message });
33
+ }
34
+ const sdk = projectSdk(root);
35
+ const outDir = path.resolve(root, options.out ?? ".lucent/native");
36
+ let platforms = options.platforms;
37
+ let deferAndroid = false;
38
+ if (build && (!platforms || platforms.includes("android"))) {
39
+ writeGradleDependencies(outDir, native);
40
+ steps.start("android-dependencies", "Android dependencies");
41
+ await steps.flush();
42
+ const t = Date.now();
43
+ const deps = resolveAndroidDependencies(root, files, sdk, native, !!options.force);
44
+ const label = "Android dependencies";
45
+ if (deps.status === "resolved") steps.finish({
46
+ name: "android-dependencies",
47
+ label,
48
+ status: "ok",
49
+ detail: "resolved with Gradle",
50
+ ms: Date.now() - t
51
+ });
52
+ else if (deps.status === "cached") steps.finish({
53
+ name: "android-dependencies",
54
+ label,
55
+ status: "cached"
56
+ });
57
+ else if (deps.status === "failed") steps.finish({
58
+ name: "android-dependencies",
59
+ label,
60
+ status: "failed",
61
+ detail: deps.detail
62
+ });
63
+ else if (deps.status === "deferred") {
64
+ deferAndroid = true;
65
+ steps.finish({
66
+ name: "android-dependencies",
67
+ label,
68
+ status: "skipped",
69
+ detail: "resolved by the Gradle build"
70
+ });
71
+ notify({
72
+ level: "warn",
73
+ text: "the app's Android dependencies are not resolved yet: skipped Android here; the Gradle build compiles it (its lucentBuild task)"
74
+ });
75
+ }
76
+ }
77
+ if (!platforms && files.some((f) => platformOf(f) || usesPlatforms(f))) {
78
+ const installed = ["ios", "android"].filter((p) => sdkAvailable(p, sdk) && !(p === "android" && deferAndroid));
79
+ for (const p of ["ios", "android"]) {
80
+ if (installed.includes(p) || p === "android" && deferAndroid) continue;
81
+ const why = sdkModule(p, p === "ios" ? "Foundation" : "android.os", sdk);
82
+ notify({
83
+ level: "warn",
84
+ text: `${"missing" in why ? why.missing : `no ${p} SDK`}; skipped ${p === "ios" ? "iOS" : "Android"} (build it with --platforms ${p} once the SDK is installed)`
85
+ });
86
+ }
87
+ if (!installed.length) return outcome({ fatal: "no platform SDK is installed" });
88
+ platforms = installed;
89
+ if (build && options.prefetch) backgroundPrefetch(root, files);
90
+ }
91
+ if (build && outDir === path.join(root, ".lucent/native")) {
92
+ const mapped = mapLucentPaths(root);
93
+ if (mapped) notify(mapped);
94
+ }
95
+ const modules = moduleSummary(files, platforms);
96
+ const moduleCount = modules.length;
97
+ const key = inputsKey(files, outDir) + (platforms ? `:${platforms.join(",")}` : "") + `:${createHash("sha256").update(JSON.stringify(native)).digest("hex").slice(0, 12)}`;
98
+ const checked = path.join(root, ".lucent/check.json");
99
+ if (!build && !options.force) {
100
+ if ((fs.existsSync(checked) ? JSON.parse(fs.readFileSync(checked, "utf8")) : {}).inputs === key) return outcome({
101
+ ok: true,
102
+ upToDate: true,
103
+ modules
104
+ });
105
+ }
106
+ if (build && !options.force && isUpToDate(outDir, key)) {
107
+ steps.finish({
108
+ name: "up-to-date",
109
+ label: "Up to date",
110
+ status: "ok",
111
+ detail: `${plural(moduleCount, "module")}, nothing to build`,
112
+ ms: Date.now() - t0
113
+ });
114
+ return outcome({
115
+ ok: true,
116
+ upToDate: true,
117
+ modules
118
+ });
119
+ }
120
+ const imports = sdkImports(files);
121
+ const wanted = ["ios", "android"].flatMap((p) => (platforms ?? []).includes(p) ? imports[p].map((m) => [p, m]) : []);
122
+ if (wanted.length) {
123
+ const names = wanted.map(([, m]) => m);
124
+ const listed = names.length > 3 ? `${names.slice(0, 3).join(" · ")} +${names.length - 3} more` : names.join(" · ");
125
+ steps.start("sdk", `SDK bindings ${listed}`);
126
+ await steps.flush();
127
+ const t = Date.now();
128
+ const before = extractionCount();
129
+ for (const [p, m] of wanted) sdkModule(p, m, sdk);
130
+ const extracted = extractionCount() - before;
131
+ steps.finish({
132
+ name: "sdk",
133
+ label: "SDK bindings",
134
+ status: extracted ? "ok" : "cached",
135
+ detail: listed,
136
+ ms: extracted ? Date.now() - t : void 0
137
+ });
138
+ }
139
+ steps.start("check", `Checking ${plural(moduleCount, "module")}`);
140
+ await steps.flush();
141
+ const tCheck = Date.now();
142
+ const result = compile(files, {
143
+ platforms,
144
+ sdk
145
+ });
146
+ const diagnostics = result.diagnostics.map((d) => ({
147
+ ...d,
148
+ file: d.file && path.relative(root, d.file)
149
+ }));
150
+ if (!result.ok) {
151
+ steps.finish({
152
+ name: "check",
153
+ label: `Checked ${plural(moduleCount, "module")}`,
154
+ status: "failed",
155
+ detail: plural(diagnostics.length, "error"),
156
+ ms: Date.now() - tCheck
157
+ });
158
+ return outcome({
159
+ modules,
160
+ diagnostics
161
+ });
162
+ }
163
+ const names = [...result.proxies.keys()];
164
+ steps.finish({
165
+ name: "check",
166
+ label: `Checked ${plural(names.length, "module")}`,
167
+ status: "ok",
168
+ ms: Date.now() - tCheck
169
+ });
170
+ if (!build) {
171
+ fs.mkdirSync(path.dirname(checked), { recursive: true });
172
+ fs.writeFileSync(checked, `${JSON.stringify({ inputs: key })}\n`);
173
+ return outcome({
174
+ ok: true,
175
+ modules
176
+ });
177
+ }
178
+ const tWrite = Date.now();
179
+ const w = writeNativePackage(result, outDir, {
180
+ inputsKey: key,
181
+ native
182
+ });
183
+ const written = new Set(w.written.map((f) => path.relative(outDir, f)));
184
+ const changed = names.filter((n) => [...written].some((f) => f.startsWith("cpp/generated/") && path.basename(f).startsWith(`${moduleNamespace(n)}.`))).length;
185
+ steps.finish({
186
+ name: "generate",
187
+ label: "Generated C++",
188
+ status: "ok",
189
+ detail: changed === names.length ? `${changed} changed` : `${changed} changed, ${names.length - changed} cached`,
190
+ ms: Date.now() - tWrite
191
+ });
192
+ steps.finish({
193
+ name: "package",
194
+ label: "Native package",
195
+ status: "ok",
196
+ detail: path.relative(root, outDir) || "."
197
+ });
198
+ for (const n of missingInfoPlistKeys(root, native)) notify(n);
199
+ const nativeChanged = w.removed.length > 0 || [...written].some((f) => !f.startsWith("js/") && f !== "manifest.json");
200
+ return outcome({
201
+ ok: true,
202
+ modules,
203
+ next: {
204
+ rebuild: nativeChanged,
205
+ podInstall: w.structureChanged,
206
+ reload: !nativeChanged && [...written].some((f) => f.startsWith("js/"))
207
+ }
208
+ });
209
+ }
210
+ function moduleSummary(files, platforms) {
211
+ const built = (platforms ?? ["ios", "android"]).filter((p) => p !== "host");
212
+ const byModule = /* @__PURE__ */ new Map();
213
+ for (const f of files) {
214
+ const set = byModule.get(moduleNameOf(f)) ?? /* @__PURE__ */ new Set();
215
+ const p = platformOf(f);
216
+ if (p) set.add(p);
217
+ else if (usesPlatforms(f)) for (const b of built) set.add(b);
218
+ byModule.set(moduleNameOf(f), set);
219
+ }
220
+ return [...byModule].map(([name, set]) => ({
221
+ name,
222
+ platforms: set.size ? ["ios", "android"].filter((p) => set.has(p)) : ["shared"]
223
+ }));
224
+ }
225
+ function plural(n, word) {
226
+ return `${n} ${word}${n === 1 ? "" : "s"}`;
227
+ }
228
+ function nextText(next) {
229
+ return next.rebuild ? `rebuild the app${next.podInstall ? " (iOS: pod install first)" : ""}` : next.reload ? "reload the app" : "nothing to do: the native package did not change";
230
+ }
231
+ //#endregion
232
+ export { nextText as n, plural as r, buildProject as t };
@@ -0,0 +1,150 @@
1
+ import { t as packageFile } from "./version-bqpIO5sP.js";
2
+ import { c as withGradleDependencies, s as runtimeDir, w as forgetLoadedSdks, x as podsSearchPaths } from "./src-BD7f1_aZ.js";
3
+ import { t as withLucentPaths } from "./tsconfig-S4uyLNzf.js";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { spawn, spawnSync } from "node:child_process";
7
+ import { createHash } from "node:crypto";
8
+ //#region src/cli/project.ts
9
+ function mapLucentPaths(root) {
10
+ const file = path.join(root, "tsconfig.json");
11
+ if (!fs.existsSync(file)) return void 0;
12
+ let text;
13
+ try {
14
+ text = withLucentPaths(fs.readFileSync(file, "utf8"));
15
+ } catch (e) {
16
+ return {
17
+ level: "warn",
18
+ text: `${e.message}; add "paths": { "lucent:*": ["./.lucent/native/types/*"] } to its compilerOptions yourself`
19
+ };
20
+ }
21
+ if (text === void 0) return void 0;
22
+ fs.writeFileSync(file, text);
23
+ return {
24
+ level: "ok",
25
+ text: "mapped lucent:* in tsconfig.json"
26
+ };
27
+ }
28
+ function projectSdk(root) {
29
+ const pods = podsSearchPaths(path.join(root, "ios"));
30
+ return {
31
+ android: { classpath: path.join(root, ".lucent/android-classpath.json") },
32
+ ...pods ? { ios: pods } : {}
33
+ };
34
+ }
35
+ function resolveAndroidDependencies(root, files, sdk, native, force) {
36
+ const android = path.join(root, "android");
37
+ const gradlew = path.join(android, process.platform === "win32" ? "gradlew.bat" : "gradlew");
38
+ if (!sdkImports(files).android.length || !fs.existsSync(gradlew)) return { status: "none" };
39
+ if (process.env.LUCENT_GRADLE_CLASSPATH) return { status: "cached" };
40
+ if (process.env.LUCENT_NO_GRADLE) return fs.existsSync(sdk.android.classpath) ? { status: "cached" } : { status: "deferred" };
41
+ const stateFile = path.join(root, ".lucent/android-classpath.state.json");
42
+ const inputs = gradleInputsHash(root, native);
43
+ const state = fs.existsSync(stateFile) ? JSON.parse(fs.readFileSync(stateFile, "utf8")) : {};
44
+ if (!force && state.inputs === inputs && state.ok === false) return {
45
+ status: "failed",
46
+ detail: "Gradle could not resolve them for these build files before; lucent build --force retries"
47
+ };
48
+ if (!force && state.inputs === inputs && fs.existsSync(sdk.android.classpath)) return { status: "cached" };
49
+ const script = packageFile("gradle/lucent-classpath.init.gradle");
50
+ const r = spawnSync(gradlew, [
51
+ "-q",
52
+ "--init-script",
53
+ script,
54
+ ":app:lucentClasspath"
55
+ ], {
56
+ cwd: android,
57
+ encoding: "utf8"
58
+ });
59
+ fs.mkdirSync(path.dirname(stateFile), { recursive: true });
60
+ fs.writeFileSync(stateFile, JSON.stringify({
61
+ inputs,
62
+ ok: r.status === 0
63
+ }) + "\n");
64
+ forgetLoadedSdks();
65
+ if (r.status === 0) return { status: "resolved" };
66
+ return {
67
+ status: "failed",
68
+ detail: `Gradle could not resolve them (retried when the build files or the lockfile change, or with lucent build --force):\n${(r.stderr || r.stdout).trim().split("\n").slice(-8).join("\n")}`
69
+ };
70
+ }
71
+ function writeGradleDependencies(out, native) {
72
+ const file = path.join(out, "android/build.gradle");
73
+ const text = withGradleDependencies(fs.readFileSync(path.join(runtimeDir(), "native/android/build.gradle"), "utf8"), native);
74
+ if (fs.existsSync(file) && fs.readFileSync(file, "utf8") === text) return;
75
+ fs.mkdirSync(path.dirname(file), { recursive: true });
76
+ fs.writeFileSync(file, text);
77
+ }
78
+ function missingInfoPlistKeys(root, native) {
79
+ const keys = Object.entries(native.infoPlist);
80
+ const out = [];
81
+ if (!keys.length) return out;
82
+ const ios = path.join(root, "ios");
83
+ const plists = fs.existsSync(ios) ? fs.readdirSync(ios).map((d) => path.join(ios, d, "Info.plist")).filter((f) => fs.existsSync(f)) : [];
84
+ for (const plist of plists) {
85
+ const text = fs.readFileSync(plist, "utf8");
86
+ for (const [key, { from }] of keys) if (!text.includes(`<key>${key}</key>`)) out.push({
87
+ level: "warn",
88
+ text: `${from} needs ${key} in ${path.relative(root, plist)} (the Expo config plugin adds it)`
89
+ });
90
+ }
91
+ return out;
92
+ }
93
+ function gradleInputsHash(root, native) {
94
+ const android = path.join(root, "android");
95
+ const gradle = [
96
+ "settings.gradle",
97
+ "settings.gradle.kts",
98
+ "build.gradle",
99
+ "build.gradle.kts",
100
+ "app/build.gradle",
101
+ "app/build.gradle.kts",
102
+ "gradle.properties",
103
+ "gradle/libs.versions.toml"
104
+ ].map((f) => path.join(android, f));
105
+ const h = createHash("sha256");
106
+ for (const f of [...gradle, ...lockfiles(root)]) h.update(`${f}\0${fs.existsSync(f) ? fs.readFileSync(f) : ""}\0`);
107
+ h.update(JSON.stringify(native.gradle));
108
+ return h.digest("hex").slice(0, 16);
109
+ }
110
+ function lockfiles(root) {
111
+ const names = [
112
+ "package-lock.json",
113
+ "yarn.lock",
114
+ "pnpm-lock.yaml",
115
+ "bun.lock",
116
+ "bun.lockb"
117
+ ];
118
+ for (let dir = path.resolve(root);; dir = path.dirname(dir)) {
119
+ const found = names.map((n) => path.join(dir, n)).filter((f) => fs.existsSync(f));
120
+ if (found.length || path.dirname(dir) === dir) return found;
121
+ }
122
+ }
123
+ function sdkImports(files) {
124
+ const out = {
125
+ ios: /* @__PURE__ */ new Set(),
126
+ android: /* @__PURE__ */ new Set()
127
+ };
128
+ for (const f of files) for (const m of fs.readFileSync(f, "utf8").matchAll(/["']lucent:(ios|android)\/([\w.]+)["']/g)) out[m[1]].add(m[2]);
129
+ return {
130
+ ios: [...out.ios].sort(),
131
+ android: [...out.android].sort()
132
+ };
133
+ }
134
+ function backgroundPrefetch(root, files) {
135
+ const imports = sdkImports(files);
136
+ for (const p of ["ios", "android"]) for (const m of imports[p]) spawn(process.execPath, [
137
+ process.argv[1],
138
+ "sdk",
139
+ "prefetch",
140
+ `--${p}`,
141
+ m,
142
+ "--root",
143
+ root
144
+ ], {
145
+ detached: true,
146
+ stdio: "ignore"
147
+ }).unref();
148
+ }
149
+ //#endregion
150
+ export { resolveAndroidDependencies as a, projectSdk as i, mapLucentPaths as n, sdkImports as o, missingInfoPlistKeys as r, writeGradleDependencies as s, backgroundPrefetch as t };
@@ -0,0 +1,64 @@
1
+ import { D as sdkModule, O as sdkModules, b as coverage, g as projectFiles } from "./src-BD7f1_aZ.js";
2
+ import { i as table } from "./format-D9fnIMEx.js";
3
+ import { i as projectSdk, o as sdkImports } from "./project-D8tEet0k.js";
4
+ import fs from "node:fs";
5
+ //#region src/cli/commands/sdk-coverage.ts
6
+ function run({ root, flags, out }) {
7
+ const t = out.theme;
8
+ const sdk = projectSdk(root);
9
+ const list = (flag) => (typeof flags[flag] === "string" ? flags[flag] : "").split(",").filter(Boolean);
10
+ const wanted = {
11
+ ios: list("ios"),
12
+ android: list("android")
13
+ };
14
+ if (!wanted.ios.length && !wanted.android.length) Object.assign(wanted, sdkImports(projectFiles(root)));
15
+ const reports = [];
16
+ for (const platform of ["ios", "android"]) {
17
+ const listed = () => {
18
+ const all = sdkModules(platform, sdk);
19
+ return "missing" in all ? [] : all;
20
+ };
21
+ const modules = wanted[platform].flatMap((m) => m.endsWith(".*") ? listed().filter((x) => x.startsWith(m.slice(0, -1))) : [m]);
22
+ for (const m of modules) {
23
+ const r = sdkModule(platform, m, sdk);
24
+ if ("missing" in r) {
25
+ out.error(`${t.error(t.symbols.fail)} ${r.missing}`);
26
+ return 1;
27
+ }
28
+ reports.push(coverage(r.schema));
29
+ }
30
+ }
31
+ if (flags.json) out.data(reports);
32
+ else {
33
+ const pct = (n, t) => `${t ? (100 * n / t).toFixed(1) : "0.0"}%`;
34
+ const rows = reports.map((c) => [
35
+ c.module,
36
+ String(c.total),
37
+ String(c.idiomatic),
38
+ String(c.raw),
39
+ `${c.unrepresentable} (${pct(c.unrepresentable, c.total)})`
40
+ ]);
41
+ for (const line of table([[
42
+ "module",
43
+ "total",
44
+ "idiomatic",
45
+ "raw",
46
+ "unrepresentable"
47
+ ].map((h) => t.dim(h)), ...rows])) out.print(line);
48
+ }
49
+ const baselineFile = typeof flags.check === "string" ? flags.check : "";
50
+ if (!baselineFile) return 0;
51
+ const baseline = new Map(JSON.parse(fs.readFileSync(baselineFile, "utf8")).map((c) => [c.module, c]));
52
+ const share = (c) => c.total ? 100 * c.unrepresentable / c.total : 0;
53
+ let dropped = false;
54
+ for (const c of reports) {
55
+ const b = baseline.get(c.module);
56
+ if (b && share(c) > share(b) + .05) {
57
+ process.stderr.write(`${t.symbols.fail} ${c.module}: ${share(c).toFixed(2)}% unrepresentable, ${share(b).toFixed(2)}% in the baseline\n`);
58
+ dropped = true;
59
+ }
60
+ }
61
+ return dropped ? 1 : 0;
62
+ }
63
+ //#endregion
64
+ export { run };
@@ -0,0 +1,89 @@
1
+ import { C as extractionCount, D as sdkModule, O as sdkModules, g as projectFiles } from "./src-BD7f1_aZ.js";
2
+ import { i as projectSdk, o as sdkImports } from "./project-D8tEet0k.js";
3
+ import { t as plainSteps } from "./steps--_h-FFS7.js";
4
+ //#region src/cli/commands/sdk-prefetch.ts
5
+ async function run({ root, flags, out }) {
6
+ const t = out.theme;
7
+ const listed = (p) => typeof flags[p] === "string" ? flags[p].split(",").filter(Boolean) : void 0;
8
+ let wanted = {
9
+ ios: listed("ios"),
10
+ android: listed("android")
11
+ };
12
+ if (!wanted.ios && !wanted.android && !flags.all) wanted = sdkImports(projectFiles(root));
13
+ const sdk = projectSdk(root);
14
+ const jobs = [];
15
+ let failed = 0;
16
+ for (const p of ["ios", "android"]) {
17
+ let modules = wanted[p];
18
+ if (flags.all || flags[p] === "") {
19
+ const everything = sdkModules(p, sdk);
20
+ if (!Array.isArray(everything)) {
21
+ out.error(`${t.error(t.symbols.fail)} ${everything.missing}`);
22
+ failed++;
23
+ continue;
24
+ }
25
+ modules = everything;
26
+ }
27
+ for (const m of modules ?? []) jobs.push([p, m]);
28
+ }
29
+ const steps = out.json ? plainSteps(() => {}, t) : out.terminal.interactive ? (await import("./live-steps-BGcWFM9M.js")).liveSteps(t) : plainSteps((l) => out.print(l), t);
30
+ let extracted = 0;
31
+ let cached = 0;
32
+ try {
33
+ for (const [i, [p, m]] of jobs.entries()) {
34
+ const name = `lucent:${p}/${m}`;
35
+ steps.start(name, `${name} ${t.dim(`${i + 1}/${jobs.length}`)}`);
36
+ await steps.flush();
37
+ const t0 = Date.now();
38
+ const before = extractionCount();
39
+ const r = sdkModule(p, m, sdk);
40
+ if ("missing" in r) {
41
+ steps.finish({
42
+ name,
43
+ label: name,
44
+ status: "failed",
45
+ detail: r.missing
46
+ });
47
+ failed++;
48
+ } else if (extractionCount() > before) {
49
+ steps.finish({
50
+ name,
51
+ label: name,
52
+ status: "ok",
53
+ ms: Date.now() - t0
54
+ });
55
+ extracted++;
56
+ } else {
57
+ steps.finish({
58
+ name,
59
+ label: name,
60
+ status: "cached"
61
+ });
62
+ cached++;
63
+ }
64
+ }
65
+ } finally {
66
+ await steps.close();
67
+ }
68
+ if (out.json) {
69
+ out.data({
70
+ ok: failed === 0,
71
+ modules: steps.results.map((s) => ({
72
+ module: s.name,
73
+ status: s.status,
74
+ ...s.ms !== void 0 ? { ms: s.ms } : {},
75
+ ...s.detail ? { error: s.detail } : {}
76
+ }))
77
+ });
78
+ return failed ? 1 : 0;
79
+ }
80
+ const parts = [
81
+ extracted && `${extracted} extracted`,
82
+ cached && `${cached} cached`,
83
+ failed && t.error(`${failed} failed`)
84
+ ].filter(Boolean);
85
+ out.print(`\n${jobs.length} module${jobs.length === 1 ? "" : "s"}: ${parts.join(", ") || "nothing to do"}`);
86
+ return failed ? 1 : 0;
87
+ }
88
+ //#endregion
89
+ export { run };
@@ -0,0 +1,124 @@
1
+ import { D as sdkModule, E as sdkAvailable, S as cachedModules, g as projectFiles, k as sdkNames } from "./src-BD7f1_aZ.js";
2
+ import { i as table } from "./format-D9fnIMEx.js";
3
+ import { i as projectSdk, o as sdkImports } from "./project-D8tEet0k.js";
4
+ //#region src/cli/commands/sdk-search.ts
5
+ function run({ root, positionals, out }) {
6
+ const t = out.theme;
7
+ const term = positionals.join(" ").trim();
8
+ if (!term) {
9
+ out.error(`${t.error(t.symbols.fail)} search for a name: lucent sdk search <term>`);
10
+ return 2;
11
+ }
12
+ const needle = term.toLowerCase();
13
+ const hit = (name) => name.toLowerCase().includes(needle);
14
+ const sdk = projectSdk(root);
15
+ let imports = {
16
+ ios: [],
17
+ android: []
18
+ };
19
+ try {
20
+ imports = sdkImports(projectFiles(root));
21
+ } catch {}
22
+ const matches = [];
23
+ let searched = 0;
24
+ let total = 0;
25
+ for (const platform of ["ios", "android"]) {
26
+ if (!sdkAvailable(platform, sdk)) continue;
27
+ const cached = cachedModules(platform, sdk);
28
+ const withSchema = [.../* @__PURE__ */ new Set([...imports[platform], ..."missing" in cached ? [] : cached.schemas])].sort();
29
+ const namesOnly = "missing" in cached ? [] : cached.names.filter((m) => !withSchema.includes(m));
30
+ total += withSchema.length + namesOnly.length;
31
+ const importLine = (module, name) => `import { ${name} } from "lucent:${platform}/${module}";`;
32
+ for (const module of withSchema) {
33
+ const r = sdkModule(platform, module, sdk);
34
+ if ("missing" in r) continue;
35
+ searched++;
36
+ matches.push(...schemaMatches(r.schema, platform, hit, importLine));
37
+ }
38
+ for (const module of namesOnly) {
39
+ const r = sdkNames(platform, module, sdk);
40
+ if ("missing" in r) continue;
41
+ searched++;
42
+ for (const [name, info] of Object.entries(r.names.types)) if (hit(name)) matches.push({
43
+ platform,
44
+ module,
45
+ kind: info.kind === "protocol" ? "protocol" : info.kind === "class" ? "class" : info.kind === "enum" ? "enum" : "struct",
46
+ name,
47
+ import: importLine(module, name)
48
+ });
49
+ }
50
+ }
51
+ if (out.json) {
52
+ out.data({
53
+ term,
54
+ searched,
55
+ matches
56
+ });
57
+ return 0;
58
+ }
59
+ const groups = /* @__PURE__ */ new Map();
60
+ for (const m of matches) groups.set(`${m.platform}\0${m.module}`, [...groups.get(`${m.platform}\0${m.module}`) ?? [], m]);
61
+ const LIMIT = 12;
62
+ for (const [key, list] of groups) {
63
+ const [platform, module] = key.split("\0");
64
+ out.print(`${t.brand(platform)} ${t.bold(module)}`);
65
+ const shown = list.slice(0, LIMIT);
66
+ const types = new Set(shown.filter((m) => !m.name.includes(".")).map((m) => m.name));
67
+ for (const line of table(shown.map((m) => [
68
+ ` ${t.dim(m.kind)}`,
69
+ m.name,
70
+ types.has(m.name) ? t.dim(m.import) : ""
71
+ ]))) out.print(line.trimEnd());
72
+ if (list.length > LIMIT) out.print(t.dim(` … ${list.length - LIMIT} more (lucent sdk search ${term} --json lists them all)`));
73
+ out.print("");
74
+ }
75
+ if (!matches.length) out.print(`${t.dim(t.symbols.off)} nothing named like ${term}`);
76
+ out.print(t.dim(`searched ${searched} module${searched === 1 ? "" : "s"}${total > searched ? ` of ${total}` : ""} (your imports and the SDK cache; lucent sdk prefetch --all to search every module)`));
77
+ return 0;
78
+ }
79
+ function schemaMatches(schema, platform, hit, importLine) {
80
+ const out = [];
81
+ const module = schema.module;
82
+ for (const type of schema.types) {
83
+ const kind = type.kind === "class" ? type.interface ? platform === "ios" ? "protocol" : "interface" : "class" : type.kind;
84
+ if (hit(type.name)) out.push({
85
+ platform,
86
+ module,
87
+ kind,
88
+ name: type.name,
89
+ import: importLine(module, type.name)
90
+ });
91
+ if (type.kind !== "class") continue;
92
+ for (const m of type.methods ?? []) if (hit(m.name)) out.push({
93
+ platform,
94
+ module,
95
+ kind: "method",
96
+ name: `${type.name}.${m.name}(${m.params.map((p) => p.name).join(", ")})`,
97
+ import: importLine(module, type.name)
98
+ });
99
+ for (const p of type.properties ?? []) if (hit(p.name)) out.push({
100
+ platform,
101
+ module,
102
+ kind: "property",
103
+ name: `${type.name}.${p.name}`,
104
+ import: importLine(module, type.name)
105
+ });
106
+ }
107
+ for (const f of schema.functions ?? []) if (hit(f.name)) out.push({
108
+ platform,
109
+ module,
110
+ kind: "function",
111
+ name: `${f.name}(${f.params.map((p) => p.name).join(", ")})`,
112
+ import: importLine(module, f.name)
113
+ });
114
+ for (const c of schema.constants ?? []) if (hit(c.name)) out.push({
115
+ platform,
116
+ module,
117
+ kind: "constant",
118
+ name: c.name,
119
+ import: importLine(module, c.name)
120
+ });
121
+ return out;
122
+ }
123
+ //#endregion
124
+ export { run };