@travetto/openapi 3.0.2 → 3.1.0-rc.0

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,6 +1,7 @@
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.tsx and execute "npx trv doc" to rebuild -->
3
3
  # OpenAPI Specification
4
+
4
5
  ## OpenAPI integration support for the Travetto framework
5
6
 
6
7
  **Install: @travetto/openapi**
@@ -12,7 +13,7 @@ npm install @travetto/openapi
12
13
  yarn add @travetto/openapi
13
14
  ```
14
15
 
15
- 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.
16
+ 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.
16
17
 
17
18
  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.
18
19
 
@@ -23,9 +24,9 @@ All of the high level configurations can be found in the following structure:
23
24
 
24
25
  **Code: Config: OpenAPI Configuration**
25
26
  ```typescript
26
- import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
27
+ import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts';
27
28
 
28
- import { Config, EnvVar } from '@travetto/config';
29
+ import { Config } from '@travetto/config';
29
30
  import { path, RootIndex } from '@travetto/manifest';
30
31
  import { GlobalEnv } from '@travetto/base';
31
32
  import { Required } from '@travetto/schema';
@@ -70,7 +71,7 @@ export class ApiHostConfig {
70
71
  /**
71
72
  * OpenAPI Version
72
73
  */
73
- openapi = '3.0.1';
74
+ openapi = '3.1.0';
74
75
  }
75
76
 
76
77
  /**
@@ -81,12 +82,10 @@ export class ApiSpecConfig {
81
82
  /**
82
83
  * Where to output file to
83
84
  */
84
- @EnvVar('TRV_OPENAPI_OUTPUT')
85
85
  output: string = 'openapi.yml';
86
86
  /**
87
87
  * Should file be generated at runtime
88
88
  */
89
- @EnvVar('TRV_OPENAPI_PERSIST')
90
89
  persist?: boolean;
