@open-norantec/herbal 1.0.2-alpha.17 → 1.0.2-alpha.19
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/dist/abstracts/client.abstract.class.d.ts +14 -0
- package/dist/abstracts/client.abstract.class.js +36 -0
- package/dist/abstracts/index.d.ts +1 -0
- package/dist/abstracts/index.js +1 -0
- package/dist/cli/herbal.js +50 -49
- package/dist/clients/index.d.ts +1 -0
- package/dist/clients/index.js +17 -0
- package/dist/clients/typescript-client.class.d.ts +23 -0
- package/dist/clients/typescript-client.class.js +375 -0
- package/dist/core.js +4 -5
- package/dist/{create.d.ts → create/create-application.d.ts} +0 -18
- package/dist/create/create-application.js +18 -0
- package/dist/create/create-client.d.ts +9 -0
- package/dist/create/create-client.js +17 -0
- package/dist/create/index.d.ts +2 -0
- package/dist/create/index.js +18 -0
- package/dist/decorators/method.decorator.d.ts +4 -2
- package/dist/decorators/method.decorator.js +36 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +4 -4
- package/dist/create.js +0 -205
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Constructor } from 'type-fest';
|
|
3
|
+
import { GroupsFactory } from '../decorators/client-groups.decorator';
|
|
4
|
+
import { OpenAPIObject } from 'zod-openapi/dist/openapi3-ts/dist/model/openapi31';
|
|
5
|
+
export interface CreateClientOptions {
|
|
6
|
+
Module: Constructor<any>;
|
|
7
|
+
allowedClientGroupsFactory?: GroupsFactory;
|
|
8
|
+
}
|
|
9
|
+
export declare abstract class Client {
|
|
10
|
+
readonly options: CreateClientOptions;
|
|
11
|
+
protected document: OpenAPIObject;
|
|
12
|
+
constructor(options: CreateClientOptions);
|
|
13
|
+
abstract generateClientSourceFile(currentGroup?: string): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Client = void 0;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
var nest_util_class_1 = require("../utilities/nest-util.class");
|
|
6
|
+
var string_util_class_1 = require("@open-norantec/utilities/dist/string-util.class");
|
|
7
|
+
var controller_util_class_1 = require("../utilities/controller-util.class");
|
|
8
|
+
var method_decorator_1 = require("../decorators/method.decorator");
|
|
9
|
+
var Client = (function () {
|
|
10
|
+
function Client(options) {
|
|
11
|
+
var _this = this;
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.document = {
|
|
14
|
+
openapi: '3.1.0',
|
|
15
|
+
info: {
|
|
16
|
+
title: 'API Documentation',
|
|
17
|
+
version: '1.0.0',
|
|
18
|
+
},
|
|
19
|
+
paths: {},
|
|
20
|
+
};
|
|
21
|
+
nest_util_class_1.NestUtil.getControllerClasses(options.Module).forEach(function (Class) {
|
|
22
|
+
if (string_util_class_1.StringUtil.isFalsyString(Class === null || Class === void 0 ? void 0 : Class.name) || !(0, controller_util_class_1.isHerbalController)(Class))
|
|
23
|
+
return;
|
|
24
|
+
var controllerName = (0, controller_util_class_1.getControllerName)(Class);
|
|
25
|
+
var pool = method_decorator_1.Method.getPool(Class.prototype);
|
|
26
|
+
if (string_util_class_1.StringUtil.isFalsyString(controllerName) || pool === null)
|
|
27
|
+
return;
|
|
28
|
+
Object.entries(pool.getOpenAPIPathsObject()).forEach(function (_a) {
|
|
29
|
+
var pathname = _a[0], schemas = _a[1];
|
|
30
|
+
_this.document.paths[["/".concat(controllerName), pathname].join('')] = schemas;
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return Client;
|
|
35
|
+
}());
|
|
36
|
+
exports.Client = Client;
|
package/dist/abstracts/index.js
CHANGED
|
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./auth-adapter.abstract.class"), exports);
|
|
18
|
+
__exportStar(require("./client.abstract.class"), exports);
|
package/dist/cli/herbal.js
CHANGED
|
@@ -115,8 +115,7 @@ var createHandleOutputFile = function (disableWriteFile) { return function (file
|
|
|
115
115
|
}
|
|
116
116
|
}; };
|
|
117
117
|
command
|
|
118
|
-
.addCommand((0, forge_1.createCommand)({
|
|
119
|
-
name: 'build',
|
|
118
|
+
.addCommand((0, forge_1.createCommand)('build', {
|
|
120
119
|
hiddenOptions: ['--watch', '--execute-after-build'],
|
|
121
120
|
onLog: log,
|
|
122
121
|
defaultOptions: function (source, output, options) { return ({
|
|
@@ -126,8 +125,7 @@ command
|
|
|
126
125
|
onOutputFile: createHandleOutputFile(!!(options === null || options === void 0 ? void 0 : options.disableWriteFile)),
|
|
127
126
|
}); },
|
|
128
127
|
}))
|
|
129
|
-
.addCommand((0, forge_1.createCommand)({
|
|
130
|
-
name: 'watch',
|
|
128
|
+
.addCommand((0, forge_1.createCommand)('watch', {
|
|
131
129
|
hiddenOptions: [
|
|
132
130
|
'--watch',
|
|
133
131
|
'--execute-after-build',
|
|
@@ -146,51 +144,54 @@ command
|
|
|
146
144
|
onOutputFile: createHandleOutputFile(true),
|
|
147
145
|
}); },
|
|
148
146
|
}))
|
|
149
|
-
.addCommand((0, forge_1.createCommand)({
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
147
|
+
.addCommand((0, forge_1.createCommand)('generate-client', function (_a) {
|
|
148
|
+
var addOption = _a.addOption;
|
|
149
|
+
addOption('--group', 'Client group name to generate');
|
|
150
|
+
return {
|
|
151
|
+
onLog: log,
|
|
152
|
+
hiddenOptions: [
|
|
153
|
+
'--watch',
|
|
154
|
+
'--execute-after-build',
|
|
155
|
+
'--obfuscate',
|
|
156
|
+
'--obfuscator-config-file <string>',
|
|
157
|
+
'--disable-write-file',
|
|
158
|
+
],
|
|
159
|
+
defaultOptions: function (source, output, options) { return ({
|
|
160
|
+
watch: false,
|
|
161
|
+
executeAfterBuild: false,
|
|
162
|
+
obfuscate: false,
|
|
163
|
+
customTransformers: function (program) {
|
|
164
|
+
return {
|
|
165
|
+
before: [(0, reflect_declaration_1.transformer)(program)],
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
getWatcher: handleGetWatcher,
|
|
169
|
+
onGetFileContent: handleGetFileContent,
|
|
170
|
+
onOutputFile: createHandleOutputFile(false),
|
|
171
|
+
getVirtualEntryFileContent: function (buildEntryFilePath) {
|
|
172
|
+
return [
|
|
173
|
+
"const entry = require('".concat(buildEntryFilePath, "')"),
|
|
174
|
+
"const { isClient } = require(\'@open-norantec/herbal\')",
|
|
175
|
+
'module.exports = () => {',
|
|
176
|
+
' let client = entry;',
|
|
177
|
+
' if (!isClient(client)) { client = entry?.default; }',
|
|
178
|
+
" if (!isClient(client)) return '';",
|
|
179
|
+
" try { return client.instance.generateClientSourceFile() ?? ''; } catch (error) { throw error; }",
|
|
180
|
+
'};',
|
|
181
|
+
].join('\n');
|
|
182
|
+
},
|
|
183
|
+
rewriteOutputFile: function (code) {
|
|
184
|
+
try {
|
|
185
|
+
var generateCodeMethod = requireFromString(code);
|
|
186
|
+
if (typeof generateCodeMethod !== 'function')
|
|
187
|
+
return '';
|
|
188
|
+
return generateCodeMethod({ group: options === null || options === void 0 ? void 0 : options.group });
|
|
189
|
+
}
|
|
190
|
+
catch (_a) {
|
|
187
191
|
return '';
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
}); },
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
}); },
|
|
195
|
+
};
|
|
195
196
|
}));
|
|
196
197
|
command.parse(process.argv);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './typescript-client.class';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./typescript-client.class"), exports);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { SchemaObject } from 'zod-openapi/dist/openapi3-ts/dist/model/openapi31';
|
|
3
|
+
import { Client, CreateClientOptions } from '../abstracts/client.abstract.class';
|
|
4
|
+
declare namespace OpenApiToTypescript {
|
|
5
|
+
interface Options {
|
|
6
|
+
useInterface?: boolean;
|
|
7
|
+
export?: boolean;
|
|
8
|
+
generateJSDoc?: boolean;
|
|
9
|
+
preferUnknown?: boolean;
|
|
10
|
+
singleLine?: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface TypeResult {
|
|
13
|
+
code: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export declare function convertOpenApiToTypescript(schema: SchemaObject, name?: string, options?: OpenApiToTypescript.Options): OpenApiToTypescript.TypeResult;
|
|
18
|
+
export declare class TypeScriptClient extends Client implements Client {
|
|
19
|
+
readonly options: CreateClientOptions;
|
|
20
|
+
constructor(options: CreateClientOptions);
|
|
21
|
+
generateClientSourceFile(): string;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
if (typeof b !== "function" && b !== null)
|
|
11
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
+
extendStatics(d, b);
|
|
13
|
+
function __() { this.constructor = d; }
|
|
14
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
+
};
|
|
16
|
+
})();
|
|
17
|
+
var __assign = (this && this.__assign) || function () {
|
|
18
|
+
__assign = Object.assign || function(t) {
|
|
19
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
20
|
+
s = arguments[i];
|
|
21
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
22
|
+
t[p] = s[p];
|
|
23
|
+
}
|
|
24
|
+
return t;
|
|
25
|
+
};
|
|
26
|
+
return __assign.apply(this, arguments);
|
|
27
|
+
};
|
|
28
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
29
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
30
|
+
if (ar || !(i in from)) {
|
|
31
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
32
|
+
ar[i] = from[i];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.TypeScriptClient = exports.convertOpenApiToTypescript = void 0;
|
|
39
|
+
require("reflect-metadata");
|
|
40
|
+
var client_abstract_class_1 = require("../abstracts/client.abstract.class");
|
|
41
|
+
var nest_util_class_1 = require("../utilities/nest-util.class");
|
|
42
|
+
var string_util_class_1 = require("@open-norantec/utilities/dist/string-util.class");
|
|
43
|
+
var controller_util_class_1 = require("../utilities/controller-util.class");
|
|
44
|
+
var method_decorator_1 = require("../decorators/method.decorator");
|
|
45
|
+
var OpenApiToTypescriptConverter = (function () {
|
|
46
|
+
function OpenApiToTypescriptConverter(options) {
|
|
47
|
+
if (options === void 0) { options = {}; }
|
|
48
|
+
this.options = __assign({ useInterface: false, export: true, generateJSDoc: true, preferUnknown: true, singleLine: true }, options);
|
|
49
|
+
}
|
|
50
|
+
OpenApiToTypescriptConverter.prototype.convert = function (schema, name) {
|
|
51
|
+
var typeString = this.parseSchema(schema, 0, name);
|
|
52
|
+
if (name) {
|
|
53
|
+
var exportKeyword = this.options.export ? 'export ' : '';
|
|
54
|
+
if (this.options.useInterface && schema.type === 'object' && schema.properties) {
|
|
55
|
+
var code_1 = "".concat(exportKeyword).concat(typeString);
|
|
56
|
+
return { code: code_1, name: name };
|
|
57
|
+
}
|
|
58
|
+
var code = "".concat(exportKeyword, "type ").concat(name, " = ").concat(typeString, ";");
|
|
59
|
+
return { code: code, name: name };
|
|
60
|
+
}
|
|
61
|
+
return { code: typeString };
|
|
62
|
+
};
|
|
63
|
+
OpenApiToTypescriptConverter.prototype.generateTypes = function (schemas) {
|
|
64
|
+
var _this = this;
|
|
65
|
+
if (!schemas)
|
|
66
|
+
return '';
|
|
67
|
+
var lines = [];
|
|
68
|
+
Object.entries(schemas).forEach(function (_a) {
|
|
69
|
+
var name = _a[0], schema = _a[1];
|
|
70
|
+
var result = _this.convert(schema, name);
|
|
71
|
+
lines.push(result.code);
|
|
72
|
+
});
|
|
73
|
+
return lines.join('\n');
|
|
74
|
+
};
|
|
75
|
+
OpenApiToTypescriptConverter.fromZodResult = function (result, name, options) {
|
|
76
|
+
var converter = new OpenApiToTypescriptConverter(options);
|
|
77
|
+
return converter.convert(result.schema, name);
|
|
78
|
+
};
|
|
79
|
+
OpenApiToTypescriptConverter.prototype.parseSchema = function (schema, depth, name) {
|
|
80
|
+
if (depth === void 0) { depth = 0; }
|
|
81
|
+
if ('$ref' in schema && typeof schema.$ref === 'string') {
|
|
82
|
+
return this.refToTypeName(schema.$ref);
|
|
83
|
+
}
|
|
84
|
+
var s = schema;
|
|
85
|
+
if (s.oneOf) {
|
|
86
|
+
return this.parseOneOf(s.oneOf, depth);
|
|
87
|
+
}
|
|
88
|
+
if (s.anyOf) {
|
|
89
|
+
return this.parseAnyOf(s.anyOf, depth);
|
|
90
|
+
}
|
|
91
|
+
if (s.allOf) {
|
|
92
|
+
return this.parseAllOf(s.allOf, depth);
|
|
93
|
+
}
|
|
94
|
+
switch (s.type) {
|
|
95
|
+
case 'object':
|
|
96
|
+
return this.parseObject(s, depth, name);
|
|
97
|
+
case 'array':
|
|
98
|
+
return this.parseArray(s, depth);
|
|
99
|
+
case 'string':
|
|
100
|
+
return this.parseString(s);
|
|
101
|
+
case 'integer':
|
|
102
|
+
case 'number':
|
|
103
|
+
return 'number';
|
|
104
|
+
case 'boolean':
|
|
105
|
+
return 'boolean';
|
|
106
|
+
default:
|
|
107
|
+
if (s.enum) {
|
|
108
|
+
return this.parseEnum(s.enum);
|
|
109
|
+
}
|
|
110
|
+
if (Array.isArray(s.type)) {
|
|
111
|
+
return s.type.join(' | ');
|
|
112
|
+
}
|
|
113
|
+
if (Object.keys(s).length === 0 || (s.type === undefined && !s.enum)) {
|
|
114
|
+
return this.options.preferUnknown ? 'unknown' : 'any';
|
|
115
|
+
}
|
|
116
|
+
return this.options.preferUnknown ? 'unknown' : 'any';
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
OpenApiToTypescriptConverter.prototype.parseObject = function (schema, depth, name) {
|
|
120
|
+
var _this = this;
|
|
121
|
+
if (schema.additionalProperties && !schema.properties) {
|
|
122
|
+
if (typeof schema.additionalProperties === 'boolean') {
|
|
123
|
+
return 'Record<string, unknown>';
|
|
124
|
+
}
|
|
125
|
+
var valueType = this.parseSchema(schema.additionalProperties, depth);
|
|
126
|
+
return "Record<string, ".concat(valueType, ">");
|
|
127
|
+
}
|
|
128
|
+
var properties = schema.properties || {};
|
|
129
|
+
var required = schema.required || [];
|
|
130
|
+
if (Object.keys(properties).length === 0) {
|
|
131
|
+
if (schema.additionalProperties) {
|
|
132
|
+
if (typeof schema.additionalProperties === 'boolean') {
|
|
133
|
+
return 'Record<string, unknown>';
|
|
134
|
+
}
|
|
135
|
+
var valueType = this.parseSchema(schema.additionalProperties, depth);
|
|
136
|
+
return "Record<string, ".concat(valueType, ">");
|
|
137
|
+
}
|
|
138
|
+
return 'Record<string, never>';
|
|
139
|
+
}
|
|
140
|
+
if (this.options.useInterface && name && depth === 0) {
|
|
141
|
+
var props_1 = [];
|
|
142
|
+
Object.entries(properties).forEach(function (_a) {
|
|
143
|
+
var key = _a[0], propSchema = _a[1];
|
|
144
|
+
var isRequired = required.includes(key);
|
|
145
|
+
var tsType = _this.parseSchema(propSchema, depth + 1);
|
|
146
|
+
var optional = isRequired ? '' : '?';
|
|
147
|
+
props_1.push("".concat(key).concat(optional, ": ").concat(tsType));
|
|
148
|
+
});
|
|
149
|
+
return "interface ".concat(name, " { ").concat(props_1.join('; '), " }");
|
|
150
|
+
}
|
|
151
|
+
var props = [];
|
|
152
|
+
Object.entries(properties).forEach(function (_a) {
|
|
153
|
+
var key = _a[0], propSchema = _a[1];
|
|
154
|
+
var isRequired = required.includes(key);
|
|
155
|
+
var tsType = _this.parseSchema(propSchema, depth + 1);
|
|
156
|
+
var optional = isRequired ? '' : '?';
|
|
157
|
+
props.push("".concat(key).concat(optional, ": ").concat(tsType));
|
|
158
|
+
});
|
|
159
|
+
return "{ ".concat(props.join('; '), " }");
|
|
160
|
+
};
|
|
161
|
+
OpenApiToTypescriptConverter.prototype.parseArray = function (schema, depth) {
|
|
162
|
+
var _this = this;
|
|
163
|
+
var items = schema.items;
|
|
164
|
+
if (!items) {
|
|
165
|
+
return 'unknown[]';
|
|
166
|
+
}
|
|
167
|
+
if (Array.isArray(items)) {
|
|
168
|
+
var types = items.map(function (item) { return _this.parseSchema(item, depth); });
|
|
169
|
+
return "[".concat(types.join(', '), "]");
|
|
170
|
+
}
|
|
171
|
+
var itemType = this.parseSchema(items, depth);
|
|
172
|
+
if (itemType.includes('|') || itemType.includes('&')) {
|
|
173
|
+
return "(".concat(itemType, ")[]");
|
|
174
|
+
}
|
|
175
|
+
return "".concat(itemType, "[]");
|
|
176
|
+
};
|
|
177
|
+
OpenApiToTypescriptConverter.prototype.parseString = function (schema) {
|
|
178
|
+
if (schema.enum) {
|
|
179
|
+
return this.parseEnum(schema.enum);
|
|
180
|
+
}
|
|
181
|
+
return 'string';
|
|
182
|
+
};
|
|
183
|
+
OpenApiToTypescriptConverter.prototype.parseEnum = function (values) {
|
|
184
|
+
var literals = values.map(function (v) {
|
|
185
|
+
if (v === null)
|
|
186
|
+
return 'null';
|
|
187
|
+
if (typeof v === 'string') {
|
|
188
|
+
return "'".concat(v.replace(/'/g, "\\'"), "'");
|
|
189
|
+
}
|
|
190
|
+
return String(v);
|
|
191
|
+
});
|
|
192
|
+
return literals.join(' | ');
|
|
193
|
+
};
|
|
194
|
+
OpenApiToTypescriptConverter.prototype.parseOneOf = function (schemas, depth) {
|
|
195
|
+
var _this = this;
|
|
196
|
+
var types = schemas.map(function (s) { return _this.parseSchema(s, depth); });
|
|
197
|
+
return types.join(' | ');
|
|
198
|
+
};
|
|
199
|
+
OpenApiToTypescriptConverter.prototype.parseAnyOf = function (schemas, depth) {
|
|
200
|
+
var _this = this;
|
|
201
|
+
var types = schemas.map(function (s) { return _this.parseSchema(s, depth); });
|
|
202
|
+
return types.join(' | ');
|
|
203
|
+
};
|
|
204
|
+
OpenApiToTypescriptConverter.prototype.parseAllOf = function (schemas, depth) {
|
|
205
|
+
var _this = this;
|
|
206
|
+
var types = schemas.map(function (s) {
|
|
207
|
+
var parsed = _this.parseSchema(s, depth);
|
|
208
|
+
return parsed;
|
|
209
|
+
});
|
|
210
|
+
var uniqueTypes = __spreadArray([], Array.from(new Set(types)), true);
|
|
211
|
+
if (uniqueTypes.length === 1) {
|
|
212
|
+
return uniqueTypes[0];
|
|
213
|
+
}
|
|
214
|
+
return uniqueTypes.join(' & ');
|
|
215
|
+
};
|
|
216
|
+
OpenApiToTypescriptConverter.prototype.refToTypeName = function (ref) {
|
|
217
|
+
var parts = ref.split('/');
|
|
218
|
+
return parts[parts.length - 1] || 'unknown';
|
|
219
|
+
};
|
|
220
|
+
return OpenApiToTypescriptConverter;
|
|
221
|
+
}());
|
|
222
|
+
function convertOpenApiToTypescript(schema, name, options) {
|
|
223
|
+
var converter = new OpenApiToTypescriptConverter(options);
|
|
224
|
+
return converter.convert(schema, name);
|
|
225
|
+
}
|
|
226
|
+
exports.convertOpenApiToTypescript = convertOpenApiToTypescript;
|
|
227
|
+
var TypeScriptClient = (function (_super) {
|
|
228
|
+
__extends(TypeScriptClient, _super);
|
|
229
|
+
function TypeScriptClient(options) {
|
|
230
|
+
var _this = _super.call(this, options) || this;
|
|
231
|
+
_this.options = options;
|
|
232
|
+
return _this;
|
|
233
|
+
}
|
|
234
|
+
TypeScriptClient.prototype.generateClientSourceFile = function () {
|
|
235
|
+
var options = this.options;
|
|
236
|
+
if (!(options === null || options === void 0 ? void 0 : options.Module))
|
|
237
|
+
throw new Error("Parameter 'Module' must be specified");
|
|
238
|
+
var METHOD_TYPE_MAP_NAME = 'MethodTypeMap';
|
|
239
|
+
var METHOD_TYPE_MAP_KEYS_NAME = 'MethodTypeMapKeys';
|
|
240
|
+
var RESPONSE_CALLBACK_DATA_NAME = 'ResponseCallbackData';
|
|
241
|
+
var REQUEST_OPTIONS_NAME = 'RequestOptions';
|
|
242
|
+
var RESULT_TYPE_NAME = 'Result';
|
|
243
|
+
var REQUEST_METHOD_MAP_NAME = 'REQUEST_METHOD_MAP';
|
|
244
|
+
var RESPONSE_CACHE_MAP_NAME = 'RESPONSE_CACHE_MAP';
|
|
245
|
+
var REQUEST_BODY_TYPE_ANNOTATION = "".concat(METHOD_TYPE_MAP_NAME, "[T]['request']");
|
|
246
|
+
var RESULT_TYPE_ANNOTATION = "".concat(RESULT_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[T]['response']>");
|
|
247
|
+
var methodTypeMapCodeLines = nest_util_class_1.NestUtil.getControllerClasses(options.Module)
|
|
248
|
+
.reduce(function (result, Class) {
|
|
249
|
+
if (string_util_class_1.StringUtil.isFalsyString(Class === null || Class === void 0 ? void 0 : Class.name) || !(0, controller_util_class_1.isHerbalController)(Class))
|
|
250
|
+
return result;
|
|
251
|
+
var controllerName = (0, controller_util_class_1.getControllerName)(Class);
|
|
252
|
+
var pool = method_decorator_1.Method.getPool(Class.prototype);
|
|
253
|
+
if (string_util_class_1.StringUtil.isFalsyString(controllerName) || pool === null)
|
|
254
|
+
return result;
|
|
255
|
+
return result.concat(Object.entries(pool.getOpenAPIPathsObject())
|
|
256
|
+
.map(function (_a) {
|
|
257
|
+
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
258
|
+
var pathname = _a[0], schema = _a[1];
|
|
259
|
+
var requestSchema = (_e = (_d = (_c = (_b = schema === null || schema === void 0 ? void 0 : schema.post) === null || _b === void 0 ? void 0 : _b.requestBody) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d['application/json']) === null || _e === void 0 ? void 0 : _e.schema;
|
|
260
|
+
var responseSchema = (_k = (_j = (_h = (_g = (_f = schema === null || schema === void 0 ? void 0 : schema.post) === null || _f === void 0 ? void 0 : _f.responses) === null || _g === void 0 ? void 0 : _g['200']) === null || _h === void 0 ? void 0 : _h.content) === null || _j === void 0 ? void 0 : _j['application/json']) === null || _k === void 0 ? void 0 : _k.schema;
|
|
261
|
+
if (!requestSchema && !responseSchema)
|
|
262
|
+
return null;
|
|
263
|
+
return [
|
|
264
|
+
"'/".concat(controllerName).concat(pathname, "': {"),
|
|
265
|
+
" request: ".concat(((_l = convertOpenApiToTypescript(requestSchema)) === null || _l === void 0 ? void 0 : _l.code) || 'any', ";"),
|
|
266
|
+
" response: ".concat(((_m = convertOpenApiToTypescript(responseSchema)) === null || _m === void 0 ? void 0 : _m.code) || 'any', ";"),
|
|
267
|
+
' };',
|
|
268
|
+
].join('');
|
|
269
|
+
})
|
|
270
|
+
.filter(function (value) { return value !== null; }));
|
|
271
|
+
}, [])
|
|
272
|
+
.map(function (line) { return " ".concat(line); });
|
|
273
|
+
methodTypeMapCodeLines.unshift("export interface ".concat(METHOD_TYPE_MAP_NAME, " {"));
|
|
274
|
+
methodTypeMapCodeLines.push('}');
|
|
275
|
+
return [
|
|
276
|
+
"import * as hash from 'object-hash';",
|
|
277
|
+
"import * as _ from 'lodash';",
|
|
278
|
+
"\n".concat(methodTypeMapCodeLines.join('\n')),
|
|
279
|
+
"\ntype ".concat(METHOD_TYPE_MAP_KEYS_NAME, " = keyof ").concat(METHOD_TYPE_MAP_NAME, ";"),
|
|
280
|
+
"\ntype ".concat(RESPONSE_CALLBACK_DATA_NAME, "<K extends ").concat(METHOD_TYPE_MAP_KEYS_NAME, "> = {"),
|
|
281
|
+
' url: K;',
|
|
282
|
+
" result: ".concat(RESULT_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[K]['response']>;"),
|
|
283
|
+
'};',
|
|
284
|
+
"\nexport interface ".concat(REQUEST_OPTIONS_NAME, " extends RequestInit {"),
|
|
285
|
+
' headers?: Record<string, any>;',
|
|
286
|
+
' ignoreCache?: boolean;',
|
|
287
|
+
' prefix?: string;',
|
|
288
|
+
' timeout?: number;',
|
|
289
|
+
' getAuthorizationCredential?: () => string;',
|
|
290
|
+
" onRequest?: (context: { cached: boolean; id: string; options: Omit<".concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>; prefix: string | undefined; requestBody: string; url: string; }) => void | Promise<void>;"),
|
|
291
|
+
" onResponse?: <K extends ".concat(METHOD_TYPE_MAP_KEYS_NAME, ">(response: ").concat(RESPONSE_CALLBACK_DATA_NAME, "<K>, id: string) => void | Promise<void>;"),
|
|
292
|
+
'}',
|
|
293
|
+
"\nexport interface ".concat(RESULT_TYPE_NAME, "<T> {"),
|
|
294
|
+
' error: Error | null;',
|
|
295
|
+
" response: T | null;",
|
|
296
|
+
' status: number;',
|
|
297
|
+
' statusText: string;',
|
|
298
|
+
' headers?: Record<string, any>;',
|
|
299
|
+
'}',
|
|
300
|
+
'\nexport class Client {',
|
|
301
|
+
" public constructor(private readonly options: ".concat(REQUEST_OPTIONS_NAME, " = {}) {}"),
|
|
302
|
+
"\n protected readonly ".concat(REQUEST_METHOD_MAP_NAME, " = new Map<keyof ").concat(METHOD_TYPE_MAP_NAME, ", (...params: any[]) => Promise<unknown>>();"),
|
|
303
|
+
"\n protected readonly ".concat(RESPONSE_CACHE_MAP_NAME, " = new Map<string, ").concat(RESULT_TYPE_NAME, "<unknown>>();"),
|
|
304
|
+
"\n public createRequest<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T): (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
|
|
305
|
+
" if (typeof this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) !== 'function') {"),
|
|
306
|
+
" this.".concat(REQUEST_METHOD_MAP_NAME, ".set(url, (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => this.request.call(this, url, requestBody, options));"),
|
|
307
|
+
' }',
|
|
308
|
+
" return this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) as (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, ">;"),
|
|
309
|
+
' }',
|
|
310
|
+
"\n public async request<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T, requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: Omit<").concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>): Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
|
|
311
|
+
' const id = `${Math.random().toString(32).slice(2)}${Date.now().toString(16)}`;',
|
|
312
|
+
' const requestHash = hash(requestBody ?? null);',
|
|
313
|
+
' const requestBodyString = JSON.stringify(requestBody);',
|
|
314
|
+
" const finalOptions = _.merge({}, this?.options, _.omit(options, ['getAuthorizationCredential', 'onRequest', 'onResponse']));",
|
|
315
|
+
" const onRequestOptions = _.omit(finalOptions, ['getAuthorizationCredential', 'onRequest', 'onResponse']);",
|
|
316
|
+
' const { getAuthorizationCredential, onResponse, onRequest, ignoreCache, timeout, prefix, ...requestOptions } = finalOptions;',
|
|
317
|
+
" if (this.".concat(RESPONSE_CACHE_MAP_NAME, ".has(requestHash) && !ignoreCache) {"),
|
|
318
|
+
' onRequest?.({',
|
|
319
|
+
' prefix,',
|
|
320
|
+
' url,',
|
|
321
|
+
' requestBody: requestBodyString,',
|
|
322
|
+
' cached: true,',
|
|
323
|
+
' options: onRequestOptions,',
|
|
324
|
+
' id,',
|
|
325
|
+
' });',
|
|
326
|
+
" return this.".concat(RESPONSE_CACHE_MAP_NAME, ".get(requestHash) as ").concat(RESULT_TYPE_ANNOTATION, ";"),
|
|
327
|
+
' }',
|
|
328
|
+
' onRequest?.({',
|
|
329
|
+
' prefix,',
|
|
330
|
+
' url,',
|
|
331
|
+
' id,',
|
|
332
|
+
' requestBody: requestBodyString,',
|
|
333
|
+
' cached: false,',
|
|
334
|
+
' options: onRequestOptions,',
|
|
335
|
+
' });',
|
|
336
|
+
' const credential = getAuthorizationCredential?.();',
|
|
337
|
+
' const abortController = new AbortController();',
|
|
338
|
+
' if (timeout! > 0) {',
|
|
339
|
+
' setTimeout(() => {',
|
|
340
|
+
' abortController.abort();',
|
|
341
|
+
' }, timeout);',
|
|
342
|
+
' }',
|
|
343
|
+
" const result: ".concat(RESULT_TYPE_ANNOTATION, " = await fetch((prefix ?? '') + url, {"),
|
|
344
|
+
' ...requestOptions,',
|
|
345
|
+
' body: JSON.stringify(requestBody),',
|
|
346
|
+
" method: 'POST',",
|
|
347
|
+
' signal: abortController.signal,',
|
|
348
|
+
' headers: {',
|
|
349
|
+
' ...requestOptions?.headers,',
|
|
350
|
+
" 'Content-Type': 'application/json',",
|
|
351
|
+
" Authorization: (typeof credential === 'string' && credential.length > 0) ? credential : finalOptions?.headers?.Authorization,",
|
|
352
|
+
' },',
|
|
353
|
+
' }).then((response) => {',
|
|
354
|
+
' const status = response?.status;',
|
|
355
|
+
' const statusText = response?.statusText;',
|
|
356
|
+
' const headers = Array.from(response?.headers?.entries?.() ?? []).reduce((result, [key, value]) => {',
|
|
357
|
+
" if (typeof key !== 'string' || key.length === 0) return result;",
|
|
358
|
+
' result[key] = value;',
|
|
359
|
+
' return result;',
|
|
360
|
+
' }, {});',
|
|
361
|
+
' if (!response?.ok) {',
|
|
362
|
+
' return response.text().then((errorText) => ({ error: new Error(errorText), response: null, headers, status, statusText }));',
|
|
363
|
+
' }',
|
|
364
|
+
" return response.json().then((response) => ({ error: null, response, headers, status, statusText } as ".concat(RESULT_TYPE_ANNOTATION, "));"),
|
|
365
|
+
" }).catch((error) => Promise.resolve({ error, response: null, headers: {}, status: 0, statusText: '' }));",
|
|
366
|
+
" onResponse?.({ url, result }, id);",
|
|
367
|
+
" this.".concat(RESPONSE_CACHE_MAP_NAME, ".set(requestHash, result);"),
|
|
368
|
+
' return result;',
|
|
369
|
+
' }',
|
|
370
|
+
'}\n',
|
|
371
|
+
].join('\n');
|
|
372
|
+
};
|
|
373
|
+
return TypeScriptClient;
|
|
374
|
+
}(client_abstract_class_1.Client));
|
|
375
|
+
exports.TypeScriptClient = TypeScriptClient;
|
package/dist/core.js
CHANGED
|
@@ -158,15 +158,14 @@ var HerbalController = exports.HerbalController = (function () {
|
|
|
158
158
|
HerbalController.prototype.$call = function (name, context) {
|
|
159
159
|
var _a, _b;
|
|
160
160
|
return __awaiter(this, void 0, void 0, function () {
|
|
161
|
-
var
|
|
161
|
+
var callFn;
|
|
162
162
|
return __generator(this, function (_c) {
|
|
163
163
|
switch (_c.label) {
|
|
164
164
|
case 0:
|
|
165
|
-
|
|
166
|
-
if (
|
|
165
|
+
callFn = (_b = (_a = decorators_1.Method.getPool(this)) === null || _a === void 0 ? void 0 : _a.getCallFn) === null || _b === void 0 ? void 0 : _b.call(_a, name);
|
|
166
|
+
if (typeof callFn !== 'function')
|
|
167
167
|
throw new common_1.NotFoundException("Method ".concat(name, " not found"));
|
|
168
|
-
|
|
169
|
-
return [4, methodConfig.call(context)];
|
|
168
|
+
return [4, callFn(context)];
|
|
170
169
|
case 1: return [2, _c.sent()];
|
|
171
170
|
}
|
|
172
171
|
});
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import { CorsOptions, CorsOptionsDelegate } from '@nestjs/common/interfaces/external/cors-options.interface';
|
|
3
3
|
import { Constructor } from 'type-fest';
|
|
4
|
-
import { GroupsFactory } from './decorators/client-groups.decorator';
|
|
5
4
|
import { CanActivate, ExceptionFilter, INestApplication, NestApplicationOptions, NestInterceptor, PipeTransform, WebSocketAdapter } from '@nestjs/common';
|
|
6
5
|
export type Resolver = <T>(Class: Constructor<T>) => Promise<T>;
|
|
7
|
-
export type TypeCustomizerFn = (dataTypeMapName: string, name: string, genericName: string) => string[];
|
|
8
6
|
export interface CreateApplicationOptions {
|
|
9
7
|
Module: Constructor<any>;
|
|
10
8
|
cors?: CorsOptions | CorsOptionsDelegate<any> | false;
|
|
@@ -20,26 +18,10 @@ export interface CreateApplicationOptions {
|
|
|
20
18
|
onBeforeBootstrap?: () => void | Promise<void>;
|
|
21
19
|
worker?: (resolver: Resolver, listenPort: number) => any;
|
|
22
20
|
}
|
|
23
|
-
export interface CreateClientOptions {
|
|
24
|
-
Module: Constructor<any>;
|
|
25
|
-
allowedClientGroupsFactory?: GroupsFactory;
|
|
26
|
-
}
|
|
27
21
|
declare class Application {
|
|
28
22
|
readonly options: CreateApplicationOptions;
|
|
29
23
|
constructor(options: CreateApplicationOptions);
|
|
30
24
|
}
|
|
31
25
|
export declare function isApplication(input: any): boolean;
|
|
32
26
|
export declare function createApplication(options: CreateApplicationOptions): Application;
|
|
33
|
-
export declare abstract class Client {
|
|
34
|
-
readonly options: CreateClientOptions;
|
|
35
|
-
constructor(options: CreateClientOptions);
|
|
36
|
-
abstract generateClientSourceFile(currentGroup?: string): string;
|
|
37
|
-
}
|
|
38
|
-
declare class TypeScriptClient extends Client implements Client {
|
|
39
|
-
readonly options: CreateClientOptions;
|
|
40
|
-
constructor(options: CreateClientOptions);
|
|
41
|
-
generateClientSourceFile(): string;
|
|
42
|
-
}
|
|
43
|
-
export declare function isClient(input: any): boolean;
|
|
44
|
-
export declare function createTypeScriptClient(options: CreateClientOptions): TypeScriptClient;
|
|
45
27
|
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createApplication = exports.isApplication = void 0;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
var Application = (function () {
|
|
6
|
+
function Application(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
return Application;
|
|
10
|
+
}());
|
|
11
|
+
function isApplication(input) {
|
|
12
|
+
return input instanceof Application;
|
|
13
|
+
}
|
|
14
|
+
exports.isApplication = isApplication;
|
|
15
|
+
function createApplication(options) {
|
|
16
|
+
return new Application(options);
|
|
17
|
+
}
|
|
18
|
+
exports.createApplication = createApplication;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Constructor } from 'type-fest';
|
|
2
|
+
import { Client as ClientFactory, CreateClientOptions } from '../abstracts/client.abstract.class';
|
|
3
|
+
declare class Client {
|
|
4
|
+
readonly instance: ClientFactory;
|
|
5
|
+
constructor(instance: ClientFactory);
|
|
6
|
+
}
|
|
7
|
+
export declare function isClient(input: any): boolean;
|
|
8
|
+
export declare function createClient(Class: Constructor<ClientFactory>, options: CreateClientOptions): Client;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createClient = exports.isClient = void 0;
|
|
4
|
+
var Client = (function () {
|
|
5
|
+
function Client(instance) {
|
|
6
|
+
this.instance = instance;
|
|
7
|
+
}
|
|
8
|
+
return Client;
|
|
9
|
+
}());
|
|
10
|
+
function isClient(input) {
|
|
11
|
+
return input instanceof Client;
|
|
12
|
+
}
|
|
13
|
+
exports.isClient = isClient;
|
|
14
|
+
function createClient(Class, options) {
|
|
15
|
+
return new Client(new Class(options));
|
|
16
|
+
}
|
|
17
|
+
exports.createClient = createClient;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./create-application"), exports);
|
|
18
|
+
__exportStar(require("./create-client"), exports);
|
|
@@ -6,6 +6,7 @@ import { HeaderUtil } from '@open-norantec/utilities/dist/header-util.class';
|
|
|
6
6
|
import { Constructor } from 'type-fest';
|
|
7
7
|
import { Type } from '@nestjs/common';
|
|
8
8
|
import { RequestContext } from '../types';
|
|
9
|
+
import { PathsObject } from 'zod-openapi/dist/openapi3-ts/dist/model/openapi31';
|
|
9
10
|
export interface MethodOptions<IS extends z.Schema<any>, OS extends z.Schema<any>> {
|
|
10
11
|
inputSchema: IS;
|
|
11
12
|
outputSchema: OS;
|
|
@@ -24,7 +25,7 @@ export type MethodCallContext<IS extends z.Schema<any>> = Omit<MethodContext<IS>
|
|
|
24
25
|
export type MethodCallback<IS extends z.Schema<any>, OS extends z.Schema<any>> = (context: MethodContext<IS>) => Promise<z.infer<OS>>;
|
|
25
26
|
declare class MethodConfig<IS extends z.Schema<any>, OS extends z.Schema<any>> {
|
|
26
27
|
readonly name: string;
|
|
27
|
-
|
|
28
|
+
readonly options: MethodOptions<IS, OS>;
|
|
28
29
|
protected readonly callback: MethodCallback<IS, OS>;
|
|
29
30
|
constructor(name: string, options: MethodOptions<IS, OS>, callback: MethodCallback<IS, OS>);
|
|
30
31
|
call(callContext: MethodCallContext<IS>): Promise<z.TypeOf<OS>>;
|
|
@@ -32,7 +33,8 @@ declare class MethodConfig<IS extends z.Schema<any>, OS extends z.Schema<any>> {
|
|
|
32
33
|
declare class MethodPool {
|
|
33
34
|
protected readonly methods: Map<string, MethodConfig<any, any>>;
|
|
34
35
|
registerMethod<IS extends z.Schema<any>, OS extends z.Schema<any>>(name: string, options: MethodOptions<IS, OS>, callback: MethodCallback<IS, OS>): void;
|
|
35
|
-
|
|
36
|
+
getCallFn(name: string): any;
|
|
37
|
+
getOpenAPIPathsObject(): PathsObject;
|
|
36
38
|
}
|
|
37
39
|
export declare function Method<IS extends z.Schema<any>, OS extends z.Schema<any>>(...parameters: Parameters<typeof MethodPool.prototype.registerMethod<IS, OS>>): ClassDecorator;
|
|
38
40
|
export declare namespace Method {
|
|
@@ -53,6 +53,7 @@ var zod_1 = require("zod");
|
|
|
53
53
|
var utilities_1 = require("@open-norantec/utilities");
|
|
54
54
|
var common_1 = require("@nestjs/common");
|
|
55
55
|
var _ = require("lodash");
|
|
56
|
+
var zod_openapi_1 = require("zod-openapi");
|
|
56
57
|
var METHOD_POOL = Symbol();
|
|
57
58
|
var MethodConfig = (function () {
|
|
58
59
|
function MethodConfig(name, options, callback) {
|
|
@@ -115,9 +116,41 @@ var MethodPool = (function () {
|
|
|
115
116
|
throw new Error("Method name cannot contain slashes: ".concat(name));
|
|
116
117
|
this.methods.set(name, new MethodConfig(name, options, callback));
|
|
117
118
|
};
|
|
118
|
-
MethodPool.prototype.
|
|
119
|
-
var
|
|
120
|
-
|
|
119
|
+
MethodPool.prototype.getCallFn = function (name) {
|
|
120
|
+
var _a;
|
|
121
|
+
var callFn = (_a = this.methods.get(name)) === null || _a === void 0 ? void 0 : _a.call;
|
|
122
|
+
return typeof callFn === 'function' ? callFn.bind(this) : null;
|
|
123
|
+
};
|
|
124
|
+
MethodPool.prototype.getOpenAPIPathsObject = function () {
|
|
125
|
+
var result = {};
|
|
126
|
+
Array.from(this.methods.entries()).forEach(function (_a) {
|
|
127
|
+
var name = _a[0], config = _a[1];
|
|
128
|
+
result["/".concat(name)] = {
|
|
129
|
+
post: {
|
|
130
|
+
requestBody: {
|
|
131
|
+
description: 'Request body for method ' + name,
|
|
132
|
+
required: true,
|
|
133
|
+
content: {
|
|
134
|
+
'application/json': {
|
|
135
|
+
schema: (0, zod_openapi_1.createSchema)(config.options.inputSchema).schema,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
responses: {
|
|
140
|
+
'200': {
|
|
141
|
+
description: 'Response for method ' + name,
|
|
142
|
+
content: {
|
|
143
|
+
'application/json': (0, zod_openapi_1.createSchema)(zod_1.z.object({
|
|
144
|
+
data: config.options.outputSchema,
|
|
145
|
+
token: zod_1.z.string().nullable(),
|
|
146
|
+
})),
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
return result;
|
|
121
154
|
};
|
|
122
155
|
return MethodPool;
|
|
123
156
|
}());
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './constants';
|
|
|
8
8
|
export * from './decorators';
|
|
9
9
|
export * from './utilities';
|
|
10
10
|
export * from '@nestjs/sequelize';
|
|
11
|
+
export * from './clients';
|
|
11
12
|
export { Response } from 'express';
|
|
12
13
|
export { Request } from './types';
|
|
13
14
|
export { LoggerService } from './modules';
|
package/dist/index.js
CHANGED
|
@@ -25,5 +25,6 @@ __exportStar(require("./constants"), exports);
|
|
|
25
25
|
__exportStar(require("./decorators"), exports);
|
|
26
26
|
__exportStar(require("./utilities"), exports);
|
|
27
27
|
__exportStar(require("@nestjs/sequelize"), exports);
|
|
28
|
+
__exportStar(require("./clients"), exports);
|
|
28
29
|
var modules_1 = require("./modules");
|
|
29
30
|
Object.defineProperty(exports, "LoggerService", { enumerable: true, get: function () { return modules_1.LoggerService; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-norantec/herbal",
|
|
3
|
-
"version": "1.0.2-alpha.
|
|
3
|
+
"version": "1.0.2-alpha.19",
|
|
4
4
|
"description": "Herbal is a builder and toolchain for Nest.js applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -38,14 +38,13 @@
|
|
|
38
38
|
"@nestjs/common": "^10.0.0",
|
|
39
39
|
"@nestjs/core": "^10.4.19",
|
|
40
40
|
"@nestjs/sequelize": "^10.0.1",
|
|
41
|
-
"@open-norantec/forge": "^2.0.0-alpha.
|
|
41
|
+
"@open-norantec/forge": "^2.0.0-alpha.9",
|
|
42
42
|
"@open-norantec/utilities": "latest",
|
|
43
43
|
"commander": "^12.1.0",
|
|
44
44
|
"fs-extra": "^11.3.4",
|
|
45
45
|
"lodash": "^4.17.21",
|
|
46
46
|
"nest-winston": "^1.10.2",
|
|
47
47
|
"nj-request-scope": "^1.0.10",
|
|
48
|
-
"openapi-types": "^12.1.3",
|
|
49
48
|
"patch-package": "^8.0.1",
|
|
50
49
|
"reflect-metadata": "^0.2.2",
|
|
51
50
|
"rxjs": "^7.8.2",
|
|
@@ -54,7 +53,8 @@
|
|
|
54
53
|
"type-fest": "^4.41.0",
|
|
55
54
|
"typescript": ">=5.1.0 <5.2.0",
|
|
56
55
|
"uuid": "^11.1.0",
|
|
57
|
-
"zod": "^3.25.67"
|
|
56
|
+
"zod": "^3.25.67",
|
|
57
|
+
"zod-openapi": "4.2.4"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/express": "^5.0.3",
|
package/dist/create.js
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __extends = (this && this.__extends) || (function () {
|
|
3
|
-
var extendStatics = function (d, b) {
|
|
4
|
-
extendStatics = Object.setPrototypeOf ||
|
|
5
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
-
return extendStatics(d, b);
|
|
8
|
-
};
|
|
9
|
-
return function (d, b) {
|
|
10
|
-
if (typeof b !== "function" && b !== null)
|
|
11
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
-
extendStatics(d, b);
|
|
13
|
-
function __() { this.constructor = d; }
|
|
14
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
-
};
|
|
16
|
-
})();
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.createTypeScriptClient = exports.isClient = exports.Client = exports.createApplication = exports.isApplication = void 0;
|
|
19
|
-
require("reflect-metadata");
|
|
20
|
-
var _ = require("lodash");
|
|
21
|
-
var nest_util_class_1 = require("./utilities/nest-util.class");
|
|
22
|
-
var string_util_class_1 = require("@open-norantec/utilities/dist/string-util.class");
|
|
23
|
-
var reflect_declaration_1 = require("./transformers/reflect-declaration");
|
|
24
|
-
var client_groups_decorator_1 = require("./decorators/client-groups.decorator");
|
|
25
|
-
var controller_util_class_1 = require("./utilities/controller-util.class");
|
|
26
|
-
var Application = (function () {
|
|
27
|
-
function Application(options) {
|
|
28
|
-
this.options = options;
|
|
29
|
-
}
|
|
30
|
-
return Application;
|
|
31
|
-
}());
|
|
32
|
-
function isApplication(input) {
|
|
33
|
-
return input instanceof Application;
|
|
34
|
-
}
|
|
35
|
-
exports.isApplication = isApplication;
|
|
36
|
-
function createApplication(options) {
|
|
37
|
-
return new Application(options);
|
|
38
|
-
}
|
|
39
|
-
exports.createApplication = createApplication;
|
|
40
|
-
var Client = (function () {
|
|
41
|
-
function Client(options) {
|
|
42
|
-
this.options = options;
|
|
43
|
-
}
|
|
44
|
-
return Client;
|
|
45
|
-
}());
|
|
46
|
-
exports.Client = Client;
|
|
47
|
-
var TypeScriptClient = (function (_super) {
|
|
48
|
-
__extends(TypeScriptClient, _super);
|
|
49
|
-
function TypeScriptClient(options) {
|
|
50
|
-
var _this = _super.call(this, options) || this;
|
|
51
|
-
_this.options = options;
|
|
52
|
-
return _this;
|
|
53
|
-
}
|
|
54
|
-
TypeScriptClient.prototype.generateClientSourceFile = function () {
|
|
55
|
-
var options = this.options;
|
|
56
|
-
if (!(options === null || options === void 0 ? void 0 : options.Module))
|
|
57
|
-
throw new Error("Parameter 'Module' must be specified");
|
|
58
|
-
var METHOD_TYPE_MAP_NAME = 'MethodTypeMap';
|
|
59
|
-
var METHOD_TYPE_MAP_KEYS_NAME = 'MethodTypeMapKeys';
|
|
60
|
-
var RESPONSE_CALLBACK_DATA_NAME = 'ResponseCallbackData';
|
|
61
|
-
var REQUEST_OPTIONS_NAME = 'RequestOptions';
|
|
62
|
-
var RESULT_TYPE_NAME = 'Result';
|
|
63
|
-
var HTTP_RESPONSE_BODY_TYPE_NAME = 'HttpResponseBody';
|
|
64
|
-
var REQUEST_METHOD_MAP_NAME = 'REQUEST_METHOD_MAP';
|
|
65
|
-
var RESPONSE_CACHE_MAP_NAME = 'RESPONSE_CACHE_MAP';
|
|
66
|
-
var REQUEST_BODY_TYPE_ANNOTATION = "".concat(METHOD_TYPE_MAP_NAME, "[T]['request']");
|
|
67
|
-
var RESULT_TYPE_ANNOTATION = "".concat(RESULT_TYPE_NAME, "<").concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[T]['response']>>");
|
|
68
|
-
var methodTypeMapCodeLines = nest_util_class_1.NestUtil.getControllerClasses(options.Module)
|
|
69
|
-
.reduce(function (result, Class) {
|
|
70
|
-
if (string_util_class_1.StringUtil.isFalsyString(Class === null || Class === void 0 ? void 0 : Class.name))
|
|
71
|
-
return result;
|
|
72
|
-
var controllerName = _.camelCase(Class.name.replace(/Controller$/g, ''));
|
|
73
|
-
if (string_util_class_1.StringUtil.isFalsyString(controllerName) || !(0, controller_util_class_1.isHerbalController)(Class)) {
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
var metadataNames = Reflect.getMetadataKeys(Class.prototype).filter(function (metadataName) { return !string_util_class_1.StringUtil.isFalsyString(metadataName); });
|
|
77
|
-
return result.concat(metadataNames.reduce(function (result, metadataName) {
|
|
78
|
-
var methodName = metadataName.slice(reflect_declaration_1.DECORATOR_NAME_PREFIX.length);
|
|
79
|
-
if (string_util_class_1.StringUtil.isFalsyString(metadataName) ||
|
|
80
|
-
!metadataName.startsWith(reflect_declaration_1.DECORATOR_NAME_PREFIX) ||
|
|
81
|
-
!client_groups_decorator_1.ClientGroups.shouldShowInClient(Class, methodName, function (defaultGroupName) {
|
|
82
|
-
var _a;
|
|
83
|
-
return (_a = options.allowedClientGroupsFactory) === null || _a === void 0 ? void 0 : _a.call(options, defaultGroupName);
|
|
84
|
-
})) {
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
|
-
var scopeIdentifier = "/".concat(controllerName, "/").concat(methodName);
|
|
88
|
-
return result.concat(["'".concat(scopeIdentifier, "'"), "".concat(Reflect.getMetadata(metadataName, Class.prototype), ";")].join(': '));
|
|
89
|
-
}, []));
|
|
90
|
-
}, [])
|
|
91
|
-
.map(function (line) { return " ".concat(line); });
|
|
92
|
-
methodTypeMapCodeLines.unshift("export interface ".concat(METHOD_TYPE_MAP_NAME, " {"));
|
|
93
|
-
methodTypeMapCodeLines.push('}');
|
|
94
|
-
return [
|
|
95
|
-
"import * as hash from 'object-hash';",
|
|
96
|
-
"import * as _ from 'lodash';",
|
|
97
|
-
"\n".concat(methodTypeMapCodeLines.join('\n')),
|
|
98
|
-
"\ntype ".concat(METHOD_TYPE_MAP_KEYS_NAME, " = keyof ").concat(METHOD_TYPE_MAP_NAME, ";"),
|
|
99
|
-
"\ntype ".concat(RESPONSE_CALLBACK_DATA_NAME, "<K extends ").concat(METHOD_TYPE_MAP_KEYS_NAME, "> = {"),
|
|
100
|
-
' url: K;',
|
|
101
|
-
" result: ".concat(RESULT_TYPE_NAME, "<").concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<").concat(METHOD_TYPE_MAP_NAME, "[K]['response']>>;"),
|
|
102
|
-
'};',
|
|
103
|
-
"\nexport type ".concat(HTTP_RESPONSE_BODY_TYPE_NAME, "<T> = {"),
|
|
104
|
-
' data: T;',
|
|
105
|
-
' token: string | null;',
|
|
106
|
-
'};',
|
|
107
|
-
"\nexport interface ".concat(REQUEST_OPTIONS_NAME, " extends RequestInit {"),
|
|
108
|
-
' headers?: Record<string, any>;',
|
|
109
|
-
' ignoreCache?: boolean;',
|
|
110
|
-
' prefix?: string;',
|
|
111
|
-
' timeout?: number;',
|
|
112
|
-
' getAuthorizationCredential?: () => string;',
|
|
113
|
-
" onRequest?: (context: { cached: boolean; id: string; options: Omit<".concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>; prefix: string | undefined; requestBody: string; url: string; }) => void | Promise<void>;"),
|
|
114
|
-
" onResponse?: <K extends ".concat(METHOD_TYPE_MAP_KEYS_NAME, ">(response: ").concat(RESPONSE_CALLBACK_DATA_NAME, "<K>, id: string) => void | Promise<void>;"),
|
|
115
|
-
'}',
|
|
116
|
-
"\nexport interface ".concat(RESULT_TYPE_NAME, "<T> {"),
|
|
117
|
-
' error: Error | null;',
|
|
118
|
-
" response: T | null;",
|
|
119
|
-
' status: number;',
|
|
120
|
-
' statusText: string;',
|
|
121
|
-
' headers?: Record<string, any>;',
|
|
122
|
-
'}',
|
|
123
|
-
'\nexport class Client {',
|
|
124
|
-
" public constructor(private readonly options: ".concat(REQUEST_OPTIONS_NAME, " = {}) {}"),
|
|
125
|
-
"\n protected readonly ".concat(REQUEST_METHOD_MAP_NAME, " = new Map<keyof ").concat(METHOD_TYPE_MAP_NAME, ", (...params: any[]) => Promise<unknown>>();"),
|
|
126
|
-
"\n protected readonly ".concat(RESPONSE_CACHE_MAP_NAME, " = new Map<string, ").concat(RESULT_TYPE_NAME, "<unknown>>();"),
|
|
127
|
-
"\n public createRequest<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T): (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
|
|
128
|
-
" if (typeof this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) !== 'function') {"),
|
|
129
|
-
" this.".concat(REQUEST_METHOD_MAP_NAME, ".set(url, (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => this.request.call(this, url, requestBody, options));"),
|
|
130
|
-
' }',
|
|
131
|
-
" return this.".concat(REQUEST_METHOD_MAP_NAME, ".get(url) as (requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: ").concat(REQUEST_OPTIONS_NAME, ") => Promise<").concat(RESULT_TYPE_ANNOTATION, ">;"),
|
|
132
|
-
' }',
|
|
133
|
-
"\n public async request<T extends keyof ".concat(METHOD_TYPE_MAP_NAME, ">(url: T, requestBody?: ").concat(REQUEST_BODY_TYPE_ANNOTATION, ", options?: Omit<").concat(REQUEST_OPTIONS_NAME, ", 'getAuthorizationCredential' | 'onRequest' | 'onResponse'>): Promise<").concat(RESULT_TYPE_ANNOTATION, "> {"),
|
|
134
|
-
' const id = `${Math.random().toString(32).slice(2)}${Date.now().toString(16)}`;',
|
|
135
|
-
' const requestHash = hash(requestBody ?? null);',
|
|
136
|
-
' const requestBodyString = JSON.stringify(requestBody);',
|
|
137
|
-
" const finalOptions = _.merge({}, this?.options, _.omit(options, ['getAuthorizationCredential', 'onRequest', 'onResponse']));",
|
|
138
|
-
" const onRequestOptions = _.omit(finalOptions, ['getAuthorizationCredential', 'onRequest', 'onResponse']);",
|
|
139
|
-
' const { getAuthorizationCredential, onResponse, onRequest, ignoreCache, timeout, prefix, ...requestOptions } = finalOptions;',
|
|
140
|
-
" if (this.".concat(RESPONSE_CACHE_MAP_NAME, ".has(requestHash) && !ignoreCache) {"),
|
|
141
|
-
' onRequest?.({',
|
|
142
|
-
' prefix,',
|
|
143
|
-
' url,',
|
|
144
|
-
' requestBody: requestBodyString,',
|
|
145
|
-
' cached: true,',
|
|
146
|
-
' options: onRequestOptions,',
|
|
147
|
-
' id,',
|
|
148
|
-
' });',
|
|
149
|
-
" return this.".concat(RESPONSE_CACHE_MAP_NAME, ".get(requestHash) as ").concat(RESULT_TYPE_ANNOTATION, ";"),
|
|
150
|
-
' }',
|
|
151
|
-
' onRequest?.({',
|
|
152
|
-
' prefix,',
|
|
153
|
-
' url,',
|
|
154
|
-
' id,',
|
|
155
|
-
' requestBody: requestBodyString,',
|
|
156
|
-
' cached: false,',
|
|
157
|
-
' options: onRequestOptions,',
|
|
158
|
-
' });',
|
|
159
|
-
' const credential = getAuthorizationCredential?.();',
|
|
160
|
-
' const abortController = new AbortController();',
|
|
161
|
-
' if (timeout! > 0) {',
|
|
162
|
-
' setTimeout(() => {',
|
|
163
|
-
' abortController.abort();',
|
|
164
|
-
' }, timeout);',
|
|
165
|
-
' }',
|
|
166
|
-
" const result: ".concat(RESULT_TYPE_ANNOTATION, " = await fetch((prefix ?? '') + url, {"),
|
|
167
|
-
' ...requestOptions,',
|
|
168
|
-
' body: JSON.stringify(requestBody),',
|
|
169
|
-
" method: 'POST',",
|
|
170
|
-
' signal: abortController.signal,',
|
|
171
|
-
' headers: {',
|
|
172
|
-
' ...requestOptions?.headers,',
|
|
173
|
-
" 'Content-Type': 'application/json',",
|
|
174
|
-
" Authorization: (typeof credential === 'string' && credential.length > 0) ? credential : finalOptions?.headers?.Authorization,",
|
|
175
|
-
' },',
|
|
176
|
-
' }).then((response) => {',
|
|
177
|
-
' const status = response?.status;',
|
|
178
|
-
' const statusText = response?.statusText;',
|
|
179
|
-
' const headers = Array.from(response?.headers?.entries?.() ?? []).reduce((result, [key, value]) => {',
|
|
180
|
-
" if (typeof key !== 'string' || key.length === 0) return result;",
|
|
181
|
-
' result[key] = value;',
|
|
182
|
-
' return result;',
|
|
183
|
-
' }, {});',
|
|
184
|
-
' if (!response?.ok) {',
|
|
185
|
-
' return response.text().then((errorText) => ({ error: new Error(errorText), response: null, headers, status, statusText }));',
|
|
186
|
-
' }',
|
|
187
|
-
" return response.json().then((response) => ({ error: null, response, headers, status, statusText } as ".concat(RESULT_TYPE_ANNOTATION, "));"),
|
|
188
|
-
" }).catch((error) => Promise.resolve({ error, response: null, headers: {}, status: 0, statusText: '' }));",
|
|
189
|
-
" onResponse?.({ url, result }, id);",
|
|
190
|
-
" this.".concat(RESPONSE_CACHE_MAP_NAME, ".set(requestHash, result);"),
|
|
191
|
-
' return result;',
|
|
192
|
-
' }',
|
|
193
|
-
'}\n',
|
|
194
|
-
].join('\n');
|
|
195
|
-
};
|
|
196
|
-
return TypeScriptClient;
|
|
197
|
-
}(Client));
|
|
198
|
-
function isClient(input) {
|
|
199
|
-
return input instanceof Client;
|
|
200
|
-
}
|
|
201
|
-
exports.isClient = isClient;
|
|
202
|
-
function createTypeScriptClient(options) {
|
|
203
|
-
return new TypeScriptClient(options);
|
|
204
|
-
}
|
|
205
|
-
exports.createTypeScriptClient = createTypeScriptClient;
|