@swiftbrowser/cli 0.6.7 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +82 -11
  2. package/dist/appSources.d.ts +116 -0
  3. package/dist/appSources.js +624 -0
  4. package/dist/appSources.js.map +1 -0
  5. package/dist/browser.d.ts +4 -0
  6. package/dist/browser.js +8 -0
  7. package/dist/browser.js.map +1 -0
  8. package/dist/build.d.ts +17 -2
  9. package/dist/build.js +38 -11
  10. package/dist/build.js.map +1 -1
  11. package/dist/cli.js +28 -4
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/build.js +10 -7
  14. package/dist/commands/build.js.map +1 -1
  15. package/dist/commands/check.js +38 -8
  16. package/dist/commands/check.js.map +1 -1
  17. package/dist/commands/dev.d.ts +8 -4
  18. package/dist/commands/dev.js +25 -10
  19. package/dist/commands/dev.js.map +1 -1
  20. package/dist/commands/doctor.d.ts +8 -0
  21. package/dist/commands/doctor.js +52 -4
  22. package/dist/commands/doctor.js.map +1 -1
  23. package/dist/commands/kit.d.ts +1 -0
  24. package/dist/commands/kit.js +20 -5
  25. package/dist/commands/kit.js.map +1 -1
  26. package/dist/commands/shared.d.ts +24 -6
  27. package/dist/commands/shared.js +92 -16
  28. package/dist/commands/shared.js.map +1 -1
  29. package/dist/commands/test.d.ts +4 -2
  30. package/dist/commands/test.js +25 -17
  31. package/dist/commands/test.js.map +1 -1
  32. package/dist/compat.d.ts +2 -30
  33. package/dist/compat.js +2 -44
  34. package/dist/compat.js.map +1 -1
  35. package/dist/compiler.d.ts +50 -0
  36. package/dist/compiler.js +94 -0
  37. package/dist/compiler.js.map +1 -0
  38. package/dist/config.d.ts +5 -2
  39. package/dist/config.js +7 -3
  40. package/dist/config.js.map +1 -1
  41. package/dist/frameworks.d.ts +30 -0
  42. package/dist/frameworks.js +48 -0
  43. package/dist/frameworks.js.map +1 -0
  44. package/dist/icu.d.ts +2 -4
  45. package/dist/icu.js +7 -36
  46. package/dist/icu.js.map +1 -1
  47. package/dist/kit.d.ts +62 -17
  48. package/dist/kit.js +183 -33
  49. package/dist/kit.js.map +1 -1
  50. package/dist/log.js +2 -1
  51. package/dist/log.js.map +1 -1
  52. package/dist/manifest.d.ts +73 -0
  53. package/dist/manifest.js +324 -0
  54. package/dist/manifest.js.map +1 -0
  55. package/dist/moduleCache.d.ts +20 -0
  56. package/dist/moduleCache.js +98 -0
  57. package/dist/moduleCache.js.map +1 -0
  58. package/dist/objc.js +1 -1
  59. package/dist/objc.js.map +1 -1
  60. package/dist/packages.d.ts +8 -1
  61. package/dist/packages.js +10 -2
  62. package/dist/packages.js.map +1 -1
  63. package/dist/registry.d.ts +46 -0
  64. package/dist/registry.js +184 -0
  65. package/dist/registry.js.map +1 -0
  66. package/dist/resolve.d.ts +80 -0
  67. package/dist/resolve.js +396 -0
  68. package/dist/resolve.js.map +1 -0
  69. package/dist/stage.d.ts +5 -144
  70. package/dist/stage.js +19 -516
  71. package/dist/stage.js.map +1 -1
  72. package/dist/testDiscovery.d.ts +44 -0
  73. package/dist/testDiscovery.js +111 -0
  74. package/dist/testDiscovery.js.map +1 -0
  75. package/dist/vendor.d.ts +41 -5
  76. package/dist/vendor.js +71 -31
  77. package/dist/vendor.js.map +1 -1
  78. package/dist/wasmCompiler.d.ts +160 -0
  79. package/dist/wasmCompiler.js +628 -0
  80. package/dist/wasmCompiler.js.map +1 -0
  81. package/dist/wasmFlags.d.ts +31 -0
  82. package/dist/wasmFlags.js +56 -0
  83. package/dist/wasmFlags.js.map +1 -0
  84. package/dist/wasmPackages.d.ts +163 -0
  85. package/dist/wasmPackages.js +466 -0
  86. package/dist/wasmPackages.js.map +1 -0
  87. package/dist/wasmSdk.d.ts +27 -0
  88. package/dist/wasmSdk.js +103 -0
  89. package/dist/wasmSdk.js.map +1 -0
  90. package/package.json +6 -5