91
90
  /**
92
91
  * Skip emitting all routes
@@ -98,14 +97,14 @@ export class ApiSpecConfig {
98
97
  exposeAllSchemas: boolean = false;
99
98
 
100
99
  async postConstruct(): Promise<void> {
101
- this.output = path.toPosix(this.output);
100
+ this.output = path.resolve(this.output);
102
101
  if (!this.output || this.output === '-') {
103
102
  this.persist = false;
104
103
  } else {
105
104
  this.persist ??= GlobalEnv.dynamic;
106
105
  }
107
106
  if (this.persist) {
108
- if (!/[.](json|ya?ml)$/.test(this.output)) { // Assume a folder
107
+ if (!/[.](json|ya?ml) $/.test(this.output)) { // Assume a folder
109
108
  this.output = path.resolve(this.output, 'openapi.yml');
110
109
  }
111
110
  }
@@ -114,20 +113,20 @@ export class ApiSpecConfig {
114
113
  ```
115
114
 
116
115
  ## Spec Generation
117
- The framework, when in watch mode, will generate the [OpenAPI](https://github.com/OAI/OpenAPI-Specification) specification in either [JSON](https://www.json.org) or [YAML](https://en.wikipedia.org/wiki/YAML). This module integrates with the file watching paradigm and can regenerate the openapi spec as changes to endpoints and models are made during development. The output format is defined by the suffix of the output file, `.yaml` or `.json`.
116
+ The framework, when in watch mode, will generate the [OpenAPI](https://github.com/OAI/OpenAPI-Specification) specification in either [JSON](https://www.json.org) or [YAML](https://en.wikipedia.org/wiki/YAML). This module integrates with the file watching paradigm and can regenerate the openapi spec as changes to endpoints and models are made during development. The output format is defined by the suffix of the output file, `.yaml` or `.json`.
118
117
 
119
118
  ## CLI - openapi:spec
120
-
121
119
  The module provides a command for the [Command Line Interface](https://github.com/travetto/travetto/tree/main/module/cli#readme "CLI infrastructure for Travetto framework") to allow scripting file generation.
122
120
 
123
121
  **Terminal: OpenAPI usage**
124
122
  ```bash
125
123
  $ trv openapi:spec --help
126
124
 
127
- Usage: openapi:spec [options]
125
+ Usage: openapi:spec [options]
128
126
 
129
127
  Options:
130
- -o, --output <output> Output files (default: "./openapi.yml")
128
+ -o, --output <string> Output files
129
+ -m, --module <string> Module to run for
131
130
  -h, --help display help for command
132
131
  ```
133
132
 
@@ -136,26 +135,22 @@ The command will run your application, in non-server mode, to collect all the ro
136
135
  **Note**: The module supports generating the OpenAPI spec in real-time while listening for changes to routes and models.
137
136
 
138
137
  ## CLI - openapi:client
139
-
140
138
  The module provides a command for the [Command Line Interface](https://github.com/travetto/travetto/tree/main/module/cli#readme "CLI infrastructure for Travetto framework") to allow client generation from the API structure.
141
139
 
142
140
  **Terminal: OpenAPI usage**
143
141
  ```bash
144
142
  $ trv openapi:client --help
145
143
 
146
- Usage: openapi:client [options] <format-or-preset>
144
+ Usage: openapi:client [options] <format:string>
147
145
 
148
146
  Options:
149
- -x, --extended-help Show Extended Help
150
- -a, --additional-properties <additional-properties> Additional Properties (default: [])
151
- -i, --input <input> Input file (default:
152
- "./openapi.yml")
153
- -o, --output <output> Output folder (default:
154
- "./api-client")
155
- -d, --docker-image <docker-image> Docker Image to use (default:
156
- "arcsine/openapi-generator:latest")
157
- -w, --watch Watch for file changes
158
- -h, --help display help for command
147
+ -x, --extended-help Show Extended Help
148
+ -a, --additional-properties <string> Additional Properties (default: [])
149
+ -i, --input <string> Input file (default: "./openapi.yml")
150
+ -o, --output <string> Output folder (default: "./api-client")
151
+ -d, --docker-image <string> Docker Image to user (default: "arcsine/openapi-generator:latest")
152
+ -w, --watch Watch for file changes
153
+ -h, --help display help for command
159
154
 
160
155
  Available Presets
161
156
  ----------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/openapi",
3
- "version": "3.0.2",
3
+ "version": "3.1.0-rc.0",
4
4
  "description": "OpenAPI integration support for the Travetto framework",
5
5
  "keywords": [
6
6
  "rest",
@@ -26,14 +26,14 @@
26
26
  "directory": "module/openapi"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/config": "^3.0.2",
30
- "@travetto/rest": "^3.0.2",
31
- "@travetto/schema": "^3.0.2",
32
- "@travetto/yaml": "^3.0.2",
29
+ "@travetto/config": "^3.1.0-rc.0",
30
+ "@travetto/rest": "^3.1.0-rc.0",
31
+ "@travetto/schema": "^3.1.0-rc.0",
32
+ "@travetto/yaml": "^3.1.0-rc.0",
33
33
  "openapi3-ts": "^3.1.2"
34
34
  },
35
35
  "peerDependencies": {
36
- "@travetto/cli": "^3.0.2"
36
+ "@travetto/cli": "^3.1.0-rc.0"
37
37
  },
38
38
  "peerDependenciesMeta": {
39
39
  "@travetto/cli": {
package/src/config.ts CHANGED
@@ -1,11 +1,10 @@
1
- import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/src/model/OpenApi';
1
+ import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts';
2
2
 
3
- import { Config, EnvVar } from '@travetto/config';
3
+ import { Config } from '@travetto/config';
4
4
  import { path, RootIndex } from '@travetto/manifest';
5
5
  import { GlobalEnv } from '@travetto/base';
6
6
  import { Required } from '@travetto/schema';
7
7
 
8
-
9
8
  /**
10
9
  * API Information, infers as much as possible from the package.json
11
10
  */
