@travetto/openapi 3.0.0-rc.3 → 3.0.0-rc.6
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 +36 -35
- package/{index.ts → __index__.ts} +0 -0
- package/package.json +12 -11
- package/src/config.ts +32 -16
- package/src/service.ts +4 -1
- package/src/spec-generate.ts +3 -3
- package/{bin/cli-openapi_client.ts → support/cli.openapi_client.ts} +37 -28
- package/{bin/cli-openapi_spec.ts → support/cli.openapi_spec.ts} +8 -8
- package/support/main.generate.ts +11 -0
- package/{resources → support/resources}/presets.json +0 -0
- package/bin/generate.ts +0 -12
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
-
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/openapi/
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/openapi/DOC.ts and execute "npx trv doc" to rebuild -->
|
|
3
3
|
# OpenAPI Specification
|
|
4
4
|
## OpenAPI integration support for the travetto framework
|
|
5
5
|
|
|
@@ -10,7 +10,7 @@ npm install @travetto/openapi
|
|
|
10
10
|
|
|
11
11
|
In the [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") module, the controllers and endpoints can be described via decorators, comments, or typings. This only provides the general metadata internally. This is not sufficient to generate a usable API doc, and so this module exists to bridge that gap.
|
|
12
12
|
|
|
13
|
-
The module is provides an [OpenAPI](https://github.com/OAI/OpenAPI-Specification) v3.x representation of the API metadata provided via the [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") and [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.
|
|
13
|
+
The module is provides an [OpenAPI](https://github.com/OAI/OpenAPI-Specification) v3.x representation of the API metadata provided via the [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") and [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.") modules.
|
|
14
14
|
|
|
15
15
|
## Configuration
|
|
16
16
|
By installing the dependency, the [OpenAPI](https://github.com/OAI/OpenAPI-Specification) endpoint is automatically generated and exposed at the root of the application as `/openapi.yml` or `/openapi.json` (by default).
|
|
@@ -19,31 +19,45 @@ All of the high level configurations can be found in the following structure:
|
|
|
19
19
|
|
|
20
20
|
**Code: Config: OpenAPI Configuration**
|
|
21
21
|
```typescript
|
|
22
|
-
import * as path from 'path';
|
|
23
|
-
import * as fs from 'fs/promises';
|
|
24
22
|
import { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
|
|
25
23
|
|
|
26
24
|
import { Config } from '@travetto/config';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
25
|
+
import { path, RootIndex } from '@travetto/manifest';
|
|
26
|
+
import { GlobalEnv } from '@travetto/base';
|
|
27
|
+
import { Required } from '@travetto/schema';
|
|
29
28
|
|
|
30
29
|
/**
|
|
31
30
|
* API Information, infers as much as possible from the package.json
|
|
32
31
|
*/
|
|
33
|
-
@Config('api.info'
|
|
32
|
+
@Config('api.info')
|
|
34
33
|
export class ApiInfoConfig {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
@Required(false)
|
|
35
|
+
contact: ContactObject;
|
|
36
|
+
@Required(false)
|
|
37
|
+
description?: string;
|
|
38
|
+
@Required(false)
|
|
39
|
+
license: LicenseObject;
|
|
40
|
+
@Required(false)
|
|
38
41
|
termsOfService?: string;
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
@Required(false)
|
|
43
|
+
title: string;
|
|
44
|
+
@Required(false)
|
|
45
|
+
version: string;
|
|
46
|
+
|
|
47
|
+
postConstruct(): void {
|
|
48
|
+
const info = RootIndex.mainPackage;
|
|
49
|
+
this.contact ??= info.author ?? {};
|
|
50
|
+
this.description ??= info.description;
|
|
51
|
+
this.license ??= { name: info.license! };
|
|
52
|
+
this.title ??= info.name;
|
|
53
|
+
this.version ??= info.version;
|
|
54
|
+
}
|
|
41
55
|
}
|
|
42
56
|
|
|
43
57
|
/**
|
|
44
58
|
* The API host, infers from rest host configuration
|
|
45
59
|
*/
|
|
46
|
-
@Config('api.host'
|
|
60
|
+
@Config('api.host')
|
|
47
61
|
export class ApiHostConfig {
|
|
48
62
|
/**
|
|
49
63
|
* List of servers
|
|
@@ -58,7 +72,7 @@ export class ApiHostConfig {
|
|
|
58
72
|
/**
|
|
59
73
|
* The spec file configuration
|
|
60
74
|
*/
|
|
61
|
-
@Config('api.spec'
|
|
75
|
+
@Config('api.spec')
|
|
62
76
|
export class ApiSpecConfig {
|
|
63
77
|
/**
|
|
64
78
|
* Where to output file to
|
|
@@ -67,7 +81,7 @@ export class ApiSpecConfig {
|
|
|
67
81
|
/**
|
|
68
82
|
* Should file be generated at runtime
|
|
69
83
|
*/
|
|
70
|
-
persist
|
|
84
|
+
persist?: boolean;
|
|
71
85
|
/**
|
|
72
86
|
* Skip emitting all routes
|
|
73
87
|
*/
|
|
@@ -78,15 +92,16 @@ export class ApiSpecConfig {
|
|
|
78
92
|
exposeAllSchemas: boolean = false;
|
|
79
93
|
|
|
80
94
|
async postConstruct(): Promise<void> {
|
|
81
|
-
this.output =
|
|
95
|
+
this.output = path.toPosix(this.output);
|
|
82
96
|
if (!this.output || this.output === '-') {
|
|
83
97
|
this.persist = false;
|
|
98
|
+
} else {
|
|
99
|
+
this.persist ??= GlobalEnv.dynamic;
|
|
84
100
|
}
|
|
85
101
|
if (this.persist) {
|
|
86
102
|
if (!/[.](json|ya?ml)$/.test(this.output)) { // Assume a folder
|
|
87
|
-
this.output =
|
|
103
|
+
this.output = path.resolve(this.output, 'openapi.yml');
|
|
88
104
|
}
|
|
89
|
-
await fs.mkdir(path.dirname(this.output), { recursive: true });
|
|
90
105
|
}
|
|
91
106
|
}
|
|
92
107
|
}
|
|
@@ -108,6 +123,8 @@ Usage: openapi:spec [options]
|
|
|
108
123
|
Options:
|
|
109
124
|
-o, --output <output> Output files (default: "./openapi.yml")
|
|
110
125
|
-h, --help display help for command
|
|
126
|
+
|
|
127
|
+
[s[r[u
|
|
111
128
|
```
|
|
112
129
|
|
|
113
130
|
The command will run your application, in non-server mode, to collect all the routes and model information, to produce the `openapi.yml`. Once produced, the code will store the output in the specified location.
|
|
@@ -122,23 +139,7 @@ The module provides a command for the [Command Line Interface](https://github.co
|
|
|
122
139
|
```bash
|
|
123
140
|
$ trv openapi:client --help
|
|
124
141
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Options:
|
|
128
|
-
-x, --extended-help Show Extended Help
|
|
129
|
-
-a, --additional-properties <additional-properties> Additional Properties (default: [])
|
|
130
|
-
-i, --input <input> Input file (default: "@trv:openapi/openapi.yml")
|
|
131
|
-
-o, --output <output> Output folder (default: "@trv:openapi/api-client")
|
|
132
|
-
-d, --docker-image <docker-image> Docker Image to use (default: "arcsine/openapi-generator:latest")
|
|
133
|
-
-w, --watch Watch for file changes
|
|
134
|
-
-h, --help display help for command
|
|
135
|
-
|
|
136
|
-
Available Presets
|
|
137
|
-
----------------------------------
|
|
138
|
-
* @trv:angular10 -- typescript-angular supportsES6=true,ngVersion=10.0
|
|
139
|
-
* @trv:angular11 -- typescript-angular supportsES6=true,ngVersion=11.0
|
|
140
|
-
* @trv:angular12 -- typescript-angular supportsES6=true,ngVersion=11.0
|
|
141
|
-
* @trv:fetch -- typescript-fetch
|
|
142
|
+
[s[r[u
|
|
142
143
|
```
|
|
143
144
|
|
|
144
145
|
This tool relies upon a custom build of [OpenAPI client generation tools](https://github.com/OpenAPITools/openapi-generator), which supports watching. This allows for fast responsive client generation as the shape of the API changes.
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/openapi",
|
|
3
|
-
"
|
|
4
|
-
"version": "3.0.0-rc.3",
|
|
3
|
+
"version": "3.0.0-rc.6",
|
|
5
4
|
"description": "OpenAPI integration support for the travetto framework",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"rest",
|
|
@@ -17,31 +16,33 @@
|
|
|
17
16
|
"name": "Travetto Framework"
|
|
18
17
|
},
|
|
19
18
|
"files": [
|
|
20
|
-
"
|
|
19
|
+
"__index__.ts",
|
|
21
20
|
"src",
|
|
22
|
-
"
|
|
23
|
-
"resources"
|
|
21
|
+
"support"
|
|
24
22
|
],
|
|
25
|
-
"main": "
|
|
23
|
+
"main": "__index__.ts",
|
|
26
24
|
"repository": {
|
|
27
25
|
"url": "https://github.com/travetto/travetto.git",
|
|
28
26
|
"directory": "module/openapi"
|
|
29
27
|
},
|
|
30
28
|
"dependencies": {
|
|
31
|
-
"@travetto/config": "^3.0.0-rc.
|
|
32
|
-
"@travetto/rest": "^3.0.0-rc.
|
|
33
|
-
"@travetto/schema": "^3.0.0-rc.
|
|
34
|
-
"@travetto/yaml": "^3.0.0-rc.
|
|
29
|
+
"@travetto/config": "^3.0.0-rc.6",
|
|
30
|
+
"@travetto/rest": "^3.0.0-rc.6",
|
|
31
|
+
"@travetto/schema": "^3.0.0-rc.6",
|
|
32
|
+
"@travetto/yaml": "^3.0.0-rc.4",
|
|
35
33
|
"openapi3-ts": "^2.0.2"
|
|
36
34
|
},
|
|
37
35
|
"peerDependencies": {
|
|
38
|
-
"@travetto/cli": "^3.0.0-rc.
|
|
36
|
+
"@travetto/cli": "^3.0.0-rc.4"
|
|
39
37
|
},
|
|
40
38
|
"peerDependenciesMeta": {
|
|
41
39
|
"@travetto/cli": {
|
|
42
40
|
"optional": true
|
|
43
41
|
}
|
|
44
42
|
},
|
|
43
|
+
"travetto": {
|
|
44
|
+
"displayName": "OpenAPI Specification"
|
|
45
|
+
},
|
|
45
46
|
"publishConfig": {
|
|
46
47
|
"access": "public"
|
|
47
48
|
}
|
package/src/config.ts
CHANGED
|
@@ -1,28 +1,43 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import * as fs from 'fs/promises';
|
|
3
1
|
import { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
|
|
4
2
|
|
|
5
3
|
import { Config } from '@travetto/config';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { path, RootIndex } from '@travetto/manifest';
|
|
5
|
+
import { GlobalEnv } from '@travetto/base';
|
|
6
|
+
import { Required } from '@travetto/schema';
|
|
7
|
+
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* API Information, infers as much as possible from the package.json
|
|
11
11
|
*/
|
|
12
|
-
@Config('api.info'
|
|
12
|
+
@Config('api.info')
|
|
13
13
|
export class ApiInfoConfig {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
@Required(false)
|
|
15
|
+
contact: ContactObject;
|
|
16
|
+
@Required(false)
|
|
17
|
+
description?: string;
|
|
18
|
+
@Required(false)
|
|
19
|
+
license: LicenseObject;
|
|
20
|
+
@Required(false)
|
|
17
21
|
termsOfService?: string;
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
@Required(false)
|
|
23
|
+
title: string;
|
|
24
|
+
@Required(false)
|
|
25
|
+
version: string;
|
|
26
|
+
|
|
27
|
+
postConstruct(): void {
|
|
28
|
+
const info = RootIndex.mainPackage;
|
|
29
|
+
this.contact ??= info.author ?? {};
|
|
30
|
+
this.description ??= info.description;
|
|
31
|
+
this.license ??= { name: info.license! };
|
|
32
|
+
this.title ??= info.name;
|
|
33
|
+
this.version ??= info.version;
|
|
34
|
+
}
|
|
20
35
|
}
|
|
21
36
|
|
|
22
37
|
/**
|
|
23
38
|
* The API host, infers from rest host configuration
|
|
24
39
|
*/
|
|
25
|
-
@Config('api.host'
|
|
40
|
+
@Config('api.host')
|
|
26
41
|
export class ApiHostConfig {
|
|
27
42
|
/**
|
|
28
43
|
* List of servers
|
|
@@ -37,7 +52,7 @@ export class ApiHostConfig {
|
|
|
37
52
|
/**
|
|
38
53
|
* The spec file configuration
|
|
39
54
|
*/
|
|
40
|
-
@Config('api.spec'
|
|
55
|
+
@Config('api.spec')
|
|
41
56
|
export class ApiSpecConfig {
|
|
42
57
|
/**
|
|
43
58
|
* Where to output file to
|
|
@@ -46,7 +61,7 @@ export class ApiSpecConfig {
|
|
|
46
61
|
/**
|
|
47
62
|
* Should file be generated at runtime
|
|
48
63
|
*/
|
|
49
|
-
persist
|
|
64
|
+
persist?: boolean;
|
|
50
65
|
/**
|
|
51
66
|
* Skip emitting all routes
|
|
52
67
|
*/
|
|
@@ -57,15 +72,16 @@ export class ApiSpecConfig {
|
|
|
57
72
|
exposeAllSchemas: boolean = false;
|
|
58
73
|
|
|
59
74
|
async postConstruct(): Promise<void> {
|
|
60
|
-
this.output =
|
|
75
|
+
this.output = path.toPosix(this.output);
|
|
61
76
|
if (!this.output || this.output === '-') {
|
|
62
77
|
this.persist = false;
|
|
78
|
+
} else {
|
|
79
|
+
this.persist ??= GlobalEnv.dynamic;
|
|
63
80
|
}
|
|
64
81
|
if (this.persist) {
|
|
65
82
|
if (!/[.](json|ya?ml)$/.test(this.output)) { // Assume a folder
|
|
66
|
-
this.output =
|
|
83
|
+
this.output = path.resolve(this.output, 'openapi.yml');
|
|
67
84
|
}
|
|
68
|
-
await fs.mkdir(path.dirname(this.output), { recursive: true });
|
|
69
85
|
}
|
|
70
86
|
}
|
|
71
87
|
}
|
package/src/service.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
2
|
import { OpenAPIObject } from 'openapi3-ts';
|
|
3
3
|
|
|
4
|
+
import { path } from '@travetto/manifest';
|
|
4
5
|
import { Injectable, Inject } from '@travetto/di';
|
|
5
6
|
import { ControllerRegistry, RestConfig } from '@travetto/rest';
|
|
6
7
|
import { SchemaRegistry } from '@travetto/schema';
|
|
@@ -78,6 +79,8 @@ export class OpenApiService {
|
|
|
78
79
|
JSON.stringify(this.spec, undefined, 2) :
|
|
79
80
|
YamlUtil.serialize(this.spec);
|
|
80
81
|
|
|
82
|
+
// TODO: Should use file abstraction
|
|
83
|
+
await fs.mkdir(path.dirname(this.apiSpecConfig.output), { recursive: true });
|
|
81
84
|
await fs.writeFile(this.apiSpecConfig.output, output);
|
|
82
85
|
} catch (err) {
|
|
83
86
|
console.error('Unable to persist openapi spec', err);
|
package/src/spec-generate.ts
CHANGED
|
@@ -40,7 +40,7 @@ export class SpecGenerator {
|
|
|
40
40
|
* @param cls
|
|
41
41
|
*/
|
|
42
42
|
#getTypeId(cls: Class): string {
|
|
43
|
-
return cls.name?.replace('
|
|
43
|
+
return cls.name?.replace('Ⲑsyn', '');
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -69,7 +69,7 @@ export class SpecGenerator {
|
|
|
69
69
|
const viewConf = SchemaRegistry.has(field.type) && SchemaRegistry.getViewSchema(field.type, field.view);
|
|
70
70
|
const schemaConf = viewConf && viewConf.schema;
|
|
71
71
|
if (!schemaConf) {
|
|
72
|
-
throw new Error(`Unknown class, not registered as a schema: ${field.type
|
|
72
|
+
throw new Error(`Unknown class, not registered as a schema: ${field.type.Ⲑid}`);
|
|
73
73
|
}
|
|
74
74
|
const params: ParameterObject[] = [];
|
|
75
75
|
for (const sub of Object.values(schemaConf)) {
|
|
@@ -379,7 +379,7 @@ export class SpecGenerator {
|
|
|
379
379
|
|
|
380
380
|
if (!config.skipRoutes) {
|
|
381
381
|
for (const cls of ControllerRegistry.getClasses()) {
|
|
382
|
-
if (cls
|
|
382
|
+
if (cls.Ⲑid !== OpenApiController.Ⲑid) {
|
|
383
383
|
this.processController(cls);
|
|
384
384
|
}
|
|
385
385
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
3
|
+
import cp from 'child_process';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const presets: Record<string, [string, object] | [string]> = JSON.parse(readFileSync(PathUtil.resolveUnix(__dirname, '..', 'resources', 'presets.json'), 'utf8'));
|
|
5
|
+
import { path } from '@travetto/manifest';
|
|
6
|
+
import { ExecUtil, FileResourceProvider } from '@travetto/base';
|
|
7
|
+
import { CliCommand, cliTpl, OptionConfig, ListOptionConfig } from '@travetto/cli';
|
|
10
8
|
|
|
11
9
|
type Options = {
|
|
12
10
|
extendedHelp: OptionConfig<boolean>;
|
|
@@ -20,26 +18,36 @@ type Options = {
|
|
|
20
18
|
* CLI for generating the cli client
|
|
21
19
|
*/
|
|
22
20
|
export class OpenApiClientCommand extends CliCommand<Options> {
|
|
21
|
+
#presets: Record<string, [string, object] | [string]>;
|
|
23
22
|
name = 'openapi:client';
|
|
23
|
+
#resources = new FileResourceProvider(['@travetto/openapi']);
|
|
24
|
+
|
|
25
|
+
async getPresets(): Promise<Record<string, [string, object] | [string]>> {
|
|
26
|
+
if (!this.#presets) {
|
|
27
|
+
const text = await this.#resources.read('presets.json');
|
|
28
|
+
this.#presets = JSON.parse(text);
|
|
29
|
+
}
|
|
30
|
+
return this.#presets;
|
|
31
|
+
}
|
|
24
32
|
|
|
25
33
|
presetMap(prop?: object): string {
|
|
26
34
|
return !prop || Object.keys(prop).length === 0 ? '' : Object.entries(prop).map(([k, v]) => `${k}=${v}`).join(',');
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
getListOfFormats(): string[] {
|
|
30
|
-
const
|
|
31
|
-
|
|
38
|
+
const formatCache = path.resolve('.trv-openapi-formats.json');
|
|
39
|
+
if (!existsSync(formatCache)) {
|
|
40
|
+
const stdout = cp.execSync(`docker run --rm ${this.cmd.dockerImage} list`, { stdio: ['pipe', 'pipe'], encoding: 'utf8' }).trim();
|
|
32
41
|
const lines = stdout
|
|
33
42
|
.split('DOCUMENTATION')[0]
|
|
34
43
|
.trim()
|
|
35
44
|
.split(/\n/g)
|
|
36
45
|
.filter(x => /^\s+-/.test(x) && !/\((beta|experimental)\)/.test(x))
|
|
37
46
|
.map(x => x.replace(/^\s+-\s+/, '').trim());
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const list: string[] = JSON.parse(json);
|
|
47
|
+
|
|
48
|
+
writeFileSync(formatCache, JSON.stringify([...lines.sort(),]));
|
|
49
|
+
}
|
|
50
|
+
const list: string[] = JSON.parse(readFileSync(formatCache, 'utf8'));
|
|
43
51
|
return list;
|
|
44
52
|
}
|
|
45
53
|
|
|
@@ -47,29 +55,30 @@ export class OpenApiClientCommand extends CliCommand<Options> {
|
|
|
47
55
|
return {
|
|
48
56
|
extendedHelp: this.boolOption({ name: 'extended-help', short: 'x', desc: 'Show Extended Help' }),
|
|
49
57
|
props: this.listOption({ name: 'additional-properties', short: 'a', desc: 'Additional Properties' }),
|
|
50
|
-
input: this.option({ desc: 'Input file', def: './openapi.yml', combine: v =>
|
|
51
|
-
output: this.option({ desc: 'Output folder', def: './api-client', combine: v =>
|
|
58
|
+
input: this.option({ desc: 'Input file', def: './openapi.yml', combine: v => path.resolve(v), completion: true }),
|
|
59
|
+
output: this.option({ desc: 'Output folder', def: './api-client', combine: v => path.resolve(v), completion: true }),
|
|
52
60
|
dockerImage: this.option({ desc: 'Docker Image to use', def: 'arcsine/openapi-generator:latest' }),
|
|
53
61
|
watch: this.boolOption({ desc: 'Watch for file changes' })
|
|
54
62
|
};
|
|
55
63
|
}
|
|
56
64
|
|
|
57
|
-
help(): string {
|
|
65
|
+
async help(): Promise<string> {
|
|
66
|
+
const presets = await this.getPresets();
|
|
58
67
|
const presetLen = Math.max(...Object.keys(presets).map(x => x.length));
|
|
59
68
|
const presetEntries = Object
|
|
60
69
|
.entries(presets)
|
|
61
70
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
62
|
-
.map(([k, [cmd, v]]) => [`@
|
|
71
|
+
.map(([k, [cmd, v]]) => [`@travetto/${k}`.padEnd(presetLen + 5), [cmd, this.presetMap(v)]] as const);
|
|
63
72
|
|
|
64
|
-
const presetText =
|
|
73
|
+
const presetText = cliTpl`
|
|
65
74
|
${{ subtitle: 'Available Presets' }}
|
|
66
75
|
----------------------------------
|
|
67
|
-
${presetEntries.map(([k, [cmd, param]]) =>
|
|
76
|
+
${presetEntries.map(([k, [cmd, param]]) => cliTpl`* ${{ input: k }} -- ${{ identifier: cmd }} ${{ param }}`).join('\n')}`;
|
|
68
77
|
|
|
69
|
-
const formatText =
|
|
78
|
+
const formatText = cliTpl`
|
|
70
79
|
${{ subtitle: 'Available Formats' }}
|
|
71
80
|
----------------------------------
|
|
72
|
-
${this.getListOfFormats().map(x =>
|
|
81
|
+
${this.getListOfFormats().map(x => cliTpl`* ${{ input: x }}`).join('\n')} `;
|
|
73
82
|
|
|
74
83
|
return this.cmd.extendedHelp ? `${presetText}\n${formatText}` : presetText;
|
|
75
84
|
}
|
|
@@ -80,7 +89,7 @@ ${this.getListOfFormats().map(x => color`* ${{ input: x }}`).join('\n')} `;
|
|
|
80
89
|
|
|
81
90
|
async action(format: string): Promise<void> {
|
|
82
91
|
if (!format) {
|
|
83
|
-
this.showHelp(new Error('Format is required'));
|
|
92
|
+
return this.showHelp(new Error('Format is required'));
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
// Ensure its there
|
|
@@ -88,9 +97,9 @@ ${this.getListOfFormats().map(x => color`* ${{ input: x }}`).join('\n')} `;
|
|
|
88
97
|
|
|
89
98
|
let propMap = Object.fromEntries(this.cmd.props?.map(p => p.split('=')) ?? []);
|
|
90
99
|
|
|
91
|
-
if (format.startsWith('@
|
|
92
|
-
const key = format.split('@
|
|
93
|
-
const [fmt, props] =
|
|
100
|
+
if (format.startsWith('@travetto/')) {
|
|
101
|
+
const key = format.split('@travetto/')[1];
|
|
102
|
+
const [fmt, props] = (await this.getPresets())[key];
|
|
94
103
|
format = fmt;
|
|
95
104
|
propMap = { ...props, ...propMap };
|
|
96
105
|
}
|
|
@@ -116,6 +125,6 @@ ${this.getListOfFormats().map(x => color`* ${{ input: x }}`).join('\n')} `;
|
|
|
116
125
|
];
|
|
117
126
|
|
|
118
127
|
const { result } = ExecUtil.spawn('docker', args, { stdio: [0, 1, 2] });
|
|
119
|
-
await result.catch(err =>
|
|
128
|
+
await result.catch(err => this.exit(1));
|
|
120
129
|
}
|
|
121
130
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CliCommand, OptionConfig } from '@travetto/cli
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { CliCommand, OptionConfig } from '@travetto/cli';
|
|
2
|
+
import { RootIndex } from '@travetto/manifest';
|
|
3
|
+
import { ExecUtil, GlobalEnvConfig } from '@travetto/base';
|
|
4
4
|
|
|
5
5
|
type Options = {
|
|
6
6
|
output: OptionConfig<string>;
|
|
@@ -16,15 +16,15 @@ export class OpenApiSpecCommand extends CliCommand<Options> {
|
|
|
16
16
|
return { output: this.option({ desc: 'Output files', def: './openapi.yml' }) };
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
envInit():
|
|
20
|
-
|
|
21
|
-
debug:
|
|
19
|
+
envInit(): GlobalEnvConfig {
|
|
20
|
+
return {
|
|
21
|
+
debug: false,
|
|
22
22
|
set: { API_SPEC_OUTPUT: this.cmd.output }
|
|
23
|
-
}
|
|
23
|
+
};
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async action(): Promise<void> {
|
|
27
|
-
const result = await ExecUtil.
|
|
27
|
+
const result = await ExecUtil.worker(RootIndex.resolveFileImport('@travetto/openapi/support/main.generate.ts')).message;
|
|
28
28
|
|
|
29
29
|
if (this.cmd.output === '-' || !this.cmd.output) {
|
|
30
30
|
console.log!(result);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DependencyRegistry } from '@travetto/di';
|
|
2
|
+
import { RootRegistry } from '@travetto/registry';
|
|
3
|
+
|
|
4
|
+
import { OpenApiService } from '../src/service';
|
|
5
|
+
|
|
6
|
+
export async function main(): Promise<unknown> {
|
|
7
|
+
await RootRegistry.init();
|
|
8
|
+
|
|
9
|
+
const instance = await DependencyRegistry.getInstance(OpenApiService);
|
|
10
|
+
return instance.spec;
|
|
11
|
+
}
|
|
File without changes
|
package/bin/generate.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ExecUtil } from '@travetto/boot';
|
|
2
|
-
|
|
3
|
-
export async function main(): Promise<void> {
|
|
4
|
-
const { PhaseManager } = await import('@travetto/base');
|
|
5
|
-
await PhaseManager.run('init');
|
|
6
|
-
|
|
7
|
-
const { DependencyRegistry } = await import('@travetto/di');
|
|
8
|
-
const { OpenApiService } = await import('../src/service');
|
|
9
|
-
|
|
10
|
-
const instance = await DependencyRegistry.getInstance(OpenApiService);
|
|
11
|
-
ExecUtil.mainResponse(await instance.spec);
|
|
12
|
-
}
|