@travetto/openapi 7.1.4 → 8.0.0-alpha.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 +5 -2
- package/package.json +5 -5
- package/src/config.ts +5 -2
- package/src/generate.ts +10 -7
- package/src/service.ts +18 -5
- package/support/bin/help.ts +3 -4
- package/support/cli.openapi_spec.ts +10 -6
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/oas
|
|
|
31
31
|
import { Config } from '@travetto/config';
|
|
32
32
|
import { Runtime } from '@travetto/runtime';
|
|
33
33
|
import { Required } from '@travetto/schema';
|
|
34
|
+
import { PostConstruct } from '@travetto/di';
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* API Information, infers as much as possible from the package.json
|
|
@@ -50,7 +51,8 @@ export class ApiInfoConfig {
|
|
|
50
51
|
@Required(false)
|
|
51
52
|
version: string;
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
@PostConstruct()
|
|
55
|
+
finalizeConfig(): void {
|
|
54
56
|
this.title ??= Runtime.main.name;
|
|
55
57
|
this.version ??= Runtime.main.version;
|
|
56
58
|
this.description ??= Runtime.main.description;
|
|
@@ -94,7 +96,8 @@ export class ApiSpecConfig {
|
|
|
94
96
|
*/
|
|
95
97
|
exposeAllSchemas: boolean = false;
|
|
96
98
|
|
|
97
|
-
|
|
99
|
+
@PostConstruct()
|
|
100
|
+
async finalizeConfig(): Promise<void> {
|
|
98
101
|
if (!this.output || this.output === '-') {
|
|
99
102
|
this.persist = false;
|
|
100
103
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/openapi",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenAPI integration support for the Travetto framework",
|
|
6
6
|
"keywords": [
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
"directory": "module/openapi"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@travetto/config": "^
|
|
31
|
-
"@travetto/schema": "^
|
|
32
|
-
"@travetto/web": "^
|
|
30
|
+
"@travetto/config": "^8.0.0-alpha.1",
|
|
31
|
+
"@travetto/schema": "^8.0.0-alpha.1",
|
|
32
|
+
"@travetto/web": "^8.0.0-alpha.1",
|
|
33
33
|
"openapi3-ts": "^4.5.0",
|
|
34
34
|
"yaml": "^2.8.2"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@travetto/cli": "^
|
|
37
|
+
"@travetto/cli": "^8.0.0-alpha.1"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
40
40
|
"@travetto/cli": {
|
package/src/config.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { ServerObject, ContactObject, LicenseObject } from 'openapi3-ts/oas
|
|
|
5
5
|
import { Config } from '@travetto/config';
|
|
6
6
|
import { Runtime } from '@travetto/runtime';
|
|
7
7
|
import { Required } from '@travetto/schema';
|
|
8
|
+
import { PostConstruct } from '@travetto/di';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* API Information, infers as much as possible from the package.json
|
|
@@ -24,7 +25,8 @@ export class ApiInfoConfig {
|
|
|
24
25
|
@Required(false)
|
|
25
26
|
version: string;
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
@PostConstruct()
|
|
29
|
+
finalizeConfig(): void {
|
|
28
30
|
this.title ??= Runtime.main.name;
|
|
29
31
|
this.version ??= Runtime.main.version;
|
|
30
32
|
this.description ??= Runtime.main.description;
|
|
@@ -68,7 +70,8 @@ export class ApiSpecConfig {
|
|
|
68
70
|
*/
|
|
69
71
|
exposeAllSchemas: boolean = false;
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
@PostConstruct()
|
|
74
|
+
async finalizeConfig(): Promise<void> {
|
|
72
75
|
if (!this.output || this.output === '-') {
|
|
73
76
|
this.persist = false;
|
|
74
77
|
} else {
|
package/src/generate.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { Readable } from 'node:stream';
|
|
2
1
|
import type {
|
|
3
2
|
SchemaObject, SchemasObject, ParameterObject, OperationObject,
|
|
4
3
|
RequestBodyObject, TagObject, PathsObject, PathItemObject
|
|
5
4
|
} from 'openapi3-ts/oas31';
|
|
6
5
|
|
|
7
6
|
import { type EndpointConfig, type ControllerConfig, type EndpointParameterConfig, type ControllerVisitor, HTTP_METHODS } from '@travetto/web';
|
|
8
|
-
import {
|
|
7
|
+
import { RuntimeError, castTo, type Class, describeFunction } from '@travetto/runtime';
|
|
9
8
|
import {
|
|
10
9
|
type SchemaFieldConfig, type SchemaClassConfig, SchemaNameResolver,
|
|
11
10
|
type SchemaInputConfig, SchemaRegistryIndex, type SchemaBasicType, type SchemaParameterConfig
|
|
@@ -48,7 +47,7 @@ export class OpenapiVisitor implements ControllerVisitor<GeneratedSpec> {
|
|
|
48
47
|
*/
|
|
49
48
|
#schemaToDotParams(location: 'query' | 'header', input: SchemaInputConfig, prefix: string = '', rootField: SchemaInputConfig = input): ParameterObject[] {
|
|
50
49
|
if (!SchemaRegistryIndex.has(input.type)) {
|
|
51
|
-
throw new
|
|
50
|
+
throw new RuntimeError(`Unknown class, not registered as a schema: ${input.type.Ⲑid}`);
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
const fields = SchemaRegistryIndex.get(input.type).getFields(input.view);
|
|
@@ -78,7 +77,7 @@ export class OpenapiVisitor implements ControllerVisitor<GeneratedSpec> {
|
|
|
78
77
|
* Get the type for a given class
|
|
79
78
|
*/
|
|
80
79
|
#getType(inputOrClass: SchemaInputConfig | Class): Record<string, unknown> {
|
|
81
|
-
let field: { type: Class
|
|
80
|
+
let field: { type: Class, precision?: [number, number | undefined] };
|
|
82
81
|
if (!isInputConfig(inputOrClass)) {
|
|
83
82
|
field = { type: inputOrClass };
|
|
84
83
|
} else {
|
|
@@ -94,6 +93,10 @@ export class OpenapiVisitor implements ControllerVisitor<GeneratedSpec> {
|
|
|
94
93
|
} else {
|
|
95
94
|
switch (field.type) {
|
|
96
95
|
case String: out.type = 'string'; break;
|
|
96
|
+
case castTo(BigInt):
|
|
97
|
+
out.type = 'integer';
|
|
98
|
+
out.format = 'int64';
|
|
99
|
+
break;
|
|
97
100
|
case Number: {
|
|
98
101
|
if (field.precision) {
|
|
99
102
|
const [, decimals] = field.precision;
|
|
@@ -150,10 +153,10 @@ export class OpenapiVisitor implements ControllerVisitor<GeneratedSpec> {
|
|
|
150
153
|
config.minLength = input.minlength.limit;
|
|
151
154
|
}
|
|
152
155
|
if (input.min) {
|
|
153
|
-
config.minimum =
|
|
156
|
+
config.minimum = input.min.limit instanceof Date ? input.min.limit.getTime() : castTo(input.min.limit);
|
|
154
157
|
}
|
|
155
158
|
if (input.max) {
|
|
156
|
-
config.maximum =
|
|
159
|
+
config.maximum = input.max.limit instanceof Date ? input.max.limit.getTime() : castTo(input.max.limit);
|
|
157
160
|
}
|
|
158
161
|
if (input.enum) {
|
|
159
162
|
config.enum = input.enum.values;
|
|
@@ -238,7 +241,7 @@ export class OpenapiVisitor implements ControllerVisitor<GeneratedSpec> {
|
|
|
238
241
|
#getEndpointBody(body?: SchemaBasicType, mime?: string | null): RequestBodyObject {
|
|
239
242
|
if (!body || body.type === undefined) {
|
|
240
243
|
return { content: {}, description: '' };
|
|
241
|
-
} else if (body.
|
|
244
|
+
} else if (body.binary) {
|
|
242
245
|
return {
|
|
243
246
|
content: {
|
|
244
247
|
[mime ?? 'application/octet-stream']: { schema: { type: 'string', format: 'binary' } },
|
package/src/service.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { createReadStream, existsSync } from 'node:fs';
|
|
1
2
|
import type { OpenAPIObject } from 'openapi3-ts/oas31';
|
|
2
3
|
import { stringify } from 'yaml';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { ManifestFileUtil } from '@travetto/manifest';
|
|
6
|
+
import { BinaryMetadataUtil, JSONUtil } from '@travetto/runtime';
|
|
7
|
+
import { Injectable, Inject, PostConstruct } from '@travetto/di';
|
|
6
8
|
import { ControllerVisitUtil, type WebConfig } from '@travetto/web';
|
|
7
9
|
|
|
8
10
|
import type { ApiHostConfig, ApiInfoConfig, ApiSpecConfig } from './config.ts';
|
|
@@ -41,7 +43,8 @@ export class OpenApiService {
|
|
|
41
43
|
/**
|
|
42
44
|
* Initialize after schemas are readied
|
|
43
45
|
*/
|
|
44
|
-
|
|
46
|
+
@PostConstruct()
|
|
47
|
+
async finalizeConfig(): Promise<void> {
|
|
45
48
|
if (!this.apiHostConfig.servers && this.webConfig.baseUrl) {
|
|
46
49
|
this.apiHostConfig.servers = [{ url: this.webConfig.baseUrl }];
|
|
47
50
|
}
|
|
@@ -73,10 +76,20 @@ export class OpenApiService {
|
|
|
73
76
|
const spec = await this.getSpec();
|
|
74
77
|
|
|
75
78
|
const output = this.apiSpecConfig.output.endsWith('.json') ?
|
|
76
|
-
|
|
79
|
+
JSONUtil.toUTF8Pretty(spec) :
|
|
77
80
|
stringify(spec);
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
if (existsSync(this.apiSpecConfig.output)) {
|
|
83
|
+
const existing = await BinaryMetadataUtil.hash(createReadStream(this.apiSpecConfig.output));
|
|
84
|
+
const toWrite = BinaryMetadataUtil.hash(output);
|
|
85
|
+
|
|
86
|
+
if (existing === toWrite) {
|
|
87
|
+
console.debug('OpenAPI spec unchanged, skipping write');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
await ManifestFileUtil.bufferedFileWrite(this.apiSpecConfig.output, output);
|
|
80
93
|
} catch (error) {
|
|
81
94
|
console.error('Unable to persist openapi spec', error);
|
|
82
95
|
}
|
package/support/bin/help.ts
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { JSONUtil, ExecUtil, Runtime } from '@travetto/runtime';
|
|
6
6
|
import { cliTpl } from '@travetto/cli';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -22,10 +22,9 @@ export class OpenApiClientHelp {
|
|
|
22
22
|
.map(line => line.replace(/^\s+-\s+/, '').trim());
|
|
23
23
|
|
|
24
24
|
await fs.mkdir(path.dirname(formatCache), { recursive: true });
|
|
25
|
-
await fs.writeFile(formatCache,
|
|
25
|
+
await fs.writeFile(formatCache, JSONUtil.toUTF8([...lines.toSorted(),]));
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
return list;
|
|
27
|
+
return await fs.readFile(formatCache).then(JSONUtil.fromBinaryArray<string[]>);
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
static async help(dockerImage: string, extendedHelp: boolean): Promise<string[]> {
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import { type CliCommandShape, CliCommand } from '@travetto/cli';
|
|
5
|
-
import { Env } from '@travetto/runtime';
|
|
4
|
+
import { type CliCommandShape, CliCommand, CliModuleFlag } from '@travetto/cli';
|
|
5
|
+
import { JSONUtil, Env } from '@travetto/runtime';
|
|
6
6
|
import { Registry } from '@travetto/registry';
|
|
7
7
|
import { DependencyRegistryIndex } from '@travetto/di';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* CLI for outputting the open api spec to a local file
|
|
11
11
|
*/
|
|
12
|
-
@CliCommand(
|
|
12
|
+
@CliCommand()
|
|
13
13
|
export class OpenApiSpecCommand implements CliCommandShape {
|
|
14
14
|
|
|
15
15
|
/** Output files */
|
|
16
16
|
output?: string;
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
@CliModuleFlag({ short: 'm' })
|
|
19
|
+
module: string;
|
|
20
|
+
|
|
21
|
+
finalize(): void {
|
|
19
22
|
Env.DEBUG.set(false);
|
|
20
23
|
}
|
|
21
24
|
|
|
@@ -26,12 +29,13 @@ export class OpenApiSpecCommand implements CliCommandShape {
|
|
|
26
29
|
|
|
27
30
|
const instance = await DependencyRegistryIndex.getInstance(OpenApiService);
|
|
28
31
|
const result = await instance.getSpec();
|
|
32
|
+
const text = JSONUtil.toUTF8Pretty(result);
|
|
29
33
|
|
|
30
34
|
if (this.output === '-' || !this.output) {
|
|
31
|
-
console.log!(
|
|
35
|
+
console.log!(text);
|
|
32
36
|
} else {
|
|
33
37
|
await fs.mkdir(path.dirname(this.output), { recursive: true });
|
|
34
|
-
await fs.writeFile(this.output,
|
|
38
|
+
await fs.writeFile(this.output, text, 'utf8');
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
}
|