Skip to content

Commit 6ae3c04

Browse files
ampagenttmm
andcommitted
build(zero-swift): bundle the CLI for npm
The CLI ran from its TypeScript sources and imported other workspace packages' sources by relative path, so it couldn't be published. `pnpm --filter zero-swift build` now bundles bin.ts with esbuild into dist/, leaving out typescript and @rocicorp/zero. publishConfig points the bin at the bundle. bin.ts is the entry point because cli.ts's own check (its URL against argv[1]) fails behind npm's .bin symlink. @rocicorp/zero is a peer dependency (>=1.11.0, the first release with sync protocol 53): drift record must run the app's own copy. In the workspace, a workspace:* devDependency satisfies it. Checked by packing the CLI and running codegen, codegen --check, and drift record in a scratch app against @rocicorp/zero 1.11.0 from npm. The package stays private, at 0.1.0, until the publish is approved. Amp-Thread-ID: https://ampcode.com/threads/T-c513a037-a257-45e0-b9a9-15c15edfe859 Co-authored-by: tmm <tmm@tmm.dev>
1 parent e1541c3 commit 6ae3c04

8 files changed

Lines changed: 101 additions & 12 deletions

File tree

‎.github/workflows/swift.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ jobs:
4747
run: pnpm --filter zero-swift run test
4848
- name: Check types
4949
run: pnpm --filter zero-conformance --filter zero-swift run check-types
50+
# The published CLI is a bundle; this keeps it bundling.
51+
- name: Build the zero-swift CLI
52+
run: pnpm --filter zero-swift run build
5053
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
5154
with:
5255
name: generated-vectors

