@mittwald/api-code-generator 0.0.0-development-f25b020-20260331 → 3.1.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 (110) hide show
  1. package/README.md +0 -72
  2. package/bin/cli.js +0 -0
  3. package/dist/{types/commands → commands}/generate/index.d.ts +1 -1
  4. package/dist/{esm/commands → commands}/generate/index.js +4 -8
  5. package/dist/generation/format.d.ts +1 -0
  6. package/dist/{esm/generation → generation}/format.js +2 -2
  7. package/dist/{esm/generation → generation}/model/CodeGenerationModel.js +0 -9
  8. package/dist/{esm/generation/refs → generation/model}/assertNoRefs.js +2 -3
  9. package/dist/{types/generation → generation}/model/components/Components.d.ts +0 -6
  10. package/dist/{esm/generation → generation}/model/components/Components.js +0 -19
  11. package/dist/{types/generation → generation}/model/components/Parameters.d.ts +5 -3
  12. package/dist/{esm/generation → generation}/model/components/Parameters.js +4 -9
  13. package/dist/{esm/generation → generation}/model/components/Responses.js +1 -1
  14. package/dist/{esm/generation → generation}/model/components/Schemas.js +1 -4
  15. package/dist/{types/generation → generation}/model/components/SecurityScheme.d.ts +1 -2
  16. package/dist/{esm/generation → generation}/model/components/SecurityScheme.js +3 -4
  17. package/dist/{esm/generation → generation}/model/components/SecuritySchemes.js +2 -2
  18. package/dist/{types/generation → generation}/model/paths/Paths.d.ts +2 -8
  19. package/dist/generation/model/paths/Paths.js +100 -0
  20. package/dist/{types/generation → generation}/model/paths/operation/Operation.d.ts +1 -4
  21. package/dist/{esm/generation → generation}/model/paths/operation/Operation.js +8 -37
  22. package/dist/{esm/generation → generation}/model/paths/operation/RequestParameters.js +11 -17
  23. package/dist/{types/generation → generation}/prepareTypeScriptOutput.d.ts +1 -1
  24. package/dist/{esm/generation → generation}/prepareTypeScriptOutput.js +2 -2
  25. package/dist/{types/openapi → openapi}/OpenApiSpec.d.ts +0 -1
  26. package/dist/{esm/openapi → openapi}/OpenApiSpec.js +0 -16
  27. package/package.json +35 -60
  28. package/LICENSE +0 -21
  29. package/dist/esm/generation/model/paths/Paths.js +0 -192
  30. package/dist/esm/generation/populateNullableTypes.js +0 -26
  31. package/dist/esm/generation/refs/extractComponentRefName.js +0 -8
  32. package/dist/esm/generation/refs/isRef.js +0 -3
  33. package/dist/esm/index.js +0 -7
  34. package/dist/esm/lib/writeIfChangedAsync.js +0 -8
  35. package/dist/types/generation/format.d.ts +0 -1
  36. package/dist/types/generation/populateNullableTypes.d.ts +0 -2
  37. package/dist/types/generation/refs/extractComponentRefName.d.ts +0 -2
  38. package/dist/types/generation/refs/isRef.d.ts +0 -2
  39. package/dist/types/index.d.ts +0 -7
  40. package/dist/types/lib/writeIfChangedAsync.d.ts +0 -1
  41. /package/dist/{types/commands → commands}/validate/index.d.ts +0 -0
  42. /package/dist/{esm/commands → commands}/validate/index.js +0 -0
  43. /package/dist/{types/generation → generation}/asyncStringJoin.d.ts +0 -0
  44. /package/dist/{esm/generation → generation}/asyncStringJoin.js +0 -0
  45. /package/dist/{types/generation → generation}/asyncStringJoin.test.d.ts +0 -0
  46. /package/dist/{esm/generation → generation}/asyncStringJoin.test.js +0 -0
  47. /package/dist/{types/generation → generation}/compileJsonSchema.d.ts +0 -0
  48. /package/dist/{esm/generation → generation}/compileJsonSchema.js +0 -0
  49. /package/dist/{types/generation → generation}/model/CodeGenerationModel.d.ts +0 -0
  50. /package/dist/{types/generation/refs → generation/model}/assertNoRefs.d.ts +0 -0
  51. /package/dist/{types/generation → generation}/model/components/RequestBodies.d.ts +0 -0
  52. /package/dist/{esm/generation → generation}/model/components/RequestBodies.js +0 -0
  53. /package/dist/{types/generation → generation}/model/components/Response.d.ts +0 -0
  54. /package/dist/{esm/generation → generation}/model/components/Response.js +0 -0
  55. /package/dist/{types/generation → generation}/model/components/ResponseContent.d.ts +0 -0
  56. /package/dist/{esm/generation → generation}/model/components/ResponseContent.js +0 -0
  57. /package/dist/{types/generation → generation}/model/components/Responses.d.ts +0 -0
  58. /package/dist/{types/generation → generation}/model/components/Schemas.d.ts +0 -0
  59. /package/dist/{types/generation → generation}/model/components/SecuritySchemes.d.ts +0 -0
  60. /package/dist/{types/generation → generation}/model/global/JSONSchema.d.ts +0 -0
  61. /package/dist/{esm/generation → generation}/model/global/JSONSchema.js +0 -0
  62. /package/dist/{types/generation → generation}/model/global/Name.d.ts +0 -0
  63. /package/dist/{esm/generation → generation}/model/global/Name.js +0 -0
  64. /package/dist/{types/generation → generation}/model/global/Name.test.d.ts +0 -0
  65. /package/dist/{esm/generation → generation}/model/global/Name.test.js +0 -0
  66. /package/dist/{types/generation → generation}/model/paths/Path.d.ts +0 -0
  67. /package/dist/{esm/generation → generation}/model/paths/Path.js +0 -0
  68. /package/dist/{types/generation → generation}/model/paths/operation/RequestParameters.d.ts +0 -0
  69. /package/dist/{types/generation → generation}/model/paths/operation/responses/Response.d.ts +0 -0
  70. /package/dist/{esm/generation → generation}/model/paths/operation/responses/Response.js +0 -0
  71. /package/dist/{types/generation → generation}/model/paths/operation/responses/ResponseContent.d.ts +0 -0
  72. /package/dist/{esm/generation → generation}/model/paths/operation/responses/ResponseContent.js +0 -0
  73. /package/dist/{types/generation → generation}/model/paths/operation/responses/ResponseContentTypes.d.ts +0 -0
  74. /package/dist/{esm/generation → generation}/model/paths/operation/responses/ResponseContentTypes.js +0 -0
  75. /package/dist/{types/generation → generation}/model/paths/operation/responses/Responses.d.ts +0 -0
  76. /package/dist/{esm/generation → generation}/model/paths/operation/responses/Responses.js +0 -0
  77. /package/dist/{types/generation → generation}/model/tags/Tag.d.ts +0 -0
  78. /package/dist/{esm/generation → generation}/model/tags/Tag.js +0 -0
  79. /package/dist/{types/generation → generation}/refs/componentRefsToCustomTypes.d.ts +0 -0
  80. /package/dist/{esm/generation → generation}/refs/componentRefsToCustomTypes.js +0 -0
  81. /package/dist/{types/generation → generation}/refs/componentRefsToCustomTypes.test.d.ts +0 -0
  82. /package/dist/{esm/generation → generation}/refs/componentRefsToCustomTypes.test.js +0 -0
  83. /package/dist/{types/generation → generation}/refs/refNameToTSName.d.ts +0 -0
  84. /package/dist/{esm/generation → generation}/refs/refNameToTSName.js +0 -0
  85. /package/dist/{types/generation → generation}/refs/refNameToTSName.test.d.ts +0 -0
  86. /package/dist/{esm/generation → generation}/refs/refNameToTSName.test.js +0 -0
  87. /package/dist/{types/generation → generation}/refs/splitRefNamespaces.d.ts +0 -0
  88. /package/dist/{esm/generation → generation}/refs/splitRefNamespaces.js +0 -0
  89. /package/dist/{types/generation → generation}/refs/splitRefNamespaces.test.d.ts +0 -0
  90. /package/dist/{esm/generation → generation}/refs/splitRefNamespaces.test.js +0 -0
  91. /package/dist/{types/generation → generation}/tsNamespaceName.d.ts +0 -0
  92. /package/dist/{esm/generation → generation}/tsNamespaceName.js +0 -0
  93. /package/dist/{types/generation → generation}/tsTypeName.d.ts +0 -0
  94. /package/dist/{esm/generation → generation}/tsTypeName.js +0 -0
  95. /package/dist/{types/generation → generation}/tsTypeName.test.d.ts +0 -0
  96. /package/dist/{esm/generation → generation}/tsTypeName.test.js +0 -0
  97. /package/dist/{types/lib → lib}/makeError.d.ts +0 -0
  98. /package/dist/{esm/lib → lib}/makeError.js +0 -0
  99. /package/dist/{types/lib → lib}/relativePath.d.ts +0 -0
  100. /package/dist/{esm/lib → lib}/relativePath.js +0 -0
  101. /package/dist/{types/loading → loading}/UniversalContentLoader.d.ts +0 -0
  102. /package/dist/{esm/loading → loading}/UniversalContentLoader.js +0 -0
  103. /package/dist/{types/loading → loading}/UniversalContentLoader.test.d.ts +0 -0
  104. /package/dist/{esm/loading → loading}/UniversalContentLoader.test.js +0 -0
  105. /package/dist/{types/loading → loading}/UniversalFileLoader.d.ts +0 -0
  106. /package/dist/{esm/loading → loading}/UniversalFileLoader.js +0 -0
  107. /package/dist/{types/loading → loading}/types.d.ts +0 -0
  108. /package/dist/{esm/loading → loading}/types.js +0 -0
  109. /package/dist/{types/openapi → openapi}/OpenAPISchemaValidationError.d.ts +0 -0
  110. /package/dist/{esm/openapi → openapi}/OpenAPISchemaValidationError.js +0 -0
