@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
@@ -9,6 +9,7 @@ const Codes = {
9
9
  UnsupportedCall: "LUCENT1007",
10
10
  UnsupportedAssignmentTarget: "LUCENT1008",
11
11
  UnsupportedLoop: "LUCENT1009",
12
+ AwaitNative: "LUCENT1010",
12
13
  AnyType: "LUCENT2001",
13
14
  UnsupportedType: "LUCENT2002",
14
15
  InexactObject: "LUCENT2003",
@@ -25,9 +26,38 @@ const Codes = {
25
26
  PlatformConformance: "LUCENT3005",
26
27
  MainThreadOnly: "LUCENT3006",
27
28
  Unavailable: "LUCENT3007",
29
+ ConstantOutsideGroup: "LUCENT3008",
30
+ BlockingOnMain: "LUCENT3009",
31
+ ModuleNameClash: "LUCENT3010",
32
+ NotIsolated: "LUCENT3011",
33
+ NotTransferable: "LUCENT3012",
34
+ ComponentExport: "LUCENT3020",
35
+ ComponentContract: "LUCENT3021",
36
+ ComponentMainThread: "LUCENT3022",
37
+ ComponentPlatforms: "LUCENT3023",
38
+ ToolkitBody: "LUCENT3024",
39
+ BorrowEscape: "LUCENT3030",
40
+ UseAfterMove: "LUCENT3031",
28
41
  TypeScript: "LUCENT9001"
29
42
  };
30
43
  const ex = (source, name = "example.lucent.ts") => ({ [name]: source });
44
+ const component = (source, name = "title") => ({
45
+ "package.json": "{ \"name\": \"example-app\" }\n",
46
+ [`${name}.lucent.tsx`]: source
47
+ });
48
+ const LABEL_IMPORTS = "import { PLATFORM } from \"lucent:platform\";\nimport { appContext } from \"lucent:android\";\nimport { TextView } from \"lucent:android/android.widget\";\nimport { UILabel } from \"lucent:ios/UIKit\";\n";
49
+ const LABEL_BODY = " if (PLATFORM === \"ios\") {\n const label = new UILabel();\n label.text = props.title;\n return label;\n }\n const text = new TextView(appContext());\n text.setText(props.title);\n return text;\n}\n";
50
+ const splitTitle = (implProps) => ({
51
+ "package.json": "{ \"name\": \"example-app\" }\n",
52
+ "title.lucent.tsx": "import type { TextView } from \"lucent:android/android.widget\";\nimport type { UILabel } from \"lucent:ios/UIKit\";\nexport declare function Title(props: { title: string; lines: number }): UILabel | TextView;\n",
53
+ "title.ios.lucent.tsx": `import { UILabel } from "lucent:ios/UIKit";\nexport function Title(props: ${implProps}): UILabel {\n const label = new UILabel();\n label.text = props.title;\n return label;\n}\n`,
54
+ "title.android.lucent.tsx": `import { appContext } from "lucent:android";\nimport { TextView } from "lucent:android/android.widget";\nexport function Title(props: ${implProps}): TextView {\n const text = new TextView(appContext());\n text.setText(props.title);\n return text;\n}\n`
55
+ });
56
+ const TOOLKIT_TITLE = {
57
+ "package.json": "{ \"name\": \"example-app\" }\n",
58
+ "title.lucent.tsx": "import type { TextView } from \"lucent:android/android.widget\";\nimport type { View } from \"lucent:swiftui\";\nexport declare function Title(props: { title: string }): View | TextView;\n",
59
+ "title.android.lucent.tsx": "import { appContext } from \"lucent:android\";\nimport { TextView } from \"lucent:android/android.widget\";\nimport { effect } from \"lucent:ui\";\nexport function Title(props: { title: string }): TextView {\n const text = new TextView(appContext());\n effect(() => text.setText(props.title));\n return text;\n}\n"
60
+ };
31
61
  const Explanations = {
32
62
  LUCENT1001: {
33
63
  title: "Syntax outside the subset",
@@ -39,8 +69,8 @@ const Explanations = {
39
69
  },
40
70
  LUCENT1002: {
41
71
  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.",
72
+ summary: "An operator the subset doesn't support, such as `delete`, `in` on anything but a record, or `instanceof` with a generic class. A loose `==` that JavaScript converts for, or comparing two functions, is refused too.",
73
+ 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. Two functions cannot be compared, because a function value has no stable identity (a named function is a new value at each use).",
44
74
  fix: "use a Map or a Record for keys that come and go, or an optional field for one that may be missing",
45
75
  wrong: ex("export function clear(tags: { name?: string }): { name?: string } {\n delete tags.name;\n return tags;\n}\n"),
46
76
  right: ex("export function clear(tags: { name?: string }): { name?: string } {\n tags.name = undefined;\n return tags;\n}\n")
@@ -101,6 +131,15 @@ const Explanations = {
101
131
  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
132
  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
133
  },
134
+ LUCENT1010: {
135
+ title: "Await on a native object",
136
+ summary: "`await` on a platform SDK object, such as a Play services Task or a Java future: it is not a promise.",
137
+ details: "A native object reports its completion through its own API, usually a listener, so awaiting it would give the object back at once. Lucent does not recognize libraries by class name, so it cannot pick that API for you. `fromCallback` from `lucent:core` turns the listener into a promise: register it, then call `resolve` or `reject` from it.",
138
+ fix: "wrap the listener or callback that reports its completion in fromCallback (lucent:core), and await that",
139
+ wrong: ex("import { PLATFORM } from \"lucent:platform\";\nimport { CompletableFuture } from \"lucent:android/java.util.concurrent\";\nexport async function ready(): Promise<boolean> {\n if (PLATFORM !== \"android\") return true;\n const value = await CompletableFuture.completedFuture(\"ready\");\n return value !== null;\n}\n"),
140
+ right: ex("import { fromCallback } from \"lucent:core\";\nimport { PLATFORM } from \"lucent:platform\";\nimport type { Throwable } from \"lucent:android/java.lang\";\nimport { CompletableFuture } from \"lucent:android/java.util.concurrent\";\nexport async function ready(): Promise<boolean> {\n if (PLATFORM !== \"android\") return true;\n const future = CompletableFuture.completedFuture(\"ready\");\n const value = await fromCallback<string | null>((resolve, reject) => {\n future?.whenComplete((v: string | null, failure: Throwable | null) => {\n if (failure) reject(new Error(failure.getMessage() ?? \"failed\"));\n else resolve(v);\n });\n });\n return value !== null;\n}\n"),
141
+ sdk: "android"
142
+ },
104
143
  LUCENT2001: {
105
144
  title: "Value without a native type",
106
145
  summary: "`any`, or `unknown` outside a `catch` clause: every value needs a native type.",
@@ -111,8 +150,8 @@ const Explanations = {
111
150
  },
112
151
  LUCENT2002: {
113
152
  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.",
153
+ summary: "A type with no native representation: intersections, `symbol`, `object`, `WeakMap`, `Intl`, or an index signature mixed with properties.",
154
+ details: "Each type maps to one native representation. An intersection can combine unrelated layouts, `symbol` is not implemented yet, and `object` says nothing about the layout.",
116
155
  fix: "spell the combined type out as one object type, or use a concrete type",
117
156
  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
157
  right: ex("type Person = { name: string; age: number };\nexport function label(p: Person): string {\n return `${p.name} (${p.age})`;\n}\n")
@@ -239,11 +278,128 @@ const Explanations = {
239
278
  title: "Platform API newer than the oldest supported OS",
240
279
  summary: "A platform API newer than the oldest supported OS version, used without an `available()` or `SDK_INT` check around it.",
241
280
  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"),
281
+ fix: "check first: if (available(\"ios\", 16)) …, if (available(\"android\", 26)) … or Build_VERSION.SDK_INT >= 26",
282
+ 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(10n, 10);\n return \"made\";\n }\n return \"none\";\n}\n"),
283
+ 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(10n, 10);\n return \"made\";\n }\n return \"none\";\n}\n"),
245
284
  sdk: "android"
246
285
  },
286
+ LUCENT3008: {
287
+ title: "Constant outside its group",
288
+ summary: "An Android SDK argument that is a constant outside the @IntDef or @StringDef group the SDK allows there.",
289
+ details: "The SDK says which constants a parameter takes (@IntDef, @StringDef). A literal or constant outside that group compiles, as in Java, but the platform rejects or misreads it; Lucent warns, as Android lint does.",
290
+ fix: "pass one of the constants the warning lists",
291
+ severity: "warning",
292
+ wrong: ex("import { PLATFORM } from \"lucent:platform\";\nimport { Toast } from \"lucent:android/android.widget\";\nimport { appContext } from \"lucent:android\";\nexport async function toast(): Promise<boolean> {\n if (PLATFORM === \"android\") return Toast.makeText(appContext(), \"hi\", 5) !== null;\n return false;\n}\n"),
293
+ right: ex("import { PLATFORM } from \"lucent:platform\";\nimport { Toast } from \"lucent:android/android.widget\";\nimport { appContext } from \"lucent:android\";\nexport async function toast(): Promise<boolean> {\n if (PLATFORM === \"android\")\n return Toast.makeText(appContext(), \"hi\", Toast.LENGTH_SHORT) !== null;\n return false;\n}\n"),
294
+ sdk: "android"
295
+ },
296
+ LUCENT3009: {
297
+ title: "Blocking call on the main thread",
298
+ summary: "An Android SDK member marked @WorkerThread, called inside main(() => …) or a main-thread callback.",
299
+ details: "@WorkerThread members do blocking work (disk, network, IPC). On the main thread they freeze the UI and can trigger an \"application not responding\" dialog. The call compiles, but Lucent warns, as Android lint does.",
300
+ fix: "call it outside main(() => …): async Lucent functions run on the Lucent thread",
301
+ severity: "warning",
302
+ wrong: ex("import { PLATFORM } from \"lucent:platform\";\nimport { BlockedNumberContract } from \"lucent:android/android.provider\";\nimport { appContext } from \"lucent:android\";\nimport { main } from \"lucent:thread\";\nexport async function blocked(n: string): Promise<boolean> {\n if (PLATFORM === \"android\") return main(() => BlockedNumberContract.isBlocked(appContext(), n));\n return false;\n}\n"),
303
+ right: ex("import { PLATFORM } from \"lucent:platform\";\nimport { BlockedNumberContract } from \"lucent:android/android.provider\";\nimport { appContext } from \"lucent:android\";\nexport async function blocked(n: string): Promise<boolean> {\n if (PLATFORM === \"android\") return BlockedNumberContract.isBlocked(appContext(), n);\n return false;\n}\n")
304
+ },
305
+ LUCENT3010: {
306
+ title: "Two modules with one name",
307
+ summary: "Two Lucent modules in one app whose files give them the same module name.",
308
+ details: "A module's name is its file name without the directory, the platform suffix and `.lucent.ts` (inside a Lucent package, its path under the package's sources). The app's native side registers each module under that name, so two files that share it would be one module.",
309
+ fix: "rename one of the files",
310
+ wrong: {
311
+ "screens/clock.lucent.ts": "export function now(): number {\n return Date.now();\n}\n",
312
+ "sdk/clock.lucent.ts": "export function zone(): string {\n return \"UTC\";\n}\n"
313
+ },
314
+ right: {
315
+ "screens/clock.lucent.ts": "export function now(): number {\n return Date.now();\n}\n",
316
+ "sdk/zones.lucent.ts": "export function zone(): string {\n return \"UTC\";\n}\n"
317
+ }
318
+ },
319
+ LUCENT3011: {
320
+ title: "Code that cannot run in a compute task",
321
+ summary: "A compute() task touches module state or a computed constant, native code unfit for workers, code the compiler cannot follow, or asynchronous work.",
322
+ details: "A compute task runs on a worker thread while module code keeps running, so it may only touch its input and what it makes. Module state, non-literal constants (a reload assigns them again), main-thread native code, function values the compiler cannot follow, `await` and timers break that rule. The message gives the path, through every call, to what breaks it.",
323
+ fix: "pass what the task needs as its input, and apply its result where you await it",
324
+ wrong: ex("import { compute } from \"lucent:core\";\nconst weights: number[] = [1, 2, 3];\nfunction score(x: number): number {\n return x * (weights[0] ?? 1);\n}\nexport async function run(x: number): Promise<number> {\n return await compute(score, x);\n}\n"),
325
+ right: ex("import { compute } from \"lucent:core\";\nconst weights: number[] = [1, 2, 3];\nfunction score(job: { x: number; weights: number[] }): number {\n return job.x * (job.weights[0] ?? 1);\n}\nexport async function run(x: number): Promise<number> {\n return await compute(score, { x, weights });\n}\n")
326
+ },
327
+ LUCENT3012: {
328
+ title: "Value that cannot cross to a compute task",
329
+ summary: "A compute() task's input or result holds something other than data, such as a function, a promise or a main-thread native object.",
330
+ details: "A compute task's input is copied at submission, and its result comes back to the caller. Both must be numbers, strings, booleans, arrays, tuples, records, maps, sets, byte arrays, dates, or objects made of those. Functions, promises, main-thread native objects and values of unknown or generic type cannot cross, and the message names which part.",
331
+ fix: "pass the data the task needs, and keep functions, signals and native objects on the calling side",
332
+ wrong: ex("import { compute } from \"lucent:core\";\ntype Job = { values: number[]; report: (n: number) => void };\nfunction total(job: Job): number {\n return job.values.reduce((a, b) => a + b, 0);\n}\nexport async function run(values: number[]): Promise<number> {\n return await compute(total, { values, report: () => {} });\n}\n"),
333
+ right: ex("import { compute } from \"lucent:core\";\nfunction total(values: number[]): number {\n return values.reduce((a, b) => a + b, 0);\n}\nexport async function run(values: number[]): Promise<number> {\n return await compute(total, values);\n}\n")
334
+ },
335
+ LUCENT3020: {
336
+ title: "Export that cannot be a component",
337
+ summary: "An exported `.lucent.tsx` function that returns a view but cannot be a component, or Lucent code calling a component.",
338
+ details: "An exported `.lucent.tsx` function that returns a platform view (a `UIView`, an Android `View`, or a subclass) is a component. React mounts it through a native host, and Lucent identifies it by its package's name, module path and export name. So it returns its view on every path and synchronously, takes one props object or none, and has no type parameters.",
339
+ fix: "return the view on every path, from one props object, and move other work into a separate function",
340
+ wrong: component(`${LABEL_IMPORTS}export function Title(props: { title: string; shown: boolean }) {\n if (!props.shown) return undefined;\n${LABEL_BODY}`),
341
+ right: component(`${LABEL_IMPORTS}export function Title(props: { title: string }) {\n${LABEL_BODY}`),
342
+ sdk: "ios"
343
+ },
344
+ LUCENT3021: {
345
+ title: "Component prop, event or command that cannot cross",
346
+ summary: "A component prop, event or ref command whose type views cannot carry, or whose name React or the host keeps.",
347
+ details: "Props, event arguments and command arguments and results are plain data: numbers, strings, booleans, string literal unions, arrays and plain objects, possibly null. A function prop is an event named `on…`, whose call from the view posts its arguments to JavaScript, so it returns nothing. `key`, `ref`, `children` and `style` belong to React and the host.",
348
+ fix: "pass plain data, make events return nothing, and name them onSomething",
349
+ wrong: component(`${LABEL_IMPORTS}export function Title(props: { title: string; onMeasure?: (width: number) => number }) {\n${LABEL_BODY}`),
350
+ right: component(`${LABEL_IMPORTS}export function Title(props: { title: string; onMeasure?: (width: number) => void }) {\n${LABEL_BODY}`),
351
+ sdk: "ios"
352
+ },
353
+ LUCENT3022: {
354
+ title: "Component code that cannot run on the main thread",
355
+ summary: "A component's setup, or a function it creates, using module state, code the compiler cannot follow, or native code unfit for the main thread.",
356
+ details: "A component sets up its view on the main (UI) thread, where the handlers it gives the view run too. Module variables belong to the module's thread, code the compiler cannot follow may do anything, and blocking or background-only native code freezes the UI. Calling an event prop directly (`props.onChange?.(value)`) is fine: it posts the event to JavaScript.",
357
+ fix: "keep the state in the component (a local), or pass it in as a prop",
358
+ wrong: component(`${LABEL_IMPORTS}let shown = 0;\nexport function Title(props: { title: string }) {\n shown++;\n${LABEL_BODY}`),
359
+ right: component(`${LABEL_IMPORTS}export function Title(props: { title: string }) {\n${LABEL_BODY}`),
360
+ sdk: "ios"
361
+ },
362
+ LUCENT3023: {
363
+ title: "Component that differs between platforms",
364
+ summary: "A component whose props, events or commands differ between platforms or from its declaration, or that is a component on one platform only.",
365
+ details: "React sees one component on every platform, so its props, events and commands are the same in every platform's implementation. A split module's shared declaration states the same contract, and the component returns a view on every platform.",
366
+ fix: "give every platform's implementation the declared props",
367
+ wrong: splitTitle("{ title: string }"),
368
+ right: splitTitle("{ title: string; lines: number }"),
369
+ sdk: "ios"
370
+ },
371
+ LUCENT3024: {
372
+ title: "SwiftUI or Compose body that cannot be compiled",
373
+ summary: "A component's SwiftUI or Jetpack Compose body that Lucent cannot write out in Swift or Kotlin, or toolkit code used outside such a body.",
374
+ details: "A component can draw with its platform's toolkit, SwiftUI or Jetpack Compose (internal, under LUCENT_VIEWS=fabric). Lucent writes that body out as Swift or Kotlin, showing the numbers, booleans and strings its setup computes. Toolkit views exist only in a body, whose callbacks call the setup's functions: it doesn't change the setup's state or send events.",
375
+ fix: "make the view in the body, and move logic into a function of the setup that the body calls",
376
+ wrong: {
377
+ ...TOOLKIT_TITLE,
378
+ "title.ios.lucent.tsx": "import { Text } from \"lucent:swiftui\";\nimport { signal } from \"lucent:ui\";\nexport function Title(props: { title: string }) {\n const taps = signal(0);\n return <Text onTapGesture={() => taps.set(taps.peek() + 1)}>{props.title}</Text>;\n}\n"
379
+ },
380
+ right: {
381
+ ...TOOLKIT_TITLE,
382
+ "title.ios.lucent.tsx": "import { Text } from \"lucent:swiftui\";\nimport { signal } from \"lucent:ui\";\nexport function Title(props: { title: string }) {\n const taps = signal(0);\n const tap = () => {\n taps.set(taps.peek() + 1);\n };\n return <Text onTapGesture={() => tap()}>{props.title}</Text>;\n}\n"
383
+ },
384
+ sdk: "ios",
385
+ views: true
386
+ },
387
+ LUCENT3030: {
388
+ title: "Borrowed bytes that outlive their borrow",
389
+ summary: "A span that withRead or withWrite lends escapes its callback: returned, stored, kept by a closure or callee, or held across await.",
390
+ details: "withRead and withWrite lend a buffer's bytes for one synchronous call, and refuse conflicting use only while it runs. After it, a task may write, release or move the bytes, so the message shows how the span would outlive the call. Copy what you need inside the callback, or snapshot the buffer with toUint8Array().",
391
+ fix: "copy what you need out of the span inside the callback, and return that",
392
+ wrong: ex("import { NativeBuffer } from \"lucent:core\";\nexport function first(buffer: NativeBuffer): number {\n const bytes = buffer.withRead((lent) => lent);\n return bytes[0] ?? 0;\n}\n"),
393
+ right: ex("import { NativeBuffer } from \"lucent:core\";\nexport function first(buffer: NativeBuffer): number {\n return buffer.withRead((bytes) => bytes[0] ?? 0);\n}\n")
394
+ },
395
+ LUCENT3031: {
396
+ title: "Native buffer used after it moved",
397
+ summary: "A NativeBuffer is used after transfer() or after it was handed to compute(), which move its bytes to another buffer.",
398
+ details: "Moving a buffer hands its bytes, uncopied, to a new owner: the buffer that transfer returns, or a compute task. The old buffer then throws an InvalidStateError on every use, and where the move certainly came first, the compiler reports the use. Use the buffer the move gave you, or copy the bytes before moving them.",
399
+ fix: "use the buffer transfer() returned, or what the task gives back",
400
+ wrong: ex("import { NativeBuffer } from \"lucent:core\";\nexport function size(): number {\n const buffer = NativeBuffer.allocate(8);\n const moved = buffer.transfer();\n return buffer.byteLength + moved.byteLength;\n}\n"),
401
+ right: ex("import { NativeBuffer } from \"lucent:core\";\nexport function size(): number {\n const buffer = NativeBuffer.allocate(8);\n const moved = buffer.transfer();\n return moved.byteLength;\n}\n")
402
+ },
247
403
  LUCENT9001: {
248
404
  title: "TypeScript error",
249
405
  summary: "A TypeScript error. Lucent stops at type errors, because it compiles from the checker's types.",
package/dist/compiler.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as Explanations, r as docsUrl, t as Codes } from "./codes-CIuwXt1S.js";
2
- import { A as formatDiagnostic, C as extractionCount, D as sdkModule, E as sdkAvailable, O as sdkModules, S as cachedModules, T as prefetch, _ as usesPlatforms, a as inputsKey, b as coverage, c as withGradleDependencies, d as coreJsPath, f as coreTypesPath, g as projectFiles, h as platformOf, i as report, k as sdkNames, l as writeNativePackage, m as moduleNameOf, n as compile, o as isUpToDate, p as findLucentFiles, r as compileDirectory, s as runtimeDir, t as checkSources, u as LUCENT_EXTENSION, v as moduleNamespace, w as forgetLoadedSdks, x as podsSearchPaths, y as sdkDts } from "./src-BD7f1_aZ.js";
3
- import { a as satisfies, i as nativeDependencies, n as lucentPackages, r as lucentVersion } from "./packages-HyskKIsY.js";
4
- export { Codes, Explanations, LUCENT_EXTENSION, cachedModules, checkSources, compile, compileDirectory, coreJsPath, coreTypesPath, docsUrl, extractionCount, findLucentFiles, forgetLoadedSdks, formatDiagnostic, inputsKey, isUpToDate, lucentPackages, lucentVersion, moduleNameOf, moduleNamespace, nativeDependencies, platformOf, podsSearchPaths, prefetch as prefetchSdk, projectFiles, report, runtimeDir, satisfies, sdkAvailable, coverage as sdkCoverage, sdkDts, sdkModule, sdkModules, sdkNames, usesPlatforms, withGradleDependencies, writeNativePackage };
1
+ import { n as Explanations, r as docsUrl, t as Codes } from "./codes-D-6LxUqD.js";
2
+ import { A as findLucentFiles, C as bindExtensions, D as LUCENT_EXTENSION, E as identityScript, F as moduleNamespace, G as cachedModules, I as extensionDts, J as forgetLoadedSdks, L as sdkDts, M as platformOf, N as projectFiles, O as coreJsPath, P as usesPlatforms, Q as sdkNames, R as coverage, S as inNativePackage, T as RUNTIME_ABI, W as podsSearchPaths, X as sdkAvailable, Y as prefetch, _ as VIEW_CONTRACT_VERSION, a as report, b as PACKAGE_FIELDS, c as sdkModules, d as isUpToDate, f as runtimeDir, g as libraryBuildGradle, h as toolkitsFrom, i as projectExtensions, j as moduleNameOf, k as coreTypesPath, l as deferredLibraryGradle, m as jsxToolkits, n as compile, o as sdkDeclarations, p as writeNativePackage, q as extractionCount, r as compileDirectory, s as sdkModule, t as checkSources, tt as formatDiagnostic, u as inputsKey, v as resolveNative, w as forgetExtensionHeaders, x as fileHashes, y as EXTENSION_FIELDS } from "./src-ChnmWLwn.js";
3
+ import { i as satisfies, n as lucentPackages, r as lucentVersion } from "./packages-CSmKeaAh.js";
4
+ export { Codes, EXTENSION_FIELDS, Explanations, LUCENT_EXTENSION, PACKAGE_FIELDS, RUNTIME_ABI, VIEW_CONTRACT_VERSION, bindExtensions, cachedModules, checkSources, compile, compileDirectory, coreJsPath, coreTypesPath, deferredLibraryGradle, docsUrl, extensionDts, extractionCount, fileHashes, findLucentFiles, forgetExtensionHeaders, forgetLoadedSdks, formatDiagnostic, identityScript, inNativePackage, inputsKey, isUpToDate, jsxToolkits, libraryBuildGradle, lucentPackages, lucentVersion, moduleNameOf, moduleNamespace, platformOf, podsSearchPaths, prefetch as prefetchSdk, projectExtensions, projectFiles, report, resolveNative, runtimeDir, satisfies, sdkAvailable, coverage as sdkCoverage, sdkDeclarations, sdkDts, sdkModule, sdkModules, sdkNames, toolkitsFrom, usesPlatforms, writeNativePackage };
@@ -1,5 +1,5 @@
1
1
  import { i as table, n as duration, t as codeFrame } from "./format-D9fnIMEx.js";
2
- import { n as nextText } from "./pipeline-CH7-2cxu.js";
2
+ import { i as ACTION_TEXT, n as nextText } from "./pipeline-BM_VM2X_.js";
3
3
  import { Box, Text, render, useApp, useInput } from "ink";
4
4
  import { useState, useSyncExternalStore } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -55,7 +55,7 @@ function Dashboard({ session, theme: t, root, open, doctor }) {
55
55
  cell(m.platforms.android),
56
56
  when
57
57
  ])], 3);
58
- const status = last?.fatal ? t.error(`${t.symbols.fail} ${last.fatal}`) : last?.ok && last.next?.rebuild ? t.warn(`next: ${nextText(last.next)}`) : "";
58
+ const status = last?.fatal ? t.error(`${t.symbols.fail} ${last.fatal}`) : last?.ok && last.actions?.length ? t.warn(`next: ${last.actions.map((a) => `${ACTION_TEXT[a.kind]} (${a.targets.join(", ")})`).join(", ")}`) : last?.ok && last.next?.rebuild ? t.warn(`next: ${nextText(last.next)}`) : "";
59
59
  const rule = (title) => t.dim(`${t.symbols.rule} ${title} ${t.symbols.rule.repeat(Math.max(3, t.terminal.width - title.length - 4))}`);
60
60
  return /* @__PURE__ */ jsxs(Box, {
61
61
  flexDirection: "column",
@@ -1,10 +1,10 @@
1
1
  import { t as createTheme } from "./theme-uv5bc0aK.js";
2
2
  import { n as version } from "./version-bqpIO5sP.js";
3
- import { h as platformOf, m as moduleNameOf, u as LUCENT_EXTENSION } from "./src-BD7f1_aZ.js";
4
- import { n as lucentPackages } from "./packages-HyskKIsY.js";
5
- import { n as nextText, r as plural, t as buildProject } from "./pipeline-CH7-2cxu.js";
3
+ import { D as LUCENT_EXTENSION, M as platformOf, j as moduleNameOf } from "./src-ChnmWLwn.js";
4
+ import { n as lucentPackages } from "./packages-CSmKeaAh.js";
5
+ import { i as ACTION_TEXT, n as nextText, r as plural, t as buildProject } from "./pipeline-BM_VM2X_.js";
6
6
  import { t as plainSteps } from "./steps--_h-FFS7.js";
7
- import { n as systemProbe, t as diagnose } from "./doctor-C0PrfWT6.js";
7
+ import { n as systemProbe, t as diagnose } from "./doctor-CTAX3euc.js";
8
8
  import fs from "node:fs";
9
9
  import path from "node:path";
10
10
  import { spawn } from "node:child_process";
@@ -25,7 +25,8 @@ function compact(session, out) {
25
25
  }
26
26
  if (last.ok) {
27
27
  const next = last.next?.rebuild ? ` ${t.dim("·")} ${nextText(last.next)}` : "";
28
- out.print(`${time} ${t.success(t.symbols.ok)} ${plural(s.modules.length, "module")} ${t.dim(`${last.ms} ms`)}${next}`);
28
+ const actions = (last.actions ?? []).map((a) => `${ACTION_TEXT[a.kind]} (${a.targets.join(", ")})`).join(", ");
29
+ out.print(`${time} ${t.success(t.symbols.ok)} ${plural(s.modules.length, "module")} ${t.dim(`${last.ms} ms`)}${next}${actions ? ` ${t.dim("·")} ${actions}` : ""}`);
29
30
  return;
30
31
  }
31
32
  out.error(`${time} ${t.error(t.symbols.fail)} ${plural(s.problems.length, "error")}`);
@@ -59,6 +60,7 @@ function createStore(initial = {
59
60
  };
60
61
  }
61
62
  const DEBOUNCE_MS = 40;
63
+ const ALWAYS_READ = (file) => LUCENT_EXTENSION.test(file) || ["lucent.json", "package.json"].includes(path.basename(file));
62
64
  function startSession(root) {
63
65
  const store = createStore();
64
66
  const theme = createTheme({
@@ -68,15 +70,22 @@ function startSession(root) {
68
70
  links: false,
69
71
  width: 80
70
72
  });
71
- let building = false;
73
+ let building;
72
74
  let queued;
73
75
  let timer;
76
+ let nativeInputs = [];
77
+ let stopped = false;
78
+ let readSince = 0;
74
79
  const build = async (force) => {
80
+ if (stopped) return;
75
81
  if (building) {
82
+ building.abort();
76
83
  queued = { force: force || !!queued?.force };
77
84
  return;
78
85
  }
79
- building = true;
86
+ const controller = new AbortController();
87
+ const started = Date.now();
88
+ building = controller;
80
89
  store.set({
81
90
  ...store.get(),
82
91
  building: true,
@@ -90,8 +99,19 @@ function startSession(root) {
90
99
  const at = /* @__PURE__ */ new Date();
91
100
  const r = await buildProject(root, {
92
101
  mode: "build",
93
- force
102
+ force,
103
+ signal: controller.signal
94
104
  }, plainSteps(() => {}, theme), (n) => notices.push(n));
105
+ if (r.superseded) {
106
+ building = void 0;
107
+ const again = queued ?? { force };
108
+ queued = void 0;
109
+ build(again.force);
110
+ return;
111
+ }
112
+ nativeInputs = r.nativeInputs;
113
+ readSince = started;
114
+ watch();
95
115
  const failing = /* @__PURE__ */ new Map();
96
116
  for (const d of r.diagnostics) {
97
117
  if (!d.file) continue;
@@ -125,35 +145,52 @@ function startSession(root) {
125
145
  ms: r.ms,
126
146
  ok: r.ok,
127
147
  next: r.ok && !r.upToDate ? r.next : void 0,
148
+ actions: r.actions,
128
149
  fatal: r.fatal
129
150
  },
130
- problems: r.diagnostics.map((d) => ({
151
+ problems: [...r.diagnostics, ...r.warnings].map((d) => ({
131
152
  ...d,
132
153
  source: d.file ? source(d.file) : void 0
133
154
  })),
134
155
  notices
135
156
  });
136
- building = false;
157
+ building = void 0;
137
158
  if (queued) {
138
159
  const again = queued;
139
160
  queued = void 0;
140
161
  build(again.force);
141
162
  }
142
163
  };
143
- const changed = (name) => {
144
- if (!name || !LUCENT_EXTENSION.test(name) || name.split(path.sep).some((part) => part === "node_modules" || part.startsWith("."))) return;
164
+ const relevant = (file, dir) => {
165
+ if (path.relative(dir, file).split(path.sep).some((part) => part === "node_modules" || part.startsWith("."))) return false;
166
+ return ALWAYS_READ(file) || nativeInputs.some((p) => file === p || file.startsWith(`${p}${path.sep}`));
167
+ };
168
+ const changed = (dir, name) => {
169
+ if (!name || !relevant(path.join(dir, name), dir)) return;
170
+ const file = path.join(dir, name);
171
+ if (fs.existsSync(file) && fs.statSync(file).mtimeMs < readSince) return;
145
172
  clearTimeout(timer);
146
173
  timer = setTimeout(() => void build(false), DEBOUNCE_MS);
147
174
  };
148
- let packages = [];
149
- try {
150
- packages = lucentPackages(root).map((p) => p.sources).filter((dir) => path.relative(root, dir).startsWith(".."));
151
- } catch {}
152
- const watchers = [root, ...packages].map((dir) => fs.watch(dir, { recursive: true }, (_event, name) => changed(name)));
153
- store.set({
154
- ...store.get(),
155
- watching: [root, ...packages].map((d) => path.relative(root, d) || ".")
156
- });
175
+ const watchers = /* @__PURE__ */ new Map();
176
+ const watch = () => {
177
+ if (stopped) return;
178
+ let packages = [];
179
+ try {
180
+ packages = lucentPackages(root).map((p) => p.dir).filter((dir) => path.relative(root, dir).startsWith(".."));
181
+ } catch {}
182
+ const dirs = /* @__PURE__ */ new Set([root, ...packages]);
183
+ for (const [dir, w] of watchers) if (!dirs.has(dir)) {
184
+ w.close();
185
+ watchers.delete(dir);
186
+ }
187
+ for (const dir of dirs) if (!watchers.has(dir)) watchers.set(dir, fs.watch(dir, { recursive: true }, (_event, name) => changed(dir, name)));
188
+ store.set({
189
+ ...store.get(),
190
+ watching: [...dirs].map((d) => path.relative(root, d) || ".")
191
+ });
192
+ };
193
+ watch();
157
194
  build(false);
158
195
  return {
159
196
  store,
@@ -164,8 +201,10 @@ function startSession(root) {
164
201
  build(true);
165
202
  },
166
203
  stop() {
204
+ stopped = true;
167
205
  clearTimeout(timer);
168
- for (const w of watchers) w.close();
206
+ building?.abort();
207
+ for (const w of watchers.values()) w.close();
169
208
  }
170
209
  };
171
210
  }
@@ -187,7 +226,7 @@ async function run({ root, flags, out }) {
187
226
  session.stop();
188
227
  return 0;
189
228
  }
190
- const { dashboard } = await import("./dashboard-B-NzjjaN.js");
229
+ const { dashboard } = await import("./dashboard-CC-HXhcd.js");
191
230
  await dashboard({
192
231
  session,
193
232
  theme: out.theme,
@@ -12,7 +12,9 @@ function wrap(text, width, indent) {
12
12
  }
13
13
  function renderDiagnostic(d, source, theme) {
14
14
  const width = theme.terminal.width;
15
- const out = [`${` ${theme.error("error")} ${theme.bold(d.code)} `}${wrap(d.message.split("\n").join(" "), Math.max(20, width - 2 - 6 - d.code.length - 2), " ".repeat(6 + d.code.length + 4))}`];
15
+ const label = d.severity === "warning" ? theme.warn("warning") : theme.error("error");
16
+ const labelWidth = d.severity === "warning" ? 7 : 5;
17
+ const out = [`${` ${label} ${theme.bold(d.code)} `}${wrap(d.message.split("\n").join(" "), Math.max(20, width - 2 - (labelWidth + 1) - d.code.length - 2), " ".repeat(labelWidth + 1 + d.code.length + 4))}`];
16
18
  if (d.file) {
17
19
  out.push("", ` ${theme.dim(d.line ? `${d.file}:${d.line}:${d.column ?? 1}` : d.file)}`);
18
20
  if (source !== void 0 && d.line) out.push(codeFrame(source, {
@@ -1,4 +1,4 @@
1
- import { n as lucentPackages } from "./packages-HyskKIsY.js";
1
+ import { n as lucentPackages } from "./packages-CSmKeaAh.js";
2
2
  import { t as packageManagerOf } from "./package-manager-BnxwCySi.js";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
@@ -1,6 +1,6 @@
1
1
  import { n as version } from "./version-bqpIO5sP.js";
2
2
  import { i as table } from "./format-D9fnIMEx.js";
3
- import { n as systemProbe, t as diagnose } from "./doctor-C0PrfWT6.js";
3
+ import { n as systemProbe, t as diagnose } from "./doctor-CTAX3euc.js";
4
4
  //#region src/cli/commands/doctor.ts
5
5
  function run({ root, out }) {
6
6
  const checks = diagnose(root, systemProbe(version()));
@@ -1,4 +1,4 @@
1
- import { n as Explanations, r as docsUrl } from "./codes-CIuwXt1S.js";
1
+ import { n as Explanations, r as docsUrl } from "./codes-D-6LxUqD.js";
2
2
  import { i as table, r as link } from "./format-D9fnIMEx.js";
3
3
  //#region src/cli/commands/explain.ts
4
4
  function run({ positionals, out }) {
@@ -2,35 +2,6 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  //#region ../compiler/src/packages.ts
5
- function nativeDependencies(packages) {
6
- const out = {
7
- pods: {},
8
- gradle: {},
9
- permissions: [],
10
- infoPlist: {}
11
- };
12
- const owners = /* @__PURE__ */ new Map();
13
- const merge = (kind, into, key, value, from) => {
14
- const id = `${kind} ${key}`;
15
- if (into[key] !== void 0 && into[key] !== value) throw new Error(`${kind}${key}: ${owners.get(id)} wants ${into[key]}, ${from} wants ${value}`);
16
- into[key] = value;
17
- if (!owners.has(id)) owners.set(id, from);
18
- };
19
- for (const p of packages) {
20
- for (const [pod, version] of Object.entries(p.native?.ios?.pods ?? {})) merge("pod ", out.pods, pod, version, p.name);
21
- for (const [artifact, version] of Object.entries(p.native?.android?.dependencies ?? {})) merge("", out.gradle, artifact, version, p.name);
22
- for (const perm of p.native?.android?.permissions ?? []) if (!out.permissions.includes(perm)) out.permissions.push(perm);
23
- for (const [key, value] of Object.entries(p.native?.ios?.infoPlist ?? {})) {
24
- merge("Info.plist ", Object.fromEntries(Object.entries(out.infoPlist).map(([k, v]) => [k, v.value])), key, value, p.name);
25
- out.infoPlist[key] ??= {
26
- value,
27
- from: p.name
28
- };
29
- }
30
- }
31
- out.permissions.sort();
32
- return out;
33
- }
34
5
  const read = (file) => {
35
6
  try {
36
7
  return JSON.parse(fs.readFileSync(file, "utf8"));
@@ -43,14 +14,12 @@ function lucentPackageOf(file) {
43
14
  const pkg = read(path.join(dir, "package.json"));
44
15
  if (pkg) {
45
16
  if (!pkg.lucent || !pkg.name) return void 0;
46
- const native = fs.existsSync(path.join(dir, "lucent.json")) ? JSON.parse(fs.readFileSync(path.join(dir, "lucent.json"), "utf8")) : void 0;
47
17
  return {
48
18
  name: pkg.name,
49
19
  version: pkg.version ?? "0.0.0",
50
20
  dir,
51
21
  sources: path.join(dir, pkg.lucent.sources ?? "."),
52
- compatible: pkg.lucent.compatible,
53
- ...native ? { native } : {}
22
+ compatible: pkg.lucent.compatible
54
23
  };
55
24
  }
56
25
  if (path.dirname(dir) === dir) return void 0;
@@ -147,4 +116,4 @@ function comparator(v, c) {
147
116
  return op === ">=" ? d >= 0 : op === ">" ? d > 0 : op === "<=" ? d <= 0 : d < 0;
148
117
  }
149
118
  //#endregion
150
- export { satisfies as a, nativeDependencies as i, lucentPackages as n, lucentVersion as r, lucentPackageOf as t };
119
+ export { satisfies as i, lucentPackages as n, lucentVersion as r, lucentPackageOf as t };