@travetto/openapi 3.0.0-rc.2 → 3.0.0-rc.20

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 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/doc.ts and execute "npx trv doc" to rebuild -->
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. ") modules.
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
- import { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
22
+ import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
25
23
 
26
- import { Config } from '@travetto/config';
27
- import { PathUtil, EnvUtil } from '@travetto/boot';
28
- import { AppManifest } from '@travetto/base';
24
+ import { Config, EnvVar } from '@travetto/config';
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', { internal: true })
32
+ @Config('api.info')
34
33
  export class ApiInfoConfig {
35
- contact: ContactObject = AppManifest.info.author ?? {};
36
- description?: string = AppManifest.info.description;
37
- license: LicenseObject = { name: AppManifest.info.license! };
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
- title: string = AppManifest.info.name;
40
- version: string = AppManifest.info.version ?? '0.0.0';
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', { internal: true })
60
+ @Config('api.host')
47
61
  export class ApiHostConfig {
48
62
  /**
49
63
  * List of servers
@@ -58,16 +72,18 @@ export class ApiHostConfig {
58
72
  /**
59
73
  * The spec file configuration
60
74
  */
61
- @Config('api.spec', { internal: true })
75
+ @Config('api.spec')
62
76
  export class ApiSpecConfig {
63
77
  /**
64
78
  * Where to output file to
65
79
  */
80
+ @EnvVar('TRV_OPENAPI_OUTPUT')
66
81
  output: string = 'openapi.yml';
67
82
  /**
68
83
  * Should file be generated at runtime
69
84
  */
70
- persist: boolean = EnvUtil.isDynamic();
85
+ @EnvVar('TRV_OPENAPI_PERSIST')
86
+ persist?: boolean;
71
87
  /**
72
88
  * Skip emitting all routes
73
89
  */
@@ -78,15 +94,16 @@ export class ApiSpecConfig {
78
94
  exposeAllSchemas: boolean = false;
79
95
 
80
96
  async postConstruct(): Promise<void> {
81
- this.output = PathUtil.toUnix(this.output);
97
+ this.output = path.toPosix(this.output);
82
98
  if (!this.output || this.output === '-') {
83
99
  this.persist = false;
100
+ } else {
101
+ this.persist ??= GlobalEnv.dynamic;
84
102
  }
85
103
  if (this.persist) {
86
104
  if (!/[.](json|ya?ml)$/.test(this.output)) { // Assume a folder
87
- this.output = PathUtil.resolveUnix(this.output, 'openapi.yml');
105
+ this.output = path.resolve(this.output, 'openapi.yml');
88
106
  }
89
- await fs.mkdir(path.dirname(this.output), { recursive: true });
90
107
  }
91
108
  }
92
109
  }
@@ -127,18 +144,21 @@ Usage: openapi:client [options] [format-or-preset]
127
144
  Options:
128
145
  -x, --extended-help Show Extended Help
129
146
  -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")
147
+ -i, --input <input> Input file (default:
148
+ "@travetto/openapi/openapi.yml")
149
+ -o, --output <output> Output folder (default:
150
+ "@travetto/openapi/api-client")
151
+ -d, --docker-image <docker-image> Docker Image to use (default:
152
+ "arcsine/openapi-generator:latest")
133
153
  -w, --watch Watch for file changes
134
154
  -h, --help display help for command
135
155
 
136
156
  Available Presets
137
157
  ----------------------------------
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
158
+ * @travetto/angular10 -- typescript-angular supportsES6=true,ngVersion=10.0
159
+ * @travetto/angular11 -- typescript-angular supportsES6=true,ngVersion=11.0
160
+ * @travetto/angular12 -- typescript-angular supportsES6=true,ngVersion=11.0
161
+ * @travetto/fetch -- typescript-fetch
142
162
  ```
143
163
 
144
164
  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
- "displayName": "OpenAPI Specification",
4
- "version": "3.0.0-rc.2",
3
+ "version": "3.0.0-rc.20",
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
- "index.ts",
19
+ "__index__.ts",
21
20
  "src",
22
- "bin",
23
- "resources"
21
+ "support"
24
22
  ],
25
- "main": "index.ts",
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.2",
32
- "@travetto/rest": "^3.0.0-rc.2",
33
- "@travetto/schema": "^3.0.0-rc.2",
34
- "@travetto/yaml": "^3.0.0-rc.0",
35
- "openapi3-ts": "^2.0.2"
29
+ "@travetto/config": "^3.0.0-rc.19",
30
+ "@travetto/rest": "^3.0.0-rc.20",
31
+ "@travetto/schema": "^3.0.0-rc.19",
32
+ "@travetto/yaml": "^3.0.0-rc.15",
33
+ "openapi3-ts": "^3.1.2"
36
34
  },
37
35
  "peerDependencies": {
38
- "@travetto/cli": "^3.0.0-rc.0"
36
+ "@travetto/cli": "^3.0.0-rc.16"
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
- import { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
1
+ import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
2
+
3
+ import { Config, EnvVar } from '@travetto/config';
4
+ import { path, RootIndex } from '@travetto/manifest';
5
+ import { GlobalEnv } from '@travetto/base';
6
+ import { Required } from '@travetto/schema';
4
7
 
5
- import { Config } from '@travetto/config';
6
- import { PathUtil, EnvUtil } from '@travetto/boot';
7
- import { AppManifest } from '@travetto/base';
8
8
 
9
9
  /**
10
10
  * API Information, infers as much as possible from the package.json
11
11
  */
12
- @Config('api.info', { internal: true })
12
+ @Config('api.info')
13
13
  export class ApiInfoConfig {
14
- contact: ContactObject = AppManifest.info.author ?? {};
15
- description?: string = AppManifest.info.description;
16
- license: LicenseObject = { name: AppManifest.info.license! };
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
- title: string = AppManifest.info.name;
19
- version: string = AppManifest.info.version ?? '0.0.0';
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', { internal: true })
40
+ @Config('api.host')
26
41
  export class ApiHostConfig {
27
42
  /**
28
43
  * List of servers
@@ -37,16 +52,18 @@ export class ApiHostConfig {
37
52
  /**
38
53
  * The spec file configuration
39
54
  */
40
- @Config('api.spec', { internal: true })
55
+ @Config('api.spec')
41
56
  export class ApiSpecConfig {
42
57
  /**
43
58
  * Where to output file to
44
59
  */
60
+ @EnvVar('TRV_OPENAPI_OUTPUT')
45
61
  output: string = 'openapi.yml';
46
62
  /**
47
63
  * Should file be generated at runtime
48
64
  */
49
- persist: boolean = EnvUtil.isDynamic();
65
+ @EnvVar('TRV_OPENAPI_PERSIST')
66
+ persist?: boolean;
50
67
  /**
51
68
  * Skip emitting all routes
52
69
  */
@@ -57,15 +74,16 @@ export class ApiSpecConfig {
57
74
  exposeAllSchemas: boolean = false;
58
75
 
59
76
  async postConstruct(): Promise<void> {
60
- this.output = PathUtil.toUnix(this.output);
77
+ this.output = path.toPosix(this.output);
61
78
  if (!this.output || this.output === '-') {
62
79
  this.persist = false;
80
+ } else {
81
+ this.persist ??= GlobalEnv.dynamic;
63
82
  }
64
83
  if (this.persist) {
65
84
  if (!/[.](json|ya?ml)$/.test(this.output)) { // Assume a folder
66
- this.output = PathUtil.resolveUnix(this.output, 'openapi.yml');
85
+ this.output = path.resolve(this.output, 'openapi.yml');
67
86
  }
68
- await fs.mkdir(path.dirname(this.output), { recursive: true });
69
87
  }
70
88
  }
71
89
  }
package/src/service.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { promises as fs } from 'fs';
2
- import { OpenAPIObject } from 'openapi3-ts';
1
+ import fs from 'fs/promises';
2
+ import type { 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);
@@ -40,7 +40,7 @@ export class SpecGenerator {
40
40
  * @param cls
41
41
  */
42
42
  #getTypeId(cls: Class): string {
43
- return cls.name?.replace('syn', '');
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.ᚕid}`);
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)) {
@@ -85,8 +85,7 @@ export class SpecGenerator {
85
85
  ...this.#getType(sub)
86
86
  } : this.#getType(sub),
87
87
  required: !!(rootField?.required?.active && sub.required?.active),
88
- in: location,
89
- extract: undefined
88
+ in: location
90
89
  });