package/README.md CHANGED
@@ -1,73 +1 @@
1
1
  Common code base used by `@mittwald/api-client-*` package.
2
-
3
- ## CLI
4
-
5
- Use the CLI commands provided by this package to build your API client and
6
- validate the OpenAPI-Spec:
7
-
8
- ```shell
9
- acg validate spec/openapi.json
10
- acg generate --name MittwaldAPIV2 spec/openapi.json src/generated --optionalHeader x-access-token
11
- ```
12
-
13
- ## TypeScript API
14
-
15
- If you need to generate the client in code, you can use the TypeScript API
16
- demonstrated in this template:
17
-
18
- ```typescript
19
- import * as path from "path";
20
- import { UniversalContentLoader } from "@mittwald/api-code-generator/js";
21
- import { UniversalFileLoader } from "@mittwald/api-code-generator/js";
22
- import { OpenApiSpec } from "@mittwald/api-code-generator/js";
23
- import { CodeGenerationModel } from "@mittwald/api-code-generator/js";
24
- import { prepareTypeScriptOutput } from "@mittwald/api-code-generator/js";
25
- import { writeIfChangedAsync } from "@mittwald/api-code-generator/js";
26
-
27
- const name = "MittwaldAPIV2";
28
- const inout = `${process.cwd()}/spec/openapi.json`;
29
- const output = `${process.cwd()}/src/generated`;
30
-
31
- // Loading OpenAPI spec
32
- const loader = new UniversalContentLoader(new UniversalFileLoader(input));
33
- const openApiDoc = await loader.load();
34
-
35
- // Parsing OpenAPI spec
36
- const spec = await OpenApiSpec.parse(openApiDoc, {
37
- skipValidation: flags.skipValidation,
38
- });
39
-
40
- // Building transformation model
41
- const model = CodeGenerationModel.fromDoc(name, spec.document);
42
-
43
- // Generating descriptors
44
- const descriptorsFileContent = model.paths.compileDescriptors();
45
- await writeIfChangedAsync(
46
- path.join(output, "descriptors.ts"),
47
- await prepareTypeScriptOutput(descriptorsFileContent),
48
- );
49
-
50
- // Generating types
51
- const typesFileContent = await model.compileTypes({
52
- rootNamespace: flags.name,
53
- optionalHeaders: ["x-access-token"],
54
- });
55
- await writeIfChangedAsync(
56
- path.join(output, "types.ts"),
57
- await prepareTypeScriptOutput(typesFileContent),
58
- );
59
-
60
- // Generating client
61
- const clientFileContent = model.paths.compileClient();
62
- await writeIfChangedAsync(
63
- path.join(output, "client.ts"),
64
- await prepareTypeScriptOutput(clientFileContent),
65
- );
66
-
67
- // if needed: Generating React client
68
- const reactClientFileContent = model.paths.compileReactClient();
69
- await writeIfChangedAsync(
70
- path.join(output, "client-react.ts"),
71
- await prepareTypeScriptOutput(reactClientFileContent),
72
- );
73
- ```
package/bin/cli.js CHANGED
File without changes
@@ -4,7 +4,7 @@ export default class Generate extends Command {
4
4
  static flags: {
5
5
  skipValidation: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
6
6
  name: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
- optionalHeader: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ optionalHeader: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[], import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
8
  };
9
9
  static args: {
10
10
  input: import("@oclif/core/lib/interfaces/parser.js").Arg<string, {
@@ -2,10 +2,10 @@ import { Args, Command, Flags, ux } from "@oclif/core";
2
2
  import { UniversalContentLoader } from "../../loading/UniversalContentLoader.js";
3
3
  import { OpenApiSpec } from "../../openapi/OpenApiSpec.js";
4
4
  import { CodeGenerationModel } from "../../generation/model/CodeGenerationModel.js";
5
+ import jetpack from "fs-jetpack";
5
6
  import * as path from "path";
6
7
  import { prepareTypeScriptOutput } from "../../generation/prepareTypeScriptOutput.js";
7
8
  import { UniversalFileLoader } from "../../loading/UniversalFileLoader.js";
8
- import { writeIfChangedAsync } from "../../lib/writeIfChangedAsync.js";
9
9
  export default class Generate extends Command {
10
10
  static description = "Generate code from the provided OpenAPI spec.";
11
11
  static flags = {
@@ -49,22 +49,18 @@ export default class Generate extends Command {
49
49
  ux.action.stop();
50
50
  ux.action.start("Generating descriptors");
51
51
  const descriptorsFileContent = model.paths.compileDescriptors();
52
- await writeIfChangedAsync(path.join(args.output, "descriptors.ts"), await prepareTypeScriptOutput(descriptorsFileContent));
52
+ await jetpack.writeAsync(path.join(args.output, "descriptors.ts"), prepareTypeScriptOutput(descriptorsFileContent));
53
53
  ux.action.stop();
54
54
  ux.action.start("Generating types");
55
55
  const typesFileContent = await model.compileTypes({
56
56
  rootNamespace: flags.name,
57
57
  optionalHeaders: flags.optionalHeader,
58
58
  });
59
- await writeIfChangedAsync(path.join(args.output, "types.ts"), await prepareTypeScriptOutput(typesFileContent));
59
+ await jetpack.writeAsync(path.join(args.output, "types.ts"), prepareTypeScriptOutput(typesFileContent));
60
60
  ux.action.stop();
61
61
  ux.action.start("Generating client");
62
62
  const clientFileContent = model.paths.compileClient();
63
- await writeIfChangedAsync(path.join(args.output, "client.ts"), await prepareTypeScriptOutput(clientFileContent));
64
- ux.action.stop();
65
- ux.action.start("Generating React client");
66
- const reactClientFileContent = model.paths.compileReactClient();
67
- await writeIfChangedAsync(path.join(args.output, "client-react.ts"), await prepareTypeScriptOutput(reactClientFileContent));
63
+ await jetpack.writeAsync(path.join(args.output, "client.ts"), prepareTypeScriptOutput(clientFileContent));
68
64
  ux.action.stop();
69
65
  }
70
66
  }
@@ -0,0 +1 @@
1
+ export declare const format: (ts: string) => string;
@@ -1,9 +1,9 @@
1
1
  import prettier from "prettier";
2
2
  import VError from "verror";
3
3
  import { makeError } from "../lib/makeError.js";
4
- export const format = async (ts) => {
4
+ export const format = (ts) => {
5
5
  try {
6
- return await prettier.format(ts, {
6
+ return prettier.format(ts, {
7
7
  plugins: [],
8
8
  parser: "typescript",
9
9
  });
@@ -22,19 +22,10 @@ export class CodeGenerationModel {
22
22
  const t = {
23
23
  ns: this.rootNamespace.tsType,
24
24
  components: await this.components.compileTypes(opts),
25
- operationTypes: await this.paths.compileOperationTypes(),
26
25
  paths: await this.paths.compileTypes(opts),
27
26
  };
28
27
  return `\
29
- import * as descriptors from "./descriptors.js";
30
- import {
31
- InferredRequestData,
32
- InferredResponseData,
33
- HttpStatus
34
- } from "@mittwald/api-client-commons";
35
-
36
28
  export declare module ${t.ns} {
37
- ${t.operationTypes}
38
29
  ${t.components}
39
30
  ${t.paths}
40
31
  }
@@ -1,6 +1,5 @@
1
- import { isRef } from "./isRef.js";
2
1
  export function assertNoRefs(obj) {
3
- if (isRef(obj)) {
4
- throw new Error(`$ref's are not supported here (ref: ${obj.$ref})`);
2
+ if ("$ref" in obj) {
3
+ throw new Error(`$ref's are not supported here (ref: ${obj.$ref}`);
5
4
  }
6
5
  }
@@ -5,10 +5,6 @@ import { Parameters } from "./Parameters.js";
5
5
  import { RequestBodies } from "./RequestBodies.js";
6
6
  import { Responses } from "./Responses.js";
7
7
  import { SecuritySchemes } from "./SecuritySchemes.js";
8
- import { OpenAPIV3 } from "openapi-types";
9
- export type ComponentTypeName = keyof OpenAPIV3.ComponentsObject;
10
- export type ComponentType<T extends ComponentTypeName> = Required<OpenAPIV3.ComponentsObject>[T][string];
11
- export type ResolvedComponentType<T extends ComponentTypeName> = Exclude<ComponentType<T>, OpenAPIV3.ReferenceObject>;
12
8
  export declare class Components {
13
9
  static readonly ns = "Components";
14
10
  name: Name;
@@ -17,8 +13,6 @@ export declare class Components {
17
13
  parameters: Parameters;
18
14
  requestBodies: RequestBodies;
19
15
  responses: Responses;
20
- model: CodeGenerationModel;
21
16
  constructor(model: CodeGenerationModel);
22
17
  compileTypes(opts: TypeCompilationOptions): Promise<string>;
23
- resolveRef<T extends ComponentTypeName>(componentType: T, obj: ComponentType<T>): ResolvedComponentType<T>;
24
18
  }
@@ -4,9 +4,6 @@ import { Parameters } from "./Parameters.js";
4
4
  import { RequestBodies } from "./RequestBodies.js";
5
5
  import { Responses } from "./Responses.js";
6
6
  import { SecuritySchemes } from "./SecuritySchemes.js";
7
- import { extractComponentRefName } from "../../refs/extractComponentRefName.js";
8
- import { assertNoRefs } from "../../refs/assertNoRefs.js";
9
- import invariant from "invariant";
10
7
  export class Components {
11
8
  static ns = "Components";
12
9
  name;
@@ -15,9 +12,7 @@ export class Components {
15
12
  parameters;
16
13
  requestBodies;
17
14
  responses;
18
- model;
19
15
  constructor(model) {
20
- this.model = model;
21
16
  this.name = new Name(Components.ns, model.rootNamespace);
22
17
  this.schemas = new Schemas(this, model.doc.components?.schemas ?? {});
23
18
  this.securitySchemes = new SecuritySchemes(this, model.doc.components?.securitySchemes ?? {});
@@ -44,18 +39,4 @@ export class Components {
44
39
  }
45
40
  `;
46
41
  }
47
- resolveRef(componentType, obj) {
48
- if ("$ref" in obj) {
49
- invariant(typeof obj.$ref === "string", "PathItemRefs are not supported by now");
50
- const refName = extractComponentRefName(obj.$ref, componentType);
51
- const resolved = this.model.doc.components?.[componentType]?.[refName];
52
- if (resolved === undefined) {
53
- throw new Error(`Could not find ref ${obj.$ref} in components.${componentType}`);
54
- }
55
- assertNoRefs(resolved);
56
- return resolved;
57
- }
58
- assertNoRefs(obj);
59
- return obj;
60
- }
61
42
  }
@@ -1,11 +1,13 @@
1
+ import { JSONSchema } from "../global/JSONSchema.js";
1
2
  import { Name } from "../global/Name.js";
2
- import { Components, ComponentType } from "./Components.js";
3
+ import { Components } from "./Components.js";
3
4
  import { TypeCompilationOptions } from "../CodeGenerationModel.js";
5
+ import { OpenAPIV3 } from "openapi-types";
4
6
  export declare class Parameters {
5
7
  static readonly ns = "Parameters";
8
+ readonly schemas: JSONSchema[];
6
9
  readonly components: Components;
7
10
  readonly name: Name;
8
- readonly parameters: Record<string, ComponentType<"parameters">>;
9
- constructor(components: Components, parametersObject: Record<string, ComponentType<"parameters">>);
11
+ constructor(components: Components, schemas: OpenAPIV3.ComponentsObject["parameters"]);
10
12
  compileTypes(opts: TypeCompilationOptions): Promise<string>;
11
13
  }
@@ -1,25 +1,20 @@
1
1
  import { JSONSchema } from "../global/JSONSchema.js";
2
2
  import { Name } from "../global/Name.js";
3
3
  import { asyncStringJoin } from "../../asyncStringJoin.js";
4
- import { assertNoRefs } from "../../refs/assertNoRefs.js";
5
4
  export class Parameters {
6
5
  static ns = "Parameters";
6
+ schemas;
7
7
  components;
8
8
  name;
9
- parameters;
10
- constructor(components, parametersObject) {
9
+ constructor(components, schemas) {
11
10
  this.components = components;
12
11
  this.name = new Name(Parameters.ns, components.name);
13
- this.parameters = parametersObject;
12
+ this.schemas = Object.entries(schemas ?? {}).map(([schemaName, schema]) => new JSONSchema(new Name(schemaName, this.name), schema));
14
13
  }
15
14
  async compileTypes(opts) {
16
- const schemas = Object.entries(this.parameters).map(([name, param]) => {
17
- assertNoRefs(param);
18
- return new JSONSchema(new Name(name, this.name), param.schema);
19
- });
20
15
  const t = {
21
16
  ns: Parameters.ns,
22
- types: await asyncStringJoin(schemas, (schema) => schema.compile(opts)),
17
+ types: await asyncStringJoin(this.schemas, (schema) => schema.compile(opts)),
23
18
  };
24
19
  return `\
25
20
  namespace ${t.ns} {
@@ -1,7 +1,7 @@
1
1
  import { Name } from "../global/Name.js";
2
2
  import { asyncStringJoin } from "../../asyncStringJoin.js";
3
3
  import { Response } from "./Response.js";
4
- import { assertNoRefs } from "../../refs/assertNoRefs.js";
4
+ import { assertNoRefs } from "../assertNoRefs.js";
5
5
  export class Responses {
6
6
  static ns = "Responses";
7
7
  responses;
@@ -1,7 +1,6 @@
1
1
  import { JSONSchema } from "../global/JSONSchema.js";
2
2
  import { Name } from "../global/Name.js";
3
3
  import { asyncStringJoin } from "../../asyncStringJoin.js";
4
- import { populateNullableTypes } from "../../populateNullableTypes.js";
5
4
  export class Schemas {
6
5
  static ns = "Schemas";
7
6
  schemas;
@@ -10,9 +9,7 @@ export class Schemas {
10
9
  constructor(components, schemas) {
11
10
  this.components = components;
12
11
  this.name = new Name(Schemas.ns, components.name);
13
- this.schemas = Object.entries(schemas ?? {}).map(([schemaName, schema]) => {
14
- return new JSONSchema(new Name(schemaName, this.name), populateNullableTypes(schema));
15
- });
12
+ this.schemas = Object.entries(schemas ?? {}).map(([schemaName, schema]) => new JSONSchema(new Name(schemaName, this.name), schema));
16
13
  }
17
14
  async compileTypes(opts) {
18
15
  const t = {
@@ -2,10 +2,9 @@ import { OpenAPIV3 } from "openapi-types";
2
2
  import { Name } from "../global/Name.js";
3
3
  import { SecuritySchemes } from "./SecuritySchemes.js";
4
4
  import { JSONSchema } from "../global/JSONSchema.js";
5
- export type SecuritySchemeType = OpenAPIV3.ApiKeySecurityScheme | OpenAPIV3.HttpSecurityScheme;
6
5
  export declare class SecurityScheme {
7
6
  readonly in: string;
8
7
  readonly name: Name;
9
8
  readonly jsonSchema: JSONSchema;
10
- constructor(schemes: SecuritySchemes, name: string, doc: SecuritySchemeType);
9
+ constructor(schemes: SecuritySchemes, name: string, doc: OpenAPIV3.ApiKeySecurityScheme);
11
10
  }
@@ -6,17 +6,16 @@ export class SecurityScheme {
6
6
  jsonSchema;
7
7
  constructor(schemes, name, doc) {
8
8
  this.name = new Name(name, schemes.name);
9
- this.in = doc.type === "http" ? "header" : doc.in;
10
- const propName = doc.type === "http" ? "Authorization" : doc.name;
9
+ this.in = doc.in;
11
10
  this.jsonSchema = new JSONSchema(this.name, {
12
11
  type: "object",
13
12
  description: doc.description,
14
13
  properties: {
15
- [propName]: {
14
+ [doc.name]: {
16
15
  type: "string",
17
16
  },
18
17
  },
19
- required: [propName],
18
+ required: [doc.name],
20
19
  });
21
20
  }
22
21
  }
@@ -1,6 +1,6 @@
1
1
  import { Name } from "../global/Name.js";
2
2
  import invariant from "invariant";
3
- import { assertNoRefs } from "../../refs/assertNoRefs.js";
3
+ import { assertNoRefs } from "../assertNoRefs.js";
4
4
  import { asyncStringJoin } from "../../asyncStringJoin.js";
5
5
  import { SecurityScheme } from "./SecurityScheme.js";
6
6
  export class SecuritySchemes {
@@ -13,7 +13,7 @@ export class SecuritySchemes {
13
13
  this.name = new Name(SecuritySchemes.ns, components.name);
14
14
  Object.values(doc).forEach((scheme) => {
15
15
  assertNoRefs(scheme);
16
- invariant(scheme.type === "apiKey" || scheme.type === "http", `Security scheme type '${scheme.type}' is not supported (allowed types: 'apiKey', 'http')`);
16
+ invariant(scheme.type === "apiKey" || scheme.type === "http", `Security scheme type '${scheme.type}' is supported (allowed types: 'apiKey', 'http')`);
17
17
  });
18
18
  this.schemes = Object.entries(doc).map(([name, scheme]) => new SecurityScheme(this, name, scheme));
19
19
  }
@@ -11,15 +11,9 @@ export declare class Paths {
11
11
  readonly name: Name;
12
12
  constructor(model: CodeGenerationModel, paths: OpenAPIV3.PathsObject);
13
13
  compileTypes(opts: TypeCompilationOptions): Promise<string>;
14
- compileOperationTypes(): Promise<string>;
15
14
  compileDescriptors(): string;
16
- getFlattenedOperations(httpMethod?: string): Operation[];
17
- getGroupedOperationsByTag(httpMethod?: string): Array<[Tag, Operation[]]>;
15
+ getFlattenedOperations(): Operation[];
16
+ getGroupedOperationsByTag(): Array<[Tag, Operation[]]>;
18
17
  private compileClientMethodsOfTag;
19
18
  compileClient(): string;
20
- private compileReactClientApiName;
21
- private compileReactClientApiBuilderOfTag;
22
- private compileReactClientPropertyInitializer;
23
- private compileReactClientProperties;
24
- compileReactClient(): string;
25
19
  }
@@ -0,0 +1,100 @@
1
+ import { Name } from "../global/Name.js";
2
+ import { Path } from "./Path.js";
3
+ import { asyncStringJoin } from "../../asyncStringJoin.js";
4
+ export class Paths {
5
+ static ns = "Paths";
6
+ paths;
7
+ model;
8
+ name;
9
+ constructor(model, paths) {
10
+ this.model = model;
11
+ this.name = new Name(Paths.ns, model.rootNamespace);
12
+ this.paths = Object.entries(paths ?? {})
13
+ .map(([name, pathDoc]) => {
14
+ if (pathDoc) {
15
+ return Path.fromDoc(this, name, pathDoc);
16
+ }
17
+ })
18
+ .filter((p) => !!p);
19
+ }
20
+ async compileTypes(opts) {
21
+ const t = {
22
+ ns: Paths.ns,
23
+ types: await asyncStringJoin(this.paths, (path) => path.compileTypes(opts)),
24
+ };
25
+ return `\
26
+ namespace ${t.ns} {
27
+ ${t.types}
28
+ }
29
+ `;
30
+ }
31
+ compileDescriptors() {
32
+ const t = {
33
+ ns: this.model.rootNamespace.tsType,
34
+ descriptors: this.getFlattenedOperations()
35
+ .map((operation) => operation.compileDescriptor())
36
+ .join("\r\n"),
37
+ };
38
+ return `\
39
+ import { Simplify } from "@mittwald/api-client-commons";
40
+ import { RequestType } from "@mittwald/api-client-commons";
41
+ import { Response } from "@mittwald/api-client-commons";
42
+ import { OpenAPIOperation } from "@mittwald/api-client-commons";
43
+ import { ${t.ns} } from "./types.js";
44
+
45
+ ${t.descriptors}
46
+ `;
47
+ }
48
+ getFlattenedOperations() {
49
+ return this.paths.flatMap((p) => p.operations);
50
+ }
51
+ getGroupedOperationsByTag() {
52
+ const result = new Map();
53
+ for (const operation of this.getFlattenedOperations()) {
54
+ for (const tag of operation.tags) {
55
+ const operationsOfTag = result.get(tag);
56
+ if (operationsOfTag) {
57
+ operationsOfTag.push(operation);
58
+ }
59
+ else {
60
+ result.set(tag, [operation]);
61
+ }
62
+ }
63
+ }
64
+ return Array.from(result.entries());
65
+ }
66
+ compileClientMethodsOfTag(tag, operations) {
67
+ const tagName = tag.name.tsVar;
68
+ const t = {
69
+ tag: tagName,
70
+ comment: tag.description,
71
+ methods: operations
72
+ .map((op) => op.compileClientMethod(tagName))
73
+ .join(",\r\n"),
74
+ };
75
+ return `\
76
+ /** ${t.comment} */
77
+ public readonly ${t.tag} = {
78
+ ${t.methods}
79
+ }
80
+ `;
81
+ }
82
+ compileClient() {
83
+ const t = {
84
+ clientClassName: `${this.model.rootNamespace.tsType}Client`,
85
+ methods: this.getGroupedOperationsByTag()
86
+ .map(([tag, operations]) => this.compileClientMethodsOfTag(tag, operations))
87
+ .join("\r\n"),
88
+ };
89
+ return `\
90
+ import * as descriptors from "./descriptors.js";
91
+ import { ApiClientBase } from "@mittwald/api-client-commons";
92
+
93
+ export class ${t.clientClassName} extends ApiClientBase {
94
+ ${t.methods}
95
+ }
96
+
97
+ export default ${t.clientClassName}
98
+ `;
99
+ }
100
+ }
@@ -17,8 +17,5 @@ export declare class Operation {
17
17
  static fromDoc(path: Path, httpMethod: string, doc: OpenAPIV3.OperationObject): Operation;
18
18
  compileTypes(options: TypeCompilationOptions): Promise<string>;
19
19
  compileDescriptor(): string;
20
- compileRequestResponseTypes(): string;
21
- private getMethodName;
22
- compileClientMethod(tag: Tag): string;
23
- compileReactClientMethod(tag: Tag): string;
20
+ compileClientMethod(tagNamePrefix: string): string;
24
21
  }
@@ -1,6 +1,7 @@
1
1
  import { RequestParameters } from "./RequestParameters.js";
2
2
  import { Name } from "../../global/Name.js";
3
3
  import { Responses } from "./responses/Responses.js";
4
+ import invariant from "invariant";
4
5
  export class Operation {
5
6
  path;
6
7
  id;
@@ -10,8 +11,8 @@ export class Operation {
10
11
  summary;
11
12
  tags;
12
13
  constructor(path, httpMethod, doc) {
13
- const fallbackId = `${httpMethod.raw}-${path.name.raw}`;
14
- this.id = new Name(doc.operationId ?? fallbackId);
14
+ invariant(doc.operationId !== undefined, "Property 'operationId' does not exist in operation object");
15
+ this.id = new Name(doc.operationId);
15
16
  this.path = path;
16
17
  this.httpMethod = httpMethod;
17
18
  this.parameters = RequestParameters.fromDoc(this, doc);
@@ -59,28 +60,13 @@ export class Operation {
59
60
  };
60
61
  `;
61
62
  }
62
- compileRequestResponseTypes() {
63
- const t = {
64
- ns: this.id.tsType,
65
- descriptor: this.id.tsVar,
66
- };
67
- return `\
68
- namespace ${t.ns} {
69
- type RequestData = InferredRequestData<typeof descriptors.${t.descriptor}>;
70
- type ResponseData<TStatus extends HttpStatus = 200> = InferredResponseData<typeof descriptors.${t.descriptor}, TStatus>;
71
- }
72
- `;
73
- }
74
- getMethodName(tag) {
63
+ compileClientMethod(tagNamePrefix) {
75
64
  const methodName = this.id.tsVar;
76
- return new Name(methodName.startsWith(tag.name.tsVar)
77
- ? methodName.substring(tag.name.tsVar.length)
78
- : methodName).tsVar;
79
- }
80
- compileClientMethod(tag) {
81
- const methodName = this.getMethodName(tag);
65
+ const methodNameWithoutTagPrefix = new Name(methodName.startsWith(tagNamePrefix)
66
+ ? methodName.substring(tagNamePrefix.length)
67
+ : methodName);
82
68
  const t = {
83
- methodName,
69
+ methodName: methodNameWithoutTagPrefix.tsVar,
84
70
  descriptorName: this.id.tsVar,
85
71
  };
86
72
  return `\
@@ -90,19 +76,4 @@ export class Operation {
90
76
  )
91
77
  `;
92
78
  }
93
- compileReactClientMethod(tag) {
94
- const methodName = this.getMethodName(tag);
95
- const t = {
96
- methodName,
97
- descriptorName: this.id.tsVar,
98
- tag: tag.name.tsVar,
99
- };
100
- return `\
101
- /** ${this.summary} */
102
- ${t.methodName}: new ApiCallAsyncResourceFactory(
103
- descriptors.${t.descriptorName},
104
- baseClient.${t.tag}.${t.methodName}
105
- ).getApiResource
106
- `;
107
- }
108
79
  }
@@ -1,7 +1,6 @@
1
1
  import { JSONSchema } from "../../global/JSONSchema.js";
2
2
  import { Name } from "../../global/Name.js";
3
- import { isRef } from "../../../refs/isRef.js";
4
- import invariant from "invariant";
3
+ import { assertNoRefs } from "../../assertNoRefs.js";
5
4
  export class RequestParameters {
6
5
  static ns = "Parameters";
7
6
  path;
@@ -16,20 +15,16 @@ export class RequestParameters {
16
15
  this.header = header;
17
16
  this.body = body;
18
17
  }
19
- static constructParametersSchema(components, name, $in, parameters = [], securitySchemes) {
18
+ static constructParametersSchema(name, $in, parameters = [], securitySchemes) {
20
19
  const properties = {};
21
20
  const required = [];
22
21
  for (const parameter of parameters) {
23
- const resolvedParameter = components.resolveRef("parameters", parameter);
24
- if (resolvedParameter.in === $in) {
25
- const jsonSchemaObject = isRef(parameter)
26
- ? parameter
27
- : parameter.schema;
28
- invariant(!!jsonSchemaObject, `Could not find schema for request parameter ${name.raw}`);
29
- properties[resolvedParameter.name] = jsonSchemaObject;
30
- if (resolvedParameter.required) {
31
- required.push(resolvedParameter.name);
32
- }
22
+ assertNoRefs(parameter);
23
+ if (parameter.in === $in && parameter.schema) {
24
+ properties[parameter.name] = parameter.schema;
25
+ }
26
+ if (parameter.required) {
27
+ required.push(parameter.name);
33
28
  }
34
29
  }
35
30
  const securitySchemesJSONSchemas = securitySchemes
@@ -55,10 +50,9 @@ export class RequestParameters {
55
50
  : undefined;
56
51
  const requiredSecuritySchemeNames = doc.security?.flatMap((obj) => Object.keys(obj)) ?? [];
57
52
  const requiredSecuritySchemes = requiredSecuritySchemeNames.map((name) => operation.path.paths.model.components.securitySchemes.requireScheme(name));
58
- const components = operation.path.paths.model.components;
59
- const path = RequestParameters.constructParametersSchema(components, name, "path", doc.parameters, requiredSecuritySchemes);
60
- const header = RequestParameters.constructParametersSchema(components, name, "header", doc.parameters, requiredSecuritySchemes);
61
- const query = RequestParameters.constructParametersSchema(components, name, "query", doc.parameters, requiredSecuritySchemes);
53
+ const path = RequestParameters.constructParametersSchema(name, "path", doc.parameters, requiredSecuritySchemes);
54
+ const header = RequestParameters.constructParametersSchema(name, "header", doc.parameters, requiredSecuritySchemes);
55
+ const query = RequestParameters.constructParametersSchema(name, "query", doc.parameters, requiredSecuritySchemes);
62
56
  return new RequestParameters(operation, body, path, query, header);
63
57
  }
64
58
  async compileTypes(opts) {
@@ -1 +1 @@
1
- export declare const prepareTypeScriptOutput: (content: string) => Promise<string>;
1
+ export declare const prepareTypeScriptOutput: (content: string) => string;
@@ -4,7 +4,7 @@ const header = `\
4
4
  /* prettier-ignore */
5
5
  /* This file is auto-generated with acg (@mittwald/api-code-generator) */
6
6
  `;
7
- export const prepareTypeScriptOutput = async (content) => {
8
- const formatted = await format(content);
7
+ export const prepareTypeScriptOutput = (content) => {
8
+ const formatted = format(content);
9
9
  return header + formatted;
10
10
  };
@@ -5,7 +5,6 @@ interface ParserOptions {
5
5
  export declare class OpenApiSpec {
6
6
  readonly document: OpenAPIV3.Document;
7
7
  constructor(document: OpenAPIV3.Document);
8
- private static convertToOpenApi;
9
8
  static parse(doc: any, opts?: ParserOptions): Promise<OpenApiSpec>;
10
9
  }
11
10
  export {};