swagger-typescript-api 13.0.9 → 13.0.11

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.
Files changed (69) hide show
  1. package/README.md +3 -3
  2. package/dist/chunk-3OGOYA5P.cjs +104 -0
  3. package/dist/chunk-3OGOYA5P.cjs.map +1 -0
  4. package/dist/chunk-R4CYI34W.js +65 -0
  5. package/dist/chunk-R4CYI34W.js.map +1 -0
  6. package/dist/cli.cjs +43 -0
  7. package/dist/cli.cjs.map +1 -0
  8. package/dist/cli.js +36 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/lib.cjs +21 -0
  11. package/dist/lib.cjs.map +1 -0
  12. package/dist/lib.js +4 -0
  13. package/dist/lib.js.map +1 -0
  14. package/index.d.ts +1 -1
  15. package/package.json +25 -14
  16. package/templates/base/http-clients/axios-http-client.ejs +3 -0
  17. package/templates/base/http-clients/fetch-http-client.ejs +3 -3
  18. package/cli/constants.js +0 -6
  19. package/cli/execute.js +0 -180
  20. package/cli/index.js +0 -94
  21. package/cli/operations/display-help.js +0 -177
  22. package/cli/operations/display-version.js +0 -5
  23. package/cli/parse-args.js +0 -24
  24. package/cli/process-option.js +0 -75
  25. package/index.js +0 -344
  26. package/src/code-formatter.js +0 -114
  27. package/src/code-gen-process.js +0 -569
  28. package/src/commands/generate-templates/configuration.js +0 -31
  29. package/src/commands/generate-templates/index.js +0 -10
  30. package/src/commands/generate-templates/templates-gen-process.js +0 -205
  31. package/src/component-type-name-resolver.js +0 -42
  32. package/src/configuration.js +0 -445
  33. package/src/constants.js +0 -77
  34. package/src/index.js +0 -16
  35. package/src/schema-components-map.js +0 -76
  36. package/src/schema-parser/base-schema-parsers/array.js +0 -41
  37. package/src/schema-parser/base-schema-parsers/complex.js +0 -49
  38. package/src/schema-parser/base-schema-parsers/discriminator.js +0 -305
  39. package/src/schema-parser/base-schema-parsers/enum.js +0 -156
  40. package/src/schema-parser/base-schema-parsers/object.js +0 -103
  41. package/src/schema-parser/base-schema-parsers/primitive.js +0 -61
  42. package/src/schema-parser/complex-schema-parsers/all-of.js +0 -26
  43. package/src/schema-parser/complex-schema-parsers/any-of.js +0 -27
  44. package/src/schema-parser/complex-schema-parsers/not.js +0 -9
  45. package/src/schema-parser/complex-schema-parsers/one-of.js +0 -27
  46. package/src/schema-parser/mono-schema-parser.js +0 -46
  47. package/src/schema-parser/schema-formatters.js +0 -164
  48. package/src/schema-parser/schema-parser-fabric.js +0 -130
  49. package/src/schema-parser/schema-parser.js +0 -295
  50. package/src/schema-parser/schema-utils.js +0 -319
  51. package/src/schema-parser/util/enum-key-resolver.js +0 -24
  52. package/src/schema-routes/schema-routes.js +0 -1208
  53. package/src/schema-routes/util/specific-arg-name-resolver.js +0 -24
  54. package/src/schema-walker.js +0 -91
  55. package/src/swagger-schema-resolver.js +0 -195
  56. package/src/templates-worker.js +0 -243
  57. package/src/translators/javascript.js +0 -81
  58. package/src/translators/translator.js +0 -33
  59. package/src/type-name-formatter.js +0 -111
  60. package/src/util/file-system.js +0 -95
  61. package/src/util/id.js +0 -7
  62. package/src/util/internal-case.js +0 -7
  63. package/src/util/logger.js +0 -142
  64. package/src/util/name-resolver.js +0 -103
  65. package/src/util/object-assign.js +0 -17
  66. package/src/util/pascal-case.js +0 -7
  67. package/src/util/random.js +0 -11
  68. package/src/util/request.js +0 -63
  69. package/src/util/sort-by-property.js +0 -15
