@shipworthy/openapi-cli 0.0.2 → 1.0.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.
- package/README.md +165 -103
- package/dist/bin.js +2 -1
- package/dist/cli.d.ts +1 -1
- package/dist/commands/generate/command.d.ts +19 -2
- package/dist/commands/generate/command.js +74 -6
- package/dist/commands/generate/{plugins/typescript/flags.d.ts → flags.d.ts} +5 -4
- package/dist/commands/generate/{plugins/typescript/flags.js → flags.js} +5 -12
- package/dist/commands/generate/output.d.ts +15 -0
- package/dist/commands/generate/output.js +35 -0
- package/dist/commands/generate/plan.d.ts +53 -0
- package/dist/commands/generate/plan.js +93 -0
- package/dist/commands/generate/render.d.ts +25 -0
- package/dist/commands/generate/render.js +63 -0
- package/dist/commands/generate/source.d.ts +5 -0
- package/dist/commands/generate/source.js +18 -0
- package/dist/commands/generate/stamp.d.ts +14 -10
- package/dist/commands/generate/stamp.js +16 -28
- package/dist/commands/input.js +2 -2
- package/dist/commands/overlay/command.js +1 -1
- package/package.json +18 -17
- package/dist/commands/generate/ensure.d.ts +0 -9
- package/dist/commands/generate/ensure.js +0 -31
- package/dist/commands/generate/files.d.ts +0 -4
- package/dist/commands/generate/files.js +0 -16
- package/dist/commands/generate/force.d.ts +0 -2
- package/dist/commands/generate/force.js +0 -2
- package/dist/commands/generate/plugins/standard-schema/plugin.d.ts +0 -7
- package/dist/commands/generate/plugins/standard-schema/plugin.js +0 -44
- package/dist/commands/generate/plugins/tanstack-query/plugin.d.ts +0 -9
- package/dist/commands/generate/plugins/tanstack-query/plugin.js +0 -42
- package/dist/commands/generate/plugins/typescript/plugin.d.ts +0 -32
- package/dist/commands/generate/plugins/typescript/plugin.js +0 -84
- package/dist/commands/generate/plugins/zod/plugin.d.ts +0 -8
- package/dist/commands/generate/plugins/zod/plugin.js +0 -48
- package/dist/commands/generate/publish.d.ts +0 -11
- package/dist/commands/generate/publish.js +0 -23
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Option, Path } from "effect";
|
|
2
|
-
import { CliError, Command } from "effect/cli";
|
|
3
|
-
export declare const dependencies: readonly [];
|
|
4
|
-
export declare const standardSchema: Command.Command<"standard-schema", {
|
|
5
|
-
readonly input: URL;
|
|
6
|
-
readonly output: Option.Option<string>;
|
|
7
|
-
}, {}, CliError.UserError, import("effect/Crypto").Crypto | import("effect/Stdio").Stdio | (import("effect/FileSystem").FileSystem | import("effect/http/HttpClient").HttpClient | Path.Path)>;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { generate as transform } from "@shipworthy/openapi-generator";
|
|
2
|
-
import { Clock, Effect, Option, Path, Result, Schema } from "effect";
|
|
3
|
-
import { Argument, CliError, Command, Flag } from "effect/cli";
|
|
4
|
-
import { asCliError, schemaSource } from "../../../input.js";
|
|
5
|
-
import { publish } from "../../publish.js";
|
|
6
|
-
import { fileHeader, generatorStamp } from "../../stamp.js";
|
|
7
|
-
import { writeStdout } from "../typescript/plugin.js";
|
|
8
|
-
export const dependencies = [];
|
|
9
|
-
const specifier = "@shipworthy/openapi-standard-schema";
|
|
10
|
-
const run = Effect.fn("run")(function* (flags) {
|
|
11
|
-
const output = Option.getOrUndefined(flags.output);
|
|
12
|
-
const started = yield* Clock.currentTimeMillis;
|
|
13
|
-
const decoded = Schema.decodeUnknownResult(Schema.String)(yield* transform({
|
|
14
|
-
specifier,
|
|
15
|
-
exportName: "standardSchema",
|
|
16
|
-
source: flags.input,
|
|
17
|
-
}));
|
|
18
|
-
if (Result.isFailure(decoded)) {
|
|
19
|
-
return yield* new CliError.UserError({ cause: decoded.failure });
|
|
20
|
-
}
|
|
21
|
-
const text = `${fileHeader(yield* generatorStamp(specifier, flags.input))}${decoded.success}`;
|
|
22
|
-
if (!output) {
|
|
23
|
-
yield* writeStdout(text);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const path = yield* Path.Path;
|
|
27
|
-
yield* publish({
|
|
28
|
-
result: text,
|
|
29
|
-
outputPath: path.resolve(output),
|
|
30
|
-
check: false,
|
|
31
|
-
label: flags.input.href,
|
|
32
|
-
outputLabel: output,
|
|
33
|
-
started,
|
|
34
|
-
});
|
|
35
|
-
}, Effect.mapError(asCliError));
|
|
36
|
-
export const standardSchema = Command.make("standard-schema", {
|
|
37
|
-
input: Argument.String("input").pipe(Argument.withDescription("OpenAPI schema file or URL."), Argument.mapEffect(schemaSource)),
|
|
38
|
-
output: Flag.String("output").pipe(Flag.withAlias("o"), Flag.withDescription("Output file. Writes to stdout when omitted."), Flag.optional),
|
|
39
|
-
}, run).pipe(Command.withDescription("Generate Standard Schema validators from an OpenAPI schema."), Command.withShortDescription("Generate Standard Schema validators"), Command.withExamples([
|
|
40
|
-
{
|
|
41
|
-
command: "openapi generate standard-schema ./openapi.yaml -o ./schemas.ts",
|
|
42
|
-
description: "Write Standard Schema validators",
|
|
43
|
-
},
|
|
44
|
-
]));
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Path } from "effect";
|
|
2
|
-
import { CliError, Command } from "effect/cli";
|
|
3
|
-
export declare const dependencies: readonly ["typescript"];
|
|
4
|
-
export declare const tanstackQuery: Command.Command<"tanstack-query", {
|
|
5
|
-
readonly input: URL;
|
|
6
|
-
readonly output: string;
|
|
7
|
-
readonly name: string;
|
|
8
|
-
readonly force: boolean;
|
|
9
|
-
}, {}, CliError.UserError, import("effect/Crypto").Crypto | import("effect/Stdio").Stdio | (import("effect/FileSystem").FileSystem | import("effect/http/HttpClient").HttpClient | Path.Path)>;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { generate as transform } from "@shipworthy/openapi-generator";
|
|
2
|
-
import { Clock, Effect, Path, Result, Schema } from "effect";
|
|
3
|
-
import { Argument, CliError, Command, Flag } from "effect/cli";
|
|
4
|
-
import { asCliError, schemaSource } from "../../../input.js";
|
|
5
|
-
import { ensureDependencies } from "../../ensure.js";
|
|
6
|
-
import { force } from "../../force.js";
|
|
7
|
-
import { ClientName, pascalCase, writeGenerated } from "../../files.js";
|
|
8
|
-
import { fileHeader, generatorStamp } from "../../stamp.js";
|
|
9
|
-
export const dependencies = ["typescript"];
|
|
10
|
-
const specifier = "@shipworthy/openapi-tanstack-query/generator";
|
|
11
|
-
const run = Effect.fn("run")(function* (flags) {
|
|
12
|
-
const started = yield* Clock.currentTimeMillis;
|
|
13
|
-
const path = yield* Path.Path;
|
|
14
|
-
yield* ensureDependencies(dependencies, {
|
|
15
|
-
source: flags.input,
|
|
16
|
-
directory: path.resolve(flags.output, flags.name),
|
|
17
|
-
started,
|
|
18
|
-
force: flags.force,
|
|
19
|
-
});
|
|
20
|
-
const decoded = Schema.decodeUnknownResult(Schema.String)(yield* transform({
|
|
21
|
-
specifier,
|
|
22
|
-
exportName: "tanstackQuery",
|
|
23
|
-
source: flags.input,
|
|
24
|
-
pluginOptions: { prefix: pascalCase(flags.name), name: flags.name },
|
|
25
|
-
}));
|
|
26
|
-
if (Result.isFailure(decoded)) {
|
|
27
|
-
return yield* new CliError.UserError({ cause: decoded.failure });
|
|
28
|
-
}
|
|
29
|
-
const header = fileHeader(yield* generatorStamp(specifier, flags.input));
|
|
30
|
-
yield* writeGenerated(flags.output, flags.name, { "client.ts": `${header}${decoded.success}` });
|
|
31
|
-
}, Effect.mapError(asCliError));
|
|
32
|
-
export const tanstackQuery = Command.make("tanstack-query", {
|
|
33
|
-
input: Argument.String("input").pipe(Argument.withDescription("OpenAPI schema file or URL."), Argument.mapEffect(schemaSource)),
|
|
34
|
-
output: Flag.String("output").pipe(Flag.withAlias("o"), Flag.withDescription("Directory that will contain <name>/client.ts.")),
|
|
35
|
-
name: Flag.String("name").pipe(Flag.withDescription("Client name. Used as the output directory and the generated function prefix."), Flag.withSchema(ClientName)),
|
|
36
|
-
force,
|
|
37
|
-
}, run).pipe(Command.withDescription("Generate TanStack Query utils from an OpenAPI schema."), Command.withShortDescription("Generate TanStack Query utils"), Command.withExamples([
|
|
38
|
-
{
|
|
39
|
-
command: "openapi generate tanstack-query ./openapi.yaml -o ./src/generated --name hotels",
|
|
40
|
-
description: "Write hotels/client.ts",
|
|
41
|
-
},
|
|
42
|
-
]));
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Effect, Option, Path, Stdio } from "effect";
|
|
2
|
-
import { CliError, Command } from "effect/cli";
|
|
3
|
-
import { type TypeFlags } from "./flags.ts";
|
|
4
|
-
export declare const dependencies: readonly [];
|
|
5
|
-
export declare const typescriptSpecifier = "@shipworthy/openapi-typescript";
|
|
6
|
-
export declare const writeStdout: (text: string) => Effect.Effect<void, import("effect/PlatformError").PlatformError, Stdio.Stdio>;
|
|
7
|
-
export declare const renderTypescript: (options: {
|
|
8
|
-
readonly source: URL | string;
|
|
9
|
-
readonly generator: {
|
|
10
|
-
readonly name: string;
|
|
11
|
-
readonly stamp: string;
|
|
12
|
-
};
|
|
13
|
-
readonly outputPath?: string;
|
|
14
|
-
readonly flags: TypeFlags;
|
|
15
|
-
readonly check: boolean;
|
|
16
|
-
readonly label: string;
|
|
17
|
-
readonly outputLabel: string;
|
|
18
|
-
readonly started: number;
|
|
19
|
-
}) => Effect.Effect<void, import("effect/PlatformError").BadArgument | import("effect/PlatformError").PlatformError | import("effect/Schema").SchemaError | CliError.UserError | import("@shipworthy/openapi-generator").GenerateError, Stdio.Stdio | (import("effect/FileSystem").FileSystem | import("effect/http/HttpClient").HttpClient | Path.Path)>;
|
|
20
|
-
export declare const typescript: Command.Command<"typescript", {
|
|
21
|
-
readonly enum: boolean;
|
|
22
|
-
readonly enumValues: boolean;
|
|
23
|
-
readonly conditionalEnums: boolean;
|
|
24
|
-
readonly dedupeEnums: boolean;
|
|
25
|
-
readonly exportType: boolean;
|
|
26
|
-
readonly arrayLength: boolean;
|
|
27
|
-
readonly rootTypes: boolean;
|
|
28
|
-
readonly readWriteMarkers: boolean;
|
|
29
|
-
readonly input: Option.Option<URL>;
|
|
30
|
-
readonly output: Option.Option<string>;
|
|
31
|
-
readonly check: boolean;
|
|
32
|
-
}, {}, CliError.UserError, import("effect/Crypto").Crypto | Stdio.Stdio | (import("effect/FileSystem").FileSystem | import("effect/http/HttpClient").HttpClient | Path.Path)>;
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { generate as transform } from "@shipworthy/openapi-generator";
|
|
2
|
-
import { Clock, Console, Effect, Option, Path, Stdio, Stream } from "effect";
|
|
3
|
-
import { Argument, CliError, Command, Flag } from "effect/cli";
|
|
4
|
-
import { asCliError, schemaSource } from "../../../input.js";
|
|
5
|
-
import { version } from "../../../../version.js";
|
|
6
|
-
import { publish } from "../../publish.js";
|
|
7
|
-
import { fileHeader, generatorStamp } from "../../stamp.js";
|
|
8
|
-
import { pluginOptions, typeFlags } from "./flags.js";
|
|
9
|
-
export const dependencies = [];
|
|
10
|
-
export const typescriptSpecifier = "@shipworthy/openapi-typescript";
|
|
11
|
-
const typescriptModule = Effect.fn("typescriptModule")(function* () {
|
|
12
|
-
return yield* Effect.tryPromise({
|
|
13
|
-
try: () => import("@shipworthy/openapi-typescript"),
|
|
14
|
-
catch: (cause) => new CliError.UserError({ cause }),
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
const readStdin = Effect.fn("readStdin")(function* () {
|
|
18
|
-
const stdio = yield* Stdio.Stdio;
|
|
19
|
-
return yield* stdio.stdin.pipe(Stream.decodeText(), Stream.mkString);
|
|
20
|
-
});
|
|
21
|
-
export const writeStdout = Effect.fn("writeStdout")(function* (text) {
|
|
22
|
-
const stdio = yield* Stdio.Stdio;
|
|
23
|
-
yield* Stream.run(Stream.make(text), stdio.stdout({ endOnDone: false }));
|
|
24
|
-
});
|
|
25
|
-
export const renderTypescript = Effect.fn("renderTypescript")(function* (options) {
|
|
26
|
-
if (options.outputPath)
|
|
27
|
-
yield* Console.info(`openapi generate typescript ${yield* version}`);
|
|
28
|
-
const nodes = yield* transform({
|
|
29
|
-
specifier: typescriptSpecifier,
|
|
30
|
-
exportName: "typescript",
|
|
31
|
-
source: options.source,
|
|
32
|
-
pluginOptions: pluginOptions({ ...options.flags, silent: options.outputPath === undefined }),
|
|
33
|
-
});
|
|
34
|
-
const types = yield* typescriptModule();
|
|
35
|
-
// Print each top-level declaration on its own so a blank line separates them.
|
|
36
|
-
const body = nodes.map((node) => types.astToString([node])).join("\n");
|
|
37
|
-
const printed = yield* Effect.tryPromise({
|
|
38
|
-
try: () => types.formatTypeScript(`${fileHeader(options.generator)}${body}`),
|
|
39
|
-
catch: (cause) => new CliError.UserError({ cause }),
|
|
40
|
-
});
|
|
41
|
-
if (!options.outputPath) {
|
|
42
|
-
yield* writeStdout(printed);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
yield* publish({
|
|
46
|
-
result: printed,
|
|
47
|
-
outputPath: options.outputPath,
|
|
48
|
-
check: options.check,
|
|
49
|
-
label: options.label,
|
|
50
|
-
outputLabel: options.outputLabel,
|
|
51
|
-
started: options.started,
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
const run = Effect.fn("run")(function* (flags) {
|
|
55
|
-
const output = Option.getOrUndefined(flags.output);
|
|
56
|
-
const input = Option.getOrUndefined(flags.input);
|
|
57
|
-
const started = yield* Clock.currentTimeMillis;
|
|
58
|
-
const path = yield* Path.Path;
|
|
59
|
-
const source = input ?? (yield* readStdin());
|
|
60
|
-
yield* renderTypescript({
|
|
61
|
-
source,
|
|
62
|
-
generator: yield* generatorStamp(typescriptSpecifier, source),
|
|
63
|
-
outputPath: output === undefined ? undefined : path.resolve(output),
|
|
64
|
-
flags,
|
|
65
|
-
check: flags.check,
|
|
66
|
-
label: input?.href ?? "stdin",
|
|
67
|
-
outputLabel: output ?? "stdout",
|
|
68
|
-
started,
|
|
69
|
-
});
|
|
70
|
-
}, Effect.mapError(asCliError));
|
|
71
|
-
export const typescript = Command.make("typescript", {
|
|
72
|
-
input: Argument.String("input").pipe(Argument.withDescription("OpenAPI schema file or URL. Omit to read stdin."), Argument.optional, Argument.mapEffect((input) => Option.match(input, {
|
|
73
|
-
onNone: () => Effect.succeed(Option.none()),
|
|
74
|
-
onSome: (value) => Effect.asSome(schemaSource(value)),
|
|
75
|
-
}))),
|
|
76
|
-
output: Flag.String("output").pipe(Flag.withAlias("o"), Flag.withDescription("Output file. Writes to stdout when omitted."), Flag.optional),
|
|
77
|
-
check: Flag.Boolean("check").pipe(Flag.withDescription("Check that the generated types are up-to-date."), Flag.withDefault(false)),
|
|
78
|
-
...typeFlags,
|
|
79
|
-
}, run).pipe(Command.withDescription("Convert an OpenAPI schema to TypeScript."), Command.withShortDescription("Generate TypeScript types"), Command.withExamples([
|
|
80
|
-
{
|
|
81
|
-
command: "openapi generate typescript ./openapi.yaml -o ./schema.ts",
|
|
82
|
-
description: "Write TypeScript types for a local schema",
|
|
83
|
-
},
|
|
84
|
-
]));
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Path } from "effect";
|
|
2
|
-
import { CliError, Command } from "effect/cli";
|
|
3
|
-
export declare const dependencies: readonly ["typescript"];
|
|
4
|
-
export declare const zod: Command.Command<"zod", {
|
|
5
|
-
readonly input: URL;
|
|
6
|
-
readonly output: string;
|
|
7
|
-
readonly force: boolean;
|
|
8
|
-
}, {}, CliError.UserError, import("effect/Crypto").Crypto | import("effect/Stdio").Stdio | (import("effect/FileSystem").FileSystem | import("effect/http/HttpClient").HttpClient | Path.Path)>;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { generate as transform } from "@shipworthy/openapi-generator";
|
|
2
|
-
import { Clock, Effect, Path, Result, Schema } from "effect";
|
|
3
|
-
import { Argument, CliError, Command, Flag } from "effect/cli";
|
|
4
|
-
import { asCliError, schemaSource } from "../../../input.js";
|
|
5
|
-
import { ensureDependencies } from "../../ensure.js";
|
|
6
|
-
import { force } from "../../force.js";
|
|
7
|
-
import { publish } from "../../publish.js";
|
|
8
|
-
import { fileHeader, generatorStamp } from "../../stamp.js";
|
|
9
|
-
export const dependencies = ["typescript"];
|
|
10
|
-
const specifier = "@shipworthy/openapi-zod";
|
|
11
|
-
const run = Effect.fn("run")(function* (flags) {
|
|
12
|
-
const started = yield* Clock.currentTimeMillis;
|
|
13
|
-
const path = yield* Path.Path;
|
|
14
|
-
const outputPath = path.resolve(flags.output);
|
|
15
|
-
yield* ensureDependencies(dependencies, {
|
|
16
|
-
source: flags.input,
|
|
17
|
-
directory: path.dirname(outputPath),
|
|
18
|
-
started,
|
|
19
|
-
force: flags.force,
|
|
20
|
-
});
|
|
21
|
-
const decoded = Schema.decodeUnknownResult(Schema.String)(yield* transform({
|
|
22
|
-
specifier,
|
|
23
|
-
exportName: "zod",
|
|
24
|
-
source: flags.input,
|
|
25
|
-
}));
|
|
26
|
-
if (Result.isFailure(decoded)) {
|
|
27
|
-
return yield* new CliError.UserError({ cause: decoded.failure });
|
|
28
|
-
}
|
|
29
|
-
const header = fileHeader(yield* generatorStamp(specifier, flags.input));
|
|
30
|
-
yield* publish({
|
|
31
|
-
result: `${header}${decoded.success}`,
|
|
32
|
-
outputPath,
|
|
33
|
-
check: false,
|
|
34
|
-
label: flags.input.href,
|
|
35
|
-
outputLabel: flags.output,
|
|
36
|
-
started,
|
|
37
|
-
});
|
|
38
|
-
}, Effect.mapError(asCliError));
|
|
39
|
-
export const zod = Command.make("zod", {
|
|
40
|
-
input: Argument.String("input").pipe(Argument.withDescription("OpenAPI schema file or URL."), Argument.mapEffect(schemaSource)),
|
|
41
|
-
output: Flag.String("output").pipe(Flag.withAlias("o"), Flag.withDescription("Output file. types.ts is written next to it.")),
|
|
42
|
-
force,
|
|
43
|
-
}, run).pipe(Command.withDescription("Generate Zod validators from an OpenAPI schema."), Command.withShortDescription("Generate Zod validators"), Command.withExamples([
|
|
44
|
-
{
|
|
45
|
-
command: "openapi generate zod ./openapi.yaml -o ./src/generated/hotels/zod-schema.ts",
|
|
46
|
-
description: "Write hotels/zod-schema.ts and hotels/types.ts",
|
|
47
|
-
},
|
|
48
|
-
]));
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Effect, FileSystem, Path } from "effect";
|
|
2
|
-
import { CliError } from "effect/cli";
|
|
3
|
-
export declare function formatTime(t: number): string;
|
|
4
|
-
export declare const publish: (options: {
|
|
5
|
-
readonly result: string;
|
|
6
|
-
readonly outputPath: string;
|
|
7
|
-
readonly check: boolean;
|
|
8
|
-
readonly label: string;
|
|
9
|
-
readonly outputLabel: string;
|
|
10
|
-
readonly started: number;
|
|
11
|
-
}) => Effect.Effect<undefined, import("effect/PlatformError").PlatformError | CliError.UserError, FileSystem.FileSystem | Path.Path>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Clock, Console, Effect, FileSystem, Path } from "effect";
|
|
2
|
-
import { CliError } from "effect/cli";
|
|
3
|
-
export function formatTime(t) {
|
|
4
|
-
if (t < 1000)
|
|
5
|
-
return `${Math.round(10 * t) / 10}ms`;
|
|
6
|
-
if (t < 60000)
|
|
7
|
-
return `${Math.round(t / 100) / 10}s`;
|
|
8
|
-
return `${Math.round(t / 6000) / 10}m`;
|
|
9
|
-
}
|
|
10
|
-
export const publish = Effect.fn("publish")(function* (options) {
|
|
11
|
-
const fs = yield* FileSystem.FileSystem;
|
|
12
|
-
const path = yield* Path.Path;
|
|
13
|
-
if (options.check) {
|
|
14
|
-
const previous = yield* fs.readFileString(options.outputPath);
|
|
15
|
-
if (previous === options.result)
|
|
16
|
-
return;
|
|
17
|
-
return yield* new CliError.UserError({ cause: "Generated types are not up-to-date!" });
|
|
18
|
-
}
|
|
19
|
-
yield* fs.makeDirectory(path.dirname(options.outputPath), { recursive: true });
|
|
20
|
-
yield* fs.writeFileString(options.outputPath, options.result);
|
|
21
|
-
const elapsed = (yield* Clock.currentTimeMillis) - options.started;
|
|
22
|
-
yield* Console.log(`${options.label} → ${options.outputLabel} [${formatTime(elapsed)}]`);
|
|
23
|
-
});
|