zero-swift 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +23 -0
  2. package/dist/bin.js +279 -68
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -55,6 +55,29 @@ Rename a row struct whose name clashes with a type you use. A table named
55
55
  `list` generates `struct List`, which hides SwiftUI's `List`; set
56
56
  `tables.list.type` to `NoteList`, or set a `typePrefix`.
57
57
 
58
+ ### Names
59
+
60
+ Tables, columns, relationships, JSON fields and enumeration values keep
61
+ their names where Swift allows them, and keywords are backticked. Otherwise:
62
+
63
+ - Characters Swift doesn't allow in identifiers become `_` (`a-b` is
64
+ `a_b`), and a leading digit gets a `_`. A name with none it allows is `_`
65
+ and its code points in hex: the enumeration value `+` is `_2B`.
66
+ - A member that is taken, that the generated code declares (such as
67
+ `columnValues`, `hashValue`, `zeroValue` or `rawValue`), or that Swift
68
+ doesn't allow even backticked (`self`, `Type`, `Protocol`) gets `_`
69
+ appended until it is free: `self_`. Names that need no change are claimed
70
+ first, so with columns `a-b` and `a_b`, `a_b` keeps its name and `a-b` is
71
+ `a_b_`.
72
+ - A row struct name that is a keyword, taken, or a type the generated code
73
+ uses (such as `Zero`, `ZeroRow` or `Codable`) gets `Row`, then a number
74
+ from 2: `zero` is `ZeroRow2`.
75
+
76
+ A renamed member still reads and writes the original name: the column
77
+ names, `CodingKeys`, and enumeration raw values use it.
78
+
79
+ A recursive `json<T>()` type is `JSONValue` where it recurs.
80
+
58
81
  Each config key has an option, such as `--schema-file`, `--out`,
59
82
  `--type-prefix`, and `--access`, that overrides it. `--config` picks the
60
83
  config file. Run `npx zero-swift codegen --help` for the full list.
package/dist/bin.js CHANGED
@@ -9,7 +9,7 @@ import { Cli, z } from "incur";
9
9
  // package.json