@@ -1,24 +0,0 @@
1
- import { NameResolver } from "../../util/name-resolver.js";
2
-
3
- class SpecificArgNameResolver extends NameResolver {
4
- counter = 1;
5
- /**
6
- * @param {CodeGenConfig} config;
7
- * @param {Logger} logger;
8
- * @param {string[]} reservedNames
9
- */
10
- constructor(config, logger, reservedNames) {
11
- super(config, logger, reservedNames, (variants) => {
12
- const generatedVariant =
13
- (variants[0] && `${variants[0]}${this.counter++}`) ||
14
- `${this.config.specificArgNameResolverName}${this.counter++}`;
15
- this.logger.debug(
16
- "generated fallback type name for specific arg - ",
17
- generatedVariant,
18
- );
19
- return generatedVariant;
20
- });
21
- }
22
- }
23
-
24
- export { SpecificArgNameResolver };
@@ -1,91 +0,0 @@
1
- import _ from "lodash";
2
-
3
- // TODO: WIP
4
- // this class will be needed to walk by schema everywhere
5
- class SchemaWalker {
6
- /** @type {Logger} */
7
- logger;
8
- /** @type {CodeGenConfig} */
9
- config;
10
- /** @type {SwaggerSchemaResolver} */
11
- swaggerSchemaResolver;
12
- /** @type {Map<string, Record<string, any>>} */
13
- schemas = new Map();
14
- /** @type {Map<string, Record<string, any>>} */
15
- caches = new Map();
16
-
17
- constructor({ config, logger }) {
18
- this.logger = logger;
19
- this.config = config;
20
- }
21
-
22
- /**
23
- * @param name {string}
24
- * @param schema {Record<string, any>}
25
- */
26
- addSchema = (name, schema) => {
27
- this.schemas.set(name, _.cloneDeep(schema));
28
- };
29
-
30
- /**
31
- * @param ref {string}
32
- * @returns {any}
33
- */
34
- findByRef = (ref) => {
35
- this.logger.debug("try to resolve ref by path", ref);
36
-
37
- if (this.caches.has(ref)) {
38
- return this.caches.get(ref);
39
- }
40
-
41
- const schemas = Array.from(this.schemas.values());
42
- if (this._isLocalRef(ref)) {
43
- for (const schema of schemas) {
44
- const refData = this._getRefDataFromSchema(schema, ref);
45
- if (refData) {
46
- return refData;
47
- }
48
- }
49
- } else if (this._isRemoteRef(ref)) {
50
- this.logger.debug("remote refs not supported", ref);
51
- return null;
52
- } else {
53
- const [address, path] = path.split("#");
54
- let swaggerSchemaObject;
55
-
56
- if (this.schemas.has(address)) {
57
- swaggerSchemaObject = this.schemas.get(address);
58
- } else {
59
- const pathToSchema = path.resolve(process.cwd(), address);
60
- const swaggerSchemaFile =
61
- this.swaggerSchemaResolver.getSwaggerSchemaByPath(pathToSchema);
62
- swaggerSchemaObject =
63
- this.swaggerSchemaResolver.processSwaggerSchemaFile(
64
- swaggerSchemaFile,
65
- );
66
- this.schemas.set(address, swaggerSchemaObject);
67
- }
68
-
69
- return this._getRefDataFromSchema(swaggerSchemaObject, path);
70
- }
71
- };
72
-
73
- _isLocalRef = (ref) => {
74
- return ref.startsWith("#");
75
- };
76
-
77
- _isRemoteRef = (ref) => {
78
- return ref.startsWith("http://") || ref.startsWith("https://");
79
- };
80
-
81
- _getRefDataFromSchema = (schema, ref) => {
82
- const path = ref.replace("#", "").split("/");
83
- const refData = _.get(schema, path);
84
- if (refData) {
85
- this.caches.set(ref, refData);
86
- }
87
- return refData;
88
- };
89
- }
90
-
91
- export { SchemaWalker };
@@ -1,195 +0,0 @@
1
- import yaml from "js-yaml";
2
- import _ from "lodash";
3
- import converter from "swagger2openapi";
4
- import { Request } from "./util/request.js";
5
-
6
- class SwaggerSchemaResolver {
7
- /**
8
- * @type {CodeGenConfig}
9
- */
10
- config;
11
- /**
12
- * @type {Logger}
13
- */
14
- logger;
15
- /**
16
- * @type {FileSystem}
17
- */
18
- fileSystem;
19
- /**
20
- * @type {Request}
21
- */
22
- request;
23
-
24
- constructor({ config, logger, fileSystem }) {
25
- this.config = config;
26
- this.logger = logger;
27
- this.fileSystem = fileSystem;
28
- this.request = new Request(config, logger);
29
- }
30
-
31
- /**
32
- *
33
- * @returns {Promise<{usageSchema: Record<string, *>, originalSchema: Record<string, *>}>}
34
- */
35
- async create() {
36
- const {
37
- spec,
38
- patch,
39
- input,
40
- url,
41
- disableStrictSSL,
42
- disableProxy,
43
- authorizationToken,
44
- } = this.config;
45
-
46
- if (this.config.spec) {
47
- return await this.convertSwaggerObject(spec, { patch });
48
- }
49
-
50
- const swaggerSchemaFile = await this.fetchSwaggerSchemaFile(
51
- input,
52
- url,
53
- disableStrictSSL,
54
- disableProxy,
55
- authorizationToken,
56
- );
57
- const swaggerSchemaObject =
58
- this.processSwaggerSchemaFile(swaggerSchemaFile);
59
- return await this.convertSwaggerObject(swaggerSchemaObject, { patch });
60
- }
61
-
62
- /**
63
- *
64
- * @param swaggerSchema {Record<string, any>}
65
- * @param converterOptions {{ patch?: boolean }}
66
- * @returns {Promise<{ usageSchema: Record<string, any>, originalSchema: Record<string, any>}>}
67
- */
68
- convertSwaggerObject(swaggerSchema, converterOptions) {
69
- return new Promise((resolve) => {
70
- const result = _.cloneDeep(swaggerSchema);
71
- result.info = _.merge(
72
- {
73
- title: "No title",
74
- version: "",
75
- },
76
- result.info,
77
- );
78
-
79
- if (!result.openapi) {
80
- result.paths = _.merge({}, result.paths);
81
-
82
- converter.convertObj(
83
- result,
84
- {
85
- ...converterOptions,
86
- warnOnly: true,
87
- refSiblings: "preserve",
88
- rbname: "requestBodyName",
89
- },
90
- (err, options) => {
91
- const parsedSwaggerSchema = _.get(
92
- err,
93
- "options.openapi",
94
- _.get(options, "openapi"),
95
- );
96
- if (!parsedSwaggerSchema && err) {
97
- throw new Error(err);
98
- }
99
- this.config.update({ convertedFromSwagger2: true });
100
- resolve({
101
- usageSchema: parsedSwaggerSchema,
102
- originalSchema: result,
103
- });
104
- },
105
- );
106
- } else {
107
- resolve({
108
- usageSchema: result,
109
- originalSchema: _.cloneDeep(result),
110
- });
111
- }
112
- });
113
- }
114
-
115
- getSwaggerSchemaByPath = (pathToSwagger) => {
116
- this.logger.log(`try to get swagger by path "${pathToSwagger}"`);
117
- return this.fileSystem.getFileContent(pathToSwagger);
118
- };
119
-
120
- async fetchSwaggerSchemaFile(
121
- pathToSwagger,
122
- urlToSwagger,
123
- disableStrictSSL,
124
- disableProxy,
125
- authToken,
126
- ) {
127
- if (this.fileSystem.pathIsExist(pathToSwagger)) {
128
- return this.getSwaggerSchemaByPath(pathToSwagger);
129
- } else {
130
- this.logger.log(`try to get swagger by URL "${urlToSwagger}"`);
131
- return await this.request.download({
132
- url: urlToSwagger,
133
- disableStrictSSL,
134
- authToken,
135
- disableProxy,
136
- });
137
- }
138
- }
139
-
140
- processSwaggerSchemaFile(file) {
141
- if (typeof file !== "string") return file;
142
-
143
- try {
144
- return JSON.parse(file);
145
- } catch (e) {
146
- return yaml.load(file);
147
- }
148
- }
149
-
150
- fixSwaggerSchema({ usageSchema, originalSchema }) {
151
- const usagePaths = _.get(usageSchema, "paths");
152
- const originalPaths = _.get(originalSchema, "paths");
153
-
154
- // walk by routes
155
- _.each(usagePaths, (usagePathObject, route) => {
156
- const originalPathObject = _.get(originalPaths, route);
157
-
158
- // walk by methods
159
- _.each(usagePathObject, (usageRouteInfo, methodName) => {
160
- const originalRouteInfo = _.get(originalPathObject, methodName);
161
- const usageRouteParams = _.get(usageRouteInfo, "parameters", []);
162
- const originalRouteParams = _.get(originalRouteInfo, "parameters", []);
163
-
164
- if (typeof usageRouteInfo === "object") {
165
- usageRouteInfo.consumes = _.uniq(
166
- _.compact([
167
- ...(usageRouteInfo.consumes || []),
168
- ...(originalRouteInfo.consumes || []),
169
- ]),
170
- );
171
- usageRouteInfo.produces = _.uniq(
172
- _.compact([
173
- ...(usageRouteInfo.produces || []),
174
- ...(originalRouteInfo.produces || []),
175
- ]),
176
- );
177
- }
178
-
179
- _.each(originalRouteParams, (originalRouteParam) => {
180
- const existUsageParam = _.find(
181
- usageRouteParams,
182
- (param) =>
183
- originalRouteParam.in === param.in &&
184
- originalRouteParam.name === param.name,
185
- );
186
- if (!existUsageParam) {
187
- usageRouteParams.push(originalRouteParam);
188
- }
189
- });
190
- });
191
- });
192
- }
193
- }
194
-
195
- export { SwaggerSchemaResolver };
@@ -1,243 +0,0 @@
1
- import { resolve } from "node:path";
2
- import path from "node:path";
3
- import url from "node:url";
4
- import * as Eta from "eta";
5
- import _ from "lodash";
6
-
7
- class TemplatesWorker {
8
- /**
9
- * @type {CodeGenConfig}
10
- */
11
- config;
12
-
13
- /**
14
- * @type {Logger}
15
- */
16
- logger;
17
-
18
- /**
19
- * @type {FileSystem}
20
- */
21
- fileSystem;
22
-
23
- getRenderTemplateData;
24
-
25
- constructor({ config, logger, fileSystem, getRenderTemplateData }) {
26
- this.config = config;
27
- this.logger = logger;
28
- this.fileSystem = fileSystem;
29
- this.getRenderTemplateData = getRenderTemplateData;
30
- }
31
-
32
- /**
33
- *
34
- * @param config {CodeGenConfig}
35
- * @returns {CodeGenConfig.templatePaths}
36
- */
37
- getTemplatePaths = (config) => {
38
- const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
39
- const baseTemplatesPath = resolve(__dirname, "../templates/base");
40
- const defaultTemplatesPath = resolve(__dirname, "../templates/default");
41
- const modularTemplatesPath = resolve(__dirname, "../templates/modular");
42
- const originalTemplatesPath = config.modular
43
- ? modularTemplatesPath
44
- : defaultTemplatesPath;
45
- const customTemplatesPath =
46
- (config.templates && resolve(process.cwd(), config.templates)) || null;
47
-
48
- return {
49
- /** `templates/base` */
50
- base: baseTemplatesPath,
51
- /** `templates/default` */
52
- default: defaultTemplatesPath,
53
- /** `templates/modular` */
54
- modular: modularTemplatesPath,
55
- /** usage path if `--templates` option is not set */
56
- original: originalTemplatesPath,
57
- /** custom path to templates (`--templates`) */
58
- custom: customTemplatesPath,
59
- };
60
- };
61
-
62
- cropExtension = (path) =>
63
- this.config.templateExtensions.reduce(
64
- (path, ext) => (_.endsWith(path, ext) ? path.replace(ext, "") : path),
65
- path,
66
- );
67
-
68
- getTemplateFullPath = (path, fileName) => {
69
- const raw = resolve(path, "./", this.cropExtension(fileName));
70
- const pathVariants = this.config.templateExtensions.map(
71
- (extension) => `${raw}${extension}`,
72
- );
73
-
74
- return pathVariants.find(
75
- (variant) => !!this.fileSystem.pathIsExist(variant),
76
- );
77
- };
78
-
79
- requireFnFromTemplate = (packageOrPath) => {
80
- const isPath =
81
- _.startsWith(packageOrPath, "./") || _.startsWith(packageOrPath, "../");
82
-
83
- if (isPath) {
84
- return require(
85
- path.resolve(
86
- this.config.templatePaths.custom ||
87
- this.config.templatePaths.original,
88
- packageOrPath,
89
- ),
90
- );
91
- }
92
-
93
- return require(packageOrPath);
94
- };
95
-
96
- getTemplate = ({ fileName, name, path }) => {
97
- const { templatePaths } = this.config;
98
-
99
- if (path) {
100
- return this.fileSystem.getFileContent(path);
101
- }
102
-
103
- if (!fileName) return "";
104
-
105
- const customFullPath =
106
- templatePaths.custom &&
107
- this.getTemplateFullPath(templatePaths.custom, fileName);
108
- let fileContent =
109
- customFullPath && this.fileSystem.getFileContent(customFullPath);
110
-
111
- if (fileContent) {
112
- this.logger.log(
113
- `"${_.lowerCase(name)}" template found in "${templatePaths.custom}"`,
114
- );
115
- return fileContent;
116
- }
117
-
118
- const baseFullPath = this.getTemplateFullPath(templatePaths.base, fileName);
119
-
120
- if (baseFullPath) {
121
- fileContent = this.fileSystem.getFileContent(baseFullPath);
122
- } else {
123
- if (templatePaths.custom) {
124
- this.logger.warn(
125
- `"${_.lowerCase(name)}" template not found in "${
126
- templatePaths.custom
127
- }"`,
128
- "\nCode generator will use the default template",
129
- );
130
- } else {
131
- this.logger.log(
132
- `Code generator will use the default template for "${_.lowerCase(
133
- name,
134
- )}"`,
135
- );
136
- }
137
- }
138
-
139
- const originalFullPath = this.getTemplateFullPath(
140
- templatePaths.original,
141
- fileName,
142
- );
143
-
144
- if (originalFullPath) {
145
- fileContent = this.fileSystem.getFileContent(originalFullPath);
146
- }
147
-
148
- return fileContent;
149
- };
150
-
151
- getTemplates = ({ templatePaths }) => {
152
- if (templatePaths.custom) {
153
- this.logger.log(
154
- `try to read templates from directory "${templatePaths.custom}"`,
155
- );
156
- }
157
-
158
- return _.reduce(
159
- this.config.templateInfos,
160
- (acc, { fileName, name }) => ({
161
- ...acc,
162
- [name]: this.getTemplate({ fileName, name }),
163
- }),
164
- {},
165
- );
166
- };
167
-
168
- findTemplateWithExt = (path) => {
169
- const raw = this.cropExtension(path);
170
- const pathVariants = this.config.templateExtensions.map(
171
- (extension) => `${raw}${extension}`,
172
- );
173
- return pathVariants.find((variant) => this.fileSystem.pathIsExist(variant));
174
- };
175
-
176
- getTemplateContent = (path) => {
177
- const foundTemplatePathKey = _.keys(this.config.templatePaths).find((key) =>
178
- _.startsWith(path, `@${key}`),
179
- );
180
-
181
- const rawPath = resolve(
182
- _.replace(
183
- path,
184
- `@${foundTemplatePathKey}`,
185
- this.config.templatePaths[foundTemplatePathKey],
186
- ),
187
- );
188
- const fixedPath = this.findTemplateWithExt(rawPath);
189
-
190
- if (fixedPath) {
191
- return this.fileSystem.getFileContent(fixedPath);
192
- }
193
-
194
- const customPath =
195
- this.config.templatePaths.custom &&
196
- this.findTemplateWithExt(resolve(this.config.templatePaths.custom, path));
197
-
198
- if (customPath) {
199
- return this.fileSystem.getFileContent(customPath);
200
- }
201
-
202
- const originalPath = this.findTemplateWithExt(
203
- resolve(this.config.templatePaths.original, path),
204
- );
205
-
206
- if (originalPath) {
207
- return this.fileSystem.getFileContent(originalPath);
208
- }
209
-
210
- return "";
211
- };
212
-
213
- /**
214
- * @param template
215
- * @param configuration
216
- * @param options
217
- * @returns {Promise<string|string|void>}
218
- */
219
- renderTemplate = (template, configuration, options) => {
220
- if (!template) return "";
221
-
222
- return Eta.render(
223
- template,
224
- {
225
- ...this.getRenderTemplateData(),
226
- ...configuration,
227
- },
228
- {
229
- async: false,
230
- ...(options || {}),
231
- includeFile: (path, configuration, options) => {
232
- return this.renderTemplate(
233
- this.getTemplateContent(path),
234
- configuration,
235
- options,
236
- );
237
- },
238
- },
239
- );
240
- };
241
- }
242
-
243
- export { TemplatesWorker };
@@ -1,81 +0,0 @@
1
- import ts from "typescript";
2
- import { Translator } from "./translator.js";
3
-
4
- class JavascriptTranslator extends Translator {
5
- /**
6
- * @param {TranslatorIO} input
7
- * @returns {Record<string, string>}
8
- */
9
- compileTSCode = (input) => {
10
- const fileNameFull = `${input.fileName}${input.fileExtension}`;
11
- const output = {};
12
- const host = ts.createCompilerHost(this.config.compilerTsConfig, true);
13
- const fileNames = [fileNameFull];
14
- const originalSourceFileGet = host.getSourceFile.bind(host);
15
- host.getSourceFile = (
16
- sourceFileName,
17
- languageVersion,
18
- onError,
19
- shouldCreateNewSourceFile,
20
- ) => {
21
- if (sourceFileName !== fileNameFull)
22
- return originalSourceFileGet(
23
- sourceFileName,
24
- languageVersion,
25
- onError,
26
- shouldCreateNewSourceFile,
27
- );
28
-
29
- return ts.createSourceFile(
30
- sourceFileName,
31
- input.fileContent,
32
- languageVersion,
33
- true,
34
- ts.ScriptKind.TS,
35
- );
36
- };
37
-
38
- host.writeFile = (fileName, contents) => {
39
- output[fileName] = contents;
40
- };
41
-
42
- ts.createProgram(fileNames, this.config.compilerTsConfig, host).emit();
43
-
44
- return output;
45
- };
46
-
47
- translate = async (input) => {
48
- const compiled = this.compileTSCode(input);
49
-
50
- const jsFileName = `${input.fileName}${ts.Extension.Js}`;
51
- const dtsFileName = `${input.fileName}${ts.Extension.Dts}`;
52
- const sourceContent = compiled[jsFileName];
53
- const tsImportRows = input.fileContent
54
- .split("\n")
55
- .filter((line) => line.startsWith("import "));
56
- const declarationContent = compiled[dtsFileName]
57
- .split("\n")
58
- .map((line) => {
59
- if (line.startsWith("import ")) {
60
- return tsImportRows.shift();
61
- }
62
- return line;
63
- })
64
- .join("\n");
65
-
66
- return [
67
- {
68
- fileName: input.fileName,
69
- fileExtension: ts.Extension.Js,
70
- fileContent: await this.codeFormatter.formatCode(sourceContent),
71
- },
72
- {
73
- fileName: input.fileName,
74
- fileExtension: ts.Extension.Dts,
75
- fileContent: await this.codeFormatter.formatCode(declarationContent),
76
- },
77
- ];
78
- };
79
- }
80
-
81
- export { JavascriptTranslator };
@@ -1,33 +0,0 @@
1
- /**
2
- * @typedef {{ fileName: string, fileExtension: string, fileContent: string }} TranslatorIO
3
- */
4
-
5
- class Translator {
6
- /** @type {Logger} */
7
- logger;
8
- /** @type {CodeGenConfig} */
9
- config;
10
- /** @type {CodeFormatter} */
11
- codeFormatter;
12
-
13
- /**
14
- * @param codeGenProcess
15
- */
16
- constructor(codeGenProcess) {
17
- this.logger = codeGenProcess.logger;
18
- this.config = codeGenProcess.config;
19
- this.codeFormatter = codeGenProcess.codeFormatter;
20
- }
21
-
22
- /**
23
- *
24
- * @param input {TranslatorIO}
25
- * @return {Promise<TranslatorIO[]>}
26
- */
27
- // eslint-disable-next-line no-unused-vars
28
- translate(input) {
29
- throw new Error("not implemented");
30
- }
31
- }
32
-
33
- export { Translator };