@lucent-lang/lucent 0.0.4 → 0.1.0

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-B555m0wU.js} +10 -6
  4. package/dist/{build-CAIrRSYA.js → build-UZ5Zm5m6.js} +1 -1
  5. package/dist/{build-check-QozuNJm5.js → build-check-Dmf8_yiw.js} +28 -13
  6. package/dist/{check-1SCmYlqA.js → check-D-H9WLG4.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-C8iF5-6T.js} +2 -2
  11. package/dist/{dev-BYWMP7oC.js → dev-B3lSx5CF.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-BBY0df_2.js +700 -0
  18. package/dist/project-BLhWwnns.js +342 -0
  19. package/dist/sdk-coverage-DFGiDOzR.js +113 -0
  20. package/dist/sdk-diff-DpPYWzrl.js +109 -0
  21. package/dist/sdk-lock-QOxEFD1o.js +38 -0
  22. package/dist/{sdk-prefetch-mo04JDZV.js → sdk-prefetch-DX6ztlPN.js} +2 -2
  23. package/dist/{sdk-search-Iv4K3-8a.js → sdk-search-BShBL1LL.js} +2 -2
  24. package/dist/{sdk-show-CkrdlqlP.js → sdk-show-B3bI-0M7.js} +5 -4
  25. package/dist/sdk-usage-ljX5bTuZ.js +95 -0
  26. package/dist/src-DlICbK91.js +39682 -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 +2 -1
  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 +77 -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
@@ -0,0 +1,67 @@
1
+ {
2
+ "$id": "https://lucent-lang.dev/schemas/sdk-lock.schema.json",
3
+ "title": "lucent-sdk.lock.json, and .lucent/sdk-usage.json",
4
+ "description": "The SDKs a project's modules were read from and the SDK symbols its code uses. No machine paths.",
5
+ "type": "object",
6
+ "required": ["format", "targets", "modules", "symbols"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "format": { "const": 1 },
10
+ "targets": {
11
+ "type": "array",
12
+ "description": "The targets platform code was compiled for: a --frozen build needs each one's SDK",
13
+ "items": { "enum": ["ios", "android"] }
14
+ },
15
+ "modules": {
16
+ "type": "object",
17
+ "description": "<platform>/<module> → how the build read it",
18
+ "additionalProperties": {
19
+ "type": "object",
20
+ "required": ["artifacts"],
21
+ "additionalProperties": false,
22
+ "properties": {
23
+ "artifacts": {
24
+ "type": "array",
25
+ "description": "The artifacts its schema was read from: <id>#<content hash>",
26
+ "items": { "type": "string", "pattern": "^[^#]+#\\w+$" }
27
+ },
28
+ "schema": {
29
+ "type": "string",
30
+ "description": "Where the SDK cache keeps that schema: <scope>/<entry>"
31
+ }
32
+ }
33
+ }
34
+ },
35
+ "symbols": {
36
+ "type": "array",
37
+ "items": {
38
+ "type": "object",
39
+ "required": ["platform", "module", "kind", "name", "signature"],
40
+ "additionalProperties": false,
41
+ "properties": {
42
+ "platform": { "enum": ["ios", "android"] },
43
+ "module": { "type": "string" },
44
+ "owner": { "type": "string", "description": "The declaring type's Lucent name" },
45
+ "kind": { "enum": ["type", "constructor", "method", "property", "function", "constant"] },
46
+ "name": {
47
+ "type": "string",
48
+ "description": "The Lucent name; constructor for constructors"
49
+ },
50
+ "static": { "const": true },
51
+ "symbol": {
52
+ "type": "string",
53
+ "description": "The native identity: swift:, objc:, c: or jvm:"
54
+ },
55
+ "signature": { "type": "string" },
56
+ "since": { "type": ["number", "string"] },
57
+ "deprecated": { "const": true },
58
+ "cases": { "type": "array", "items": { "type": "string" } },
59
+ "roles": {
60
+ "type": "array",
61
+ "items": { "enum": ["call", "new", "get", "set", "implement"] }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // TypeScript language-service plugin: adds Lucent diagnostics to *.lucent.ts
3
- // (index.js, not .cjs: tsserver resolves plugin paths without "exports").
4
- // files. tsserver loads plugins with require() and its own `typescript`,
3
+ // files, and types platform Lucent files' JSX with their toolkit (index.js,
4
+ // not .cjs: tsserver resolves plugin paths without "exports"). tsserver loads plugins with require() and its own `typescript`,
5
5
  // while the compiler is an ES module that walks ASTs from its own
6
6
  // `typescript`; so the plugin imports the compiler asynchronously and hands
7
7
  // it file paths and unsaved text, never the editor's AST.
@@ -9,9 +9,74 @@
9
9
  const LUCENT_FILE = /\.lucent\.tsx?$/;
10
10
  const TYPESCRIPT_PASSTHROUGH = "LUCENT9001";
11
11
 
12
+ // A platform's Lucent files write JSX with its toolkit (the compiler's TOOLKITS,
13
+ // ui/toolkits.ts; a test keeps them equal): their implicit JSX runtime import
14
+ // resolves to lucent:<toolkit>, whose module declares the JSX namespace.
15
+ const TOOLKIT_JSX = { ios: "swiftui", android: "compose" };
16
+ const PLATFORM_FILE = /\.(ios|android)\.lucent\.tsx$/;
17
+ const JSX_RUNTIME = /\/jsx-(dev-)?runtime$/;
18
+
19
+ /**
20
+ * Types each platform Lucent file's JSX with its toolkit, the app's other
21
+ * files' JSX as they are: TypeScript imports a JSX runtime implicitly, per
22
+ * file, and the host resolves that import. An app whose JSX has no runtime
23
+ * import (React Native's `jsx: react-native`) gets React's as its import
24
+ * source, which types React's JSX alike (react/jsx-runtime's JSX is
25
+ * React.JSX), once it has platform Lucent files.
26
+ */
27
+ function withToolkitJsx(ts, host) {
28
+ const settings = host.getCompilationSettings.bind(host);
29
+ host.getCompilationSettings = () => {
30
+ const options = settings();
31
+ const imported =
32
+ options.jsx === ts.JsxEmit.ReactJSX ||
33
+ options.jsx === ts.JsxEmit.ReactJSXDev ||
34
+ options.jsx === ts.JsxEmit.React ||
35
+ options.jsxImportSource;
36
+ if (imported || !host.getScriptFileNames().some((f) => PLATFORM_FILE.test(f))) return options;
37
+ return { ...options, jsxImportSource: "react" };
38
+ };
39
+
40
+ const resolve = host.resolveModuleNameLiterals
41
+ ? host.resolveModuleNameLiterals.bind(host)
42
+ : defaultResolution(ts, host);
43
+ host.resolveModuleNameLiterals = (literals, containing, redirected, options, sf, reused) => {
44
+ const platform = PLATFORM_FILE.exec(containing);
45
+ const toolkit = platform && TOOLKIT_JSX[platform[1]];
46
+ // The implicit import is synthesized: it has no place in the file's text.
47
+ const runtime = (l) => toolkit && l.pos < 0 && JSX_RUNTIME.test(l.text);
48
+ const own = literals.map((l) =>
49
+ runtime(l) ? Object.create(l, { text: { value: `lucent:${toolkit}` } }) : l,
50
+ );
51
+ return resolve(own, containing, redirected, options, sf, reused);
52
+ };
53
+ }
54
+
55
+ /** Module resolution as the language service does it, for a host that leaves it to it. */
56
+ function defaultResolution(ts, host) {
57
+ const cache = ts.createModuleResolutionCache(
58
+ host.getCurrentDirectory(),
59
+ (f) => f,
60
+ host.getCompilationSettings(),
61
+ );
62
+ return (literals, containing, redirected, options, sf) =>
63
+ literals.map((l) =>
64
+ ts.resolveModuleName(
65
+ l.text,
66
+ containing,
67
+ options,
68
+ host,
69
+ cache,
70
+ redirected,
71
+ ts.getModeForUsageLocation(sf, l, options),
72
+ ),
73
+ );
74
+ }
75
+
12
76
  function createPlugin(loadCompiler) {
13
77
  return function init({ typescript: ts }) {
14
78
  function create(info) {
79
+ withToolkitJsx(ts, info.languageServiceHost);
15
80
  const log = (msg) => info.project.projectService.logger.info(`[lucent] ${msg}`);
16
81
  let compiler;
17
82
  loadCompiler().then(
@@ -37,7 +102,11 @@ function createPlugin(loadCompiler) {
37
102
  : undefined;
38
103
  return snap ? snap.getText(0, snap.getLength()) : undefined;
39
104
  };
40
- for (const d of compiler.checkSources(files, readSource)) {
105
+ // Bound again each check: headers (and packages) change too; unchanged ones are read once.
106
+ const extensions = compiler.projectExtensions(
107
+ info.languageServiceHost.getCurrentDirectory(),
108
+ );
109
+ for (const d of compiler.checkSources(files, readSource, { extensions })) {
41
110
  if (d.code === TYPESCRIPT_PASSTHROUGH || !d.file) continue;
42
111
  const list = byFile.get(d.file) || [];
43
112
  list.push(d);
@@ -70,7 +139,10 @@ function createPlugin(loadCompiler) {
70
139
  ]
71
140
  .filter(Boolean)
72
141
  .join("\n"),
73
- category: ts.DiagnosticCategory.Error,
142
+ category:
143
+ d.severity === "warning"
144
+ ? ts.DiagnosticCategory.Warning
145
+ : ts.DiagnosticCategory.Error,
74
146
  code: Number(d.code.replace(/^LUCENT/, "")),
75
147
  source: "lucent",
76
148
  }));
@@ -97,3 +169,4 @@ const compiler = fs.existsSync(path.join(__dirname, "../src"))
97
169
 
98
170
  module.exports = createPlugin(() => import(compiler));
99
171
  module.exports.createPlugin = createPlugin;
172
+ module.exports.TOOLKIT_JSX = TOOLKIT_JSX;
@@ -1,232 +0,0 @@
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 };
@@ -1,150 +0,0 @@
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 };
@@ -1,64 +0,0 @@
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 };