@@ -46,7 +45,7 @@ export class ApiHostConfig {
46
45
  /**
47
46
  * OpenAPI Version
48
47
  */
49
- openapi = '3.0.1';
48
+ openapi = '3.1.0';
50
49
  }
51
50
 
52
51
  /**
@@ -57,12 +56,10 @@ export class ApiSpecConfig {
57
56
  /**
58
57
  * Where to output file to
59
58
  */
60
- @EnvVar('TRV_OPENAPI_OUTPUT')
61
59
  output: string = 'openapi.yml';
62
60
  /**
63
61
  * Should file be generated at runtime
64
62
  */
65
- @EnvVar('TRV_OPENAPI_PERSIST')
66
63
  persist?: boolean;
67
64
  /**
68
65
  * Skip emitting all routes
@@ -74,7 +71,7 @@ export class ApiSpecConfig {
74
71
  exposeAllSchemas: boolean = false;
75
72
 
76
73
  async postConstruct(): Promise<void> {
77
- this.output = path.toPosix(this.output);
74
+ this.output = path.resolve(this.output);
78
75
  if (!this.output || this.output === '-') {
79
76
  this.persist = false;
80
77
  } else {
package/src/service.ts CHANGED
@@ -65,7 +65,7 @@ export class OpenApiService {
65
65
  ...new SpecGenerator().generate(this.apiSpecConfig)
66
66
  };
67
67
  }
68
- return this._spec;
68
+ return this._spec!;
69
69
  }
70
70
 
71
71
  /**
@@ -2,7 +2,7 @@ import { Readable } from 'stream';
2
2
  import type {
3
3
  SchemaObject, SchemasObject, ParameterObject, OperationObject,
4
4
  RequestBodyObject, TagObject, PathsObject
5
- } from 'openapi3-ts/src/model/OpenApi';
5
+ } from 'openapi3-ts';
6
6
 
7
7
  import { ControllerRegistry, EndpointConfig, ControllerConfig, ParamConfig, EndpointIOType } from '@travetto/rest';
8
8
  import { Class } from '@travetto/base';
@@ -0,0 +1,57 @@
1
+ import fs from 'fs/promises';
2
+
3
+ import { path, RootIndex } from '@travetto/manifest';
4
+ import { cliTpl } from '@travetto/cli';
5
+ import { OpenApiClientPresets } from './presets';
6
+ import { ExecUtil } from '@travetto/base';
7
+
8
+ /**
9
+ * Help utility for openapi client command
10
+ */
11
+ export class OpenApiClientHelp {
12
+
13
+ static async getListOfFormats(dockerImage: string): Promise<string[]> {
14
+ const formatCache = path.resolve(RootIndex.manifest.workspacePath, RootIndex.manifest.toolFolder, 'trv-openapi-formats.json');
15
+ if (!await fs.stat(formatCache).catch(() => false)) {
16
+ const stdout = ExecUtil.spawn('docker', ['run', '--rm', dockerImage, 'list']);
17
+ const res = await stdout.result;
18
+ const lines = res.stdout
19
+ .split('DOCUMENTATION')[0]
20
+ .trim()
21
+ .split(/\n/g)
22
+ .filter(x => /^\s+-/.test(x) && !/\((beta|experimental)\)/.test(x))
23
+ .map(x => x.replace(/^\s+-\s+/, '').trim());
24
+
25
+ await fs.mkdir(path.dirname(formatCache), { recursive: true });
26
+ await fs.writeFile(formatCache, JSON.stringify([...lines.sort(),]));
27
+ }
28
+ const list: string[] = JSON.parse(await fs.readFile(formatCache, 'utf8'));
29
+ return list;
30
+ }
31
+
32
+ static async help(dockerImage: string, extendedHelp: boolean): Promise<string[]> {
33
+ const presets = await OpenApiClientPresets.getPresets();
34
+ const presetLen = Math.max(...Object.keys(presets).map(x => x.length));
35
+ const presetEntries = Object
36
+ .entries(presets)
37
+ .sort(([a], [b]) => a.localeCompare(b))
38
+ .map(([k, [cmd, v]]) => [`@travetto/${k}`.padEnd(presetLen + 5), [cmd, OpenApiClientPresets.presetMap(v)]] as const);
39
+
40
+ const presetText = [
41
+ cliTpl`${{ subtitle: 'Available Presets' }}`,
42
+ '----------------------------------',
43
+ ...presetEntries.map(([k, [cmd, param]]) => cliTpl`* ${{ input: k }} -- ${{ identifier: cmd }} ${{ param }}`),
44
+ ];
45
+
46
+ if (extendedHelp) {
47
+ const formats = await this.getListOfFormats(dockerImage);
48
+ presetText.push(
49
+ '',
50
+ cliTpl`${{ subtitle: 'Available Formats' }}`,
51
+ '----------------------------------',
52
+ ...formats.map(x => cliTpl`* ${{ input: x }}`)
53
+ );
54
+ }
55
+ return presetText;
56
+ }
57
+ }
@@ -0,0 +1,22 @@
1
+ import { FileResourceProvider } from '@travetto/base';
2
+
3
+ /**
4
+ * Presets utility for openapi client command
5
+ */
6
+ export class OpenApiClientPresets {
7
+
8
+ static #presets: Record<string, [string, object] | [string]>;
9
+ static #resources = new FileResourceProvider(['@travetto/openapi#support/resources']);
10
+
11
+ static async getPresets(): Promise<Record<string, [string, object] | [string]>> {
12
+ if (!this.#presets) {
13
+ const text = await this.#resources.read('presets.json');
14
+ this.#presets = JSON.parse(text);
15
+ }
16
+ return this.#presets;
17
+ }
18
+
19
+ static presetMap(prop?: object): string {
20
+ return !prop || Object.keys(prop).length === 0 ? '' : Object.entries(prop).map(([k, v]) => `${k}=${v}`).join(',');
21
+ }
22
+ }
@@ -1,130 +1,68 @@
1
1
  import fs from 'fs/promises';
