@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.
- package/README.md +0 -72
- package/bin/cli.js +0 -0
- package/dist/{types/commands → commands}/generate/index.d.ts +1 -1
- package/dist/{esm/commands → commands}/generate/index.js +4 -8
- package/dist/generation/format.d.ts +1 -0
- package/dist/{esm/generation → generation}/format.js +2 -2
- package/dist/{esm/generation → generation}/model/CodeGenerationModel.js +0 -9
- package/dist/{esm/generation/refs → generation/model}/assertNoRefs.js +2 -3
- package/dist/{types/generation → generation}/model/components/Components.d.ts +0 -6
- package/dist/{esm/generation → generation}/model/components/Components.js +0 -19
- package/dist/{types/generation → generation}/model/components/Parameters.d.ts +5 -3
- package/dist/{esm/generation → generation}/model/components/Parameters.js +4 -9
- package/dist/{esm/generation → generation}/model/components/Responses.js +1 -1
- package/dist/{esm/generation → generation}/model/components/Schemas.js +1 -4
- package/dist/{types/generation → generation}/model/components/SecurityScheme.d.ts +1 -2
- package/dist/{esm/generation → generation}/model/components/SecurityScheme.js +3 -4
- package/dist/{esm/generation → generation}/model/components/SecuritySchemes.js +2 -2
- package/dist/{types/generation → generation}/model/paths/Paths.d.ts +2 -8
- package/dist/generation/model/paths/Paths.js +100 -0
- package/dist/{types/generation → generation}/model/paths/operation/Operation.d.ts +1 -4
- package/dist/{esm/generation → generation}/model/paths/operation/Operation.js +8 -37
- package/dist/{esm/generation → generation}/model/paths/operation/RequestParameters.js +11 -17
- package/dist/{types/generation → generation}/prepareTypeScriptOutput.d.ts +1 -1
- package/dist/{esm/generation → generation}/prepareTypeScriptOutput.js +2 -2
- package/dist/{types/openapi → openapi}/OpenApiSpec.d.ts +0 -1
- package/dist/{esm/openapi → openapi}/OpenApiSpec.js +0 -16
- package/package.json +35 -60
- package/LICENSE +0 -21
- package/dist/esm/generation/model/paths/Paths.js +0 -192
- package/dist/esm/generation/populateNullableTypes.js +0 -26
- package/dist/esm/generation/refs/extractComponentRefName.js +0 -8
- package/dist/esm/generation/refs/isRef.js +0 -3
- package/dist/esm/index.js +0 -7
- package/dist/esm/lib/writeIfChangedAsync.js +0 -8
- package/dist/types/generation/format.d.ts +0 -1
- package/dist/types/generation/populateNullableTypes.d.ts +0 -2
- package/dist/types/generation/refs/extractComponentRefName.d.ts +0 -2
- package/dist/types/generation/refs/isRef.d.ts +0 -2
- package/dist/types/index.d.ts +0 -7
- package/dist/types/lib/writeIfChangedAsync.d.ts +0 -1
- /package/dist/{types/commands → commands}/validate/index.d.ts +0 -0
- /package/dist/{esm/commands → commands}/validate/index.js +0 -0
- /package/dist/{types/generation → generation}/asyncStringJoin.d.ts +0 -0
- /package/dist/{esm/generation → generation}/asyncStringJoin.js +0 -0
- /package/dist/{types/generation → generation}/asyncStringJoin.test.d.ts +0 -0
- /package/dist/{esm/generation → generation}/asyncStringJoin.test.js +0 -0
- /package/dist/{types/generation → generation}/compileJsonSchema.d.ts +0 -0
- /package/dist/{esm/generation → generation}/compileJsonSchema.js +0 -0
- /package/dist/{types/generation → generation}/model/CodeGenerationModel.d.ts +0 -0
- /package/dist/{types/generation/refs → generation/model}/assertNoRefs.d.ts +0 -0
- /package/dist/{types/generation → generation}/model/components/RequestBodies.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/components/RequestBodies.js +0 -0
- /package/dist/{types/generation → generation}/model/components/Response.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/components/Response.js +0 -0
- /package/dist/{types/generation → generation}/model/components/ResponseContent.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/components/ResponseContent.js +0 -0
- /package/dist/{types/generation → generation}/model/components/Responses.d.ts +0 -0
- /package/dist/{types/generation → generation}/model/components/Schemas.d.ts +0 -0
- /package/dist/{types/generation → generation}/model/components/SecuritySchemes.d.ts +0 -0
- /package/dist/{types/generation → generation}/model/global/JSONSchema.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/global/JSONSchema.js +0 -0
- /package/dist/{types/generation → generation}/model/global/Name.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/global/Name.js +0 -0
- /package/dist/{types/generation → generation}/model/global/Name.test.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/global/Name.test.js +0 -0
- /package/dist/{types/generation → generation}/model/paths/Path.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/paths/Path.js +0 -0
- /package/dist/{types/generation → generation}/model/paths/operation/RequestParameters.d.ts +0 -0
- /package/dist/{types/generation → generation}/model/paths/operation/responses/Response.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/paths/operation/responses/Response.js +0 -0
- /package/dist/{types/generation → generation}/model/paths/operation/responses/ResponseContent.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/paths/operation/responses/ResponseContent.js +0 -0
- /package/dist/{types/generation → generation}/model/paths/operation/responses/ResponseContentTypes.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/paths/operation/responses/ResponseContentTypes.js +0 -0
- /package/dist/{types/generation → generation}/model/paths/operation/responses/Responses.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/paths/operation/responses/Responses.js +0 -0
- /package/dist/{types/generation → generation}/model/tags/Tag.d.ts +0 -0
- /package/dist/{esm/generation → generation}/model/tags/Tag.js +0 -0
- /package/dist/{types/generation → generation}/refs/componentRefsToCustomTypes.d.ts +0 -0
- /package/dist/{esm/generation → generation}/refs/componentRefsToCustomTypes.js +0 -0
- /package/dist/{types/generation → generation}/refs/componentRefsToCustomTypes.test.d.ts +0 -0
- /package/dist/{esm/generation → generation}/refs/componentRefsToCustomTypes.test.js +0 -0
- /package/dist/{types/generation → generation}/refs/refNameToTSName.d.ts +0 -0
- /package/dist/{esm/generation → generation}/refs/refNameToTSName.js +0 -0
- /package/dist/{types/generation → generation}/refs/refNameToTSName.test.d.ts +0 -0
- /package/dist/{esm/generation → generation}/refs/refNameToTSName.test.js +0 -0
- /package/dist/{types/generation → generation}/refs/splitRefNamespaces.d.ts +0 -0
- /package/dist/{esm/generation → generation}/refs/splitRefNamespaces.js +0 -0
- /package/dist/{types/generation → generation}/refs/splitRefNamespaces.test.d.ts +0 -0
- /package/dist/{esm/generation → generation}/refs/splitRefNamespaces.test.js +0 -0
- /package/dist/{types/generation → generation}/tsNamespaceName.d.ts +0 -0
- /package/dist/{esm/generation → generation}/tsNamespaceName.js +0 -0
- /package/dist/{types/generation → generation}/tsTypeName.d.ts +0 -0
- /package/dist/{esm/generation → generation}/tsTypeName.js +0 -0
- /package/dist/{types/generation → generation}/tsTypeName.test.d.ts +0 -0
- /package/dist/{esm/generation → generation}/tsTypeName.test.js +0 -0
- /package/dist/{types/lib → lib}/makeError.d.ts +0 -0
- /package/dist/{esm/lib → lib}/makeError.js +0 -0
- /package/dist/{types/lib → lib}/relativePath.d.ts +0 -0
- /package/dist/{esm/lib → lib}/relativePath.js +0 -0
- /package/dist/{types/loading → loading}/UniversalContentLoader.d.ts +0 -0
- /package/dist/{esm/loading → loading}/UniversalContentLoader.js +0 -0
- /package/dist/{types/loading → loading}/UniversalContentLoader.test.d.ts +0 -0
- /package/dist/{esm/loading → loading}/UniversalContentLoader.test.js +0 -0
- /package/dist/{types/loading → loading}/UniversalFileLoader.d.ts +0 -0
- /package/dist/{esm/loading → loading}/UniversalFileLoader.js +0 -0
- /package/dist/{types/loading → loading}/types.d.ts +0 -0
- /package/dist/{esm/loading → loading}/types.js +0 -0
- /package/dist/{types/openapi → openapi}/OpenAPISchemaValidationError.d.ts +0 -0
- /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[]
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
4
|
+
export const format = (ts) => {
|
|
5
5
|
try {
|
|
6
|
-
return
|
|
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
|
}
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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 "
|
|
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:
|
|
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.
|
|
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
|
-
[
|
|
14
|
+
[doc.name]: {
|
|
16
15
|
type: "string",
|
|
17
16
|
},
|
|
18
17
|
},
|
|
19
|
-
required: [
|
|
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 "
|
|
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
|
|
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(
|
|
17
|
-
getGroupedOperationsByTag(
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
this.id = new Name(doc.operationId
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
? methodName.substring(
|
|
78
|
-
: methodName)
|
|
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 {
|
|
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(
|
|
18
|
+
static constructParametersSchema(name, $in, parameters = [], securitySchemes) {
|
|
20
19
|
const properties = {};
|
|
21
20
|
const required = [];
|
|
22
21
|
for (const parameter of parameters) {
|
|
23
|
-
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
59
|
-
const
|
|
60
|
-
const
|
|
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) =>
|
|
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 =
|
|
8
|
-
const formatted =
|
|
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 {};
|