@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.
- package/README.md +97 -0
- package/app.plugin.js +46 -10
- package/dist/{bench-CR3E7e2e.js → bench-B555m0wU.js} +10 -6
- package/dist/{build-CAIrRSYA.js → build-UZ5Zm5m6.js} +1 -1
- package/dist/{build-check-QozuNJm5.js → build-check-Dmf8_yiw.js} +28 -13
- package/dist/{check-1SCmYlqA.js → check-D-H9WLG4.js} +1 -1
- package/dist/cli.js +62 -13
- package/dist/{codes-CIuwXt1S.js → codes-D-6LxUqD.js} +163 -7
- package/dist/compiler.js +4 -4
- package/dist/{dashboard-B-NzjjaN.js → dashboard-C8iF5-6T.js} +2 -2
- package/dist/{dev-BYWMP7oC.js → dev-B3lSx5CF.js} +62 -23
- package/dist/{diagnostic-BM9sXmwl.js → diagnostic-BvwLZQS1.js} +3 -1
- package/dist/{doctor-C0PrfWT6.js → doctor-CTAX3euc.js} +1 -1
- package/dist/{doctor-DdR4JnVc.js → doctor-CrgOAV5L.js} +1 -1
- package/dist/{explain--vV1oaRl.js → explain-Byit07F-.js} +1 -1
- package/dist/{packages-HyskKIsY.js → packages-CSmKeaAh.js} +2 -33
- package/dist/pipeline-BBY0df_2.js +700 -0
- package/dist/project-BLhWwnns.js +342 -0
- package/dist/sdk-coverage-DFGiDOzR.js +113 -0
- package/dist/sdk-diff-DpPYWzrl.js +109 -0
- package/dist/sdk-lock-QOxEFD1o.js +38 -0
- package/dist/{sdk-prefetch-mo04JDZV.js → sdk-prefetch-DX6ztlPN.js} +2 -2
- package/dist/{sdk-search-Iv4K3-8a.js → sdk-search-BShBL1LL.js} +2 -2
- package/dist/{sdk-show-CkrdlqlP.js → sdk-show-B3bI-0M7.js} +5 -4
- package/dist/sdk-usage-ljX5bTuZ.js +95 -0
- package/dist/src-DlICbK91.js +39682 -0
- package/dist/trace-Bi4hkmPx.js +139 -0
- package/lib/core.cjs +368 -1
- package/lib/sdk/android.d.ts +54 -1
- package/lib/sdk/compose.d.ts +94 -0
- package/lib/sdk/compose.schemas.json.gz +0 -0
- package/lib/sdk/core.d.ts +201 -0
- package/lib/sdk/ios.d.ts +75 -2
- package/lib/sdk/ui.d.ts +129 -0
- package/metro/transformer.cjs +11 -2
- package/package.json +2 -1
- package/runtime/cpp/lucent/abort.cpp +59 -11
- package/runtime/cpp/lucent/abort.h +22 -6
- package/runtime/cpp/lucent/array.h +12 -2
- package/runtime/cpp/lucent/async.h +101 -21
- package/runtime/cpp/lucent/bigint.cpp +898 -0
- package/runtime/cpp/lucent/bigint.h +302 -0
- package/runtime/cpp/lucent/buffer.cpp +228 -0
- package/runtime/cpp/lucent/buffer.h +328 -0
- package/runtime/cpp/lucent/builtins.cpp +4 -1
- package/runtime/cpp/lucent/bytes.h +21 -2
- package/runtime/cpp/lucent/callback.cpp +29 -0
- package/runtime/cpp/lucent/callback.h +230 -0
- package/runtime/cpp/lucent/compute.cpp +370 -0
- package/runtime/cpp/lucent/compute.h +455 -0
- package/runtime/cpp/lucent/conversions.h +111 -0
- package/runtime/cpp/lucent/core.h +16 -5
- package/runtime/cpp/lucent/equality.h +107 -28
- package/runtime/cpp/lucent/execution.cpp +416 -0
- package/runtime/cpp/lucent/execution.h +270 -0
- package/runtime/cpp/lucent/extension.cpp +97 -0
- package/runtime/cpp/lucent/extension.h +210 -0
- package/runtime/cpp/lucent/helpers.h +12 -5
- package/runtime/cpp/lucent/items.h +52 -0
- package/runtime/cpp/lucent/jserror.cpp +9 -0
- package/runtime/cpp/lucent/jserror.h +11 -0
- package/runtime/cpp/lucent/jsi/convert.cpp +138 -0
- package/runtime/cpp/lucent/jsi/convert.h +128 -59
- package/runtime/cpp/lucent/jsi/host.cpp +213 -35
- package/runtime/cpp/lucent/jsi/host.h +116 -16
- package/runtime/cpp/lucent/json.h +19 -1
- package/runtime/cpp/lucent/lifecycle.cpp +260 -0
- package/runtime/cpp/lucent/lifecycle.h +124 -0
- package/runtime/cpp/lucent/lucent.h +7 -0
- package/runtime/cpp/lucent/map.h +41 -7
- package/runtime/cpp/lucent/native.cpp +35 -47
- package/runtime/cpp/lucent/native.h +116 -26
- package/runtime/cpp/lucent/number.cpp +38 -38
- package/runtime/cpp/lucent/number.h +33 -0
- package/runtime/cpp/lucent/operation.h +65 -0
- package/runtime/cpp/lucent/ops.h +14 -6
- package/runtime/cpp/lucent/platform/android.cpp +223 -10
- package/runtime/cpp/lucent/platform/android.h +227 -4
- package/runtime/cpp/lucent/platform/android_activity.cpp +258 -0
- package/runtime/cpp/lucent/platform/android_requests.h +140 -0
- package/runtime/cpp/lucent/platform/compose.h +256 -0
- package/runtime/cpp/lucent/platform/ios.h +325 -25
- package/runtime/cpp/lucent/platform/ios.mm +1 -14
- package/runtime/cpp/lucent/platform/ios_ui.h +192 -0
- package/runtime/cpp/lucent/platform/ios_ui.mm +454 -0
- package/runtime/cpp/lucent/platform/swiftui.h +190 -0
- package/runtime/cpp/lucent/presentation.cpp +11 -0
- package/runtime/cpp/lucent/presentation.h +109 -0
- package/runtime/cpp/lucent/reactive.cpp +406 -0
- package/runtime/cpp/lucent/reactive.h +566 -0
- package/runtime/cpp/lucent/report.cpp +40 -0
- package/runtime/cpp/lucent/report.h +16 -0
- package/runtime/cpp/lucent/resource.cpp +83 -0
- package/runtime/cpp/lucent/resource.h +75 -0
- package/runtime/cpp/lucent/scheduler.cpp +38 -124
- package/runtime/cpp/lucent/scheduler.h +102 -83
- package/runtime/cpp/lucent/scope.cpp +308 -0
- package/runtime/cpp/lucent/scope.h +452 -0
- package/runtime/cpp/lucent/sizing.h +263 -0
- package/runtime/cpp/lucent/slots.h +231 -0
- package/runtime/cpp/lucent/trace.cpp +539 -0
- package/runtime/cpp/lucent/trace.h +251 -0
- package/runtime/cpp/lucent/transport.cpp +9 -0
- package/runtime/cpp/lucent/transport.h +341 -0
- package/runtime/cpp/lucent/view.cpp +123 -0
- package/runtime/cpp/lucent/view.h +157 -0
- package/runtime/cpp/rn/LucentComponentView.h +121 -0
- package/runtime/cpp/rn/LucentComponentView.mm +479 -0
- package/runtime/cpp/rn/LucentModule.cpp +37 -7
- package/runtime/cpp/rn/LucentModule.h +3 -0
- package/runtime/cpp/rn/LucentViewChildren.h +80 -0
- package/runtime/cpp/rn/LucentViewChildren.mm +211 -0
- package/runtime/cpp/rn/LucentViewRegistry.h +62 -0
- package/runtime/cpp/rn/LucentViewRequests.cpp +91 -0
- package/runtime/cpp/rn/LucentViewRequests.h +104 -0
- package/runtime/cpp/rn/LucentViewSizing.h +345 -0
- package/runtime/cpp/rn/LucentViewSlots.h +242 -0
- package/runtime/cpp/rn/LucentViewValues.h +125 -0
- package/runtime/cpp/rn/LucentViews.h +440 -0
- package/runtime/cpp/rn/LucentViewsAndroid.cpp +439 -0
- package/runtime/cpp/rn/LucentViewsAndroid.h +138 -0
- package/runtime/cpp/third_party/dragonbox/LICENSE-Boost +23 -0
- package/runtime/cpp/third_party/dragonbox/README.md +16 -0
- package/runtime/cpp/third_party/dragonbox/dragonbox.h +4440 -0
- package/runtime/js/index.d.ts +11 -1
- package/runtime/js/index.js +84 -8
- package/runtime/js/views.d.ts +38 -0
- package/runtime/js/views.js +226 -0
- package/runtime/native/android/CMakeLists.txt +4 -1
- package/runtime/native/android/src/compose/java/dev/lucent/compose/CompositionRules.kt +44 -0
- package/runtime/native/android/src/compose/java/dev/lucent/compose/LucentComposition.kt +161 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentActivities.java +292 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentChildren.java +174 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentHostView.java +232 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentInitializer.java +46 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentPackage.java +4 -3
- package/runtime/native/android/src/main/java/dev/lucent/LucentRequestActivity.java +92 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentSlotView.java +102 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentViewManager.java +149 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentViewManagers.java +16 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentViews.java +44 -0
- package/runtime/test/jsi/harness.cpp +9 -0
- package/schemas/build.schema.json +96 -1
- package/schemas/check.schema.json +56 -1
- package/schemas/lucent.schema.json +495 -9
- package/schemas/sdk-diff.schema.json +70 -0
- package/schemas/sdk-lock.schema.json +67 -0
- package/ts-plugin/index.js +77 -4
- package/dist/pipeline-CH7-2cxu.js +0 -232
- package/dist/project-D8tEet0k.js +0 -150
- package/dist/sdk-coverage-BoW_3Efd.js +0 -64
- 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
|
|
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, `
|
|
115
|
-
details: "Each type maps to one native representation. An intersection can combine unrelated layouts, `
|
|
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(
|
|
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(
|
|
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-
|
|
2
|
-
import { A as
|
|
3
|
-
import {
|
|
4
|
-
export { Codes, Explanations, LUCENT_EXTENSION, cachedModules, checkSources, compile, compileDirectory, coreJsPath, coreTypesPath, docsUrl, extractionCount, findLucentFiles, forgetLoadedSdks, formatDiagnostic, inputsKey, isUpToDate, lucentPackages, lucentVersion, moduleNameOf, moduleNamespace,
|
|
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-DlICbK91.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-
|
|
2
|
+
import { i as ACTION_TEXT, n as nextText } from "./pipeline-BBY0df_2.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 {
|
|
4
|
-
import { n as lucentPackages } from "./packages-
|
|
5
|
-
import { n as nextText, r as plural, t as buildProject } from "./pipeline-
|
|
3
|
+
import { D as LUCENT_EXTENSION, M as platformOf, j as moduleNameOf } from "./src-DlICbK91.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-BBY0df_2.js";
|
|
6
6
|
import { t as plainSteps } from "./steps--_h-FFS7.js";
|
|
7
|
-
import { n as systemProbe, t as diagnose } from "./doctor-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
144
|
-
if (
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
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-
|
|
229
|
+
const { dashboard } = await import("./dashboard-C8iF5-6T.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
|
|
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,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-
|
|
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-
|
|
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
|
|
119
|
+
export { satisfies as i, lucentPackages as n, lucentVersion as r, lucentPackageOf as t };
|