package/README.md CHANGED
@@ -36,12 +36,15 @@ down), or a plain folder of Swift sources. Options for all of them:
36
36
  (with Swift 6.4 and its Swift SDK for WebAssembly): every module of the shim,
37
37
  and an archive of each module's objects, in a *kit* under
38
38
  `~/.cache/swiftbrowser/kits/` (`SWIFTBROWSER_CACHE` moves the cache). A
39
- released CLI comes with its kit, @swiftbrowser/kit (23 MB to download) and
40
- the macros for your machine (@swiftbrowser/kit-linux-x64, -linux-arm64 or
41
- -darwin-arm64, 4 MB): the first build copies it into the cache and checks
42
- that your toolchain reads its modules. Where it cannot (another host, a
43
- toolchain whose compiler reads only modules it wrote), or in a checkout of
44
- this repository, the first build compiles the kit itself, in a minute or two. A kit takes 83 MB: 50 MB of archives, 15 MB of
39
+ released CLI comes with its kit, @swiftbrowser/kit (36 MB to download): the
40
+ first build copies it into the cache and checks that your toolchain reads its
41
+ modules. Its macros (`@Model`, `#Predicate`, `@Entry`) come built as
42
+ WebAssembly, the same files on every host: the toolchain runs them through a
43
+ small launcher in @swiftbrowser/wasm-compiler, under the Node that runs the
44
+ CLI. Where the kit cannot serve (Windows, where the compiler runs no
45
+ launcher script; a toolchain whose compiler reads only modules it wrote), or
46
+ in a checkout of this repository, the first build compiles the kit itself, in
47
+ a minute or two. A kit takes 83 MB: 50 MB of archives, 15 MB of
45
48
  modules and the 18 MB macro executable; SwiftPM's scratch path for building
46
49
  kits takes 325 MB more.
47
50
  Every app built after that, in any project, compiles its own code and
@@ -55,7 +58,54 @@ the toolchain and the SDK, so a change to any of them (a newer
55
58
  SwiftPM's scratch path for kits stays in the cache, so that rebuild compiles
56
59
  only the modules the change touched, and the three most recent kits are kept.
57
60
  `SWIFTBROWSER_KIT=0` builds the shim from its sources in the app's own build
58
- instead, as before kits. `check` compiles natively and does not use the kit.
61
+ instead, as before kits. A native `check` compiles for the host against the
62
+ shim's sources and does not use the kit.
63
+
64
+ ### The WebAssembly compiler
65
+
66
+ `--compiler` (or `SWIFTBROWSER_COMPILER`, which the flag overrides) picks
67
+ what compiles the app in `check`, `dev`, `build` and `test` (src/compiler.ts):
68
+
69
+ | Value | Builds with |
70
+ |---|---|
71
+ | `auto` (the default) | the Swift toolchain when it is installed (it builds faster), else the WebAssembly compiler, saying why |
72
+ | `native` | the Swift toolchain and SwiftPM |
73
+ | `wasm` | the Swift compiler and linker built as WebAssembly (`@swiftbrowser/wasm-compiler`, the tools from `@swiftbrowser/wasm-tools` or `SWIFTBROWSER_WASM_TOOLS`): no Swift install |
74
+
75
+ So with Swift installed nothing changes, and without it `npx
76
+ @swiftbrowser/cli dev` builds with the npm packages alone, once
77
+ `swiftbrowser doctor --install` has downloaded the Swift SDK for
78
+ WebAssembly's files.
79
+
80
+ The WebAssembly compiler builds against the kit and needs only the Swift
81
+ SDK for WebAssembly's files: the toolchain's install, or, without a
82
+ toolchain, the CLI's own download (`swiftbrowser doctor --install`, 93 MB
83
+ into the cache; src/wasmSdk.ts). Without a toolchain it uses the released
84
+ kit (@swiftbrowser/kit, checked by type-checking an import of every module)
85
+ and cannot build one. It runs the kit's macros
86
+ built as WebAssembly: @swiftbrowser/kit has them, and a kit made here gets
87
+ them from `swiftbrowser kit --wasm-macros` or the first WebAssembly build
88
+ (with a toolchain; minutes the first time, swift-syntax compiling for
89
+ WebAssembly). `check` type-checks against the kit with it. Package
90
+ dependencies build with it too: without SwiftPM in charge (no toolchain, or
91
+ `--compiler wasm`), the CLI resolves them with git, honouring
92
+ `Package.resolved` (src/resolve.ts; registry packages from their
93
+ registry, src/registry.ts), and runs their manifests with the
94
+ WebAssembly tools (src/manifest.ts; @swiftbrowser/wasm-tools ships SwiftPM's
95
+ PackageDescription for this), caching both. C targets in packages compile
96
+ with clang built as WebAssembly, and package traits are followed; Ice Cubes
97
+ builds this way. A package's macro targets (TCA's) build as WebAssembly
98
+ plugins, swift-syntax compiled for them alone (minutes the first time, then
99
+ cached). The packages' compiled modules are cached too, keyed by their
100
+ inputs (src/moduleCache.ts): a rebuild compiles only what an edit reaches,
101
+ and apps share the modules of the packages they have in common. `test`
102
+ builds with it too: the app as a testable module, each test target against
103
+ it, and a runner like SwiftPM's (XCTest's tests listed from the test
104
+ module's symbol graph, Swift Testing's found as it runs; src/testDiscovery.ts),
105
+ with swift-testing's macros built as WebAssembly. In
106
+ `dev` it compiles unoptimized (`-Onone`, without a DEBUG define, so the app
107
+ behaves as it will in `build`) and keeps the compiled tools between
108
+ rebuilds: a save rebuilds Counter in about 5 s, as SwiftPM does.
59
109
 
