@lucent-lang/lucent 0.1.2 → 0.1.3
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/bin/lucent.cjs +2 -0
- package/dist/{bench-Ec_oPBhN.js → bench-BLZugR80.js} +1 -1
- package/dist/{build-B2E9SkG_.js → build-C1Uct_mH.js} +1 -1
- package/dist/{build-check-DYWM9LHo.js → build-check-hlYTmPRd.js} +1 -1
- package/dist/{check-DzsBZmBa.js → check-BksBP--n.js} +1 -1
- package/dist/cli.js +15 -11
- package/dist/{codes-D-6LxUqD.js → codes-B6AgFgAq.js} +24 -2
- package/dist/compiler.js +3 -3
- package/dist/{dashboard--hlNXMUi.js → dashboard-CzOJghrS.js} +1 -1
- package/dist/{dev-ClJalHD4.js → dev-CtaNF3sP.js} +3 -3
- package/dist/{explain-Byit07F-.js → explain-ImANcx5a.js} +1 -1
- package/dist/{pipeline-rDlFUUa1.js → pipeline-DXFTV3Mg.js} +21 -7
- package/dist/{project-MN6cwMwO.js → project-Bp9I-fLP.js} +254 -5
- package/dist/{sdk-coverage-DL81IAi9.js → sdk-coverage-BpbKBG_O.js} +33 -4
- package/dist/{sdk-diff-DbPQmOSD.js → sdk-diff-BueKDJQB.js} +3 -3
- package/dist/{sdk-lock-BWHZdSu-.js → sdk-lock-CKLnZ0Wl.js} +2 -2
- package/dist/{sdk-prefetch-D-MAqtZs.js → sdk-prefetch-rk6MuMe6.js} +2 -2
- package/dist/{sdk-search-BDercg36.js → sdk-search-U_2M81lq.js} +2 -2
- package/dist/{sdk-show-DEdKobD7.js → sdk-show-DG6H40fp.js} +2 -2
- package/dist/{sdk-usage-D_ly-uLw.js → sdk-usage-Cc7u1i0L.js} +1 -1
- package/dist/{src-Bzpv4-ox.js → src-DMbXwPlK.js} +2156 -522
- package/lib/sdk/android.d.ts +12 -0
- package/lib/sdk/compose.d.ts +17 -4
- package/lib/sdk/ui.d.ts +21 -0
- package/package.json +4 -4
- package/runtime/cpp/lucent/platform/android.cpp +152 -16
- package/runtime/cpp/lucent/platform/android.h +79 -2
- package/runtime/cpp/lucent/platform/ios.h +7 -0
- package/runtime/cpp/lucent/platform/ios_ui.h +20 -0
- package/runtime/cpp/rn/LucentComponentView.mm +12 -0
- package/runtime/cpp/rn/LucentViewSizing.h +9 -1
package/bin/lucent.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as identityScript, M as moduleNameOf, P as projectFiles, f as runtimeDir, k as coreJsPath, n as compile } from "./src-DMbXwPlK.js";
|
|
2
2
|
import { i as table } from "./format-D9fnIMEx.js";
|
|
3
3
|
import { t as renderDiagnostic } from "./diagnostic-BvwLZQS1.js";
|
|
4
4
|
import fs from "node:fs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as version } from "./version-bqpIO5sP.js";
|
|
2
2
|
import { i as table, n as duration } from "./format-D9fnIMEx.js";
|
|
3
3
|
import { t as renderDiagnostic } from "./diagnostic-BvwLZQS1.js";
|
|
4
|
-
import { a as filesText, i as ACTION_TEXT, n as nextText, r as plural, t as buildProject } from "./pipeline-
|
|
4
|
+
import { a as filesText, i as ACTION_TEXT, n as nextText, r as plural, t as buildProject } from "./pipeline-DXFTV3Mg.js";
|
|
5
5
|
import { t as plainSteps } from "./steps--_h-FFS7.js";
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path from "node:path";
|
package/dist/cli.js
CHANGED
|
@@ -115,7 +115,7 @@ const commands = [
|
|
|
115
115
|
description: "Fail unless the SDKs and SDK symbols are the ones lucent-sdk.lock.json records, with every target it lists (CI, releases)"
|
|
116
116
|
}
|
|
117
117
|
],
|
|
118
|
-
load: () => import("./build-
|
|
118
|
+
load: () => import("./build-C1Uct_mH.js")
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
name: "check",
|
|
@@ -124,7 +124,7 @@ const commands = [
|
|
|
124
124
|
name: "frozen",
|
|
125
125
|
description: "Fail unless the SDKs and SDK symbols are the ones lucent-sdk.lock.json records, with every target it lists (CI, releases)"
|
|
126
126
|
}],
|
|
127
|
-
load: () => import("./check-
|
|
127
|
+
load: () => import("./check-BksBP--n.js")
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
130
|
name: "dev",
|
|
@@ -133,7 +133,7 @@ const commands = [
|
|
|
133
133
|
name: "compact",
|
|
134
134
|
description: "One line per build instead of the dashboard (Metro runs it so)"
|
|
135
135
|
}],
|
|
136
|
-
load: () => import("./dev-
|
|
136
|
+
load: () => import("./dev-CtaNF3sP.js")
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
name: "doctor",
|
|
@@ -173,13 +173,13 @@ const commands = [
|
|
|
173
173
|
name: "explain",
|
|
174
174
|
summary: "What a LUCENT diagnostic code means, and how to fix it (every code without one)",
|
|
175
175
|
flags: [],
|
|
176
|
-
load: () => import("./explain-
|
|
176
|
+
load: () => import("./explain-ImANcx5a.js")
|
|
177
177
|
},
|
|
178
178
|
{
|
|
179
179
|
name: "bench",
|
|
180
180
|
summary: "Time the cases of your *.bench.ts files natively and as JavaScript, and show the speedup (needs a desktop Hermes)",
|
|
181
181
|
flags: [],
|
|
182
|
-
load: () => import("./bench-
|
|
182
|
+
load: () => import("./bench-BLZugR80.js")
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
name: "trace",
|
|
@@ -208,13 +208,13 @@ const commands = [
|
|
|
208
208
|
name: "sdk search",
|
|
209
209
|
summary: "Find SDK classes and members by name, with the import to copy (your imports and the SDK cache)",
|
|
210
210
|
flags: [],
|
|
211
|
-
load: () => import("./sdk-search-
|
|
211
|
+
load: () => import("./sdk-search-U_2M81lq.js")
|
|
212
212
|
},
|
|
213
213
|
{
|
|
214
214
|
name: "sdk show",
|
|
215
215
|
summary: "Print the declaration Lucent code sees for an SDK type or member: android.os.Vibrator, UIKit.UIDevice.current",
|
|
216
216
|
flags: [],
|
|
217
|
-
load: () => import("./sdk-show-
|
|
217
|
+
load: () => import("./sdk-show-DG6H40fp.js")
|
|
218
218
|
},
|
|
219
219
|
{
|
|
220
220
|
name: "sdk prefetch",
|
|
@@ -237,7 +237,7 @@ const commands = [
|
|
|
237
237
|
description: "Every module of every installed SDK"
|
|
238
238
|
}
|
|
239
239
|
],
|
|
240
|
-
load: () => import("./sdk-prefetch-
|
|
240
|
+
load: () => import("./sdk-prefetch-rk6MuMe6.js")
|
|
241
241
|
},
|
|
242
242
|
{
|
|
243
243
|
name: "sdk lock",
|
|
@@ -247,7 +247,7 @@ const commands = [
|
|
|
247
247
|
value: "list",
|
|
248
248
|
description: "Targets to record: ios, android (default: every platform the project has code for, each needing its SDK)"
|
|
249
249
|
}],
|
|
250
|
-
load: () => import("./sdk-lock-
|
|
250
|
+
load: () => import("./sdk-lock-CKLnZ0Wl.js")
|
|
251
251
|
},
|
|
252
252
|
{
|
|
253
253
|
name: "sdk diff",
|
|
@@ -256,7 +256,7 @@ const commands = [
|
|
|
256
256
|
name: "all",
|
|
257
257
|
description: "Also the other members of the modules the project uses (the locked schemas must be in this machine's SDK cache)"
|
|
258
258
|
}],
|
|
259
|
-
load: () => import("./sdk-diff-
|
|
259
|
+
load: () => import("./sdk-diff-BueKDJQB.js")
|
|
260
260
|
},
|
|
261
261
|
{
|
|
262
262
|
name: "sdk coverage",
|
|
@@ -285,9 +285,13 @@ const commands = [
|
|
|
285
285
|
{
|
|
286
286
|
name: "members",
|
|
287
287
|
description: "List every member with its stage, key and reason"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
name: "views",
|
|
291
|
+
description: "With views on (LUCENT_VIEWS=fabric), list each view class's JSX attributes by rule"
|
|
288
292
|
}
|
|
289
293
|
],
|
|
290
|
-
load: () => import("./sdk-coverage-
|
|
294
|
+
load: () => import("./sdk-coverage-BpbKBG_O.js")
|
|
291
295
|
}
|
|
292
296
|
];
|
|
293
297
|
//#endregion
|
|
@@ -36,6 +36,7 @@ const Codes = {
|
|
|
36
36
|
ComponentMainThread: "LUCENT3022",
|
|
37
37
|
ComponentPlatforms: "LUCENT3023",
|
|
38
38
|
ToolkitBody: "LUCENT3024",
|
|
39
|
+
NativeViewJsx: "LUCENT3025",
|
|
39
40
|
BorrowEscape: "LUCENT3030",
|
|
40
41
|
UseAfterMove: "LUCENT3031",
|
|
41
42
|
TypeScript: "LUCENT9001"
|
|
@@ -58,6 +59,11 @@ const TOOLKIT_TITLE = {
|
|
|
58
59
|
"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
60
|
"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
61
|
};
|
|
62
|
+
const NATIVE_TITLE = {
|
|
63
|
+
"package.json": "{ \"name\": \"example-app\" }\n",
|
|
64
|
+
"title.lucent.tsx": "import type { View } from \"lucent:android/android.view\";\nimport type { UIView } from \"lucent:ios/UIKit\";\nexport declare function Title(props: { title: string }): UIView | View;\n",
|
|
65
|
+
"title.android.lucent.tsx": "import type { View } from \"lucent:android/android.view\";\nimport { TextView } from \"lucent:android/android.widget\";\nexport function Title(props: { title: string }): View {\n return <TextView text={props.title} />;\n}\n"
|
|
66
|
+
};
|
|
61
67
|
const Explanations = {
|
|
62
68
|
LUCENT1001: {
|
|
63
69
|
title: "Syntax outside the subset",
|
|
@@ -151,7 +157,7 @@ const Explanations = {
|
|
|
151
157
|
LUCENT2002: {
|
|
152
158
|
title: "Type without a native representation",
|
|
153
159
|
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.",
|
|
160
|
+
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. A native member whose types cannot cross yet is named with its symbol and artifact: wrap it in Swift or Kotlin of your own.",
|
|
155
161
|
fix: "spell the combined type out as one object type, or use a concrete type",
|
|
156
162
|
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"),
|
|
157
163
|
right: ex("type Person = { name: string; age: number };\nexport function label(p: Person): string {\n return `${p.name} (${p.age})`;\n}\n")
|
|
@@ -384,6 +390,22 @@ const Explanations = {
|
|
|
384
390
|
sdk: "ios",
|
|
385
391
|
views: true
|
|
386
392
|
},
|
|
393
|
+
LUCENT3025: {
|
|
394
|
+
title: "Native view JSX that cannot be compiled",
|
|
395
|
+
summary: "JSX of UIKit or Android views that Lucent cannot make: a view, attribute or child its declarations do not provide for.",
|
|
396
|
+
details: "A component can return its platform's views as JSX, declared as returning UIView or View (internal, under LUCENT_VIEWS=fabric). A tag takes what its class's declarations provide: writable properties, setters, control or listener events, and children where it inserts views at an index. Each attribute is kept up to date like an effect, from when the view mounts.",
|
|
397
|
+
fix: "write each attribute on its element, and set what the declarations do not provide for in setup code",
|
|
398
|
+
wrong: {
|
|
399
|
+
...NATIVE_TITLE,
|
|
400
|
+
"title.ios.lucent.tsx": "import { UILabel, type UIView } from \"lucent:ios/UIKit\";\nexport function Title(props: { title: string }): UIView {\n const attributes = { text: props.title };\n return <UILabel {...attributes} />;\n}\n"
|
|
401
|
+
},
|
|
402
|
+
right: {
|
|
403
|
+
...NATIVE_TITLE,
|
|
404
|
+
"title.ios.lucent.tsx": "import { UILabel, type UIView } from \"lucent:ios/UIKit\";\nexport function Title(props: { title: string }): UIView {\n return <UILabel text={props.title} />;\n}\n"
|
|
405
|
+
},
|
|
406
|
+
sdk: "ios",
|
|
407
|
+
views: true
|
|
408
|
+
},
|
|
387
409
|
LUCENT3030: {
|
|
388
410
|
title: "Borrowed bytes that outlive their borrow",
|
|
389
411
|
summary: "A span that withRead or withWrite lends escapes its callback: returned, stored, kept by a closure or callee, or held across await.",
|
|
@@ -403,7 +425,7 @@ const Explanations = {
|
|
|
403
425
|
LUCENT9001: {
|
|
404
426
|
title: "TypeScript error",
|
|
405
427
|
summary: "A TypeScript error. Lucent stops at type errors, because it compiles from the checker's types.",
|
|
406
|
-
details: "Lucent compiles only programs that type-check: every value's native type comes from the TypeScript checker. The message is TypeScript's own.",
|
|
428
|
+
details: "Lucent compiles only programs that type-check: every value's native type comes from the TypeScript checker. The message is TypeScript's own. When a native library's type lacks a member, Lucent adds which module and installed version declare it, or that its iOS module needs importing.",
|
|
407
429
|
fix: "fix the type error; your editor shows the same message",
|
|
408
430
|
wrong: ex("export function double(n: number): number {\n return n + \"\";\n}\n"),
|
|
409
431
|
right: ex("export function double(n: number): number {\n return n * 2;\n}\n")
|
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
|
|
1
|
+
import { n as Explanations, r as docsUrl, t as Codes } from "./codes-B6AgFgAq.js";
|
|
2
|
+
import { $ as sdkNames, A as coreTypesPath, C as inNativePackage, D as identityScript, E as RUNTIME_ABI, F as usesPlatforms, G as podsSearchPaths, I as moduleNamespace, J as extractionCount, K as cachedModules, L as extensionDts, M as moduleNameOf, N as platformOf, O as LUCENT_EXTENSION, P as projectFiles, R as sdkDts, S as fileHashes, T as forgetExtensionHeaders, X as prefetch, Y as forgetLoadedSdks, Z as sdkAvailable, _ as libraryBuildGradle, a as report, b as EXTENSION_FIELDS, c as sdkModules, d as isUpToDate, f as runtimeDir, g as toolkitsFrom, h as jsxToolkits, i as projectExtensions, it as formatDiagnostic, j as findLucentFiles, k as coreJsPath, l as deferredLibraryGradle, m as viewCoverage, n as compile, o as sdkDeclarations, p as writeNativePackage, r as compileDirectory, s as sdkModule, t as checkSources, u as inputsKey, v as VIEW_CONTRACT_VERSION, w as bindExtensions, x as PACKAGE_FIELDS, y as resolveNative, z as coverage } from "./src-DMbXwPlK.js";
|
|
3
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 };
|
|
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, viewCoverage, writeNativePackage };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as table, n as duration, t as codeFrame } from "./format-D9fnIMEx.js";
|
|
2
|
-
import { i as ACTION_TEXT, n as nextText } from "./pipeline-
|
|
2
|
+
import { i as ACTION_TEXT, n as nextText } from "./pipeline-DXFTV3Mg.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";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as createTheme } from "./theme-uv5bc0aK.js";
|
|
2
2
|
import { n as version } from "./version-bqpIO5sP.js";
|
|
3
|
-
import {
|
|
3
|
+
import { M as moduleNameOf, N as platformOf, O as LUCENT_EXTENSION } from "./src-DMbXwPlK.js";
|
|
4
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-
|
|
5
|
+
import { i as ACTION_TEXT, n as nextText, r as plural, t as buildProject } from "./pipeline-DXFTV3Mg.js";
|
|
6
6
|
import { t as plainSteps } from "./steps--_h-FFS7.js";
|
|
7
7
|
import { n as systemProbe, t as diagnose } from "./doctor-CTAX3euc.js";
|
|
8
8
|
import fs from "node:fs";
|
|
@@ -226,7 +226,7 @@ async function run({ root, flags, out }) {
|
|
|
226
226
|
session.stop();
|
|
227
227
|
return 0;
|
|
228
228
|
}
|
|
229
|
-
const { dashboard } = await import("./dashboard
|
|
229
|
+
const { dashboard } = await import("./dashboard-CzOJghrS.js");
|
|
230
230
|
await dashboard({
|
|
231
231
|
session,
|
|
232
232
|
theme: out.theme,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as Explanations, r as docsUrl } from "./codes-
|
|
1
|
+
import { n as Explanations, r as docsUrl } from "./codes-B6AgFgAq.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 }) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as inNativePackage, F as usesPlatforms, I as moduleNamespace, J as extractionCount, M as moduleNameOf, N as platformOf, P as projectFiles, Q as sdkModuleArtifacts, d as isUpToDate, l as deferredLibraryGradle, n as compile, p as writeNativePackage, s as sdkModule, u as inputsKey, w as bindExtensions, y as resolveNative } from "./src-DMbXwPlK.js";
|
|
2
2
|
import { n as lucentPackages } from "./packages-CSmKeaAh.js";
|
|
3
|
-
import { a as
|
|
4
|
-
import { a as lockProblems, c as sdkUsage, d as writeUsage, i as frozenFailure, l as usageReadable, n as USAGE_FILE, o as readUsage, s as sdkUnavailable, t as LOCK_FILE, u as usedModules } from "./sdk-usage-
|
|
3
|
+
import { a as pendingAndroidModules, c as resolveAndroidDependencies, d as writeLinkedPackage, i as missingAppEntries, l as sdkImports, n as hasAndroidProject, o as projectHashes, r as mapLucentPaths, s as projectSdk, t as backgroundPrefetch, u as staleAutolinking } from "./project-Bp9I-fLP.js";
|
|
4
|
+
import { a as lockProblems, c as sdkUsage, d as writeUsage, i as frozenFailure, l as usageReadable, n as USAGE_FILE, o as readUsage, s as sdkUnavailable, t as LOCK_FILE, u as usedModules } from "./sdk-usage-Cc7u1i0L.js";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
@@ -382,13 +382,23 @@ async function buildProject(root, options, steps, notify) {
|
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
384
|
if (!deferAndroid && !platforms?.includes("android")) {
|
|
385
|
-
const
|
|
386
|
-
|
|
385
|
+
const leftOut = !!platforms;
|
|
386
|
+
const pending = pendingAndroidModules(root, files, sdk, leftOut).map((m) => `lucent:android/${m}`);
|
|
387
|
+
const subject = `${pending.join(", ")} ${pending.length === 1 ? "is" : "are"} untyped`;
|
|
388
|
+
const them = pending.length === 1 ? "it" : "them";
|
|
389
|
+
if (pending.length && leftOut && hasAndroidProject(root)) {
|
|
390
|
+
deferAndroid = true;
|
|
391
|
+
deferReason = "its dependencies are resolved by the Android build";
|
|
392
|
+
notify({
|
|
393
|
+
level: "warn",
|
|
394
|
+
text: `${subject}: this build leaves Android out, and the Android build (lucent build --platforms android, or the app's Gradle build) resolves ${them}`
|
|
395
|
+
});
|
|
396
|
+
} else if (pending.length) {
|
|
387
397
|
deferAndroid = true;
|
|
388
398
|
deferReason = "the app has no Android project yet";
|
|
389
399
|
notify({
|
|
390
400
|
level: "warn",
|
|
391
|
-
text: `${
|
|
401
|
+
text: `${subject}: the app has no Android project to resolve ${them} yet. Checked after expo prebuild, or once android/ exists${platforms ? "" : "; skipped Android here"}`
|
|
392
402
|
});
|
|
393
403
|
}
|
|
394
404
|
}
|
|
@@ -590,7 +600,11 @@ async function buildProject(root, options, steps, notify) {
|
|
|
590
600
|
const w = writeNativePackage(result, outDir, {
|
|
591
601
|
inputsKey: key,
|
|
592
602
|
native,
|
|
593
|
-
androidDeferred: deferred.includes("android")
|
|
603
|
+
androidDeferred: deferred.includes("android"),
|
|
604
|
+
app: {
|
|
605
|
+
...sdk.ios?.deploymentTarget ? { deploymentTarget: sdk.ios.deploymentTarget } : {},
|
|
606
|
+
swiftPackages: sdk.ios?.swiftPackages?.packages ?? []
|
|
607
|
+
}
|
|
594
608
|
});
|
|
595
609
|
const inPackage = (f) => path.relative(outDir, f).split(path.sep).join("/");
|
|
596
610
|
const written = new Set(w.written.map(inPackage));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as packageFile } from "./version-bqpIO5sP.js";
|
|
2
|
-
import {
|
|
2
|
+
import { G as podsSearchPaths, S as fileHashes, Y as forgetLoadedSdks, _ as libraryBuildGradle, c as sdkModules, f as runtimeDir, nt as cacheRoot, rt as hash, y as resolveNative } from "./src-DMbXwPlK.js";
|
|
3
3
|
import { n as lucentPackages } from "./packages-CSmKeaAh.js";
|
|
4
4
|
import { t as withLucentPaths } from "./tsconfig-S4uyLNzf.js";
|
|
5
5
|
import fs from "node:fs";
|
|
@@ -7,6 +7,246 @@ import path from "node:path";
|
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { spawn, spawnSync } from "node:child_process";
|
|
10
|
+
//#region ../bindgen/src/xcode.ts
|
|
11
|
+
function xcodeApp(iosDir) {
|
|
12
|
+
const name = (fs.existsSync(iosDir) ? fs.readdirSync(iosDir) : []).filter((f) => f.endsWith(".xcodeproj") && f !== "Pods.xcodeproj").sort()[0];
|
|
13
|
+
if (!name) return void 0;
|
|
14
|
+
const project = path.join(iosDir, name);
|
|
15
|
+
const file = path.join(project, "project.pbxproj");
|
|
16
|
+
if (!fs.existsSync(file)) return void 0;
|
|
17
|
+
const root = parsePlist(fs.readFileSync(file, "utf8"));
|
|
18
|
+
const objects = root.objects ?? {};
|
|
19
|
+
const object = (id) => typeof id === "string" ? objects[id] : void 0;
|
|
20
|
+
const list = (v) => Array.isArray(v) ? v : [];
|
|
21
|
+
const projectObject = object(root.rootObject);
|
|
22
|
+
const app = list(projectObject?.targets).map(object).find((t) => t?.productType === "com.apple.product-type.application");
|
|
23
|
+
const deploymentOf = (owner) => {
|
|
24
|
+
const configs = list(object(owner?.buildConfigurationList)?.buildConfigurations).map(object).sort((a, b) => Number(b?.name === "Debug") - Number(a?.name === "Debug"));
|
|
25
|
+
for (const c of configs) {
|
|
26
|
+
const value = (c?.buildSettings)?.IPHONEOS_DEPLOYMENT_TARGET;
|
|
27
|
+
if (typeof value === "string") return value;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const deploymentTarget = deploymentOf(app) ?? deploymentOf(projectObject);
|
|
31
|
+
const referenced = new Set(list(projectObject?.packageReferences).map(object).map((r) => r?.repositoryURL).filter((url) => typeof url === "string").map(identityOf));
|
|
32
|
+
const resolved = [path.join(iosDir, name.replace(/\.xcodeproj$/, ".xcworkspace")), path.join(project, "project.xcworkspace")].map((w) => path.join(w, "xcshareddata/swiftpm/Package.resolved")).find((f) => fs.existsSync(f));
|
|
33
|
+
const packages = (resolved ? pinsOf(resolved) : []).filter((p) => referenced.has(p.identity));
|
|
34
|
+
return {
|
|
35
|
+
project,
|
|
36
|
+
...deploymentTarget ? { deploymentTarget } : {},
|
|
37
|
+
packages,
|
|
38
|
+
...resolved ? { resolved } : {}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function identityOf(location) {
|
|
42
|
+
return path.basename(location.replace(/\/+$/, "")).replace(/\.git$/, "").toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
function pinsOf(resolved) {
|
|
45
|
+
const json = JSON.parse(fs.readFileSync(resolved, "utf8"));
|
|
46
|
+
return (json.pins ?? json.object?.pins?.map((p) => ({
|
|
47
|
+
location: p.repositoryURL,
|
|
48
|
+
state: p.state
|
|
49
|
+
})) ?? []).flatMap((p) => {
|
|
50
|
+
const location = p.location;
|
|
51
|
+
const revision = p.state?.revision;
|
|
52
|
+
if (!location || !revision) return [];
|
|
53
|
+
const version = p.state?.version;
|
|
54
|
+
return [{
|
|
55
|
+
identity: "identity" in p && p.identity || identityOf(location),
|
|
56
|
+
location,
|
|
57
|
+
...version ? { version } : {},
|
|
58
|
+
revision
|
|
59
|
+
}];
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function parsePlist(text) {
|
|
63
|
+
let i = 0;
|
|
64
|
+
const skip = () => {
|
|
65
|
+
for (;;) {
|
|
66
|
+
while (i < text.length && /\s/.test(text[i])) i++;
|
|
67
|
+
if (text.startsWith("//", i)) i = text.indexOf("\n", i) < 0 ? text.length : text.indexOf("\n", i);
|
|
68
|
+
else if (text.startsWith("/*", i)) i = text.indexOf("*/", i) + 2;
|
|
69
|
+
else return;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const expect = (c) => {
|
|
73
|
+
skip();
|
|
74
|
+
if (text[i] !== c) throw new Error(`project.pbxproj: expected ${c} at ${i}`);
|
|
75
|
+
i++;
|
|
76
|
+
};
|
|
77
|
+
const string = () => {
|
|
78
|
+
skip();
|
|
79
|
+
if (text[i] === "\"") {
|
|
80
|
+
let out = "";
|
|
81
|
+
for (i++; text[i] !== "\""; i++) {
|
|
82
|
+
if (i >= text.length) throw new Error("project.pbxproj: an unterminated string");
|
|
83
|
+
if (text[i] === "\\") {
|
|
84
|
+
const c = text[++i];
|
|
85
|
+
out += c === "n" ? "\n" : c === "t" ? " " : c;
|
|
86
|
+
} else out += text[i];
|
|
87
|
+
}
|
|
88
|
+
i++;
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
const start = i;
|
|
92
|
+
while (i < text.length && /[\w$./:-]/.test(text[i])) i++;
|
|
93
|
+
if (start === i) throw new Error(`project.pbxproj: a value expected at ${i}`);
|
|
94
|
+
return text.slice(start, i);
|
|
95
|
+
};
|
|
96
|
+
const value = () => {
|
|
97
|
+
skip();
|
|
98
|
+
if (text[i] === "{") {
|
|
99
|
+
i++;
|
|
100
|
+
const dict = {};
|
|
101
|
+
for (skip(); text[i] !== "}"; skip()) {
|
|
102
|
+
const key = string();
|
|
103
|
+
expect("=");
|
|
104
|
+
dict[key] = value();
|
|
105
|
+
expect(";");
|
|
106
|
+
}
|
|
107
|
+
i++;
|
|
108
|
+
return dict;
|
|
109
|
+
}
|
|
110
|
+
if (text[i] === "(") {
|
|
111
|
+
i++;
|
|
112
|
+
const array = [];
|
|
113
|
+
for (skip(); text[i] !== ")"; skip()) {
|
|
114
|
+
array.push(value());
|
|
115
|
+
skip();
|
|
116
|
+
if (text[i] === ",") i++;
|
|
117
|
+
}
|
|
118
|
+
i++;
|
|
119
|
+
return array;
|
|
120
|
+
}
|
|
121
|
+
return string();
|
|
122
|
+
};
|
|
123
|
+
return value();
|
|
124
|
+
}
|
|
125
|
+
const pinName = (p) => `${p.identity}@${p.version ?? p.revision.slice(0, 12)}`;
|
|
126
|
+
function swiftPackages(app, opts = {}) {
|
|
127
|
+
const target = app.deploymentTarget ?? "15.1";
|
|
128
|
+
const pins = app.resolved ? pinsOf(app.resolved) : [];
|
|
129
|
+
const xcode = run("xcodebuild", ["-version"], process.cwd());
|
|
130
|
+
const out = {
|
|
131
|
+
modules: [],
|
|
132
|
+
packages: [],
|
|
133
|
+
...app.resolved ? { resolved: app.resolved } : {},
|
|
134
|
+
failures: []
|
|
135
|
+
};
|
|
136
|
+
if (!app.packages.length) return out;
|
|
137
|
+
if (!xcode.ok) {
|
|
138
|
+
out.failures.push(`xcodebuild did not run: ${xcode.output}`);
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
for (const pin of app.packages) {
|
|
142
|
+
const key = hash([
|
|
143
|
+
pin.identity,
|
|
144
|
+
pin.revision,
|
|
145
|
+
target,
|
|
146
|
+
xcode.output
|
|
147
|
+
]);
|
|
148
|
+
const dir = path.join(cacheRoot(opts.cacheDir), "spm", `${pin.identity}-${key}`);
|
|
149
|
+
const done = path.join(dir, "modules.json");
|
|
150
|
+
try {
|
|
151
|
+
if (!fs.existsSync(done)) build(pin, dir, target, app.resolved);
|
|
152
|
+
const built = JSON.parse(fs.readFileSync(done, "utf8"));
|
|
153
|
+
out.packages.push({
|
|
154
|
+
...pin,
|
|
155
|
+
products: built.products
|
|
156
|
+
});
|
|
157
|
+
out.modules.push(...built.modules);
|
|
158
|
+
} catch (e) {
|
|
159
|
+
out.failures.push(`${pinName(pin)}: ${e.message}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
for (const m of out.modules) {
|
|
163
|
+
const owner = pins.find((p) => p.identity === m.package.slice(0, m.package.lastIndexOf("@")));
|
|
164
|
+
if (owner) m.package = pinName(owner);
|
|
165
|
+
else if (m.package.endsWith("@")) m.package += "unpinned";
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
function build(pin, dir, target, resolved) {
|
|
170
|
+
const src = path.join(dir, "src");
|
|
171
|
+
const derived = path.join(dir, "build");
|
|
172
|
+
fs.rmSync(dir, {
|
|
173
|
+
recursive: true,
|
|
174
|
+
force: true
|
|
175
|
+
});
|
|
176
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
177
|
+
const clone = run("git", [
|
|
178
|
+
"clone",
|
|
179
|
+
"--quiet",
|
|
180
|
+
pin.location,
|
|
181
|
+
src
|
|
182
|
+
], dir);
|
|
183
|
+
if (!clone.ok) throw new Error(`git clone ${pin.location} failed: ${clone.output}`);
|
|
184
|
+
const checkout = run("git", [
|
|
185
|
+
"-c",
|
|
186
|
+
"advice.detachedHead=false",
|
|
187
|
+
"checkout",
|
|
188
|
+
"--quiet",
|
|
189
|
+
pin.revision
|
|
190
|
+
], src);
|
|
191
|
+
if (!checkout.ok) throw new Error(`git checkout ${pin.revision} failed: ${checkout.output}`);
|
|
192
|
+
if (resolved) fs.copyFileSync(resolved, path.join(src, "Package.resolved"));
|
|
193
|
+
const manifest = run("swift", ["package", "dump-package"], src);
|
|
194
|
+
if (!manifest.ok) throw new Error(`swift package dump-package failed: ${manifest.output}`);
|
|
195
|
+
const products = JSON.parse(manifest.stdout).products.filter((p) => "library" in p.type).map((p) => p.name);
|
|
196
|
+
if (!products.length) throw new Error("its manifest declares no library product");
|
|
197
|
+
for (const product of products) {
|
|
198
|
+
const r = run("xcodebuild", [
|
|
199
|
+
"build",
|
|
200
|
+
"-quiet",
|
|
201
|
+
"-scheme",
|
|
202
|
+
product,
|
|
203
|
+
"-destination",
|
|
204
|
+
"generic/platform=iOS Simulator",
|
|
205
|
+
"-derivedDataPath",
|
|
206
|
+
derived,
|
|
207
|
+
"-skipPackagePluginValidation",
|
|
208
|
+
`IPHONEOS_DEPLOYMENT_TARGET=${target}`
|
|
209
|
+
], src);
|
|
210
|
+
if (!r.ok) throw new Error(`xcodebuild of ${product} failed: ${r.output.split("\n").slice(-20).join("\n")}`);
|
|
211
|
+
}
|
|
212
|
+
const built = path.join(derived, "Build/Products/Debug-iphonesimulator");
|
|
213
|
+
const checkouts = path.join(derived, "SourcePackages/checkouts");
|
|
214
|
+
const ownerOf = (module) => {
|
|
215
|
+
for (const id of fs.existsSync(checkouts) ? fs.readdirSync(checkouts) : []) if (fs.existsSync(path.join(checkouts, id, "Sources", module))) return id.toLowerCase();
|
|
216
|
+
return pin.identity;
|
|
217
|
+
};
|
|
218
|
+
const modules = fs.readdirSync(built).flatMap((f) => {
|
|
219
|
+
const [, module, kind] = /^(.+)\.(swiftmodule|framework)$/.exec(f) ?? [];
|
|
220
|
+
if (!module) return [];
|
|
221
|
+
const framework = kind === "framework";
|
|
222
|
+
if (framework && !fs.existsSync(path.join(built, f, "Modules", `${module}.swiftmodule`))) return [];
|
|
223
|
+
const owner = ownerOf(module);
|
|
224
|
+
return [{
|
|
225
|
+
module,
|
|
226
|
+
dir: built,
|
|
227
|
+
...framework ? { framework: true } : {},
|
|
228
|
+
package: owner === pin.identity ? pinName(pin) : `${owner}@`
|
|
229
|
+
}];
|
|
230
|
+
});
|
|
231
|
+
fs.writeFileSync(path.join(dir, "modules.json"), `${JSON.stringify({
|
|
232
|
+
products,
|
|
233
|
+
modules
|
|
234
|
+
}, null, 2)}\n`);
|
|
235
|
+
}
|
|
236
|
+
function run(cmd, args, cwd) {
|
|
237
|
+
const r = spawnSync(cmd, args, {
|
|
238
|
+
cwd,
|
|
239
|
+
encoding: "utf8",
|
|
240
|
+
maxBuffer: 1 << 26
|
|
241
|
+
});
|
|
242
|
+
const stdout = r.stdout ?? "";
|
|
243
|
+
return {
|
|
244
|
+
ok: r.status === 0,
|
|
245
|
+
stdout,
|
|
246
|
+
output: `${stdout}${r.stderr ?? r.error?.message ?? ""}`.trim()
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
//#endregion
|
|
10
250
|
//#region ../bindgen/src/vendored.ts
|
|
11
251
|
function frameworkSearchPath(framework) {
|
|
12
252
|
if (!framework.endsWith(".xcframework")) return path.dirname(framework);
|
|
@@ -65,8 +305,16 @@ function mapLucentPaths(root) {
|
|
|
65
305
|
function projectSdk(root, native) {
|
|
66
306
|
const binaries = native?.binaries ?? packageBinaries(root);
|
|
67
307
|
const pods = podsSearchPaths(path.join(root, "ios"));
|
|
308
|
+
const app = xcodeApp(path.join(root, "ios"));
|
|
309
|
+
const project = app ? {
|
|
310
|
+
...app.deploymentTarget ? { deploymentTarget: app.deploymentTarget } : {},
|
|
311
|
+
...app.packages.length ? { swiftPackages: swiftPackages(app) } : {}
|
|
312
|
+
} : {};
|
|
68
313
|
const frameworkPaths = [...new Set(binaries.ios.map(frameworkSearchPath).filter((dir) => dir !== void 0))];
|
|
69
|
-
const ios = pods || frameworkPaths.length
|
|
314
|
+
const ios = pods || frameworkPaths.length || app ? {
|
|
315
|
+
...pods,
|
|
316
|
+
...project
|
|
317
|
+
} : void 0;
|
|
70
318
|
return {
|
|
71
319
|
android: {
|
|
72
320
|
classpath: path.join(root, ".lucent/android-classpath.json"),
|
|
@@ -280,10 +528,11 @@ function gradleInputsHash(root, native) {
|
|
|
280
528
|
return h.digest("hex").slice(0, 16);
|
|
281
529
|
}
|
|
282
530
|
const gradlewOf = (root) => path.join(root, "android", process.platform === "win32" ? "gradlew.bat" : "gradlew");
|
|
283
|
-
|
|
531
|
+
const hasAndroidProject = (root) => fs.existsSync(gradlewOf(root));
|
|
532
|
+
function pendingAndroidModules(root, files, sdk, withProject = false) {
|
|
284
533
|
const imports = sdkImports(files).android;
|
|
285
534
|
const resolved = sdk.android?.classpath && fs.existsSync(sdk.android.classpath);
|
|
286
|
-
if (!imports.length || resolved ||
|
|
535
|
+
if (!imports.length || resolved || !withProject && hasAndroidProject(root)) return [];
|
|
287
536
|
const available = sdkModules("android", sdk);
|
|
288
537
|
if (!Array.isArray(available)) return [];
|
|
289
538
|
const declared = new Set(available);
|
|
@@ -339,4 +588,4 @@ function backgroundPrefetch(root, files, platforms) {
|
|
|
339
588
|
}).unref();
|
|
340
589
|
}
|
|
341
590
|
//#endregion
|
|
342
|
-
export {
|
|
591
|
+
export { pendingAndroidModules as a, resolveAndroidDependencies as c, writeLinkedPackage as d, missingAppEntries as i, sdkImports as l, hasAndroidProject as n, projectHashes as o, mapLucentPaths as r, projectSdk as s, backgroundPrefetch as t, staleAutolinking as u };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { P as projectFiles, W as symbolKey, c as sdkModules, g as toolkitsFrom, m as viewCoverage, s as sdkModule, tt as sdkSourceModule, z as coverage } from "./src-DMbXwPlK.js";
|
|
2
|
+
import { l as sdkImports, s as projectSdk } from "./project-Bp9I-fLP.js";
|
|
3
3
|
import { i as table } from "./format-D9fnIMEx.js";
|
|
4
|
-
import { n as USAGE_FILE, o as readUsage } from "./sdk-usage-
|
|
4
|
+
import { n as USAGE_FILE, o as readUsage } from "./sdk-usage-Cc7u1i0L.js";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
//#region src/cli/commands/sdk-coverage.ts
|
|
@@ -34,7 +34,15 @@ function run({ root, flags, out }) {
|
|
|
34
34
|
out.error(`${t.error(t.symbols.fail)} ${r.missing}`);
|
|
35
35
|
return 1;
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
const moduleOf = (name) => {
|
|
38
|
+
const found = sdkModule(platform, name, sdk);
|
|
39
|
+
return "missing" in found ? void 0 : found.schema;
|
|
40
|
+
};
|
|
41
|
+
const views = flags.views ? viewCoverage(r.schema, moduleOf) : void 0;
|
|
42
|
+
reports.push({
|
|
43
|
+
...coverage(r.schema, void 0, evidence),
|
|
44
|
+
...views ? { views } : {}
|
|
45
|
+
});
|
|
38
46
|
for (const toolkit of toolkitsFrom(platform, m)) {
|
|
39
47
|
const source = sdkSourceModule(platform, m, sdk);
|
|
40
48
|
if ("missing" in source) {
|
|
@@ -71,6 +79,27 @@ function run({ root, flags, out }) {
|
|
|
71
79
|
"generated",
|
|
72
80
|
"exercised"
|
|
73
81
|
].map((h) => t.dim(h)), ...rows])) out.print(line);
|
|
82
|
+
for (const c of reports) {
|
|
83
|
+
if (!c.views?.length) continue;
|
|
84
|
+
out.print("");
|
|
85
|
+
out.print(t.bold(`${c.module} views`));
|
|
86
|
+
for (const line of table([[
|
|
87
|
+
"view",
|
|
88
|
+
"made",
|
|
89
|
+
"props",
|
|
90
|
+
"events",
|
|
91
|
+
"children",
|
|
92
|
+
"left out"
|
|
93
|
+
].map((h) => t.dim(h)), ...c.views.map((v) => [
|
|
94
|
+
v.view,
|
|
95
|
+
v.made,
|
|
96
|
+
String(v.props.length),
|
|
97
|
+
String(v.events.length),
|
|
98
|
+
v.children ? "yes" : "-",
|
|
99
|
+
String(v.leftOut.length)
|
|
100
|
+
])])) out.print(line.trimEnd());
|
|
101
|
+
if (flags.members) for (const v of c.views) for (const a of [...v.props, ...v.events]) out.print(` ${v.view} ${a.name}: ${t.dim(a.explanation)}`);
|
|
102
|
+
}
|
|
74
103
|
if (flags.members) for (const c of reports) {
|
|
75
104
|
out.print("");
|
|
76
105
|
out.print(t.bold(c.module));
|