91
90
  }
92
91
  }
@@ -245,7 +244,7 @@ export class SpecGenerator {
245
244
  } else if (body.type === Readable || body.type === Buffer) {
246
245
  return {
247
246
  content: {
248
- [mime ?? 'application/octet-stream']: { type: 'string', format: 'binary' }
247
+ [mime ?? 'application/octet-stream']: { schema: { type: 'string', format: 'binary' } }
249
248
  },
250
249
  description: ''
251
250
  };
@@ -379,7 +378,7 @@ export class SpecGenerator {
379
378
 
380
379
  if (!config.skipRoutes) {
381
380
  for (const cls of ControllerRegistry.getClasses()) {
382
- if (cls.ᚕid !== OpenApiController.ᚕid) {
381
+ if (cls.Ⲑid !== OpenApiController.Ⲑid) {
383
382
  this.processController(cls);
384
383
  }
385
384
  }
@@ -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
+ }
@@ -1,12 +1,10 @@
1
- import * as path from 'path';
2
- import * as fs from 'fs/promises';
3
- import { readFileSync } from 'fs';
1
+ import fs from 'fs/promises';
2
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
3
+ import cp from 'child_process';
4
4
 
5
- import { CliCommand, OptionConfig, ListOptionConfig } from '@travetto/cli/src/command';
6
- import { AppCache, ExecUtil, PathUtil } from '@travetto/boot';
7
- import { color } from '@travetto/cli/src/color';
8
-
9
- const presets: Record<string, [string, object] | [string]> = JSON.parse(readFileSync(PathUtil.resolveUnix(__dirname, '..', 'resources', 'presets.json'), 'utf8'));
5
+ import { path, RootIndex } 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#support/resources']);
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 json = AppCache.getOrSet('openapi-formats.json', () => {
31
- const stdout = ExecUtil.execSync('docker', ['run', '--rm', this.cmd.dockerImage, 'list']);
38
+ const formatCache = path.resolve(RootIndex.manifest.workspacePath, RootIndex.manifest.outputFolder, '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
- return JSON.stringify([
39
- ...lines.sort(),
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,40 +55,41 @@ 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 => PathUtil.resolveUnix(v), completion: true }),
51
- output: this.option({ desc: 'Output folder', def: './api-client', combine: v => PathUtil.resolveUnix(v), completion: true }),
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]]) => [`@trv:${k}`.padEnd(presetLen + 5), [cmd, this.presetMap(v)]] as const);
71
+ .map(([k, [cmd, v]]) => [`@travetto/${k}`.padEnd(presetLen + 5), [cmd, this.presetMap(v)]] as const);
63
72
 
64
- const presetText = color`
73
+ const presetText = cliTpl`
65
74
  ${{ subtitle: 'Available Presets' }}
66
75
  ----------------------------------
67
- ${presetEntries.map(([k, [cmd, param]]) => color`* ${{ input: k }} -- ${{ identifier: cmd }} ${{ param }}`).join('\n')}`;
76
+ ${presetEntries.map(([k, [cmd, param]]) => cliTpl`* ${{ input: k }} -- ${{ identifier: cmd }} ${{ param }}`).join('\n')}`;
68
77
 
69
- const formatText = color`
78
+ const formatText = cliTpl`
70
79
  ${{ subtitle: 'Available Formats' }}
71
80
  ----------------------------------
72
- ${this.getListOfFormats().map(x => color`* ${{ input: x }}`).join('\n')} `;
81
+ ${this.getListOfFormats().map(x => cliTpl`* ${{ input: x }}`).join('\n')} `;
73
82
 
74
83
  return this.cmd.extendedHelp ? `${presetText}\n${formatText}` : presetText;
75
84
  }
76
85
 
77
86
  getArgs(): string {
78
- return '[format-or-preset]';
87
+ return '<format-or-preset>';
79
88
  }
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('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('@trv:')) {
92
- const key = format.split('@trv:')[1];
93
- const [fmt, props] = presets[key];
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 => process.exit(1));
128
+ await result.catch(err => this.exit(1));
120
129
  }