60
110
  Building several apps in a row (a CI job, a script) can compile the
61
111
  SwiftBrowser package once for all of them: set `SWIFTBROWSER_BUILD_ROOT` to a
@@ -140,7 +190,8 @@ was released with).
140
190
  rebuilds neither from scratch. Each unit-test target is a test target in it
141
191
  that depends on the app's. Its files get the same adjustments, along with
142
192
  the generated alias file, because a test module imports both Foundation and
143
- the app. It links the SDK's whole ICU data rather than a trimmed copy.
193
+ the app. It links the SDK's whole ICU data rather than a trimmed copy. The
194
+ WebAssembly compiler builds the same staging without SwiftPM.
144
195
 
145
196
  ## Foundation
146
197
 
@@ -232,6 +283,7 @@ CI checks.
232
283
  "corsProxy": "https://swiftbrowser-cors-proxy.you.workers.dev/",
233
284
  "packages": [
234
285
  { "url": "https://github.com/twostraws/CodeScanner", "from": "2.5.2", "products": ["CodeScanner"] },
286
+ { "id": "mona.LinkedList", "from": "1.2.0", "products": ["LinkedList"] },
235
287
  { "path": "../Shared", "products": ["SharedKit"] }
236
288
  ]
237
289
  }
@@ -250,9 +302,14 @@ files) one by one.
250
302
 
251
303
  `packages` adds Swift packages to the ones the Xcode target links: the only
252
304
  way a plain folder of sources depends on one. Each has a `url` with one rule
253
- (`from`: up to the next major version, `exact`, `branch` or `revision`), or
254
- a local `path` (relative to the project), and the `products` the app
255
- imports. They are built as described in "Swift packages".
305
+ (`from`: up to the next major version, `exact`, `branch` or `revision`), a
306
+ package registry's `id` (`scope.name`) with `from` or `exact`, or a local
307
+ `path` (relative to the project), and the `products` the app imports. They
308
+ are built as described in "Swift packages". Registries are configured as
309
+ SwiftPM configures them (`swift package-registry set`):
310
+ `.swiftpm/configuration/registries.json` in the app's folder, then in your
311
+ home folder, with credentials in `~/.netrc`; packages that depend on
312
+ registry packages (`.package(id:)`) find them the same way.
256
313
 
257
314
  `corsProxy` (or `--cors-proxy <url>` on `dev` and `build`) names a CORS proxy:
