@effect/openapi-generator 4.0.0-beta.8 → 4.0.0-beta.80

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 (41) hide show
  1. package/dist/HttpApiTransformer.d.ts +41 -0
  2. package/dist/HttpApiTransformer.d.ts.map +1 -0
  3. package/dist/HttpApiTransformer.js +383 -0
  4. package/dist/HttpApiTransformer.js.map +1 -0
  5. package/dist/JsonSchemaGenerator.d.ts +25 -3
  6. package/dist/JsonSchemaGenerator.d.ts.map +1 -1
  7. package/dist/JsonSchemaGenerator.js +178 -47
  8. package/dist/JsonSchemaGenerator.js.map +1 -1
  9. package/dist/OpenApiGenerator.d.ts +81 -7
  10. package/dist/OpenApiGenerator.d.ts.map +1 -1
  11. package/dist/OpenApiGenerator.js +707 -119
  12. package/dist/OpenApiGenerator.js.map +1 -1
  13. package/dist/OpenApiPatch.d.ts +47 -24
  14. package/dist/OpenApiPatch.d.ts.map +1 -1
  15. package/dist/OpenApiPatch.js +42 -19
  16. package/dist/OpenApiPatch.js.map +1 -1
  17. package/dist/OpenApiTransformer.d.ts +85 -12
  18. package/dist/OpenApiTransformer.d.ts.map +1 -1
  19. package/dist/OpenApiTransformer.js +85 -8
  20. package/dist/OpenApiTransformer.js.map +1 -1
  21. package/dist/ParsedOperation.d.ts +172 -1
  22. package/dist/ParsedOperation.d.ts.map +1 -1
  23. package/dist/ParsedOperation.js +32 -0
  24. package/dist/ParsedOperation.js.map +1 -1
  25. package/dist/Utils.d.ts +51 -0
  26. package/dist/Utils.d.ts.map +1 -1
  27. package/dist/Utils.js +61 -0
  28. package/dist/Utils.js.map +1 -1
  29. package/dist/main.d.ts +12 -0
  30. package/dist/main.d.ts.map +1 -1
  31. package/dist/main.js +41 -8
  32. package/dist/main.js.map +1 -1
  33. package/package.json +10 -8
  34. package/src/HttpApiTransformer.ts +538 -0
  35. package/src/JsonSchemaGenerator.ts +272 -47
  36. package/src/OpenApiGenerator.ts +994 -173
  37. package/src/OpenApiPatch.ts +56 -31
  38. package/src/OpenApiTransformer.ts +89 -12
  39. package/src/ParsedOperation.ts +220 -1
  40. package/src/Utils.ts +61 -0
  41. package/src/main.ts +58 -10
package/src/Utils.ts CHANGED
@@ -1,6 +1,27 @@
1
+ /**
2
+ * Shared utility helpers for the OpenAPI generator.
3
+ *
4
+ * This module centralizes the small transformations used while rendering
5
+ * generated TypeScript, including operation-name normalization, optional
6
+ * description handling, safe JSDoc comment emission, and direct array merging
7
+ * for code-generation accumulators.
8
+ *
9
+ * @since 4.0.0
10
+ */
1
11
  import * as String from "effect/String"
2
12
  import * as UndefinedOr from "effect/UndefinedOr"
3
13
 
