@lucent-lang/lucent 0.0.4 → 0.1.1

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 (152) hide show
  1. package/README.md +97 -0
  2. package/app.plugin.js +46 -10
  3. package/dist/{bench-CR3E7e2e.js → bench-eEez4jhQ.js} +10 -6
  4. package/dist/{build-CAIrRSYA.js → build-CpUjeHFz.js} +1 -1
  5. package/dist/{build-check-QozuNJm5.js → build-check-BA1ZEp9s.js} +28 -13
  6. package/dist/{check-1SCmYlqA.js → check-BZx3FgI6.js} +1 -1
  7. package/dist/cli.js +62 -13
  8. package/dist/{codes-CIuwXt1S.js → codes-D-6LxUqD.js} +163 -7
  9. package/dist/compiler.js +4 -4
  10. package/dist/{dashboard-B-NzjjaN.js → dashboard-CC-HXhcd.js} +2 -2
  11. package/dist/{dev-BYWMP7oC.js → dev-DI5yL8zx.js} +62 -23
  12. package/dist/{diagnostic-BM9sXmwl.js → diagnostic-BvwLZQS1.js} +3 -1
  13. package/dist/{doctor-C0PrfWT6.js → doctor-CTAX3euc.js} +1 -1
  14. package/dist/{doctor-DdR4JnVc.js → doctor-CrgOAV5L.js} +1 -1
  15. package/dist/{explain--vV1oaRl.js → explain-Byit07F-.js} +1 -1
  16. package/dist/{packages-HyskKIsY.js → packages-CSmKeaAh.js} +2 -33
  17. package/dist/pipeline-BM_VM2X_.js +700 -0
  18. package/dist/project-BKNoTEEp.js +342 -0
  19. package/dist/sdk-coverage-iiv3JqMp.js +113 -0
  20. package/dist/sdk-diff-ByJ1Gw-F.js +109 -0
  21. package/dist/sdk-lock-BQn7IyRs.js +38 -0
  22. package/dist/{sdk-prefetch-mo04JDZV.js → sdk-prefetch-Bv2pNega.js} +2 -2
  23. package/dist/{sdk-search-Iv4K3-8a.js → sdk-search-CPGJm_Ne.js} +2 -2
  24. package/dist/{sdk-show-CkrdlqlP.js → sdk-show-BUkLqRnA.js} +5 -4
  25. package/dist/sdk-usage-0ZFMAYg1.js +95 -0
  26. package/dist/src-ChnmWLwn.js +40851 -0
  27. package/dist/trace-Bi4hkmPx.js +139 -0
  28. package/lib/core.cjs +368 -1
  29. package/lib/sdk/android.d.ts +54 -1
  30. package/lib/sdk/compose.d.ts +94 -0
  31. package/lib/sdk/compose.schemas.json.gz +0 -0
  32. package/lib/sdk/core.d.ts +201 -0
  33. package/lib/sdk/ios.d.ts +75 -2
  34. package/lib/sdk/ui.d.ts +129 -0
  35. package/metro/transformer.cjs +11 -2
  36. package/package.json +4 -3
  37. package/runtime/cpp/lucent/abort.cpp +59 -11
  38. package/runtime/cpp/lucent/abort.h +22 -6
  39. package/runtime/cpp/lucent/array.h +12 -2
  40. package/runtime/cpp/lucent/async.h +101 -21
  41. package/runtime/cpp/lucent/bigint.cpp +898 -0
  42. package/runtime/cpp/lucent/bigint.h +302 -0
  43. package/runtime/cpp/lucent/buffer.cpp +228 -0
  44. package/runtime/cpp/lucent/buffer.h +328 -0
  45. package/runtime/cpp/lucent/builtins.cpp +4 -1
  46. package/runtime/cpp/lucent/bytes.h +21 -2
  47. package/runtime/cpp/lucent/callback.cpp +29 -0
  48. package/runtime/cpp/lucent/callback.h +230 -0
  49. package/runtime/cpp/lucent/compute.cpp +370 -0
  50. package/runtime/cpp/lucent/compute.h +455 -0
  51. package/runtime/cpp/lucent/conversions.h +111 -0
  52. package/runtime/cpp/lucent/core.h +16 -5
  53. package/runtime/cpp/lucent/equality.h +107 -28
  54. package/runtime/cpp/lucent/execution.cpp +416 -0
  55. package/runtime/cpp/lucent/execution.h +270 -0
  56. package/runtime/cpp/lucent/extension.cpp +97 -0
  57. package/runtime/cpp/lucent/extension.h +210 -0
  58. package/runtime/cpp/lucent/helpers.h +12 -5
  59. package/runtime/cpp/lucent/items.h +52 -0
  60. package/runtime/cpp/lucent/jserror.cpp +9 -0
  61. package/runtime/cpp/lucent/jserror.h +11 -0
  62. package/runtime/cpp/lucent/jsi/convert.cpp +138 -0
  63. package/runtime/cpp/lucent/jsi/convert.h +128 -59
  64. package/runtime/cpp/lucent/jsi/host.cpp +213 -35
  65. package/runtime/cpp/lucent/jsi/host.h +116 -16
  66. package/runtime/cpp/lucent/json.h +19 -1
  67. package/runtime/cpp/lucent/lifecycle.cpp +260 -0
  68. package/runtime/cpp/lucent/lifecycle.h +124 -0
  69. package/runtime/cpp/lucent/lucent.h +7 -0
  70. package/runtime/cpp/lucent/map.h +41 -7
  71. package/runtime/cpp/lucent/native.cpp +35 -47
  72. package/runtime/cpp/lucent/native.h +116 -26
  73. package/runtime/cpp/lucent/number.cpp +38 -38
  74. package/runtime/cpp/lucent/number.h +33 -0
  75. package/runtime/cpp/lucent/operation.h +65 -0
  76. package/runtime/cpp/lucent/ops.h +14 -6
  77. package/runtime/cpp/lucent/platform/android.cpp +223 -10
  78. package/runtime/cpp/lucent/platform/android.h +227 -4
  79. package/runtime/cpp/lucent/platform/android_activity.cpp +258 -0
  80. package/runtime/cpp/lucent/platform/android_requests.h +140 -0
  81. package/runtime/cpp/lucent/platform/compose.h +256 -0
  82. package/runtime/cpp/lucent/platform/ios.h +325 -25
  83. package/runtime/cpp/lucent/platform/ios.mm +1 -14
  84. package/runtime/cpp/lucent/platform/ios_ui.h +192 -0
  85. package/runtime/cpp/lucent/platform/ios_ui.mm +454 -0
  86. package/runtime/cpp/lucent/platform/swiftui.h +190 -0
  87. package/runtime/cpp/lucent/presentation.cpp +11 -0
  88. package/runtime/cpp/lucent/presentation.h +109 -0
  89. package/runtime/cpp/lucent/reactive.cpp +406 -0
  90. package/runtime/cpp/lucent/reactive.h +566 -0
  91. package/runtime/cpp/lucent/report.cpp +40 -0
  92. package/runtime/cpp/lucent/report.h +16 -0
  93. package/runtime/cpp/lucent/resource.cpp +83 -0
  94. package/runtime/cpp/lucent/resource.h +75 -0
  95. package/runtime/cpp/lucent/scheduler.cpp +38 -124
  96. package/runtime/cpp/lucent/scheduler.h +102 -83
  97. package/runtime/cpp/lucent/scope.cpp +308 -0
  98. package/runtime/cpp/lucent/scope.h +452 -0
  99. package/runtime/cpp/lucent/sizing.h +263 -0
  100. package/runtime/cpp/lucent/slots.h +231 -0
  101. package/runtime/cpp/lucent/trace.cpp +539 -0
  102. package/runtime/cpp/lucent/trace.h +251 -0
  103. package/runtime/cpp/lucent/transport.cpp +9 -0
  104. package/runtime/cpp/lucent/transport.h +341 -0
  105. package/runtime/cpp/lucent/view.cpp +123 -0
  106. package/runtime/cpp/lucent/view.h +157 -0
  107. package/runtime/cpp/rn/LucentComponentView.h +121 -0
  108. package/runtime/cpp/rn/LucentComponentView.mm +479 -0
  109. package/runtime/cpp/rn/LucentModule.cpp +37 -7
  110. package/runtime/cpp/rn/LucentModule.h +3 -0
  111. package/runtime/cpp/rn/LucentViewChildren.h +80 -0
  112. package/runtime/cpp/rn/LucentViewChildren.mm +211 -0
  113. package/runtime/cpp/rn/LucentViewRegistry.h +62 -0
  114. package/runtime/cpp/rn/LucentViewRequests.cpp +91 -0
  115. package/runtime/cpp/rn/LucentViewRequests.h +104 -0
  116. package/runtime/cpp/rn/LucentViewSizing.h +345 -0
  117. package/runtime/cpp/rn/LucentViewSlots.h +242 -0
  118. package/runtime/cpp/rn/LucentViewValues.h +125 -0
  119. package/runtime/cpp/rn/LucentViews.h +440 -0
  120. package/runtime/cpp/rn/LucentViewsAndroid.cpp +439 -0
  121. package/runtime/cpp/rn/LucentViewsAndroid.h +138 -0
  122. package/runtime/cpp/third_party/dragonbox/LICENSE-Boost +23 -0
  123. package/runtime/cpp/third_party/dragonbox/README.md +16 -0
  124. package/runtime/cpp/third_party/dragonbox/dragonbox.h +4440 -0
  125. package/runtime/js/index.d.ts +11 -1
  126. package/runtime/js/index.js +84 -8
  127. package/runtime/js/views.d.ts +38 -0
  128. package/runtime/js/views.js +226 -0
  129. package/runtime/native/android/CMakeLists.txt +4 -1
  130. package/runtime/native/android/src/compose/java/dev/lucent/compose/CompositionRules.kt +44 -0
  131. package/runtime/native/android/src/compose/java/dev/lucent/compose/LucentComposition.kt +161 -0
  132. package/runtime/native/android/src/main/java/dev/lucent/LucentActivities.java +292 -0
  133. package/runtime/native/android/src/main/java/dev/lucent/LucentChildren.java +174 -0
  134. package/runtime/native/android/src/main/java/dev/lucent/LucentHostView.java +232 -0
  135. package/runtime/native/android/src/main/java/dev/lucent/LucentInitializer.java +46 -0
  136. package/runtime/native/android/src/main/java/dev/lucent/LucentPackage.java +4 -3
  137. package/runtime/native/android/src/main/java/dev/lucent/LucentRequestActivity.java +92 -0
  138. package/runtime/native/android/src/main/java/dev/lucent/LucentSlotView.java +102 -0
  139. package/runtime/native/android/src/main/java/dev/lucent/LucentViewManager.java +149 -0
  140. package/runtime/native/android/src/main/java/dev/lucent/LucentViewManagers.java +16 -0
  141. package/runtime/native/android/src/main/java/dev/lucent/LucentViews.java +44 -0
  142. package/runtime/test/jsi/harness.cpp +9 -0
  143. package/schemas/build.schema.json +96 -1
  144. package/schemas/check.schema.json +56 -1
  145. package/schemas/lucent.schema.json +495 -9
  146. package/schemas/sdk-diff.schema.json +70 -0
  147. package/schemas/sdk-lock.schema.json +67 -0
  148. package/ts-plugin/index.js +85 -4
  149. package/dist/pipeline-CH7-2cxu.js +0 -232
  150. package/dist/project-D8tEet0k.js +0 -150
  151. package/dist/sdk-coverage-BoW_3Efd.js +0 -64
  152. package/dist/src-BD7f1_aZ.js +0 -11493
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # @lucent-lang/lucent
2
+
3
+ > [!WARNING]
4
+ > **Experimental: not for production.** APIs and the language subset change
5
+ > without a migration path.
6
+
7
+ Write React Native native modules in TypeScript. Lucent compiles a checked
8
+ subset to C++ and calls it through JSI: no Swift or Kotlin to write, and no
9
+ JavaScript engine in native code.
10
+
11
+ ```ts
12
+ // src/geo.lucent.ts
13
+ export type Point = { x: number; y: number };
14
+
15
+ export function squaredDistance(a: Point, b: Point): number {
16
+ const dx = a.x - b.x;
17
+ const dy = a.y - b.y;
18
+ return dx * dx + dy * dy;
19
+ }
20
+ ```
21
+
22
+ ```ts
23
+ import { squaredDistance } from "./src/geo.lucent";
24
+ squaredDistance({ x: 0, y: 0 }, { x: 3, y: 4 }); // 25, computed in C++
25
+ ```
26
+
27
+ A module also calls the iOS and Android SDKs directly, typed from your Xcode
28
+ and Android SDK. One module holds both platforms:
29
+
30
+ ```ts
31
+ // src/clipboard.lucent.ts
32
+ import { PLATFORM } from "lucent:platform";
33
+ import { UIPasteboard } from "lucent:ios/UIKit";
34
+ import { ClipboardManager, ClipDescription } from "lucent:android/android.content";
35
+ import { appContext } from "lucent:android";
36
+ import { main } from "lucent:thread";
37
+
38
+ export async function hasStringAsync(): Promise<boolean> {
39
+ if (PLATFORM === "ios") {
40
+ return UIPasteboard.general.hasStrings;
41
+ } else {
42
+ return main(
43
+ () =>
44
+ appContext()
45
+ .getSystemService(ClipboardManager)
46
+ ?.getPrimaryClipDescription()
47
+ ?.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) ?? false,
48
+ );
49
+ }
50
+ }
51
+ ```
52
+
53
+ ## Install
54
+
55
+ You need React Native 0.88 or later, or Expo SDK 58 in a development build,
56
+ and Node 22.12 or later.
57
+
58
+ ```sh
59
+ npm i -D @lucent-lang/lucent
60
+ npx lucent init
61
+ ```
62
+
63
+ `lucent init` sets the app up (the Metro config, the Expo plugin or the
64
+ Gradle task, `tsconfig.json`, `.gitignore`, a first module), showing each
65
+ change as a diff and asking before applying it. Lucent adds native code, so
66
+ an Expo app runs as a development build (`npx expo run:ios`,
67
+ `npx expo run:android`), not in Expo Go.
68
+
69
+ `npx lucent doctor` checks your machine: Xcode, the Android SDK and NDK, the
70
+ JDK, and the app's setup.
71
+
72
+ ## What's in the package
73
+
74
+ - The `lucent` CLI: `init`, `build`, `check`, `dev`, `doctor`, `sdk` and
75
+ more (`npx lucent --help`).
76
+ - The compiler, which Metro runs on `*.lucent.ts` files through
77
+ `@lucent-lang/lucent/metro`.
78
+ - The Expo config plugin (`@lucent-lang/lucent` in `app.json`'s plugins).
79
+ - An editor plugin that shows Lucent's diagnostics in TypeScript-aware
80
+ editors (`@lucent-lang/lucent/ts-plugin`).
81
+ - `@lucent-lang/lucent/core`: the JavaScript version of `lucent:core`, for
82
+ tests that run Lucent modules as plain TypeScript.
83
+
84
+ ## Docs
85
+
86
+ [What is Lucent](https://lucent-lang.dev/docs/) ·
87
+ [Install](https://lucent-lang.dev/docs/install/) ·
88
+ [Tutorial](https://lucent-lang.dev/docs/tutorial/1-shared-logic/) ·
89
+ [How it works](https://lucent-lang.dev/docs/how-it-works/) ·
90
+ [Guides](https://lucent-lang.dev/docs/guides/call-an-ios-api/) ·
91
+ [Reference](https://lucent-lang.dev/docs/reference/language/) ·
92
+ [Examples](https://lucent-lang.dev/docs/examples/) ·
93
+ [Changelog](https://github.com/Fausto95/lucent/blob/main/packages/lucent/CHANGELOG.md)
94
+
95
+ Issues and source: [github.com/Fausto95/lucent](https://github.com/Fausto95/lucent).
96
+
97
+ MIT
package/app.plugin.js CHANGED
@@ -21,6 +21,11 @@ function buildOnce(projectRoot) {
21
21
  });
22
22
  if (r.status !== 0)
23
23
  throw new Error("lucent build failed; fix the errors above and run prebuild again");
24
+ linkNativePackage(projectRoot);
25
+ }
26
+
27
+ /** Makes the app's react-native.config.js link the native package lucent build writes. */
28
+ function linkNativePackage(projectRoot) {
24
29
  const rnConfig = path.join(projectRoot, "react-native.config.js");
25
30
  const entry = `"lucent": { root: require("path").join(__dirname, ".lucent", "native") }`;
26
31
  const text = fs.existsSync(rnConfig) ? fs.readFileSync(rnConfig, "utf8") : undefined;
@@ -29,7 +34,7 @@ function buildOnce(projectRoot) {
29
34
  } else if (text.includes('"lucent-native"')) {
30
35
  // Earlier versions named the dependency lucent-native.
31
36
  fs.writeFileSync(rnConfig, text.replace('"lucent-native"', '"lucent"'));
32
- } else if (!/["']lucent["']\s*:/.test(text)) {
37
+ } else if (!/(^|[{,\s])(["']?)lucent\2\s*:/m.test(text)) {
33
38
  throw new Error(`Add ${entry} to the "dependencies" of react-native.config.js`);
34
39
  }
35
40
  }
@@ -52,15 +57,39 @@ function applyGradleTask(text) {
52
57
  return lines.join("\n");
53
58
  }
54
59
 
55
- /** Info.plist entries Lucent packages need (their lucent.json), as the last build recorded them. */
56
- function packagesInfoPlist(projectRoot) {
57
- const manifest = path.join(projectRoot, ".lucent", "native", "manifest.json");
58
- if (!fs.existsSync(manifest)) return {};
59
- return JSON.parse(fs.readFileSync(manifest, "utf8")).infoPlist || {};
60
+ /** What Lucent packages need (their lucent.json), as the last build resolved it. */
61
+ function resolvedNative(projectRoot) {
62
+ const file = path.join(projectRoot, ".lucent", "native", "resolved.json");
63
+ if (!fs.existsSync(file)) return { ios: {} };
64
+ return JSON.parse(fs.readFileSync(file, "utf8"));
65
+ }
66
+
67
+ /**
68
+ * The app's plist entries (Info.plist, entitlements) with the packages'
69
+ * added: a key the app sets keeps the app's value, except arrays, which
70
+ * gain the values they lack.
71
+ */
72
+ function withPackageEntries(app, packages) {
73
+ const out = { ...app };
74
+
75
+ for (const [key, { value }] of Object.entries(packages)) {
76
+ const own = out[key];
77
+
78
+ if (own === undefined) out[key] = value;
79
+ else if (Array.isArray(own) && Array.isArray(value))
80
+ out[key] = [...own, ...value.filter((v) => !own.includes(v))];
81
+ }
82
+
83
+ return out;
60
84
  }
61
85
 
62
86
  function withLucent(config) {
63
- const { withAppBuildGradle, withDangerousMod, withInfoPlist } = require("expo/config-plugins");
87
+ const {
88
+ withAppBuildGradle,
89
+ withDangerousMod,
90
+ withEntitlementsPlist,
91
+ withInfoPlist,
92
+ } = require("expo/config-plugins");
64
93
  // Gradle builds run lucent build first, like `lucent init` sets up in bare apps.
65
94
  config = withAppBuildGradle(config, (c) => {
66
95
  if (c.modResults.language === "groovy")
@@ -70,9 +99,14 @@ function withLucent(config) {
70
99
  // Keys the app sets itself win.
71
100
  config = withInfoPlist(config, (c) => {
72
101
  buildOnce(c.modRequest.projectRoot);
73
- for (const [key, { value }] of Object.entries(packagesInfoPlist(c.modRequest.projectRoot))) {
74
- if (c.modResults[key] === undefined) c.modResults[key] = value;
75
- }
102
+ const { ios } = resolvedNative(c.modRequest.projectRoot);
103
+ c.modResults = withPackageEntries(c.modResults, ios.infoPlist || {});
104
+ return c;
105
+ });
106
+ config = withEntitlementsPlist(config, (c) => {
107
+ buildOnce(c.modRequest.projectRoot);
108
+ const { ios } = resolvedNative(c.modRequest.projectRoot);
109
+ c.modResults = withPackageEntries(c.modResults, ios.entitlements || {});
76
110
  return c;
77
111
  });
78
112
  for (const platform of ["ios", "android"]) {
@@ -90,3 +124,5 @@ function withLucent(config) {
90
124
  module.exports = withLucent;
91
125
  module.exports.GRADLE_LINE = GRADLE_LINE;
92
126
  module.exports.applyGradleTask = applyGradleTask;
127
+ module.exports.linkNativePackage = linkNativePackage;
128
+ module.exports.withPackageEntries = withPackageEntries;
@@ -1,12 +1,12 @@
1
- import { d as coreJsPath, g as projectFiles, m as moduleNameOf, n as compile, s as runtimeDir } from "./src-BD7f1_aZ.js";
1
+ import { E as identityScript, N as projectFiles, O as coreJsPath, f as runtimeDir, j as moduleNameOf, n as compile } from "./src-ChnmWLwn.js";
2
2
  import { i as table } from "./format-D9fnIMEx.js";
3
- import { t as renderDiagnostic } from "./diagnostic-BM9sXmwl.js";
3
+ import { t as renderDiagnostic } from "./diagnostic-BvwLZQS1.js";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import os from "node:os";
7
7
  import ts from "typescript";
8
- import { spawn, spawnSync } from "node:child_process";
9
8
  import { createHash } from "node:crypto";
9
+ import { spawn, spawnSync } from "node:child_process";
10
10
  //#region ../runtime/test/sources.ts
11
11
  function runtimeSources(cppDir) {
12
12
  const list = (dir, ext) => fs.readdirSync(path.join(cppDir, dir)).filter((f) => f.endsWith(ext)).map((f) => path.join(cppDir, dir, f));
@@ -61,7 +61,7 @@ async function run({ root, out }) {
61
61
  if (!out.json) out.print(t.dim("building the native host (the first run compiles the runtime)…"));
62
62
  const exe = await buildHost(work, generated, hermes);
63
63
  const script = path.join(work, "bench.js");
64
- fs.writeFileSync(script, benchScript(root, files, benches, result.proxies));
64
+ fs.writeFileSync(script, benchScript(root, files, benches, result.proxies, result.identity));
65
65
  const r = spawnSync(exe, [script], {
66
66
  encoding: "utf8",
67
67
  timeout: 6e5,
@@ -213,7 +213,7 @@ async function buildHost(work, generated, hermes) {
213
213
  if (r.status !== 0) throw new Error(`linking the benchmark host failed:\n${r.stderr}`);
214
214
  return exe;
215
215
  }
216
- function benchScript(root, files, benches, proxies) {
216
+ function benchScript(root, files, benches, proxies, identity) {
217
217
  const defs = {};
218
218
  const jsDeps = {};
219
219
  const nativeDeps = {};
@@ -225,6 +225,7 @@ function benchScript(root, files, benches, proxies) {
225
225
  const loader = fs.readFileSync(path.join(runtimeDir(), "js/index.js"), "utf8");
226
226
  defs.core = fs.readFileSync(coreJsPath(), "utf8");
227
227
  defs.loader = loader;
228
+ defs.identity = identityScript(identity);
228
229
  defs["react-native"] = "module.exports = { TurboModuleRegistry: { get: function () { return undefined; } } };";
229
230
  const resolve = (from, spec) => {
230
231
  if (spec === "lucent:core") return "core";
@@ -250,13 +251,16 @@ function benchScript(root, files, benches, proxies) {
250
251
  }
251
252
  }
252
253
  for (const [name, proxy] of proxies) {
254
+ const up = "../".repeat(name.split("/").length - 1) || "./";
253
255
  defs[`proxy:${name}`] = proxy;
254
256
  nativeDeps[`proxy:${name}`] = {
255
- [`${"../".repeat(name.split("/").length - 1) || "./"}_lucent/runtime.js`]: "loader",
257
+ [`${up}_lucent/runtime.js`]: "loader",
258
+ [`${up}_lucent/identity.js`]: "identity",
256
259
  "react-native": "react-native"
257
260
  };
258
261
  }
259
262
  nativeDeps.loader = {};
263
+ nativeDeps.identity = {};
260
264
  return `var defs = {
261
265
  ${Object.entries(defs).map(([id, code]) => `${JSON.stringify(id)}: function (module, exports, require) {\n${code}\n}`).join(",\n")}
262
266
  };
@@ -1,4 +1,4 @@
1
- import { t as buildOrCheck } from "./build-check-QozuNJm5.js";
1
+ import { t as buildOrCheck } from "./build-check-BA1ZEp9s.js";
2
2
  //#region src/cli/commands/build.ts
3
3
  function run(invocation) {
4
4
  return buildOrCheck("build", invocation);
@@ -1,13 +1,14 @@
1
1
  import { n as version } from "./version-bqpIO5sP.js";
2
2
  import { i as table, n as duration } from "./format-D9fnIMEx.js";
3
- import { t as renderDiagnostic } from "./diagnostic-BM9sXmwl.js";
4
- import { n as nextText, r as plural, t as buildProject } from "./pipeline-CH7-2cxu.js";
3
+ import { t as renderDiagnostic } from "./diagnostic-BvwLZQS1.js";
4
+ import { a as filesText, i as ACTION_TEXT, n as nextText, r as plural, t as buildProject } from "./pipeline-BM_VM2X_.js";
5
5
  import { t as plainSteps } from "./steps--_h-FFS7.js";
6
6
  import fs from "node:fs";
7
7
  import path from "node:path";
8
8
  //#region src/cli/commands/build-check.ts
9
9
  async function buildOrCheck(command, { root, flags, out }) {
10
10
  const theme = out.theme;
11
+ const sources = /* @__PURE__ */ new Map();
11
12
  const notices = [];
12
13
  const notify = (n) => {
13
14
  notices.push(n);
@@ -22,7 +23,8 @@ async function buildOrCheck(command, { root, flags, out }) {
22
23
  force: !!flags.force,
23
24
  platforms: typeof flags.platforms === "string" && flags.platforms ? flags.platforms.split(",") : void 0,
24
25
  out: typeof flags.out === "string" ? flags.out : void 0,
25
- prefetch: true
26
+ prefetch: true,
27
+ frozen: !!flags.frozen
26
28
  }, steps, notify);
27
29
  } finally {
28
30
  await steps.close();
@@ -36,6 +38,7 @@ async function buildOrCheck(command, { root, flags, out }) {
36
38
  ok: result.ok,
37
39
  modules: result.modules.map((m) => m.name),
38
40
  diagnostics: result.diagnostics,
41
+ warnings: result.warnings,
39
42
  errors: result.diagnostics.length,
40
43
  ms: result.ms
41
44
  });
@@ -46,8 +49,10 @@ async function buildOrCheck(command, { root, flags, out }) {
46
49
  modules: result.modules,
47
50
  steps: steps.results,
48
51
  diagnostics: result.diagnostics,
52
+ warnings: result.warnings,
49
53
  notices,
50
54
  next: result.next,
55
+ actions: result.actions,
51
56
  ms: result.ms
52
57
  });
53
58
  return result.ok ? 0 : 1;
@@ -57,9 +62,13 @@ async function buildOrCheck(command, { root, flags, out }) {
57
62
  return 1;
58
63
  }
59
64
  if (!result.ok) {
60
- problems(result.diagnostics, result.modules.length, result.ms, command === "build");
65
+ problems([...result.diagnostics, ...result.warnings], result.modules.length, result.ms, command === "build");
61
66
  return 1;
62
67
  }
68
+ if (result.warnings.length) {
69
+ out.error("");
70
+ for (const d of result.warnings) out.error(`${renderDiagnostic(d, d.file ? source(d.file) : void 0, theme)}\n`);
71
+ }
63
72
  if (command === "check") {
64
73
  out.print(`${theme.success(theme.symbols.ok)} ${plural(result.modules.length, "module")}, no problems ${theme.dim(result.upToDate ? `${duration(result.ms)} (unchanged since the last check)` : duration(result.ms))}`);
65
74
  return 0;
@@ -72,19 +81,25 @@ async function buildOrCheck(command, { root, flags, out }) {
72
81
  m.platforms.join(" ")
73
82
  ]))) out.print(line);
74
83
  out.print(`${theme.dim("next")} ${nextText(result.next)}`);
84
+ for (const line of table(result.actions.map((a, i) => [
85
+ i ? "" : theme.dim("actions"),
86
+ ACTION_TEXT[a.kind],
87
+ a.targets.join(", "),
88
+ filesText(a.files)
89
+ ]))) out.print(line);
75
90
  return 0;
91
+ function source(file) {
92
+ if (!sources.has(file)) {
93
+ const abs = path.resolve(root, file);
94
+ sources.set(file, fs.existsSync(abs) ? fs.readFileSync(abs, "utf8") : void 0);
95
+ }
96
+ return sources.get(file);
97
+ }
76
98
  function problems(diagnostics, modules, ms, build) {
77
- const sources = /* @__PURE__ */ new Map();
78
- const source = (file) => {
79
- if (!sources.has(file)) {
80
- const abs = path.resolve(root, file);
81
- sources.set(file, fs.existsSync(abs) ? fs.readFileSync(abs, "utf8") : void 0);
82
- }
83
- return sources.get(file);
84
- };
85
99
  out.error("");
86
100
  for (const d of diagnostics) out.error(`${renderDiagnostic(d, d.file ? source(d.file) : void 0, theme)}\n`);
87
- const summary = `${plural(diagnostics.length, "error")} ${theme.dim("·")} ${plural(modules, "module")} ${theme.dim("·")} ${duration(ms)}`;
101
+ const errors = diagnostics.filter((d) => d.severity !== "warning").length;
102
+ const summary = `${plural(errors, "error")} ${theme.dim("·")} ${plural(modules, "module")} ${theme.dim("·")} ${duration(ms)}`;
88
103
  out.error(` ${theme.error(summary)}${build ? theme.dim(" nothing was written") : ""}`);
89
104
  }
90
105
  }
@@ -1,4 +1,4 @@
1
- import { t as buildOrCheck } from "./build-check-QozuNJm5.js";
1
+ import { t as buildOrCheck } from "./build-check-BA1ZEp9s.js";
2
2
  //#region src/cli/commands/check.ts
3
3
  function run(invocation) {
4
4
  return buildOrCheck("check", invocation);
package/dist/cli.js CHANGED
@@ -109,15 +109,22 @@ const commands = [
109
109
  name: "out",
110
110
  value: "dir",
111
111
  description: "Where to write the native package (default: .lucent/native)"
112
+ },
113
+ {
114
+ name: "frozen",
115
+ description: "Fail unless the SDKs and SDK symbols are the ones lucent-sdk.lock.json records, with every target it lists (CI, releases)"
112
116
  }
113
117
  ],
114
- load: () => import("./build-CAIrRSYA.js")
118
+ load: () => import("./build-CpUjeHFz.js")
115
119
  },
116
120
  {
117
121
  name: "check",
118
122
  summary: "Type-check and validate every module without writing anything",
119
- flags: [],
120
- load: () => import("./check-1SCmYlqA.js")
123
+ flags: [{
124
+ name: "frozen",
125
+ description: "Fail unless the SDKs and SDK symbols are the ones lucent-sdk.lock.json records, with every target it lists (CI, releases)"
126
+ }],
127
+ load: () => import("./check-BZx3FgI6.js")
121
128
  },
122
129
  {
123
130
  name: "dev",
@@ -126,13 +133,13 @@ const commands = [
126
133
  name: "compact",
127
134
  description: "One line per build instead of the dashboard (Metro runs it so)"
128
135
  }],
129
- load: () => import("./dev-BYWMP7oC.js")
136
+ load: () => import("./dev-DI5yL8zx.js")
130
137
  },
131
138
  {
132
139
  name: "doctor",
133
140
  summary: "Check the machine and the app: Node, React Native, Xcode, CocoaPods, the Android SDK, the JDK, the Metro config, versions",
134
141
  flags: [],
135
- load: () => import("./doctor-DdR4JnVc.js")
142
+ load: () => import("./doctor-CrgOAV5L.js")
136
143
  },
137
144
  {
138
145
  name: "init",
@@ -166,13 +173,27 @@ const commands = [
166
173
  name: "explain",
167
174
  summary: "What a LUCENT diagnostic code means, and how to fix it (every code without one)",
168
175
  flags: [],
169
- load: () => import("./explain--vV1oaRl.js")
176
+ load: () => import("./explain-Byit07F-.js")
170
177
  },
171
178
  {
172
179
  name: "bench",
173
180
  summary: "Time the cases of your *.bench.ts files natively and as JavaScript, and show the speedup (needs a desktop Hermes)",
174
181
  flags: [],
175
- load: () => import("./bench-CR3E7e2e.js")
182
+ load: () => import("./bench-eEez4jhQ.js")
183
+ },
184
+ {
185
+ name: "trace",
186
+ summary: "Write the last build's steps and the runtime traces given as one Chrome trace (.lucent/trace.json), and how long each cause took",
187
+ flags: [{
188
+ name: "runtime",
189
+ value: "files",
190
+ description: "Runtime traces to include, comma-separated (written with LUCENT_TRACE=<file>.json)"
191
+ }, {
192
+ name: "out",
193
+ value: "file",
194
+ description: "Where to write it (default: .lucent/trace.json)"
195
+ }],
196
+ load: () => import("./trace-Bi4hkmPx.js")
176
197
  },
177
198
  {
178
199
  name: "clean",
@@ -187,13 +208,13 @@ const commands = [
187
208
  name: "sdk search",
188
209
  summary: "Find SDK classes and members by name, with the import to copy (your imports and the SDK cache)",
189
210
  flags: [],
190
- load: () => import("./sdk-search-Iv4K3-8a.js")
211
+ load: () => import("./sdk-search-CPGJm_Ne.js")
191
212
  },
192
213
  {
193
214
  name: "sdk show",
194
215
  summary: "Print the declaration Lucent code sees for an SDK type or member: android.os.Vibrator, UIKit.UIDevice.current",
195
216
  flags: [],
196
- load: () => import("./sdk-show-CkrdlqlP.js")
217
+ load: () => import("./sdk-show-BUkLqRnA.js")
197
218
  },
198
219
  {
199
220
  name: "sdk prefetch",
@@ -216,11 +237,30 @@ const commands = [
216
237
  description: "Every module of every installed SDK"
217
238
  }
218
239
  ],
219
- load: () => import("./sdk-prefetch-mo04JDZV.js")
240
+ load: () => import("./sdk-prefetch-Bv2pNega.js")
241
+ },
242
+ {
243
+ name: "sdk lock",
244
+ summary: "Record the SDKs and SDK symbols the project uses in lucent-sdk.lock.json, for --frozen builds and sdk diff",
245
+ flags: [{
246
+ name: "platforms",
247
+ value: "list",
248
+ description: "Targets to record: ios, android (default: every platform the project has code for, each needing its SDK)"
249
+ }],
250
+ load: () => import("./sdk-lock-BQn7IyRs.js")
251
+ },
252
+ {
253
+ name: "sdk diff",
254
+ summary: "What the installed SDKs change for the SDK symbols lucent-sdk.lock.json records: removed and changed members, before rebuilding",
255
+ flags: [{
256
+ name: "all",
257
+ description: "Also the other members of the modules the project uses (the locked schemas must be in this machine's SDK cache)"
258
+ }],
259
+ load: () => import("./sdk-diff-ByJ1Gw-F.js")
220
260
  },
221
261
  {
222
262
  name: "sdk coverage",
223
- summary: "Per SDK module, the members Lucent code can call: idiomatic, raw, unrepresentable",
263
+ summary: "Per SDK module, how far members get: discovered, representable, generated by the last build, exercised",
224
264
  flags: [
225
265
  {
226
266
  name: "ios",
@@ -236,9 +276,18 @@ const commands = [
236
276
  name: "check",
237
277
  value: "baseline",
238
278
  description: "Fail when the unrepresentable share grows past a baseline JSON"
279
+ },
280
+ {
281
+ name: "exercised",
282
+ value: "file",
283
+ description: "A JSON array of the symbol keys tests or probes ran (see --members)"
284
+ },
285
+ {
286
+ name: "members",
287
+ description: "List every member with its stage, key and reason"
239
288
  }
240
289
  ],
241
- load: () => import("./sdk-coverage-BoW_3Efd.js")
290
+ load: () => import("./sdk-coverage-iiv3JqMp.js")
242
291
  }
243
292
  ];
244
293
  //#endregion
@@ -401,6 +450,6 @@ function usesLucent(root) {
401
450
  }
402
451
  installCrashHandler(version());
403
452
  const status = await main(process.argv.slice(2));
404
- if (status >= 0) process.exit(status);
453
+ if (status >= 0) process.stdout.write("", () => process.exit(status));
405
454
  //#endregion
406
455
  export {};