258
315
  the page retries a cross-origin GET or HEAD the browser refused (the server
@@ -413,6 +470,20 @@ git clone --depth 1 https://github.com/apple/sample-food-truck
413
470
  npx @swiftbrowser/cli dev sample-food-truck --target "Food Truck"
414
471
  ```
415
472
 
473
+ [The Composable Architecture](https://github.com/pointfreeco/swift-composable-architecture)
474
+ builds as it is, with the packages it brings (swift-dependencies,
475
+ swift-navigation, swift-sharing, combine-schedulers and the rest): its
476
+ macros (`@Reducer`, `@ObservableState`, `@DependencyClient`) build as
477
+ plugins, and its packages are copied and built against the shim like any
478
+ other. swift-navigation's UIKit layer builds over the shim's UIKit, whose
479
+ views and view controllers are `NSObject`s with iOS 17's traits; the
480
+ Objective-C target it swizzles view controllers with is the shim's own
481
+ lifecycle hooks here. Code a package keeps for older systems
482
+ (`#if canImport(ObjectiveC)`, CoreFoundation imports, `-ObjC` link flags,
483
+ KVO overrides) is adjusted in its copy (src/appSources.ts, vendor.ts). The
484
+ TCACounter fixture (packages/cli/test/fixtures/apps) is a counter, with
485
+ the versions it was made with pinned in its Package.resolved.
486
+
416
487
  A package SwiftBrowser has a patch for is built from its own sources with
417
488
  a few passages replaced first: code that only works with the Objective-C
418
489
  runtime and no general adjustment can take. Today that is