10
10
  var package_default = {
11
11
  name: "zero-swift",
12
- version: "0.3.0",
12
+ version: "0.4.1",
13
13
  description: "Generates the Swift row types and schema of a Zero app for the Zero Swift client.",
14
14
  license: "Apache-2.0",
15
15
  repository: {
@@ -95,36 +95,221 @@ var reservedTypeNames = /* @__PURE__ */ new Set([
95
95
  "Int",
96
96
  "Optional",
97
97
  "Set",
98
- "String"
98
+ "String",
99
+ // The protocols the generated types conform to, and the types of their
100
+ // members.
101
+ "AllCases",
102
+ "CaseIterable",
103
+ "Codable",
104
+ "CodingKey",
105
+ "CodingKeys",
106
+ "Decodable",
107
+ "Encodable",
108
+ "Equatable",
109
+ "Hashable",
110
+ "Hasher",
111
+ "Identifiable",
112
+ "KeyPath",
113
+ "PartialKeyPath",
114
+ "RawRepresentable",
115
+ "RawValue",
116
+ "Sendable"
99
117
  ]);
100
118
  var swiftKeywords = new Set(
101
- "associatedtype borrowing class consuming deinit enum extension fileprivate func import init inout internal let nonisolated open operator package private precedencegroup protocol public rethrows static struct subscript typealias var break case catch continue default defer do else fallthrough for guard if in repeat return throw switch where while Any as await false is nil self Self super throws true try".split(" ")
119
+ "associatedtype borrowing class consuming deinit enum extension fileprivate func import init inout internal let nonisolated open operator package private precedencegroup protocol public rethrows static struct subscript typealias var break case catch continue default defer do else fallthrough for guard if in repeat return throw switch where while Any as await false is nil self Self super throws true try _".split(" ")
102
120
  );
103
- var nonIdentifierChars = /[^A-Za-z0-9_]/g;
104
- var leadingDigit = /^[0-9]/;
121
+ var unusableMembers = /* @__PURE__ */ new Set(["self", "Type", "Protocol"]);
122
+ var rowMembers = [
123
+ "tableName",
124
+ "columns",
125
+ "relationships",
126
+ "columnValues",
127
+ "hashValue",
128
+ "CodingKeys",
129
+ // The parameter of `init(entry:)`, which assigns the columns.
130
+ "entry"
131
+ ];
132
+ var objectMembers = [
133
+ "zeroValue",
134
+ "valueForNull",
135
+ "hashValue",
136
+ "CodingKeys",
137
+ // The local of `init(zeroValue:)` and `zeroValue`, which use the fields.
138
+ "o"
139
+ ];
140
+ var enumMembers = [
141
+ "rawValue",
142
+ "RawValue",
143
+ "zeroValue",
144
+ "valueForNull",
145
+ "allCases",
146
+ "AllCases"
147
+ ];
148
+ var asciiIdentifierChar = /[A-Za-z0-9_]/;
149
+ var unicodeIdentifierChar = /[\p{L}\p{M}\p{N}]/u;
105
150
  var wordBoundary = /([a-z0-9])([A-Z])/g;
106
- var wordSeparators = /[^A-Za-z0-9]+/;
107
- var identifierStart = /^[A-Za-z_]/;
108
- function identifier(name) {
109
- let id = name.replace(nonIdentifierChars, "_");
110
- if (leadingDigit.test(id) || id === "") {
111
- id = "_" + id;
151
+ var identifierRanges = [
152
+ [168, 168],
153
+ [170, 170],
154
+ [173, 173],
155
+ [175, 175],
156
+ [178, 181],
157
+ [183, 186],
158
+ [188, 190],
159
+ [192, 214],
160
+ [216, 246],
161
+ [248, 767],
162
+ [768, 879],
163
+ [880, 5759],
164
+ [5761, 6157],
165
+ [6159, 7615],
166
+ [7616, 7679],
167
+ [7680, 8191],
168
+ [8304, 8591],
169
+ [9312, 9471],
170
+ [10102, 10131],
171
+ [11264, 11775],
172
+ [11904, 12287],
173
+ [12292, 12295],
174
+ [12321, 12335],
175
+ [12337, 12351],
176
+ [12352, 55295],
177
+ [63744, 64829],
178
+ [64832, 64975],
179
+ [65008, 65055],
180
+ [65056, 65071],
181
+ [65072, 65092],
182
+ [65095, 65533],
183
+ [65536, 983037]
184
+ ];
185
+ var nonHeadRanges = [
186
+ [48, 57],
187
+ [768, 879],
188
+ [7616, 7679],
189
+ [8400, 8447],
190
+ [65056, 65071]
191
+ ];
192
+ var inRanges = (c, ranges) => ranges.some(([lo, hi]) => c >= lo && c <= hi);
193
+ function isIdentifierChar(ch) {
194
+ const c = ch.codePointAt(0);
195
+ return c < 128 ? asciiIdentifierChar.test(ch) : unicodeIdentifierChar.test(ch) && inRanges(c, identifierRanges);
196
+ }
197
+ function isIdentifierHead(ch) {
198
+ return isIdentifierChar(ch) && !inRanges(ch.codePointAt(0), nonHeadRanges);
199
+ }
200
+ function sanitize(name) {
201
+ const chars = [...name];
202
+ if (!chars.some(isIdentifierChar)) {
203
+ return chars.length ? "_" + chars.map((ch) => ch.codePointAt(0).toString(16).toUpperCase()).join("_") : "_";
112
204
  }
205
+ const id = chars.map((ch) => isIdentifierChar(ch) ? ch : "_");
206
+ return (isIdentifierHead(id[0]) ? "" : "_") + id.join("");
207
+ }
208
+ function ref(id) {
113
209
  return swiftKeywords.has(id) ? "`" + id + "`" : id;
114
210
  }
211
+ function identifier(name) {
212
+ return ref(sanitize(name));
213
+ }
214
+ var Members = class {
215
+ #used;
216
+ constructor(reserved = []) {
217
+ this.#used = new Set(reserved);
218
+ }
219
+ #free(id) {
220
+ return !this.#used.has(id) && !unusableMembers.has(id);
221
+ }
222
+ #available(id, wrapped) {
223
+ return this.#free(id) && (!wrapped || this.#free("_" + id));
224
+ }
225
+ /**
226
+ * A free member for `id`, not backticked. `wrapped` also claims the
227
+ * `_id` storage of a property wrapper.
228
+ */
229
+ claim(id, wrapped = false) {
230
+ while (!this.#available(id, wrapped)) {
231
+ id += "_";
232
+ }
233
+ this.#used.add(id);
234
+ if (wrapped) {
235
+ this.#used.add("_" + id);
236
+ }
237
+ return id;
238
+ }
239
+ /**
240
+ * Claims a member for each name, from `id`, its identifier. The names
241
+ * that are their identifier and free claim first, so a name that works
242
+ * as it is keeps it.
243
+ */
244
+ claimAll(names) {
245
+ const out = [];
246
+ const keep = names.map(
247
+ (n) => n.id === n.name && this.#available(n.id, n.wrapped ?? false)
248
+ );
249
+ for (const pass of [true, false]) {
250
+ for (const [i, n] of names.entries()) {
251
+ if (keep[i] === pass) {
252
+ out[i] = this.claim(n.id, n.wrapped);
253
+ }
254
+ }
255
+ }
256
+ return out;
257
+ }
258
+ };
115
259
  function words(name) {
116
- return name.replace(wordBoundary, "$1 $2").split(wordSeparators).filter((w) => w !== "");
260
+ const out = [];
261
+ let word = "";
262
+ for (const ch of name.replace(wordBoundary, "$1 $2")) {
263
+ if (ch !== "_" && isIdentifierChar(ch)) {
264
+ word += ch;
265
+ } else if (word) {
266
+ out.push(word);
267
+ word = "";
268
+ }
269
+ }
270
+ return word ? [...out, word] : out;
271
+ }
272
+ function capitalize(w) {
273
+ const [first, ...rest] = w;
274
+ return first.toUpperCase() + rest.join("");
117
275
  }
118
276
  function pascalCase(name) {
119
- const out = words(name).map((w) => w[0].toUpperCase() + w.slice(1)).join("");
120
- return identifierStart.test(out) ? out : "_" + out;
277
+ const out = words(name).map(capitalize).join("");
278
+ if (out === "") {
279
+ return sanitize(name);
280
+ }
281
+ return isIdentifierHead([...out][0]) ? out : "_" + out;
121
282
  }
122
283
  function camelCase(name) {
123
284
  const p = pascalCase(name);
124
- return p[0] === "_" ? p : p[0].toLowerCase() + p.slice(1);
285
+ if (p[0] === "_") {
286
+ return p;
287
+ }
288
+ const [first, ...rest] = p;
289
+ return first.toLowerCase() + rest.join("");
125
290
  }
126
291
  function str(s) {
127
- return JSON.stringify(s);
292
+ let out = '"';
293
+ for (const ch of s) {
294
+ const c = ch.codePointAt(0);
295
+ if (ch === '"' || ch === "\\") {
296
+ out += "\\" + ch;
297
+ } else if (ch === "\n") {
298
+ out += "\\n";
299
+ } else if (ch === "\r") {
300
+ out += "\\r";
301
+ } else if (ch === " ") {
302
+ out += "\\t";
303
+ } else if (c < 32 || c === 127 || c >= 55296 && c <= 57343) {
304
+ out += `\\u{${(c >= 55296 && c <= 57343 ? 65533 : c).toString(16)}}`;
305
+ } else {
306
+ out += ch;
307
+ }
308
+ }
309
+ return out + '"';
310
+ }
311
+ function typeTaken(name, used) {
312
+ return used.has(name) || reservedTypeNames.has(name) || swiftKeywords.has(name);
128
313
  }
129
314
  function strings(a) {
130
315
  return `[${a.map(str).join(", ")}]`;
@@ -152,9 +337,13 @@ var Emitter = class {
152
337
  get named() {
153
338
  return this.#named;
154
339
  }
155
- /** A free type name, without the prefix: the alias, else `fallback`. */
156
- #claimBare(preferred, fallback) {
157
- const free = (name) => !this.#names.has(this.#prefix + name) && !reservedTypeNames.has(this.#prefix + name);
340
+ /**
341
+ * A free type name, without the prefix: the alias, else `path` as an
342
+ * identifier, else that with a number.
343
+ */
344
+ #claimBare(preferred, path) {
345
+ const fallback = sanitize(path);
346
+ const free = (name) => sanitize(name) === name && !typeTaken(this.#prefix + name, this.#names);
158
347
  for (const name of [preferred, fallback]) {
159
348
  if (name && free(name)) {
160
349
  this.#names.add(this.#prefix + name);
@@ -206,12 +395,16 @@ var Emitter = class {
206
395
  function generate(schema, customTypes, config, source) {
207
396
  const tableNames = Object.keys(schema.tables);
208
397
  const prefix = config.typePrefix ?? "";
398
+ const schemaName = config.schemaName ?? "app";
399
+ const zqlName = config.zql ?? "zql";
400
+ const zqlType = zqlName === "zql" ? "ZQL" : pascalCase(zqlName);
209
401
  const rowNames = /* @__PURE__ */ new Map();
210
- const used = /* @__PURE__ */ new Set();
402
+ const used = /* @__PURE__ */ new Set([zqlType]);
211
403
  for (const t of tableNames) {
212
- let name = config.tables?.[t]?.type ?? prefix + pascalCase(t);
213
- if (reservedTypeNames.has(name) || used.has(name)) {
214
- name += "Row";
404
+ const preferred = config.tables?.[t]?.type ?? prefix + pascalCase(t);
405
+ let name = preferred;
406
+ for (let i = 1; typeTaken(name, used); i++) {
407
+ name = `${preferred}Row${i === 1 ? "" : i}`;
215
408
  }
216
409
  used.add(name);
217
410
  rowNames.set(t, name);
@@ -219,9 +412,6 @@ function generate(schema, customTypes, config, source) {
219
412
  const e = new Emitter(config.access ?? "public", prefix, used);
220
413
  const bare = (name) => prefix && name.startsWith(prefix) ? name.slice(prefix.length) : name;
221
414
  const pub = e.access;
222
- const schemaName = config.schemaName ?? "app";
223
- const zqlName = config.zql ?? "zql";
224
- const zqlType = zqlName === "zql" ? "ZQL" : pascalCase(zqlName);
225
415
  const out = [
226
416
  `// Generated by \`zero-swift codegen\` from ${source}. Do not edit.`,
227
417
  "// swift-format-ignore-file",
@@ -252,21 +442,27 @@ function generate(schema, customTypes, config, source) {
252
442
  }
253
443
  const optional = c.optional === true;
254
444
  const swiftType = optional && !base.endsWith("?") ? base + "?" : base;
255
- return { name, property: identifier(name), swiftType, optional };
445
+ const id = sanitize(name);
446
+ return { name, id, property: ref(id), swiftType, optional };
256
447
  });
257
448
  const relationships = Object.entries(schema.relationships[t] ?? {}).map(
258
449
  ([name, hops]) => {
259
450
  const last = hops.at(-1);
260
451
  const dest = rowNames.get(last.destSchema);
261
- return {
262
- name,
263
- property: identifier(name),
264
- dest,
265
- one: last.cardinality === "one"
266
- };
452
+ const one = last.cardinality === "one";
453
+ const id = sanitize(name);
454
+ return { name, id, property: ref(id), dest, one };
267
455
  }
268
456
  );
269
- const identifiable = table.primaryKey.length === 1 && table.primaryKey[0] === "id" && columns.some((c) => c.name === "id" && !c.optional);
457
+ const props = [...columns, ...relationships];
458
+ const ids = new Members(rowMembers).claimAll(
459
+ props.map((p) => ({ ...p, wrapped: "one" in p && p.one }))
460
+ );
461
+ for (const [i, p] of props.entries()) {
462
+ p.id = ids[i];
463
+ p.property = ref(ids[i]);
464
+ }
465
+ const identifiable = table.primaryKey.length === 1 && table.primaryKey[0] === "id" && columns.some((c) => c.name === "id" && c.id === "id" && !c.optional);
270
466
  const conformances = ["ZeroRow", "Codable", "Hashable"];
271
467
  if (identifiable) {
272
468
  conformances.push("Identifiable");
@@ -338,6 +534,7 @@ function generate(schema, customTypes, config, source) {
338
534
  }
339
535
  lines.push(" ]");
340
536
  lines.push(" }");
537
+ lines.push(...codingKeys([...columns, ...relationships]));
341
538
  lines.push("}");
342
539
  typeDecls.push(lines.join("\n"));
343
540
  }
@@ -357,11 +554,14 @@ function generate(schema, customTypes, config, source) {
357
554
  );
358
555
  out.push(`${pub}struct ${zqlType}: Sendable {`);
359
556
  out.push(` ${pub}init() {}`);
360
- for (const t of tableNames) {
557
+ const tableIds = new Members().claimAll(
558
+ tableNames.map((t) => ({ name: t, id: sanitize(t) }))
559
+ );
560
+ for (const [i, t] of tableNames.entries()) {
361
561
  const row = rowNames.get(t);
362
562
  out.push("");
363
563
  out.push(
364
- ` ${pub}var ${identifier(t)}: Query<${row}, [${row}]> { Query(AnyQuery(.${schemaName}, ${str(t)})) }`
564
+ ` ${pub}var ${ref(tableIds[i])}: Query<${row}, [${row}]> { Query(AnyQuery(.${schemaName}, ${str(t)})) }`
365
565
  );
366
566
  }
367
567
  out.push("}");
@@ -370,28 +570,43 @@ function generate(schema, customTypes, config, source) {
370
570
  out.push("");
371
571
  return out.join("\n");
372
572
  }
573
+ function codingKeys(props) {
574
+ if (props.every((p) => p.id === p.name)) {
575
+ return [];
576
+ }
577
+ return [
578
+ "",
579
+ " private enum CodingKeys: String, CodingKey {",
580
+ ...props.map(
581
+ (p) => p.id === p.name ? ` case ${p.property}` : ` case ${p.property} = ${str(p.name)}`
582
+ ),
583
+ " }"
584
+ ];
585
+ }
373
586
  function enumDecl(pub, n) {
374
- const used = /* @__PURE__ */ new Set();
587
+ const ids = new Members(enumMembers).claimAll(
588
+ n.cases.map((value) => ({ name: value, id: camelCase(value) }))
589
+ );
375
590
  const lines = [
376
591
  `${pub}enum ${n.name}: String, ZeroEnum, Codable, CaseIterable {`
377
592
  ];
378
- for (const value of n.cases) {
379
- let c = camelCase(value);
380
- while (used.has(c)) {
381
- c += "_";
382
- }
383
- used.add(c);
384
- const id = identifier(c);
385
- lines.push(c === value ? ` case ${id}` : ` case ${id} = ${str(value)}`);
593
+ for (const [i, value] of n.cases.entries()) {
594
+ const c = ids[i];
595
+ lines.push(
596
+ c === value ? ` case ${ref(c)}` : ` case ${ref(c)} = ${str(value)}`
597
+ );
386
598
  }
387
599
  lines.push("}");
388
600
  return lines.join("\n");
389
601
  }
390
602
  function objectDecl(e, pub, n) {
391
- const fields = n.fields.map((f) => {
603
+ const ids = new Members(objectMembers).claimAll(
604
+ n.fields.map((f) => ({ name: f.name, id: sanitize(f.name) }))
605
+ );
606
+ const fields = n.fields.map((f, i) => {
392
607
  const base = e.swiftType(f.type, e.bare(n.name) + pascalCase(f.name));
393
608
  const type = f.optional && !base.endsWith("?") ? base + "?" : base;
394
- return { ...f, property: identifier(f.name), swiftType: type };
609
+ return { ...f, id: ids[i], property: ref(ids[i]), swiftType: type };
395
610
  });
396
611
  const lines = [`${pub}struct ${n.name}: ZeroValue, Codable, Hashable {`];
397
612
  for (const f of fields) {
@@ -426,6 +641,7 @@ function objectDecl(e, pub, n) {
426
641
  }
427
642
  lines.push(" return o.value");
428
643
  lines.push(" }");
644
+ lines.push(...codingKeys(fields));
429
645
  lines.push("}");
430
646
  return lines.join("\n");
431
647
  }
@@ -545,13 +761,17 @@ function property(checker, type, name) {
545
761
  const p = checker.getPropertyOfType(type, name);
546
762
  return p && checker.getTypeOfSymbol(p);
547
763
  }
764
+ var maxDepth = 32;
548
765
  var nullish = ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.Void;
549
- function model(checker, type) {
766
+ function model(checker, type, outer = /* @__PURE__ */ new Set()) {
767
+ if (outer.has(type) || outer.size >= maxDepth) {
768
+ return { kind: "json" };
769
+ }
550
770
  const alias = aliasName(type);
551
771
  if (type.isUnion()) {
552
772
  const parts = type.types.filter((t) => !(t.flags & nullish));
553
773
  const nullable = parts.length !== type.types.length;
554
- const inner = unionModel(checker, parts, alias);
774
+ const inner = unionModel(checker, parts, alias, outer);
555
775
  return nullable ? { kind: "nullable", wrapped: inner } : inner;
556
776
  }
557
777
  if (type.isIntersection()) {
@@ -571,23 +791,24 @@ function model(checker, type) {
571
791
  const [element] = checker.getTypeArguments(type);
572
792
  return {
573
793
  kind: "array",
574
- element: element ? model(checker, element) : { kind: "json" }
794
+ element: element ? model(checker, element, outer) : { kind: "json" }
575
795
  };
576
796
  }
577
797
  if (type.flags & ts.TypeFlags.Object && isPlainObject(checker, type)) {
798
+ const inside = new Set(outer).add(type);
578
799
  const fields = checker.getPropertiesOfType(type).map((p) => {
579
800
  const optional = (p.flags & ts.SymbolFlags.Optional) !== 0;
580
801
  let t = checker.getTypeOfSymbol(p);
581
802
  if (optional) {
582
803
  t = checker.getNonNullableType(t);
583
804
  }
584
- return { name: p.name, type: model(checker, t), optional };
805
+ return { name: p.name, type: model(checker, t, inside), optional };
585
806
  });
586
807
  return { kind: "object", ...alias ? { alias } : {}, fields };
587
808
  }
588
809
  return { kind: "json" };
589
810
  }
590
- function unionModel(checker, parts, alias) {
811
+ function unionModel(checker, parts, alias, outer) {
591
812
  if (parts.length === 0) return { kind: "json" };
592
813
  if (parts.every((t) => t.isStringLiteral())) {
593
814
  return enumModel(
@@ -601,7 +822,7 @@ function unionModel(checker, parts, alias) {
601
822
  if (parts.every((t) => t.flags & ts.TypeFlags.NumberLike)) {
602
823
  return { kind: "number" };
603
824
  }
604
- if (parts.length === 1) return model(checker, parts[0]);
825
+ if (parts.length === 1) return model(checker, parts[0], outer);
605
826
  return { kind: "json" };
606
827
  }
607
828
  function enumModel(cases, alias) {
@@ -707,7 +928,7 @@ var cli = Cli.create("zero-swift", {
707
928
  version: package_default.version,
708
929
  description: "Generates what the Zero Swift client needs from a Zero app's TypeScript schema, queries, and mutators."
709
930
  }).command("codegen", {
710
- description: "Generate the Swift row types, schema, and query builder from the app's TypeScript schema. Options override zero-swift.json, which is read when present.",
931
+ description: "Generate the Swift row types, schema, and query builder from the app's TypeScript schema. Options override zero-swift.json, which is read when present. See swift/Sources/Zero/Zero.docc/GettingStarted.md in github.com/wevm/zero.",
711
932
  options: z.object({
712
933
  config: z.string().optional().describe("Config file (default zero-swift.json, when present)"),
713
934
  schemaFile: z.string().optional().describe("TS schema module (default schema.ts)"),
@@ -719,20 +940,10 @@ var cli = Cli.create("zero-swift", {
719
940
  access: z.enum(["public", "internal"]).optional().describe("Access level of the generated code (default public)"),
720
941
  check
721
942
  }),
722
- examples: [
723
- { description: "Generate from zero-swift.json" },
724
- {
725
- options: {
726
- schemaFile: "shared/schema.ts",
727
- out: "Sources/App/Schema.swift"
728
- },
729
- description: "Generate without a config file"
730
- },
731
- {
732
- options: { check: true },
733
- description: "Fail in CI when the output is stale"
734
- }
735
- ],
943
+ // incur 0.7.1 prints example options as `--camelKey value`, so the hint
944
+ // shows `--schema-file` and a bare `--check` instead.
945
+ examples: [{ description: "Generate from zero-swift.json" }],
946
+ hint: "Without a config file: zero-swift codegen --schema-file shared/schema.ts --out Sources/App/Schema.swift. In CI, zero-swift codegen --check fails when the output is stale.",
736
947
  run: (c) => reporting(c.error, async () => {
737
948
  const cwd = process.cwd();
738
949
  const {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zero-swift",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Generates the Swift row types and schema of a Zero app for the Zero Swift client.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -25,9 +25,9 @@
25
25
  "oxfmt": "^0.74.0",
26
26
  "vitest": "^5.0.0",
27
27
  "@rocicorp/zero": "1.12.0",
28
+ "zero-schema": "0.0.0",
28
29
  "zero-types": "0.0.0",
29
- "zql": "0.0.0",
30
- "zero-schema": "0.0.0"
30
+ "zql": "0.0.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@rocicorp/zero": ">=1.11.0"