2
- import { existsSync, readFileSync, writeFileSync } from 'fs';
3
- import cp from 'child_process';
4
2
 
5
- import { path, RootIndex } from '@travetto/manifest';
6
- import { ExecUtil, FileResourceProvider } from '@travetto/base';
7
- import { CliCommand, cliTpl, OptionConfig, ListOptionConfig } from '@travetto/cli';
3
+ import { path } from '@travetto/manifest';
4
+ import { ExecUtil, ShutdownManager } from '@travetto/base';
5
+ import { CliCommandShape, CliCommand, CliFlag } from '@travetto/cli';
6
+
7
+ import { OpenApiClientHelp } from './bin/help';
8
+ import { OpenApiClientPresets } from './bin/presets';
8
9
 
9
- type Options = {
10
- extendedHelp: OptionConfig<boolean>;
11
- props: ListOptionConfig<string>;
12
- input: OptionConfig<string>;
13
- output: OptionConfig<string>;
14
- dockerImage: OptionConfig<string>;
15
- watch: OptionConfig<boolean>;
16
- };
17
10
  /**
18
11
  * CLI for generating the cli client
19
12
  */
20
- export class OpenApiClientCommand extends CliCommand<Options> {
21
- #presets: Record<string, [string, object] | [string]>;
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
- }
32
-
33
- presetMap(prop?: object): string {
34
- return !prop || Object.keys(prop).length === 0 ? '' : Object.entries(prop).map(([k, v]) => `${k}=${v}`).join(',');
35
- }
36
-
37
- getListOfFormats(): string[] {
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();
41
- const lines = stdout
42
- .split('DOCUMENTATION')[0]
43
- .trim()
44
- .split(/\n/g)
45
- .filter(x => /^\s+-/.test(x) && !/\((beta|experimental)\)/.test(x))
46
- .map(x => x.replace(/^\s+-\s+/, '').trim());
47
-
48
- writeFileSync(formatCache, JSON.stringify([...lines.sort(),]));
49
- }
50
- const list: string[] = JSON.parse(readFileSync(formatCache, 'utf8'));
51
- return list;
52
- }
53
-
54
- getOptions(): Options {
55
- return {
56
- extendedHelp: this.boolOption({ name: 'extended-help', short: 'x', desc: 'Show Extended Help' }),
57
- props: this.listOption({ name: 'additional-properties', short: 'a', desc: 'Additional Properties' }),
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 }),
60
- dockerImage: this.option({ desc: 'Docker Image to use', def: 'arcsine/openapi-generator:latest' }),
61
- watch: this.boolOption({ desc: 'Watch for file changes' })
62
- };
63
- }
64
-
65
- async help(): Promise<string> {
66
- const presets = await this.getPresets();
67
- const presetLen = Math.max(...Object.keys(presets).map(x => x.length));
68
- const presetEntries = Object
69
- .entries(presets)
70
- .sort(([a], [b]) => a.localeCompare(b))
71
- .map(([k, [cmd, v]]) => [`@travetto/${k}`.padEnd(presetLen + 5), [cmd, this.presetMap(v)]] as const);
72
-
73
- const presetText = cliTpl`
74
- ${{ subtitle: 'Available Presets' }}
75
- ----------------------------------
76
- ${presetEntries.map(([k, [cmd, param]]) => cliTpl`* ${{ input: k }} -- ${{ identifier: cmd }} ${{ param }}`).join('\n')}`;
77
-
78
- const formatText = cliTpl`
79
- ${{ subtitle: 'Available Formats' }}
80
- ----------------------------------
81
- ${this.getListOfFormats().map(x => cliTpl`* ${{ input: x }}`).join('\n')} `;
82
-
83
- return this.cmd.extendedHelp ? `${presetText}\n${formatText}` : presetText;
84
- }
85
-
86
- getArgs(): string {
87
- return '<format-or-preset>';
13
+ @CliCommand()
14
+ export class OpenApiClientCommand implements CliCommandShape {
15
+ @CliFlag({ desc: 'Show Extended Help', short: '-x' })
16
+ extendedHelp?: boolean;
17
+ @CliFlag({ desc: 'Additional Properties', short: '-a', name: '--additional-properties' })
18
+ props: string[] = [];
19
+ @CliFlag({ desc: 'Input file' })
20
+ input = './openapi.yml';
21
+ @CliFlag({ desc: 'Output folder' })
22
+ output = './api-client';
23
+ @CliFlag({ desc: 'Docker Image to user' })
24
+ dockerImage = 'arcsine/openapi-generator:latest';
25
+ @CliFlag({ desc: 'Watch for file changes' })
26
+ watch?: boolean;
27
+
28
+ async help(): Promise<string[]> {
29
+ return OpenApiClientHelp.help(this.dockerImage, this.extendedHelp ?? false);
88
30
  }
89
31
 
90
- async action(format: string): Promise<void> {
91
- if (!format) {
92
- return this.showHelp('Format is required');
93
- }
94
-
32
+ async main(format: string): Promise<void> {
95
33
  // Ensure its there
96
- await fs.mkdir(this.cmd.output, { recursive: true });
34
+ await fs.mkdir(this.output, { recursive: true });
97
35
 
98
- let propMap = Object.fromEntries(this.cmd.props?.map(p => p.split('=')) ?? []);
36
+ let propMap = Object.fromEntries(this.props?.map(p => p.split('=')) ?? []);
99
37
 
100
38
  if (format.startsWith('@travetto/')) {
101
39
  const key = format.split('@travetto/')[1];
102
- const [fmt, props] = (await this.getPresets())[key];
40
+ const [fmt, props] = (await OpenApiClientPresets.getPresets())[key];
103
41
  format = fmt;
104
42
  propMap = { ...props, ...propMap };
105
43
  }
106
44
 
107
- const propList = this.presetMap(propMap);
45
+ const propList = OpenApiClientPresets.presetMap(propMap);
108
46
 
109
47
  const args = [
110
48
  'run',
111
49
  '--user', `${process.geteuid?.()}:${process.getgid?.()}`,
112
- '-v', `${this.cmd.output}:/workspace`,
113
- '-v', `${path.dirname(this.cmd.input)}:/input`,
50
+ '-v', `${this.output}:/workspace`,
51
+ '-v', `${path.dirname(this.input)}:/input`,
114
52
  '-it',
115
53
  '--rm',
116
- this.cmd.dockerImage,
54
+ this.dockerImage,
117
55
  'generate',
118
56
  '--skip-validate-spec',
119
57
  '--remove-operation-id-prefix',
120
58
  '-g', format,
121
59
  '-o', '/workspace',
122
- '-i', `/input/${path.basename(this.cmd.input)}`,
123
- ...(this.cmd.watch ? ['-w'] : []),
60
+ '-i', `/input/${path.basename(this.input)}`,
61
+ ...(this.watch ? ['-w'] : []),
124
62
  ...(propList ? ['--additional-properties', propList] : [])
125
63
  ];
126
64
 
127
65
  const { result } = ExecUtil.spawn('docker', args, { stdio: [0, 1, 2] });
128
- await result.catch(err => this.exit(1));
66
+ await result.catch(err => ShutdownManager.exit(1));
129
67
  }
130
68
  }
@@ -1,37 +1,37 @@
1
- import { CliCommand, OptionConfig } from '@travetto/cli';
2
- import { RootIndex } from '@travetto/manifest';
3
- import { ExecUtil, GlobalEnvConfig } from '@travetto/base';
1
+ import fs from 'fs/promises';
4
2
 
5
- type Options = {
6
- output: OptionConfig<string>;
7
- };
3
+ import { CliCommandShape, CliCommand } from '@travetto/cli';
4
+ import { GlobalEnvConfig } from '@travetto/base';
5
+ import { RootRegistry } from '@travetto/registry';
6
+ import { DependencyRegistry } from '@travetto/di';
7
+ import { path } from '@travetto/manifest';
8
8
 
9
9
  /**
10
10
  * CLI for outputting the open api spec to a local file
11
11
  */
12
- export class OpenApiSpecCommand extends CliCommand<Options> {
13
- name = 'openapi:spec';
12
+ @CliCommand({ fields: ['module'] })
13
+ export class OpenApiSpecCommand implements CliCommandShape {
14
14
 
15
- getOptions(): Options {
16
- return { output: this.option({ desc: 'Output files', def: './openapi.yml' }) };
17
- }
15
+ /** Output files */
16
+ output?: string;
18
17
 
19
18
  envInit(): GlobalEnvConfig {
20
- return {
21
- debug: false,
22
- set: { API_SPEC_OUTPUT: this.cmd.output }
23
- };
19
+ return { debug: false };
24
20
  }
25
21
 
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;
22
+ async main(): Promise<void> {
23
+ const { OpenApiService } = await import('../src/service.js');
24
+
25
+ await RootRegistry.init();
26
+
27
+ const instance = await DependencyRegistry.getInstance(OpenApiService);
28
+ const result = instance.spec;
32
29
 
33
- if (this.cmd.output === '-' || !this.cmd.output) {
34
- console.log!(result);
30
+ if (this.output === '-' || !this.output) {
31
+ console.log!(JSON.stringify(result, null, 2));
32
+ } else {
33
+ await fs.mkdir(path.dirname(this.output), { recursive: true });
34
+ await fs.writeFile(this.output, JSON.stringify(result, null, 2), 'utf8');
35
35
  }
36
36
  }
37
37
  }
@@ -1,11 +0,0 @@
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
- }