‎packages/zero-swift-cli/README.md‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# zero-swift
2+
3+
The command-line tool for [Zero for Swift](https://github.com/wevm/zero-swift).
4+
Your Zero app's TypeScript schema, queries, and mutators stay the source of
5+
truth, and this tool generates what the Swift client needs from them.
6+
7+
```sh
8+
npm install --save-dev zero-swift
9+
```
10+
11+
It needs Node 22.18 or later, which loads TypeScript files directly. It also
12+
needs the app's own `@rocicorp/zero`, 1.11 or later.
13+
14+
## `zero-swift codegen`
15+
16+
Generates Swift from the TypeScript schema. For each table it writes a row
17+
struct, a `ZeroSchema`, and a `zql` builder with a `Query`.
18+
19+
```sh
20+
npx zero-swift codegen # reads zero-swift.json
21+
npx zero-swift codegen --check # fails when the output is out of date
22+
```
23+
24+
```json
25+
{
26+
"schema": "../web/shared/schema.ts",
27+
"output": "Sources/App/Schema.swift",
28+
"schemaName": "app",
29+
"tables": {
30+
"issue": {"columns": {"shortID": {"type": "int"}}}
31+
}
32+
}
33+
```
34+
35+
`number()` columns are `Double`. Set a column's type to `int` to make it an
36+
`Int`; it must then hold integers. For a `json<T>()` column whose `T` is a
37+
plain object or a literal union, the tool generates a `Codable` type.
38+
39+
`--schema`, `--out`, and `--config` override the config file.
40+
41+
## `zero-swift drift record`
42+
43+
You write the Swift queries and mutators by hand, and the drift harness
44+
checks them against the TypeScript ones. This command runs the TypeScript
45+
definitions on samples and records what they did. `Drift.expectNoDrift` in
46+
the Swift `ZeroTesting` library then fails a test wherever the Swift ones
47+
differ.
48+
49+
```sh
50+
npx zero-swift drift record --samples drift-samples.ts --out Tests/AppTests/drift-vectors.json
51+
```
52+
53+
The samples module's default export holds:
54+
55+
- `schema`
56+
- the `queries` and `mutators` registries
57+
- `querySamples`, each a name with optional `args` and `context`
58+
- `mutatorSamples`, each also with optional `seed` rows
59+
60+
Record again whenever either side changes. `--check` fails when the recorded
61+
file is out of date.

‎packages/zero-swift-cli/package.json‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
{
22
"name": "zero-swift",
3-
"version": "0.0.0",
3+
"version": "0.1.0",
44
"private": true,
55
"description": "Generates the Swift row types and schema of a Zero app for the Zero Swift client.",
66
"license": "Apache-2.0",
77
"bin": {
8-
"zero-swift": "./src/cli.ts"
8+
"zero-swift": "./src/bin.ts"
99
},
10+
"files": [
11+
"dist"
12+
],
1013
"type": "module",
14+
"publishConfig": {
15+
"bin": {
16+
"zero-swift": "./dist/bin.js"
17+
}
18+
},
1119
"scripts": {
20+
"build": "esbuild src/bin.ts --bundle --platform=node --format=esm --target=node22 --splitting --outdir=dist --external:@rocicorp/zero --external:typescript",
1221
"test": "vitest run",
1322
"generate": "UPDATE_GENERATED=1 vitest run",
1423
"check-types": "tsc",
@@ -20,11 +29,19 @@
2029
"typescript": "6.0.3"
2130
},
2231
"devDependencies": {
32+
"@rocicorp/zero": "workspace:*",
2333
"@types/node": "^22.10.5",
34+
"esbuild": "0.27.7",
2435
"oxfmt": "^0.65.0",
2536
"vitest": "^5.0.0",
2637
"zero-schema": "workspace:*",
2738
"zero-types": "workspace:*",
2839
"zql": "workspace:*"
40+
},
41+
"peerDependencies": {
42+
"@rocicorp/zero": ">=1.11.0"
43+
},
44+
"engines": {
45+
"node": ">=22.18"
2946
}
3047
}

‎packages/zero-swift-cli/src/bin.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env node
2+
import {main} from './cli.ts';
3+
4+
process.exitCode = await main(process.argv.slice(2));

‎packages/zero-swift-cli/src/cli.ts‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#!/usr/bin/env node
21
/**
32
* `zero-swift codegen`: generates the Swift row types, schema, and query
43
* builder of a Zero app from its TypeScript schema.
@@ -49,7 +48,7 @@ export async function codegenFile(config: Config, cwd: string) {
4948
);
5049
}
5150

52-
async function main(argv: string[]): Promise<number> {
51+
export async function main(argv: string[]): Promise<number> {
5352
const {values, positionals} = parseArgs({
5453
args: argv,
5554
allowPositionals: true,
@@ -120,7 +119,3 @@ function writeOutput(
120119
process.stdout.write(`Wrote ${relative(cwd, output)}\n`);
121120
return 0;
122121
}
123-
124-
if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
125-
process.exitCode = await main(process.argv.slice(2));
126-
}

‎pnpm-lock.yaml‎

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎swift/DESIGN.md‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,11 @@ apps/zbugs-swift/ dogfood app (iOS + macOS)
8484
A `package` type with `@inlinable` members must itself be
8585
`@usableFromInline`, or other modules silently get unspecialized calls.
8686
- The CLI ships as the unscoped npm package `zero-swift` (we don't own the
87-
`@rocicorp` scope) with a peer dependency on `@rocicorp/zero`. It is
88-
versioned with the Swift releases.
87+
`@rocicorp` scope) with a peer dependency on `@rocicorp/zero` (1.11 or
88+
later: `drift record` must run the app's own copy). It is versioned with
89+
the Swift releases. `pnpm --filter zero-swift build` bundles it with
90+
esbuild, inlining the workspace sources it imports. The package stays
91+
`private` until the first publish is approved.
8992
- License: Apache-2.0, like this repository.
9093
- Docs: a DocC catalog per library product, with a getting-started article
9194
and a JS→Swift parity matrix (`Zero.docc/JSParity.md`). Oxfmt skips the

‎swift/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ end-to-end tests against `zero-cache` and the zbugs app.
1616

1717
- Swift 6.2
1818
- iOS 26 or macOS 26. The `Zero` module also builds on Linux.
19-
- A `zero-cache` that speaks sync protocol 53 (Zero 1.12 or later)
19+
- A `zero-cache` that speaks sync protocol 53 (Zero 1.11 or later)
2020

2121
## Install
2222

@@ -89,7 +89,7 @@ Xcode with Product › Build Documentation.
8989

9090
| Zero for Swift | Sync protocol | `zero-cache` | Conformance vectors from |
9191
| -------------- | ------------- | ------------ | ------------------------ |
92-
| 0.1 | 53 | 1.12+ | Zero 1.12.0 |
92+
| 0.1 | 53 | 1.11+ | Zero 1.12 (`main`) |
9393

9494
## License
9595

0 commit comments

Comments
 (0)