14
+ /**
15
+ * Converts an OpenAPI name into the generator's camel-case form.
16
+ *
17
+ * **Details**
18
+ *
19
+ * Separators are removed, leading digits are ignored, and letters following a
20
+ * separator or digit are upper-cased without otherwise changing letter casing.
21
+ *
22
+ * @category converting
23
+ * @since 4.0.0
24
+ */
4
25
  export const camelize = (self: string): string => {
5
26
  let str = ""
6
27
  let hadSymbol = false
@@ -24,8 +45,26 @@ export const camelize = (self: string): string => {
24
45
  return str
25
46
  }
26
47
 
48
+ /**
49
+ * Converts an OpenAPI operation id into the exported operation identifier used
50
+ * by generated TypeScript modules.
51
+ *
52
+ * @category converting
53
+ * @since 4.0.0
54
+ */
27
55
  export const identifier = (operationId: string) => String.capitalize(camelize(operationId))
28
56
 
57
+ /**
58
+ * Extracts a trimmed, non-empty string from an unknown value.
59
+ *
60
+ * **Details**
61
+ *
62
+ * Returns `undefined` for non-string values and for strings containing only
63
+ * whitespace.
64
+ *
65
+ * @category filtering
66
+ * @since 4.0.0
67
+ */
29
68
  export const nonEmptyString = (a: unknown): string | undefined => {
30
69
  if (typeof a === "string") {
31
70
  const trimmed = String.trim(a)
@@ -35,6 +74,17 @@ export const nonEmptyString = (a: unknown): string | undefined => {
35
74
  }
36
75
  }
37
76
 
77
+ /**
78
+ * Renders an optional description as a JSDoc block for generated TypeScript.
79
+ *
80
+ * **Details**
81
+ *
82
+ * Returns an empty string when the description is absent and escapes any
83
+ * closing comment marker so generated source remains syntactically valid.
84
+ *
85
+ * @category converting
86
+ * @since 4.0.0
87
+ */
38
88
  export const toComment = UndefinedOr.match({
39
89
  onUndefined: () => "",
40
90
  onDefined: (description: string) =>
@@ -43,6 +93,17 @@ export const toComment = UndefinedOr.match({
43
93
  */\n`
44
94
  })
45
95
 
96
+ /**
97
+ * Appends every element from `source` into `destination` in order.
98
+ *
99
+ * **Details**
100
+ *
101
+ * This mutates `destination` directly, which avoids allocating an intermediate
102
+ * array when generator code needs to merge collections.
103
+ *
104
+ * @category concatenating
105
+ * @since 4.0.0
106
+ */
46
107
  export const spreadElementsInto = <A>(source: Array<A>, destination: Array<A>): void => {
47
108
  for (let i = 0; i < source.length; i++) {
48
109
  destination.push(source[i])
package/src/main.ts CHANGED
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Command-line entry point for generating Effect HTTP clients or HttpApi
3
+ * definitions from an OpenAPI specification.
4
+ *
5
+ * The CLI reads a spec file, optionally applies JSON patches in order, selects
6
+ * the generator layer for the requested output format, reports generation
7
+ * warnings to stderr, and writes the generated source to stdout.
8
+ *
9
+ * @since 4.0.0
10
+ */
1
11
  import * as Console from "effect/Console"
2
12
  import * as Effect from "effect/Effect"
3
13
  import type * as Schema from "effect/Schema"
@@ -10,18 +20,21 @@ import * as OpenApiPatch from "./OpenApiPatch.ts"
10
20
 
11
21
  const spec = Flag.fileParse("spec").pipe(
12
22
  Flag.withAlias("s"),
13
- Flag.withDescription("The OpenAPI spec file to generate the client from")
23
+ Flag.withDescription("The OpenAPI spec file to generate output from")
14
24
  )
15
25
 
16
26
  const name = Flag.string("name").pipe(
17
27
  Flag.withAlias("n"),
18
- Flag.withDescription("The name of the generated client"),
28
+ Flag.withDescription("The name of the generated output"),
19
29
  Flag.withDefault("Client")
20
30
  )
21
31
 
22
- const typeOnly = Flag.boolean("type-only").pipe(
23
- Flag.withAlias("t"),
24
- Flag.withDescription("Generate a type-only client without schemas")
32
+ const format = Flag.choice("format", ["httpclient", "httpclient-type-only", "httpapi"] as const).pipe(
33
+ Flag.withAlias("f"),
34
+ Flag.withDescription(
35
+ "Output format to generate: httpclient | httpclient-type-only | httpapi (default: httpclient)"
36
+ ),
37
+ Flag.withDefault("httpclient")
25
38
  )
26
39
 
27
40
  const patch = Flag.string("patch").pipe(
@@ -34,8 +47,8 @@ const patch = Flag.string("patch").pipe(
34
47
  Flag.between(0, Infinity)
35
48
  )
36
49
 
37
- const root = Command.make("openapigen", { spec, typeOnly, name, patch }).pipe(
38
- Command.withHandler(Effect.fnUntraced(function*({ name, spec, typeOnly, patch }) {
50
+ const root = Command.make("openapigen", { spec, format, name, patch }).pipe(
51
+ Command.withHandler(Effect.fnUntraced(function*({ name, spec, format, patch }) {
39
52
  let patchedSpec: Schema.Json = spec as Schema.Json
40
53
 
41
54
  if (patch.length > 0) {
@@ -53,16 +66,51 @@ const root = Command.make("openapigen", { spec, typeOnly, name, patch }).pipe(
53
66
  }
54
67
 
55
68
  const generator = yield* OpenApiGenerator.OpenApiGenerator
56
- const source = yield* generator.generate(patchedSpec as unknown as OpenAPISpec, { name, typeOnly })
69
+ const warnings: Array<OpenApiGenerator.OpenApiGeneratorWarning> = []
70
+ const source = yield* generator.generate(patchedSpec as unknown as OpenAPISpec, {
71
+ name,
72
+ format,
73
+ onWarning: (warning) => {
74
+ warnings.push(warning)
75
+ }
76
+ })
77
+ yield* Effect.forEach(
78
+ warnings,
79
+ (warning) => Console.error(formatWarning(warning)),
80
+ { discard: true }
81
+ )
57
82
  return yield* Console.log(source)
58
83
  })),
59
- Command.provide(({ typeOnly }) =>
60
- typeOnly
84
+ Command.provide(({ format }) =>
85
+ format === "httpclient-type-only"
61
86
  ? OpenApiGenerator.layerTransformerTs
62
87
  : OpenApiGenerator.layerTransformerSchema
63
88
  )
64
89
  )
65
90
 
91
+ /**
92
+ * Runs the OpenAPI generator command-line program.
93
+ *
94
+ * **Details**
95
+ *
96
+ * The command reads an OpenAPI specification, optionally applies JSON patches,
97
+ * generates source code in the selected format, writes any generation warnings
98
+ * to stderr, and prints the generated source to stdout.
99
+ *
100
+ * @category running
101
+ * @since 4.0.0
102
+ */
66
103
  export const run: Effect.Effect<void, CliError.CliError, Command.Environment> = Command.run(root, {
67
104
  version: "0.0.0"
68
105
  })
106
+
107
+ const formatWarning = (warning: OpenApiGenerator.OpenApiGeneratorWarning): string => {
108
+ const context = [
109
+ warning.method?.toUpperCase(),
110
+ warning.path,
111
+ warning.operationId ? `(${warning.operationId})` : undefined
112
+ ].filter((value): value is string => value !== undefined)
113
+ return context.length > 0
114
+ ? `WARNING [${warning.code}] ${context.join(" ")}: ${warning.message}`
115
+ : `WARNING [${warning.code}] ${warning.message}`
116
+ }