@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
package/dist/cli.js ADDED
@@ -0,0 +1,406 @@
1
+ import { t as createTheme } from "./theme-uv5bc0aK.js";
2
+ import { n as version } from "./version-bqpIO5sP.js";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import os from "node:os";
6
+ //#region src/cli/args.ts
7
+ const GLOBAL_FLAGS = [
8
+ {
9
+ name: "root",
10
+ value: "dir",
11
+ description: "Project directory (default: the current one)"
12
+ },
13
+ {
14
+ name: "json",
15
+ description: "Machine-readable output, for tools and CI"
16
+ },
17
+ {
18
+ name: "help",
19
+ description: "Show help"
20
+ }
21
+ ];
22
+ function parseArgs(argv, commands) {
23
+ const words = argv.filter((a) => !a.startsWith("-"));
24
+ const command = [...commands].sort((a, b) => b.name.split(" ").length - a.name.split(" ").length).find((c) => c.name.split(" ").every((w, i) => words[i] === w));
25
+ const firstWord = argv[0];
26
+ if (!command && firstWord && !firstWord.startsWith("-")) {
27
+ const near = closest(firstWord, [...new Set(commands.map((c) => c.name.split(" ")[0]))]);
28
+ return { error: `unknown command ${firstWord}${near ? ` (did you mean ${near}?)` : ""}` };
29
+ }
30
+ const specs = [
31
+ ...command?.flags ?? [],
32
+ ...GLOBAL_FLAGS,
33
+ ...command ? [] : [{
34
+ name: "version",
35
+ description: ""
36
+ }]
37
+ ];
38
+ const flags = {};
39
+ const positionals = [];
40
+ const nameWords = command ? command.name.split(" ").length : 0;
41
+ let skipped = 0;
42
+ for (let i = 0; i < argv.length; i++) {
43
+ const a = argv[i];
44
+ if (!a.startsWith("--")) {
45
+ if (skipped < nameWords) skipped++;
46
+ else positionals.push(a);
47
+ continue;
48
+ }
49
+ const [name, inline] = a.slice(2).split(/=(.*)/s, 2);
50
+ const spec = specs.find((f) => f.name === name);
51
+ if (!spec) return { error: `unknown flag --${name}${command ? ` for lucent ${command.name}` : ""}` };
52
+ if (!spec.value) {
53
+ flags[name] = true;
54
+ continue;
55
+ }
56
+ const next = argv[i + 1];
57
+ if (inline !== void 0) flags[name] = inline;
58
+ else if (next !== void 0 && !next.startsWith("--")) flags[name] = argv[++i];
59
+ else if (spec.optional) flags[name] = "";
60
+ else return { error: `--${name} needs a value (--${name} <${spec.value}>)` };
61
+ }
62
+ return {
63
+ command,
64
+ flags,
65
+ positionals
66
+ };
67
+ }
68
+ function closest(word, candidates) {
69
+ let best;
70
+ for (const c of candidates) {
71
+ const d = distance(word, c);
72
+ if (d <= 2 && (!best || d < best.d)) best = {
73
+ c,
74
+ d
75
+ };
76
+ }
77
+ return best?.c;
78
+ }
79
+ function distance(a, b) {
80
+ const row = Array.from({ length: b.length + 1 }, (_, j) => j);
81
+ for (let i = 1; i <= a.length; i++) {
82
+ let prev = row[0];
83
+ row[0] = i;
84
+ for (let j = 1; j <= b.length; j++) {
85
+ const cur = row[j];
86
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
87
+ prev = cur;
88
+ }
89
+ }
90
+ return row[b.length];
91
+ }
92
+ //#endregion
93
+ //#region src/cli/commands.ts
94
+ const commands = [
95
+ {
96
+ name: "build",
97
+ summary: "Compile the project's modules and write the native package (.lucent/native); skipped when nothing changed",
98
+ flags: [
99
+ {
100
+ name: "force",
101
+ description: "Rebuild even when nothing changed"
102
+ },
103
+ {
104
+ name: "platforms",
105
+ value: "list",
106
+ description: "Targets for platform code: ios, android, host (default: the SDKs installed)"
107
+ },
108
+ {
109
+ name: "out",
110
+ value: "dir",
111
+ description: "Where to write the native package (default: .lucent/native)"
112
+ }
113
+ ],
114
+ load: () => import("./build-CAIrRSYA.js")
115
+ },
116
+ {
117
+ name: "check",
118
+ summary: "Type-check and validate every module without writing anything",
119
+ flags: [],
120
+ load: () => import("./check-1SCmYlqA.js")
121
+ },
122
+ {
123
+ name: "dev",
124
+ summary: "Rebuild on every change: a live dashboard of modules, platforms and problems (one line per build outside a terminal)",
125
+ flags: [{
126
+ name: "compact",
127
+ description: "One line per build instead of the dashboard (Metro runs it so)"
128
+ }],
129
+ load: () => import("./dev-BYWMP7oC.js")
130
+ },
131
+ {
132
+ name: "doctor",
133
+ summary: "Check the machine and the app: Node, React Native, Xcode, CocoaPods, the Android SDK, the JDK, the Metro config, versions",
134
+ flags: [],
135
+ load: () => import("./doctor-DdR4JnVc.js")
136
+ },
137
+ {
138
+ name: "init",
139
+ summary: "Set an app up for Lucent: the Metro config, the Expo plugin or the Gradle task, tsconfig.json, .gitignore, a first module",
140
+ flags: [{
141
+ name: "yes",
142
+ description: "Apply every change without asking"
143
+ }],
144
+ load: () => import("./init-gIabu1S_.js")
145
+ },
146
+ {
147
+ name: "new module",
148
+ summary: "Scaffold a module in src/: shared, or with --ios / --android one module that branches on PLATFORM",
149
+ flags: [
150
+ {
151
+ name: "ios",
152
+ description: "Implement the iOS branch (without --android, the Android branch throws)"
153
+ },
154
+ {
155
+ name: "android",
156
+ description: "Implement the Android branch (without --ios, the iOS branch throws)"
157
+ },
158
+ {
159
+ name: "shared",
160
+ description: "One module for every platform (the default)"
161
+ }
162
+ ],
163
+ load: () => import("./new-module-C2mtb0op.js")
164
+ },
165
+ {
166
+ name: "explain",
167
+ summary: "What a LUCENT diagnostic code means, and how to fix it (every code without one)",
168
+ flags: [],
169
+ load: () => import("./explain--vV1oaRl.js")
170
+ },
171
+ {
172
+ name: "bench",
173
+ summary: "Time the cases of your *.bench.ts files natively and as JavaScript, and show the speedup (needs a desktop Hermes)",
174
+ flags: [],
175
+ load: () => import("./bench-CR3E7e2e.js")
176
+ },
177
+ {
178
+ name: "clean",
179
+ summary: "Remove the generated .lucent/ (the next build starts over)",
180
+ flags: [{
181
+ name: "cache",
182
+ description: "Also remove the SDK bindings cache"
183
+ }],
184
+ load: () => import("./clean-BVwpbJ5K.js")
185
+ },
186
+ {
187
+ name: "sdk search",
188
+ summary: "Find SDK classes and members by name, with the import to copy (your imports and the SDK cache)",
189
+ flags: [],
190
+ load: () => import("./sdk-search-Iv4K3-8a.js")
191
+ },
192
+ {
193
+ name: "sdk show",
194
+ summary: "Print the declaration Lucent code sees for an SDK type or member: android.os.Vibrator, UIKit.UIDevice.current",
195
+ flags: [],
196
+ load: () => import("./sdk-show-CkrdlqlP.js")
197
+ },
198
+ {
199
+ name: "sdk prefetch",
200
+ summary: "Extract SDK bindings into the cache ahead of use (default: the lucent:* modules the project imports)",
201
+ flags: [
202
+ {
203
+ name: "ios",
204
+ value: "modules",
205
+ optional: true,
206
+ description: "iOS modules, comma-separated; alone: every module"
207
+ },
208
+ {
209
+ name: "android",
210
+ value: "packages",
211
+ optional: true,
212
+ description: "Android packages, comma-separated; alone: every package"
213
+ },
214
+ {
215
+ name: "all",
216
+ description: "Every module of every installed SDK"
217
+ }
218
+ ],
219
+ load: () => import("./sdk-prefetch-mo04JDZV.js")
220
+ },
221
+ {
222
+ name: "sdk coverage",
223
+ summary: "Per SDK module, the members Lucent code can call: idiomatic, raw, unrepresentable",
224
+ flags: [
225
+ {
226
+ name: "ios",
227
+ value: "modules",
228
+ description: "iOS modules, comma-separated"
229
+ },
230
+ {
231
+ name: "android",
232
+ value: "packages",
233
+ description: "Android packages, comma-separated (p.* for a prefix)"
234
+ },
235
+ {
236
+ name: "check",
237
+ value: "baseline",
238
+ description: "Fail when the unrepresentable share grows past a baseline JSON"
239
+ }
240
+ ],
241
+ load: () => import("./sdk-coverage-BoW_3Efd.js")
242
+ }
243
+ ];
244
+ //#endregion
245
+ //#region src/cli/crash.ts
246
+ const ISSUES = "https://github.com/Fausto95/lucent/issues/new";
247
+ function installCrashHandler(version) {
248
+ const crash = (e) => {
249
+ const error = e instanceof Error ? e : new Error(String(e));
250
+ const dir = path.join(os.tmpdir(), "lucent-logs");
251
+ const log = path.join(dir, `crash-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.log`);
252
+ try {
253
+ fs.mkdirSync(dir, { recursive: true });
254
+ fs.writeFileSync(log, `lucent ${version}\nnode ${process.version} ${process.platform}-${process.arch}\nargv: ${process.argv.slice(2).join(" ")}\n\n${error.stack ?? error.message}\n`);
255
+ } catch {}
256
+ process.stderr.write(`\nlucent crashed: ${error.message}\n details: ${log}\n please report it with that file: ${ISSUES}\n`);
257
+ process.exit(70);
258
+ };
259
+ process.on("uncaughtException", crash);
260
+ process.on("unhandledRejection", crash);
261
+ }
262
+ //#endregion
263
+ //#region src/cli/help.ts
264
+ const flagLabel = (f) => `--${f.name}${f.value ? f.optional ? ` [<${f.value}>]` : ` <${f.value}>` : ""}`;
265
+ function wrap(text, width) {
266
+ const out = [];
267
+ let line = "";
268
+ for (const word of text.split(" ")) if (line && line.length + 1 + word.length > width) {
269
+ out.push(line);
270
+ line = word;
271
+ } else line = line ? `${line} ${word}` : word;
272
+ return line ? [...out, line] : out;
273
+ }
274
+ function described(rows, theme) {
275
+ const labelWidth = Math.min(34, Math.max(...rows.map(([l]) => l.length)));
276
+ const room = Math.max(20, theme.terminal.width - 2 - labelWidth - 2);
277
+ return rows.flatMap(([label, text]) => {
278
+ const lines = wrap(text, room);
279
+ if (label.length > labelWidth) return [` ${label}`, ...lines.map((l) => ` ${" ".repeat(labelWidth + 2)}${theme.dim(l)}`)];
280
+ return lines.map((l, i) => ` ${(i ? "" : label).padEnd(labelWidth + 2)}${theme.dim(l)}`);
281
+ });
282
+ }
283
+ function help(commands, theme) {
284
+ return [
285
+ `${theme.brand(theme.symbols.brand)} ${theme.bold("lucent")} ${theme.dim("native React Native modules in TypeScript")}`,
286
+ "",
287
+ theme.bold("Usage"),
288
+ " lucent <command> [flags]",
289
+ "",
290
+ theme.bold("Commands"),
291
+ ...described(commands.map((c) => [`lucent ${c.name}`, c.summary]), theme),
292
+ "",
293
+ theme.bold("Flags"),
294
+ ...described([...GLOBAL_FLAGS.map((f) => [flagLabel(f), f.description]), ["--version", "Show the version"]], theme),
295
+ "",
296
+ theme.dim("Run lucent <command> --help for a command's flags.")
297
+ ].join("\n");
298
+ }
299
+ function commandHelp(command, theme) {
300
+ const flags = [...command.flags, ...GLOBAL_FLAGS];
301
+ return [
302
+ theme.bold(`lucent ${command.name}`),
303
+ ...wrap(command.summary, theme.terminal.width - 2).map((l) => ` ${theme.dim(l)}`),
304
+ "",
305
+ theme.bold("Flags"),
306
+ ...described(flags.map((f) => [flagLabel(f), f.description]), theme)
307
+ ].join("\n");
308
+ }
309
+ //#endregion
310
+ //#region src/cli/ui/terminal.ts
311
+ const LINK_TERMINALS = /* @__PURE__ */ new Set([
312
+ "iTerm.app",
313
+ "WezTerm",
314
+ "vscode",
315
+ "ghostty",
316
+ "Hyper",
317
+ "Tabby",
318
+ "rio"
319
+ ]);
320
+ function detectTerminal(env, stream, platform = process.platform) {
321
+ const tty = !!stream.isTTY;
322
+ const dumb = env.TERM === "dumb";
323
+ const forced = env.FORCE_COLOR;
324
+ const color = env.NO_COLOR ? false : forced !== void 0 && forced !== "" ? forced !== "0" && forced !== "false" : tty && !dumb;
325
+ const interactive = tty && !dumb && !env.CI;
326
+ return {
327
+ color,
328
+ interactive,
329
+ unicode: !dumb && (platform !== "win32" || !!env.WT_SESSION || env.TERM_PROGRAM === "vscode"),
330
+ links: interactive && color && (LINK_TERMINALS.has(env.TERM_PROGRAM ?? "") || !!env.WT_SESSION || Number(env.VTE_VERSION ?? 0) >= 5e3),
331
+ width: Math.min(stream.columns || 80, 120)
332
+ };
333
+ }
334
+ //#endregion
335
+ //#region src/cli/output.ts
336
+ function createOutput(json, stdout = process.stdout, stderr = process.stderr, env = process.env) {
337
+ const terminal = detectTerminal(env, stdout);
338
+ return {
339
+ terminal,
340
+ theme: createTheme(terminal),
341
+ json,
342
+ print: (line = "") => void (json || stdout.write(`${line}\n`)),
343
+ error: (line) => void (json || stderr.write(`${line}\n`)),
344
+ data: (value) => void stdout.write(`${JSON.stringify(value, null, 2)}\n`)
345
+ };
346
+ }
347
+ //#endregion
348
+ //#region src/cli/main.ts
349
+ async function main(argv) {
350
+ const parsed = parseArgs(argv, commands);
351
+ const out = createOutput("error" in parsed ? false : !!parsed.flags.json);
352
+ if ("error" in parsed) {
353
+ out.error(`${out.theme.error(out.theme.symbols.fail)} ${parsed.error}`);
354
+ out.error(out.theme.dim("Run lucent --help for the commands and their flags."));
355
+ return 2;
356
+ }
357
+ const { command, flags, positionals } = parsed;
358
+ if (flags.version && !command) {
359
+ const sdks = (await import("./sdks-Xoyiy2E4.js")).installedSdks();
360
+ out.print(`lucent ${version()}`);
361
+ if (process.platform === "darwin") out.print(` iOS SDK ${sdks.ios ?? "not found"}`);
362
+ out.print(` Android SDK ${sdks.android ?? "not found"}`);
363
+ return 0;
364
+ }
365
+ const root = path.resolve(typeof flags.root === "string" ? flags.root : process.cwd());
366
+ if (!command && !flags.help && out.terminal.interactive) {
367
+ const name = usesLucent(root) ? "dev" : "init";
368
+ return (await commands.find((c) => c.name === name).load()).run({
369
+ root,
370
+ flags,
371
+ positionals,
372
+ out
373
+ });
374
+ }
375
+ if (!command) {
376
+ out.print(help(commands, out.theme));
377
+ return flags.help ? 0 : 1;
378
+ }
379
+ if (flags.help) {
380
+ out.print(commandHelp(command, out.theme));
381
+ return 0;
382
+ }
383
+ return (await command.load()).run({
384
+ root,
385
+ flags,
386
+ positionals,
387
+ out
388
+ });
389
+ }
390
+ function usesLucent(root) {
391
+ if (fs.existsSync(path.join(root, ".lucent"))) return true;
392
+ try {
393
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
394
+ return "@lucent-lang/lucent" in {
395
+ ...pkg.dependencies,
396
+ ...pkg.devDependencies
397
+ };
398
+ } catch {
399
+ return false;
400
+ }
401
+ }
402
+ installCrashHandler(version());
403
+ const status = await main(process.argv.slice(2));
404
+ if (status >= 0) process.exit(status);
405
+ //#endregion
406
+ export {};
@@ -0,0 +1,260 @@
1
+ //#region ../compiler/src/codes.ts
2
+ const Codes = {
3
+ UnsupportedSyntax: "LUCENT1001",
4
+ UnsupportedOperator: "LUCENT1002",
5
+ UnsupportedBuiltin: "LUCENT1003",
6
+ UnsupportedDestructuring: "LUCENT1004",
7
+ UnsupportedClassFeature: "LUCENT1005",
8
+ UnsupportedThrow: "LUCENT1006",
9
+ UnsupportedCall: "LUCENT1007",
10
+ UnsupportedAssignmentTarget: "LUCENT1008",
11
+ UnsupportedLoop: "LUCENT1009",
12
+ AnyType: "LUCENT2001",
13
+ UnsupportedType: "LUCENT2002",
14
+ InexactObject: "LUCENT2003",
15
+ ArrayVariance: "LUCENT2004",
16
+ AmbiguousUnion: "LUCENT2005",
17
+ BoundaryType: "LUCENT2006",
18
+ GenericBoundary: "LUCENT2007",
19
+ InterfaceNotImplemented: "LUCENT2008",
20
+ InterfaceMismatch: "LUCENT2009",
21
+ UnsupportedImport: "LUCENT3001",
22
+ UnsupportedTopLevel: "LUCENT3002",
23
+ UnsupportedExport: "LUCENT3003",
24
+ SdkImport: "LUCENT3004",
25
+ PlatformConformance: "LUCENT3005",
26
+ MainThreadOnly: "LUCENT3006",
27
+ Unavailable: "LUCENT3007",
28
+ TypeScript: "LUCENT9001"
29
+ };
30
+ const ex = (source, name = "example.lucent.ts") => ({ [name]: source });
31
+ const Explanations = {
32
+ LUCENT1001: {
33
+ title: "Syntax outside the subset",
34
+ summary: "Syntax outside the subset, such as `var`, getters in object literals, or an async generator.",
35
+ details: "Lucent compiles a subset of TypeScript whose every construct has a native equivalent with the same behaviour. `var` (function scoping and hoisting), `with`, labels on blocks, accessors in object literals and async generators fall outside it.",
36
+ fix: "rewrite it with the supported form: `let`/`const` for `var`, a class for an object with accessors",
37
+ wrong: ex("export function total(xs: number[]): number {\n var sum = 0;\n for (const x of xs) sum += x;\n return sum;\n}\n"),
38
+ right: ex("export function total(xs: number[]): number {\n let sum = 0;\n for (const x of xs) sum += x;\n return sum;\n}\n")
39
+ },
40
+ LUCENT1002: {
41
+ title: "Unsupported operator",
42
+ summary: "An operator used outside what the subset supports, such as `delete`, `in` on anything but a record, or `instanceof` with a generic class.",
43
+ details: "Objects in Lucent have a fixed native layout, so an operator that adds or removes properties at run time (`delete`) has no native equivalent. `in` works on records (`Record<string, T>`), whose keys are dynamic, and not on objects with a known shape.",
44
+ fix: "use a Map or a Record for keys that come and go, or an optional field for one that may be missing",
45
+ wrong: ex("export function clear(tags: { name?: string }): { name?: string } {\n delete tags.name;\n return tags;\n}\n"),
46
+ right: ex("export function clear(tags: { name?: string }): { name?: string } {\n tags.name = undefined;\n return tags;\n}\n")
47
+ },
48
+ LUCENT1003: {
49
+ title: "Built-in without a native implementation",
50
+ summary: "A built-in function or method Lucent does not implement, such as `Symbol()`, `eval` or an unknown `Math`, `Number` or string method.",
51
+ details: "Every built-in a module calls runs as native code from the Lucent runtime. The ones listed in the language reference are implemented with JavaScript's exact semantics; the rest are reported rather than approximated.",
52
+ fix: "use a built-in Lucent implements, or write the helper in the module",
53
+ wrong: ex("export function rotate(xs: number[]): number[] {\n return xs.copyWithin(0, 1);\n}\n"),
54
+ right: ex("export function rotate(xs: number[]): number[] {\n return [...xs.slice(1), ...xs.slice(0, 1)];\n}\n")
55
+ },
56
+ LUCENT1004: {
57
+ title: "Unsupported destructuring",
58
+ summary: "A destructuring form outside the subset: object rest, computed keys, or a pattern without an initializer.",
59
+ details: "Object rest (`{ a, ...rest }`) would need a new object type, made of the remaining fields at run time. Computed keys would need a dynamic lookup. Neither has a fixed native layout.",
60
+ fix: "name the fields you need, or pass the whole object",
61
+ wrong: ex("type User = { id: number; name: string; email: string };\nexport function contact(u: User): { name: string; email: string } {\n const { id, ...rest } = u;\n return rest;\n}\n"),
62
+ right: ex("type User = { id: number; name: string; email: string };\nexport function contact(u: User): { name: string; email: string } {\n const { name, email } = u;\n return { name, email };\n}\n")
63
+ },
64
+ LUCENT1005: {
65
+ title: "Unsupported class feature",
66
+ summary: "A class feature outside the subset, such as extending a built-in other than `Error`, or an override that changes the native signature.",
67
+ details: "Classes compile to C++ classes. A subclass of `Map` or `Array` would inherit the runtime's container internals. An override whose parameters or result differ from the base method's can't share its native slot.",
68
+ fix: "hold the built-in in a field instead of extending it, and keep overrides' signatures the same as the base method's",
69
+ wrong: ex("class Counts extends Map<string, number> {}\nexport function size(): number {\n return new Counts().size;\n}\n"),
70
+ right: ex("class Counts {\n readonly map = new Map<string, number>();\n}\nexport function size(): number {\n return new Counts().map.size;\n}\n")
71
+ },
72
+ LUCENT1006: {
73
+ title: "Throwing a value that is not an Error",
74
+ summary: "Throwing a value that is not an `Error`.",
75
+ details: "Errors cross into JavaScript as `Error` objects with a name, a message and a stack that points at the Lucent source. A thrown string or number has none of that and no native type to catch it by.",
76
+ fix: "throw `new Error(…)`, a built-in error such as `TypeError`, or a class that extends `Error`",
77
+ wrong: ex("export function port(text: string): number {\n const n = Number(text);\n if (!Number.isInteger(n)) throw \"not a port\";\n return n;\n}\n"),
78
+ right: ex("export function port(text: string): number {\n const n = Number(text);\n if (!Number.isInteger(n)) throw new RangeError(`not a port: ${text}`);\n return n;\n}\n")
79
+ },
80
+ LUCENT1007: {
81
+ title: "Call Lucent cannot compile",
82
+ summary: "A call Lucent cannot compile, such as spread arguments outside rest parameters, or a platform class without a constructor binding.",
83
+ details: "Native calls pass a fixed number of arguments of known types. Spreading an array into ordinary parameters has no native form. Neither does a platform API called as a promise where it has none, or a platform class without an initializer.",
84
+ fix: "pass the arguments one by one, or declare the callee with a rest parameter",
85
+ wrong: ex("function add(a: number, b: number): number {\n return a + b;\n}\nexport function sum(pair: [number, number]): number {\n return add(...pair);\n}\n"),
86
+ right: ex("function add(a: number, b: number): number {\n return a + b;\n}\nexport function sum(pair: [number, number]): number {\n return add(pair[0], pair[1]);\n}\n")
87
+ },
88
+ LUCENT1008: {
89
+ title: "Assignment to something that cannot be assigned",
90
+ summary: "An assignment to something that cannot be assigned, such as an unknown field or a function.",
91
+ details: "Assignments write to a native variable or field. A function, an import, or a field the value's type does not have is not one.",
92
+ fix: "assign a variable or a field the type declares",
93
+ wrong: ex("function tick(): number {\n return 1;\n}\nexport function reset(): void {\n // @ts-expect-error: assigning a function\n tick = () => 0;\n}\n"),
94
+ right: ex("let tick = (): number => 1;\nexport function reset(): void {\n tick = () => 0;\n}\nexport function now(): number {\n return tick();\n}\n")
95
+ },
96
+ LUCENT1009: {
97
+ title: "Loop over a value that is not iterable",
98
+ summary: "A loop over a value that is not iterable in Lucent, or `for await`.",
99
+ details: "`for…of` works on arrays, strings, maps, sets, typed arrays and generators, and `for…in` on records. Async iteration (`for await`) is not supported: await each promise in an ordinary loop.",
100
+ fix: "loop over an array (`Object.keys`, `Array.from`), or await inside a plain loop",
101
+ wrong: ex("export async function total(xs: Promise<number>[]): Promise<number> {\n let sum = 0;\n for await (const x of xs) sum += x;\n return sum;\n}\n"),
102
+ right: ex("export async function total(xs: Promise<number>[]): Promise<number> {\n let sum = 0;\n for (const x of xs) sum += await x;\n return sum;\n}\n")
103
+ },
104
+ LUCENT2001: {
105
+ title: "Value without a native type",
106
+ summary: "`any`, or `unknown` outside a `catch` clause: every value needs a native type.",
107
+ details: "Native code needs to know each value's layout at compile time. `any` gives it none, and `unknown` only stands for a caught error, whose type JavaScript does not say.",
108
+ fix: "use a concrete type, a union, or a generic parameter",
109
+ wrong: ex("export function size(value: any): number {\n return value.length;\n}\n"),
110
+ right: ex("export function size(value: string): number {\n return value.length;\n}\n")
111
+ },
112
+ LUCENT2002: {
113
+ title: "Type without a native representation",
114
+ summary: "A type with no native representation: intersections, `bigint`, `symbol`, `object`, `WeakMap`, `Intl`, or an index signature mixed with properties.",
115
+ details: "Each type maps to one native representation. An intersection can combine unrelated layouts, `bigint` and `symbol` are not implemented yet, and `object` says nothing about the layout.",
116
+ fix: "spell the combined type out as one object type, or use a concrete type",
117
+ wrong: ex("type Named = { name: string };\ntype Aged = { age: number };\nexport function label(p: Named & Aged): string {\n return `${p.name} (${p.age})`;\n}\n"),
118
+ right: ex("type Person = { name: string; age: number };\nexport function label(p: Person): string {\n return `${p.name} (${p.age})`;\n}\n")
119
+ },
120
+ LUCENT2003: {
121
+ title: "Object used as a type with a different shape",
122
+ summary: "An object used as a type with a different shape; object types must match exactly to share a native representation.",
123
+ details: "Object types with the same fields share one native struct. TypeScript lets a value with more fields stand for a type with fewer. Natively they are different structs, and the extra fields would have nowhere to go.",
124
+ fix: "pass exactly the fields the type declares, or widen the parameter's type",
125
+ wrong: ex("type Point = { x: number; y: number };\ntype Point3 = { x: number; y: number; z: number };\nfunction norm(p: Point): number {\n return Math.hypot(p.x, p.y);\n}\nexport function flat(p: Point3): number {\n return norm(p);\n}\n"),
126
+ right: ex("type Point = { x: number; y: number };\ntype Point3 = { x: number; y: number; z: number };\nfunction norm(p: Point): number {\n return Math.hypot(p.x, p.y);\n}\nexport function flat(p: Point3): number {\n return norm({ x: p.x, y: p.y });\n}\n")
127
+ },
128
+ LUCENT2004: {
129
+ title: "Collection used with another element type",
130
+ summary: "A collection used where its element type would change (`A[]` as `(A | B)[]`); annotate the value with the target type.",
131
+ details: "An array of numbers and an array of `number | string` have different native element types. One can't be used as the other: writes through the wider type wouldn't fit.",
132
+ fix: "annotate the collection with the element type it is used as",
133
+ wrong: ex("function first(xs: (number | string)[]): string {\n return String(xs[0]);\n}\nexport function f(): string {\n const xs = [1, 2];\n return first(xs);\n}\n"),
134
+ right: ex("function first(xs: (number | string)[]): string {\n return String(xs[0]);\n}\nexport function f(): string {\n const xs: (number | string)[] = [1, 2];\n return first(xs);\n}\n")
135
+ },
136
+ LUCENT2005: {
137
+ title: "Union JavaScript values cannot be told apart by",
138
+ summary: "A union JavaScript values cannot be told apart by at the boundary; add a string-literal discriminant.",
139
+ details: "A value from JavaScript carries no type, so Lucent decides which union member it is from the value itself. Object members need a string-literal field, such as `kind`, whose value names the member.",
140
+ fix: "add a string-literal field such as `kind: \"circle\"` to each object member",
141
+ wrong: ex("export function area(shape: { radius: number } | { side: number }): number {\n return \"radius\" in shape ? Math.PI * shape.radius ** 2 : shape.side ** 2;\n}\n"),
142
+ right: ex("export function area(shape: { kind: \"circle\"; radius: number } | { kind: \"square\"; side: number }): number {\n return shape.kind === \"circle\" ? Math.PI * shape.radius ** 2 : shape.side ** 2;\n}\n")
143
+ },
144
+ LUCENT2006: {
145
+ title: "Value that cannot cross the JavaScript boundary",
146
+ summary: "A value that cannot cross the JavaScript boundary, such as a generator, a match result, an `AbortSignal` or a platform object.",
147
+ details: "Exports convert their parameters and results between JavaScript and native values. Some native values have no JavaScript form: a generator's state, a platform object, a signal made in native code.",
148
+ fix: "return plain data (an array instead of a generator, fields instead of a platform object)",
149
+ wrong: ex("export function* count(n: number): Generator<number> {\n for (let i = 0; i < n; i++) yield i;\n}\n"),
150
+ right: ex("function* count(n: number): Generator<number> {\n for (let i = 0; i < n; i++) yield i;\n}\nexport function counted(n: number): number[] {\n return [...count(n)];\n}\n")
151
+ },
152
+ LUCENT2007: {
153
+ title: "Generic export",
154
+ summary: "A generic function or class exported to JavaScript; export a concrete wrapper.",
155
+ details: "Generics compile to C++ templates, instantiated for the types the module uses. JavaScript calls an export without types, so there is no instantiation to call.",
156
+ fix: "keep the generic function private and export concrete wrappers",
157
+ wrong: ex("export function last<T>(items: T[]): T | undefined {\n return items[items.length - 1];\n}\n"),
158
+ right: ex("function last<T>(items: T[]): T | undefined {\n return items[items.length - 1];\n}\nexport function lastName(names: string[]): string | undefined {\n return last(names);\n}\n")
159
+ },
160
+ LUCENT2008: {
161
+ title: "Interface not declared with implements",
162
+ summary: "A value used as an interface its class does not declare with `implements`.",
163
+ details: "An interface with methods compiles to an abstract C++ base class, and only classes that declare `implements` derive from it. A class that matches the interface only by shape, or an object literal, is not one of them.",
164
+ fix: "add `implements` to the class",
165
+ wrong: ex("interface Shape { area(): number }\nclass Square {\n constructor(readonly side: number) {}\n area(): number {\n return this.side ** 2;\n }\n}\nexport function area(): number {\n const s: Shape = new Square(2);\n return s.area();\n}\n"),
166
+ right: ex("interface Shape { area(): number }\nclass Square implements Shape {\n constructor(readonly side: number) {}\n area(): number {\n return this.side ** 2;\n }\n}\nexport function area(): number {\n const s: Shape = new Square(2);\n return s.area();\n}\n")
167
+ },
168
+ LUCENT2009: {
169
+ title: "Method signature differs from the interface's",
170
+ summary: "A class member whose native signature differs from the interface member it implements.",
171
+ details: "The implementing method overrides the interface's native method, so it needs the same parameter and result types. TypeScript accepts compatible variations (an optional parameter, a narrower result) that are different native signatures.",
172
+ fix: "declare the method with exactly the interface's parameter and result types",
173
+ wrong: ex("interface Store { get(key: string): string | undefined }\nclass Memory implements Store {\n get(key: string): string {\n return key;\n }\n}\nexport function read(): string | undefined {\n const s: Store = new Memory();\n return s.get(\"a\");\n}\n"),
174
+ right: ex("interface Store { get(key: string): string | undefined }\nclass Memory implements Store {\n get(key: string): string | undefined {\n return key;\n }\n}\nexport function read(): string | undefined {\n const s: Store = new Memory();\n return s.get(\"a\");\n}\n")
175
+ },
176
+ LUCENT3001: {
177
+ title: "Import from outside Lucent",
178
+ summary: "An import from something other than another `*.lucent.ts` file or a built-in `lucent:` module.",
179
+ details: "Everything a module runs is compiled to native code, so it can only use other Lucent modules and the built-in `lucent:` modules (`lucent:core`, `lucent:thread`, `lucent:platform`, the SDKs). An npm package or a plain `.ts` file has no native implementation.",
180
+ fix: "move the code into a *.lucent.ts module, or use a lucent: module",
181
+ wrong: {
182
+ "clock.ts": "export function now(): number {\n return Date.now();\n}\n",
183
+ "example.lucent.ts": "import { now } from \"./clock\";\nexport function stamp(): number {\n return now();\n}\n"
184
+ },
185
+ right: ex("import { now } from \"lucent:core\";\nexport function stamp(): number {\n return now();\n}\n")
186
+ },
187
+ LUCENT3002: {
188
+ title: "Statement at the top level",
189
+ summary: "A top-level statement that is not a declaration.",
190
+ details: "A module's top level holds declarations only: functions, classes, types and variables. Statements that run when the module loads have no native place to run, since native modules are created on first use.",
191
+ fix: "move the statement into a function, or into a variable's initializer",
192
+ wrong: ex("const cache = new Map<string, number>();\ncache.set(\"zero\", 0);\nexport function lookup(k: string): number | undefined {\n return cache.get(k);\n}\n"),
193
+ right: ex("const cache = new Map<string, number>([[\"zero\", 0]]);\nexport function lookup(k: string): number | undefined {\n return cache.get(k);\n}\n")
194
+ },
195
+ LUCENT3003: {
196
+ title: "Unsupported export form",
197
+ summary: "An export form Lucent does not support: export lists, re-exports, default exports.",
198
+ details: "Each export becomes a property of the module's native object, named by its declaration. Export lists, re-exports and default exports name exports apart from their declarations.",
199
+ fix: "put `export` on the declaration itself",
200
+ wrong: ex("function twice(n: number): number {\n return n * 2;\n}\nexport { twice };\n"),
201
+ right: ex("export function twice(n: number): number {\n return n * 2;\n}\n")
202
+ },
203
+ LUCENT3004: {
204
+ title: "Platform SDK import where it cannot be used",
205
+ summary: "A platform SDK import in a file whose platform cannot use it, an SDK module without bindings, or platform code used outside its platform.",
206
+ details: "`lucent:ios/*` modules exist on iOS and `lucent:android/*` on Android. A shared module uses them inside `if (PLATFORM === \"ios\")` (or the Android branch), and a `*.ios.lucent.ts` file only its own platform's.",
207
+ fix: "use the SDK inside a PLATFORM branch, or in the platform's own file",
208
+ wrong: ex("import { UIDevice } from \"lucent:ios/UIKit\";\nimport { main } from \"lucent:thread\";\nexport async function model(): Promise<string> {\n return main(() => UIDevice.current.model);\n}\n"),
209
+ right: ex("import { PLATFORM } from \"lucent:platform\";\nimport { UIDevice } from \"lucent:ios/UIKit\";\nimport { main } from \"lucent:thread\";\nexport async function model(): Promise<string> {\n if (PLATFORM === \"ios\") return main(() => UIDevice.current.model);\n return \"unknown\";\n}\n"),
210
+ sdk: "ios"
211
+ },
212
+ LUCENT3005: {
213
+ title: "Platform files that do not match their declaration",
214
+ summary: "Platform implementations that do not match their shared declaration file.",
215
+ details: "A module split into `name.ios.lucent.ts` and `name.android.lucent.ts` declares its exports in `name.lucent.ts`. Every platform file must export exactly the declared functions, with compatible types, so JavaScript sees one module.",
216
+ fix: "export the same functions, with the declared types, from every platform file",
217
+ wrong: {
218
+ "haptics.lucent.ts": "export declare function tap(): Promise<void>;\n",
219
+ "haptics.ios.lucent.ts": "export async function tap(strength: number): Promise<void> {}\n",
220
+ "haptics.android.lucent.ts": "export async function tap(): Promise<void> {}\n"
221
+ },
222
+ right: {
223
+ "haptics.lucent.ts": "export declare function tap(): Promise<void>;\n",
224
+ "haptics.ios.lucent.ts": "export async function tap(): Promise<void> {}\n",
225
+ "haptics.android.lucent.ts": "export async function tap(): Promise<void> {}\n"
226
+ },
227
+ sdk: "ios"
228
+ },
229
+ LUCENT3006: {
230
+ title: "Main-thread API off the main thread",
231
+ summary: "A main-thread-only platform API used outside `main(() => …)`.",
232
+ details: "Lucent code runs on its own thread. UIKit, and other APIs the SDK marks main-thread only, must be called on the main thread. `main(() => …)` from `lucent:thread` runs a function there, and resolves with its result.",
233
+ fix: "wrap the call in main(() => …) from lucent:thread",
234
+ wrong: ex("import { PLATFORM } from \"lucent:platform\";\nimport { UIDevice } from \"lucent:ios/UIKit\";\nexport async function model(): Promise<string> {\n if (PLATFORM === \"ios\") return UIDevice.current.model;\n return \"unknown\";\n}\n"),
235
+ right: ex("import { PLATFORM } from \"lucent:platform\";\nimport { UIDevice } from \"lucent:ios/UIKit\";\nimport { main } from \"lucent:thread\";\nexport async function model(): Promise<string> {\n if (PLATFORM === \"ios\") return main(() => UIDevice.current.model);\n return \"unknown\";\n}\n"),
236
+ sdk: "ios"
237
+ },
238
+ LUCENT3007: {
239
+ title: "Platform API newer than the oldest supported OS",
240
+ summary: "A platform API newer than the oldest supported OS version, used without an `available()` or `SDK_INT` check around it.",
241
+ details: "Apps run on older OS versions than the SDK they build with. An API introduced later crashes there, so Lucent requires a check that the running OS has it.",
242
+ fix: "check first: if (available(\"android\", 26)) … or Build_VERSION.SDK_INT >= 26",
243
+ wrong: ex("import { PLATFORM } from \"lucent:platform\";\nimport { VibrationEffect } from \"lucent:android/android.os\";\nexport async function effect(): Promise<string> {\n if (PLATFORM === \"android\") {\n VibrationEffect.createOneShot(10, 10);\n return \"made\";\n }\n return \"none\";\n}\n"),
244
+ right: ex("import { PLATFORM } from \"lucent:platform\";\nimport { available } from \"lucent:android\";\nimport { VibrationEffect } from \"lucent:android/android.os\";\nexport async function effect(): Promise<string> {\n if (PLATFORM === \"android\") {\n if (!available(\"android\", 26)) return \"too old\";\n VibrationEffect.createOneShot(10, 10);\n return \"made\";\n }\n return \"none\";\n}\n"),
245
+ sdk: "android"
246
+ },
247
+ LUCENT9001: {
248
+ title: "TypeScript error",
249
+ summary: "A TypeScript error. Lucent stops at type errors, because it compiles from the checker's types.",
250
+ details: "Lucent compiles only programs that type-check: every value's native type comes from the TypeScript checker. The message is TypeScript's own.",
251
+ fix: "fix the type error; your editor shows the same message",
252
+ wrong: ex("export function double(n: number): number {\n return n + \"\";\n}\n"),
253
+ right: ex("export function double(n: number): number {\n return n * 2;\n}\n")
254
+ }
255
+ };
256
+ function docsUrl(code) {
257
+ return `https://lucent-lang.dev/docs/reference/diagnostics/#${code.toLowerCase()}`;
258
+ }
259
+ //#endregion
260
+ export { Explanations as n, docsUrl as r, Codes as t };