Skip to content

Commit 0a7b9b5

Browse files
tmmampagent
andauthored
fix(zero-swift): name codegen options in kebab-case so help examples print as typed (#21)
incur prints example option keys as-is, so camelCase keys printed --schemaFile. The schema keys are now schema-file, schema-name and type-prefix; legacyArgv still maps the camelCase spellings. Amp-Thread-ID: https://ampcode.com/threads/T-c513a037-a257-45e0-b9a9-15c15edfe859 Co-authored-by: Amp <amp@ampcode.com>
1 parent 2134344 commit 0a7b9b5

3 files changed

Lines changed: 72 additions & 17 deletions

File tree

‎.changeset/cli-kebab-options.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'zero-swift': patch
3+
---
4+
5+
`codegen`'s options are named `schema-file`, `schema-name`, and `type-prefix` in its JSON Schema (`--schema`), so its help prints the "Generate without a config file" example again, with `--schema-file` as it is typed. `--schemaFile`, `--schemaName`, and `--typePrefix` still work.

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

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,15 @@ function writeOutput(
117117
return {path, written: current !== contents};
118118
}
119119

120+
const camelOption = /^--(schemaFile|schemaName|typePrefix)(=|$)/;
121+
const upperCase = /[A-Z]/g;
122+
120123
/**
121124
* incur reserves `--schema` (it prints a command's JSON Schema), so codegen's
122125
* schema module is `--schema-file`. This keeps 0.1.0's `codegen --schema
123-
* <path>` working; a bare `--schema` still prints the JSON Schema.
126+
* <path>` working; a bare `--schema` still prints the JSON Schema. The
127+
* options are kebab-case keys, so help examples print as typed; this also
128+
* keeps the camelCase spellings that worked before 0.4.3.
124129
*/
125130
export function legacyArgv(argv: readonly string[]): string[] {
126131
if (argv[0] !== 'codegen') return [...argv];
@@ -133,6 +138,10 @@ export function legacyArgv(argv: readonly string[]): string[] {
133138
i++;
134139
} else if (token.startsWith('--schema=')) {
135140
out.push('--schema-file', token.slice('--schema='.length));
141+
} else if (camelOption.test(token)) {
142+
const [name, ...value] = token.split('=');
143+
const kebab = name!.replace(upperCase, c => `-${c.toLowerCase()}`);
144+
out.push([kebab, ...value].join('='));
136145
} else {
137146
out.push(token);
138147
}
@@ -153,50 +162,61 @@ export const cli = Cli.create('zero-swift', {
153162
description:
154163
"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.",
155164
options: z.object({
156-
config: z
165+
'config': z
157166
.string()
158167
.optional()
159168
.describe('Config file (default zero-swift.json, when present)'),
160-
schemaFile: z
169+
'schema-file': z
161170
.string()
162171
.optional()
163172
.describe('TS schema module (default schema.ts)'),
164-
export: z
173+
'export': z
165174
.string()
166175
.optional()
167176
.describe('Export of the module that holds the schema (default schema)'),
168-
out: z
177+
'out': z
169178
.string()
170179
.optional()
171180
.describe('Swift file to write (default Schema.swift)'),
172-
schemaName: z
181+
'schema-name': z
173182
.string()
174183
.optional()
175184
.describe('Name of the generated ZeroSchema static (default app)'),
176-
zql: z
185+
'zql': z
177186
.string()
178187
.optional()
179188
.describe('Name of the generated query builder global (default zql)'),
180-
typePrefix: z
189+
'type-prefix': z
181190
.string()
182191
.optional()
183192
.describe('Prefix for every generated type name (default none)'),
184-
access: z
193+
'access': z
185194
.enum(['public', 'internal'])
186195
.optional()
187196
.describe('Access level of the generated code (default public)'),
188197
check,
189198
}),
190-
// incur 0.7.1 prints example options as `--camelKey value`, so the hint
191-
// shows `--schema-file` and a bare `--check` instead.
192-
examples: [{description: 'Generate from zero-swift.json'}],
193-
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.',
199+
// incur 0.7.1 prints a boolean example option as `--check true`, so the
200+
// hint shows a bare `--check` instead.
201+
examples: [
202+
{description: 'Generate from zero-swift.json'},
203+
{
204+
options: {
205+
'schema-file': 'shared/schema.ts',
206+
'out': 'Sources/App/Schema.swift',
207+
},
208+
description: 'Generate without a config file',
209+
},
210+
],
211+
hint: 'In CI, zero-swift codegen --check fails when the output is stale.',
194212
run: c =>
195213
reporting(c.error, async () => {
196214
const cwd = process.cwd();
197215
const {
198-
config: configOption,
199-
schemaFile,
216+
'config': configOption,
217+
'schema-file': schemaFile,
218+
'schema-name': schemaName,
219+
'type-prefix': typePrefix,
200220
out,
201221
check,
202222
...overrides
@@ -219,7 +239,9 @@ export const cli = Cli.create('zero-swift', {
219239
const config: Config = {
220240
...fileConfig,
221241
...Object.fromEntries(
222-
Object.entries(overrides).filter(([, v]) => v !== undefined),
242+
Object.entries({...overrides, schemaName, typePrefix}).filter(
243+
([, v]) => v !== undefined,
244+
),
223245
),
224246
...(schemaFile ? {schema: schemaFile} : {}),
225247
...(out ? {output: out} : {}),

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import {readFileSync, writeFileSync} from 'node:fs';
1+
import {mkdtempSync, readFileSync, rmSync, writeFileSync} from 'node:fs';
2+
import {tmpdir} from 'node:os';
3+
import {join} from 'node:path';
24
import {fileURLToPath} from 'node:url';
35
import {expect, test} from 'vitest';
46
import {cli, codegenFile, legacyArgv} from './cli.ts';
@@ -112,3 +114,29 @@ test('a missing schema is a usage error, not a crash', async () => {
112114
message: `Schema no-such-schema.ts doesn't exist. Pass --schema-file, or set "schema" in zero-swift.json.`,
113115
});
114116
});
117+
118+
test('camelCase options from before 0.4.3 still work', async () => {
119+
const dir = mkdtempSync(join(tmpdir(), 'zero-swift-cli-'));
120+
const out = join(dir, 'Schema.swift');
121+
try {
122+
let code: number | undefined;
123+
await cli.serve(
124+
legacyArgv([
125+
'codegen',
126+
`--schemaFile=${fileURLToPath(new URL('../test/fixture-schema.ts', import.meta.url))}`,
127+
'--typePrefix',
128+
'Kx',
129+
'--schemaName=kx',
130+
'--out',
131+
out,
132+
]),
133+
{stdout: () => {}, exit: c => (code = c)},
134+
);
135+
expect(code ?? 0).toBe(0);
136+
const swift = readFileSync(out, 'utf8');
137+
expect(swift).toContain('public struct KxProject');
138+
expect(swift).toContain('static let kx');
139+
} finally {
140+
rmSync(dir, {recursive: true, force: true});
141+
}
142+
});

0 commit comments

Comments
 (0)