@@ -0,0 +1,116 @@
1
+ export interface TransformResult {
2
+ text: string;
3
+ previewsStripped: number;
4
+ /** `import Foundation` lines rewritten. */
5
+ foundationRewrites: number;
6
+ }
7
+ export declare function transformSource(text: string, options?: {
8
+ bridged?: boolean;
9
+ optionalRequirements?: ReadonlySet<string>;
10
+ }): TransformResult;
11
+ /**
12
+ * `configuration.delegateClass = SceneDelegate.self` →
13
+ * `configuration._setDelegateClass(SceneDelegate.self) { SceneDelegate() }`:
14
+ * UIKit makes the scene delegate through the Objective-C runtime, and Swift
15
+ * without it can only make an instance from a metatype through a `required`
16
+ * initializer (UIKit/SceneDelegates.swift). Same line, so diagnostics keep
17
+ * their places.
18
+ */
19
+ export declare function sceneDelegateClasses(text: string): string;
20
+ /**
21
+ * `as? AnyObject` → `as? _AnyObjectValue` where the file reads a number from
22
+ * the result: `(dict[key] as? AnyObject)?.doubleValue` looks the member up on
23
+ * any object through Objective-C (nil where there is none); FoundationBridge's
24
+ * `_AnyObjectValue` (Selector.swift) has those members, optional likewise, on
25
+ * the numbers, booleans and strings a dictionary of `Any` holds.
26
+ */
27
+ export declare function numberCasts(text: string): string;
28
+ /** Whether a source uses the Objective-C runtime's selectors or attributes. */
29
+ export declare function usesObjC(text: string): boolean;
30
+ /**
31
+ * Whether a source calls POSIX mutex functions. WASI's libc module leaves
32
+ * `pthread.h` out, so a package that does is built from a copy: there
33
+ * `#if os(iOS)` holds (Darwin's `os_unfair_lock` branch) and FoundationBridge
34
+ * declares the mutex functions for the page's single thread (Locks.swift).
35
+ */
36
+ /**
37
+ * `unsafeBitCast(Selector(#function), to: UnsafeRawPointer.self)` →
38
+ * `Selector(#function)._uniquePointer`: the address that stands for the
39
+ * selector's name (FoundationBridge/Selector.swift), which on Apple
40
+ * platforms the bit cast gives, the selector being a uniqued pointer.
41
+ */
42
+ export declare function selectorPointers(text: string): string;
43
+ /** Whether a source imports ObjectiveC, which the SDK does not have on WASI (transformSource). */
44
+ export declare function importsObjectiveC(text: string): boolean;
45
+ /** Whether a source imports Dispatch, which the SDK does not have on WASI (transformSource). */
46
+ export declare function importsDispatch(text: string): boolean;
47
+ /** CoreFoundation's headers need wasi-libc's signal and mman emulations (`WASI_EMULATION_FLAGS`). */
48
+ export declare function importsCoreFoundation(text: string): boolean;
49
+ /** What a Swift module that imports CoreFoundation is compiled with for WASI: the emulations its headers include (the link has their libraries). */
50
+ export declare const WASI_EMULATION_FLAGS: readonly string[];
51
+ export declare function usesPosixMutex(text: string): boolean;
52
+ /**
53
+ * Objective-C without its runtime (FoundationBridge/Selector.swift). The
54
+ * browser's Swift has no Objective-C interop, so `@objc` (and the Interface
55
+ * Builder attributes that imply it) is dropped, and `#selector(handle(_:))`
56
+ * becomes `Selector(Self.handle(_:), name: "handle(_:)")`: the method itself,
57
+ * which the target/selector APIs call on their target. A qualified method
58
+ * (`Type.method`) is used as it is; one of another object
59
+ * (`#selector(model.refresh)`) is called bound; `getter:`/`setter:`
60
+ * selectors only have a name, as does a method of three or more arguments
61
+ * (`navigationController(_:didShow:animated:)`), which target-action never
62
+ * sends (it passes the sender and the event at most) and code only compares
63
+ * or asks about (`responds(to:)`). A method the file declares `@MainActor` is
64
+ * bound to its target in a closure instead,
65
+ * `Selector(name: "tick", isolated: { (target: Self) in target.tick })`:
66
+ * Swift 6 rejects naming a main-actor method of a class that is not
67
+ * `Sendable` unapplied (Gifu's display link proxy).
68
+ */
69
+ export declare function rewriteObjC(text: string): string;
70
+ /** Replaces every `#Preview …{ … }` block and `PreviewProvider` struct with blank lines of the same count. */
71
+ export declare function stripPreviews(text: string): {
72
+ text: string;
73
+ count: number;
74
+ };
75
+ /** Index of the `}` closing the `{` at `open`, skipping strings and comments; -1 when unbalanced. */
76
+ export declare function matchingBrace(text: string, open: number): number;
77
+ /** C-ABI entry points the browser renderer calls; the linker must keep them. */
78
+ export declare const WASM_EXPORTS: string[];
79
+ /** The reconciler recurses once per view; 8 MB of stack like a native thread. */
80
+ export declare const APP_STACK_SIZE: number;
81
+ /**
82
+ * Locale.current follows the host's choice (SB_LOCALE): the two functions
83
+ * that hard-code en_001 in swift-foundation are redirected to FoundationBridge.
84
+ */
85
+ export declare const LOCALE_WRAPS: string[];
86
+ /** The linker flags of the app's target (the manifest's `wasmExports`, without `-Xlinker`). */
87
+ export declare function appLinkerFlags(): string[];
88
+ /** The shim's products the app links: the defaults, SwiftData and the frameworks it imports. */
89
+ export declare function linkedProducts(features: StageFeatures): string[];
90
+ /** What the app's sources use beyond the shim, which decides what the staging links. */
91
+ export interface StageFeatures {
92
+ /**
93
+ * Some file imports SwiftData: the app links the SwiftData product (and so
94
+ * builds its macros, against swift-syntax), and the generated file routes
95
+ * `#Predicate` to SwiftData's copy of the macro.
96
+ */
97
+ swiftData: boolean;
98
+ /** The stand-in frameworks (StoreKit, CoreLocation, LocalAuthentication, CoreML, PhotosUI, CoreImage, UserNotifications, …) some file imports; each is linked. */
99
+ frameworks: readonly string[];
100
+ }
101
+ /** The features `sources` (their text) call for. */
102
+ export declare function featuresOf(sources: readonly string[]): StageFeatures;
103
+ /** The staged file that settles names declared by both the shim and Foundation. */
104
+ export declare const FULL_FOUNDATION_FILE = "_SwiftBrowserFoundation.swift";
105
+ /**
106
+ * The app imports both the shim and Foundation, and both declare a few names
107
+ * (a module does not shadow another's declarations, only the current module's
108
+ * do). A typealias in the app module does: these point the shared names at
109
+ * the shim's types (what its `frame(width:)` and friends take) and at
110
+ * FoundationBridge's `Timer` and `RunLoop`, which Foundation lacks on WASI
111
+ * (`RunLoop` is marked unavailable, its `Timer` needs CFRunLoop and does not
112
+ * link).
113
+ */
114
+ export declare function fullFoundationSource(features?: StageFeatures, declared?: ReadonlySet<string>): string;
115
+ /** The type names a module's sources declare at the top level (lines that start with the declaration). */
116
+ export declare function declaredTypeNames(sources: readonly string[]): Set<string>;