121
130
  }
@@ -0,0 +1,37 @@
1
+ import { CliCommand, OptionConfig } from '@travetto/cli';
2
+ import { RootIndex } from '@travetto/manifest';
3
+ import { ExecUtil, GlobalEnvConfig } from '@travetto/base';
4
+
5
+ type Options = {
6
+ output: OptionConfig<string>;
7
+ };
8
+
9
+ /**
10
+ * CLI for outputting the open api spec to a local file
11
+ */
12
+ export class OpenApiSpecCommand extends CliCommand<Options> {
13
+ name = 'openapi:spec';
14
+
15
+ getOptions(): Options {
16
+ return { output: this.option({ desc: 'Output files', def: './openapi.yml' }) };
17
+ }
18
+
19
+ envInit(): GlobalEnvConfig {
20
+ return {
21
+ debug: false,
22
+ set: { API_SPEC_OUTPUT: this.cmd.output }
23
+ };
24
+ }
25
+
26
+ async action(): Promise<void> {
27
+ const result = await ExecUtil.worker(
28
+ RootIndex.resolveFileImport('@travetto/cli/support/cli.ts'),
29
+ ['main', '@travetto/openapi/support/bin/generate.ts'],
30
+ { env: { TRV_OPENAPI_OUTPUT: this.cmd.output, TRV_OPENAPI_PERSIST: '1' } }
31
+ ).message;
32
+
33
+ if (this.cmd.output === '-' || !this.cmd.output) {
34
+ console.log!(result);
35
+ }
36
+ }
37
+ }
File without changes
@@ -1,33 +0,0 @@
1
- import { CliCommand, OptionConfig } from '@travetto/cli/src/command';
2
- import { ExecUtil } from '@travetto/boot';
3
- import { EnvInit } from '@travetto/base/bin/init';
4
-
5
- type Options = {
6
- output: OptionConfig<string>;
7
- };
8
-
9
- /**
10
- * CLI for outputting the open api spec to a local file
11
- */
12
- export class OpenApiSpecCommand extends CliCommand<Options> {
13
- name = 'openapi:spec';
14
-
15
- getOptions(): Options {
16
- return { output: this.option({ desc: 'Output files', def: './openapi.yml' }) };
17
- }
18
-
19
- envInit(): void {
20
- EnvInit.init({
21
- debug: '0',
22
- set: { API_SPEC_OUTPUT: this.cmd.output }
23
- });
24
- }
25
-
26
- async action(): Promise<void> {
27
- const result = await ExecUtil.workerMain(require.resolve('./generate')).message;
28
-
29
- if (this.cmd.output === '-' || !this.cmd.output) {
30
- console.log!(result);
31
- }
32
- }
33
- }
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
- }