swagger-typescript-api 10.0.2 → 11.0.0--alpha

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 (55) hide show
  1. package/README.md +263 -41
  2. package/index.d.ts +97 -0
  3. package/index.js +242 -115
  4. package/package.json +121 -116
  5. package/src/code-formatter.js +101 -0
  6. package/src/code-gen-process.js +456 -0
  7. package/src/configuration.js +425 -0
  8. package/src/constants.js +14 -31
  9. package/src/index.js +20 -271
  10. package/src/schema-components-map.js +60 -0
  11. package/src/schema-parser/schema-formatters.js +145 -0
  12. package/src/schema-parser/schema-parser.js +497 -0
  13. package/src/schema-parser/schema-routes.js +902 -0
  14. package/src/swagger-schema-resolver.js +187 -0
  15. package/src/templates.js +174 -155
  16. package/src/translators/JavaScript.js +3 -14
  17. package/src/type-name.js +79 -0
  18. package/src/util/file-system.js +76 -0
  19. package/src/{utils → util}/id.js +9 -9
  20. package/src/util/internal-case.js +5 -0
  21. package/src/util/logger.js +100 -0
  22. package/src/{utils/resolveName.js → util/name-resolver.js} +94 -97
  23. package/src/util/object-assign.js +11 -0
  24. package/src/util/pascal-case.js +5 -0
  25. package/src/{utils → util}/random.js +14 -14
  26. package/templates/base/data-contract-jsdoc.ejs +29 -24
  27. package/templates/base/data-contracts.ejs +3 -3
  28. package/templates/base/interface-data-contract.ejs +1 -0
  29. package/templates/base/route-docs.ejs +3 -4
  30. package/templates/base/route-type.ejs +2 -2
  31. package/templates/default/procedure-call.ejs +2 -2
  32. package/templates/default/route-types.ejs +2 -2
  33. package/templates/modular/api.ejs +2 -2
  34. package/templates/modular/procedure-call.ejs +2 -2
  35. package/templates/modular/route-types.ejs +2 -2
  36. package/src/apiConfig.js +0 -30
  37. package/src/common.js +0 -28
  38. package/src/components.js +0 -91
  39. package/src/config.js +0 -106
  40. package/src/filePrefix.js +0 -14
  41. package/src/files.js +0 -56
  42. package/src/formatFileContent.js +0 -81
  43. package/src/logger.js +0 -59
  44. package/src/modelNames.js +0 -78
  45. package/src/modelTypes.js +0 -31
  46. package/src/output.js +0 -165
  47. package/src/prettierOptions.js +0 -23
  48. package/src/render/utils/fmtToJSDocLine.js +0 -10
  49. package/src/render/utils/index.js +0 -31
  50. package/src/render/utils/templateRequire.js +0 -17
  51. package/src/routeNames.js +0 -46
  52. package/src/routes.js +0 -809
  53. package/src/schema.js +0 -474
  54. package/src/swagger.js +0 -152
  55. package/src/typeFormatters.js +0 -121
@@ -0,0 +1,187 @@
1
+ const { Configuration } = require("./configuration.js");
2
+ const _ = require("lodash");
3
+ const converter = require("swagger2openapi");
4
+ const https = require("https");
5
+ const axios = require("axios");
6
+ const yaml = require("js-yaml");
7
+
8
+ class SwaggerSchemaResolver {
9
+ /**
10
+ * @type {Configuration}
11
+ */
12
+ config;
13
+ /**
14
+ * @type {Logger}
15
+ */
16
+ logger;
17
+ /**
18
+ * @type {FileSystem}
19
+ */
20
+ fileSystem;
21
+
22
+ constructor(configuration, logger, fileSystem) {
23
+ this.config = configuration;
24
+ this.logger = logger;
25
+ this.fileSystem = fileSystem;
26
+ }
27
+
28
+ /**
29
+ *
30
+ * @returns {Promise<{usageSchema: Record<string, *>, originalSchema: Record<string, *>}>}
31
+ */
32
+ async create() {
33
+ const { spec, patch, input, url, disableStrictSSL, disableProxy, authorizationToken } = this.config;
34
+
35
+ if (this.config.spec) {
36
+ return await this.convertSwaggerObject(spec, { patch });
37
+ }
38
+
39
+ const swaggerSchemaFile = await this.fetchSwaggerSchemaFile(
40
+ input,
41
+ url,
42
+ disableStrictSSL,
43
+ disableProxy,
44
+ authorizationToken,
45
+ );
46
+ const swaggerSchemaObject = this.processSwaggerSchemaFile(swaggerSchemaFile);
47
+ return await this.convertSwaggerObject(swaggerSchemaObject, { patch });
48
+ }
49
+
50
+ /**
51
+ *
52
+ * @param swaggerSchema {Record<string, any>}
53
+ * @param converterOptions {{ patch?: boolean }}
54
+ * @returns {Promise<{ usageSchema: Record<string, any>, originalSchema: Record<string, any>}>}
55
+ */
56
+ convertSwaggerObject(swaggerSchema, converterOptions) {
57
+ return new Promise((resolve) => {
58
+ const result = _.cloneDeep(swaggerSchema);
59
+ result.info = _.merge(
60
+ {
61
+ title: "No title",
62
+ version: "",
63
+ },
64
+ result.info,
65
+ );
66
+
67
+ if (!result.openapi) {
68
+ result.paths = _.merge({}, result.paths);
69
+
70
+ converter.convertObj(
71
+ result,
72
+ {
73
+ ...converterOptions,
74
+ warnOnly: true,
75
+ refSiblings: "preserve",
76
+ rbname: "requestBodyName",
77
+ },
78
+ (err, options) => {
79
+ const parsedSwaggerSchema = _.get(err, "options.openapi", _.get(options, "openapi"));
80
+ if (!parsedSwaggerSchema && err) {
81
+ throw new Error(err);
82
+ }
83
+ this.config.update({ convertedFromSwagger2: true });
84
+ resolve({
85
+ usageSchema: parsedSwaggerSchema,
86
+ originalSchema: result,
87
+ });
88
+ },
89
+ );
90
+ } else {
91
+ resolve({
92
+ usageSchema: result,
93
+ originalSchema: _.cloneDeep(result),
94
+ });
95
+ }
96
+ });
97
+ }
98
+
99
+ fetchSwaggerSchemaFile(pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy, authorizationToken) {
100
+ return new Promise((resolve, reject) => {
101
+ if (this.fileSystem.pathIsExist(pathToSwagger)) {
102
+ this.logger.log(`try to get swagger by path "${pathToSwagger}"`);
103
+ resolve(this.fileSystem.getFileContent(pathToSwagger));
104
+ } else {
105
+ this.logger.log(`try to get swagger by URL "${urlToSwagger}"`);
106
+ // setup options for Axios
107
+ const axiosOptions = {
108
+ maxContentLength: Infinity,
109
+ maxBodyLength: Infinity,
110
+ };
111
+ //
112
+ if (disableStrictSSL) {
113
+ axiosOptions.httpsAgent = new https.Agent({
114
+ rejectUnauthorized: false,
115
+ });
116
+ }
117
+ //
118
+ if (authorizationToken) {
119
+ axiosOptions.headers = {
120
+ Authorization: authorizationToken,
121
+ };
122
+ }
123
+ //
124
+ if (disableProxy) axiosOptions.proxy = false;
125
+ //
126
+ axios
127
+ .get(urlToSwagger, axiosOptions)
128
+ .then((res) => resolve(res.data))
129
+ .catch((error) => {
130
+ const message = `error while getting swagger by URL ${urlToSwagger}`;
131
+
132
+ this.logger.error(message, "response" in error ? error.response : error);
133
+
134
+ reject(message);
135
+ });
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
+ usageRouteInfo.consumes = _.uniq(
165
+ _.compact([...(usageRouteInfo.consumes || []), ...(originalRouteInfo.consumes || [])]),
166
+ );
167
+ usageRouteInfo.produces = _.uniq(
168
+ _.compact([...(usageRouteInfo.produces || []), ...(originalRouteInfo.produces || [])]),
169
+ );
170
+
171
+ _.each(originalRouteParams, (originalRouteParam) => {
172
+ const existUsageParam = _.find(
173
+ usageRouteParams,
174
+ (param) => originalRouteParam.in === param.in && originalRouteParam.name === param.name,
175
+ );
176
+ if (!existUsageParam) {
177
+ usageRouteParams.push(originalRouteParam);
178
+ }
179
+ });
180
+ });
181
+ });
182
+ }
183
+ }
184
+
185
+ module.exports = {
186
+ SwaggerSchemaResolver,
187
+ };
package/src/templates.js CHANGED
@@ -1,155 +1,174 @@
1
- const _ = require("lodash");
2
- const Eta = require("eta");
3
- const { getFileContent, pathIsExist } = require("./files");
4
- const { config } = require("./config");
5
- const { resolve } = require("path");
6
- const { logger } = require("./logger");
7
-
8
- const TEMPLATE_EXTENSIONS = [".eta", ".ejs"];
9
-
10
- /**
11
- * name - project template name,
12
- * fileName - template file name,
13
- */
14
- const TEMPLATE_INFOS = [
15
- { name: "api", fileName: "api" },
16
- { name: "dataContracts", fileName: "data-contracts" },
17
- { name: "dataContractJsDoc", fileName: "data-contract-jsdoc" },
18
- { name: "interfaceDataContract", fileName: "interface-data-contract" },
19
- { name: "typeDataContract", fileName: "type-data-contract" },
20
- { name: "enumDataContract", fileName: "enum-data-contract" },
21
- { name: "objectFieldJsDoc", fileName: "object-field-jsdoc" },
22
- { name: "httpClient", fileName: "http-client" },
23
- { name: "routeTypes", fileName: "route-types" },
24
- { name: "routeName", fileName: "route-name" },
25
- ];
26
-
27
- const getTemplatePaths = ({ templates, modular }) => {
28
- const baseTemplatesPath = resolve(__dirname, "../templates/base");
29
- const defaultTemplatesPath = resolve(__dirname, "../templates/default");
30
- const modularTemplatesPath = resolve(__dirname, "../templates/modular");
31
- const originalTemplatesPath = modular ? modularTemplatesPath : defaultTemplatesPath;
32
- const customTemplatesPath = templates ? resolve(process.cwd(), templates) : originalTemplatesPath;
33
-
34
- return {
35
- /** `templates/base` */
36
- base: baseTemplatesPath,
37
- /** `templates/default` */
38
- default: defaultTemplatesPath,
39
- /** `templates/modular` */
40
- modular: modularTemplatesPath,
41
- /** usage path if `--templates` option is not set */
42
- original: originalTemplatesPath,
43
- /** custom path to templates (`--templates`) */
44
- custom: customTemplatesPath,
45
- };
46
- };
47
-
48
- const cropExtension = (path) =>
49
- TEMPLATE_EXTENSIONS.reduce((path, ext) => (_.endsWith(path, ext) ? path.replace(ext, "") : path), path);
50
-
51
- const getTemplateFullPath = (path, fileName) => {
52
- const raw = resolve(path, "./", cropExtension(fileName));
53
- const pathVariants = TEMPLATE_EXTENSIONS.map((extension) => `${raw}${extension}`);
54
-
55
- return pathVariants.find((variant) => !!pathIsExist(variant));
56
- };
57
-
58
- const getTemplate = ({ fileName, name, path }) => {
59
- const { templatePaths } = config;
60
-
61
- if (path) {
62
- return getFileContent(path);
63
- }
64
-
65
- if (!fileName) return "";
66
-
67
- const customFullPath = getTemplateFullPath(templatePaths.custom, fileName);
68
- let fileContent = customFullPath && getFileContent(customFullPath);
69
-
70
- if (!fileContent) {
71
- const baseFullPath = getTemplateFullPath(templatePaths.base, fileName);
72
-
73
- if (baseFullPath) {
74
- fileContent = getFileContent(baseFullPath);
75
- } else {
76
- logger.warn(
77
- `${_.lowerCase(name)} template not found in ${customFullPath}`,
78
- `\nCode generator will use the default template`,
79
- );
80
- }
81
-
82
- const originalFullPath = getTemplateFullPath(templatePaths.original, fileName);
83
-
84
- if (originalFullPath) {
85
- fileContent = getFileContent(originalFullPath);
86
- }
87
- }
88
-
89
- return fileContent;
90
- };
91
-
92
- const getTemplates = ({ templatePaths }) => {
93
- logger.log(`try to read templates from directory "${templatePaths.custom}"`);
94
-
95
- const templatesMap = _.reduce(
96
- TEMPLATE_INFOS,
97
- (acc, { fileName, name }) => ({
98
- ...acc,
99
- [name]: getTemplate({ fileName, name }),
100
- }),
101
- {},
102
- );
103
-
104
- return templatesMap;
105
- };
106
-
107
- const getTemplateContent = (path) => {
108
- const foundTemplatePathKey = _.keys(config.templatePaths).find((key) => _.startsWith(path, `@${key}`));
109
-
110
- const findPathWithExt = (path) => {
111
- const raw = cropExtension(path);
112
- const pathVariants = TEMPLATE_EXTENSIONS.map((extension) => `${raw}${extension}`);
113
- return pathVariants.find((variant) => pathIsExist(variant));
114
- };
115
-
116
- const rawPath = resolve(_.replace(path, `@${foundTemplatePathKey}`, config.templatePaths[foundTemplatePathKey]));
117
- const fixedPath = findPathWithExt(rawPath);
118
-
119
- if (fixedPath) {
120
- return getFileContent(fixedPath);
121
- }
122
-
123
- const customPath = findPathWithExt(resolve(config.templatePaths.custom, path));
124
-
125
- if (customPath) {
126
- return getFileContent(customPath);
127
- }
128
-
129
- const originalPath = findPathWithExt(resolve(config.templatePaths.original, path));
130
-
131
- if (originalPath) {
132
- return getFileContent(originalPath);
133
- }
134
-
135
- return "";
136
- };
137
-
138
- const renderTemplate = (template, configuration, options) => {
139
- if (!template) return "";
140
-
141
- return Eta.render(template, configuration, {
142
- async: false,
143
- ...(options || {}),
144
- includeFile: (path, payload, options) => {
145
- return renderTemplate(getTemplateContent(path), payload, options);
146
- },
147
- });
148
- };
149
-
150
- module.exports = {
151
- getTemplate,
152
- getTemplates,
153
- getTemplatePaths,
154
- renderTemplate,
155
- };
1
+ const { resolve } = require("path");
2
+ const _ = require("lodash");
3
+ const Eta = require("eta");
4
+ const path = require("path");
5
+
6
+ class Templates {
7
+ /**
8
+ * @type {Configuration}
9
+ */
10
+ config;
11
+
12
+ /**
13
+ * @type {Logger}
14
+ */
15
+ logger;
16
+
17
+ /**
18
+ * @type {FileSystem}
19
+ */
20
+ fileSystem;
21
+
22
+ getRenderTemplateData;
23
+
24
+ constructor(config, logger, fileSystem, getRenderTemplateData) {
25
+ this.config = config;
26
+ this.logger = logger;
27
+ this.fileSystem = fileSystem;
28
+ this.getRenderTemplateData = getRenderTemplateData;
29
+ }
30
+
31
+ getTemplatePaths = ({ templates, modular }) => {
32
+ const baseTemplatesPath = resolve(__dirname, "../templates/base");
33
+ const defaultTemplatesPath = resolve(__dirname, "../templates/default");
34
+ const modularTemplatesPath = resolve(__dirname, "../templates/modular");
35
+ const originalTemplatesPath = modular ? modularTemplatesPath : defaultTemplatesPath;
36
+ const customTemplatesPath = templates ? resolve(process.cwd(), templates) : originalTemplatesPath;
37
+
38
+ return {
39
+ /** `templates/base` */
40
+ base: baseTemplatesPath,
41
+ /** `templates/default` */
42
+ default: defaultTemplatesPath,
43
+ /** `templates/modular` */
44
+ modular: modularTemplatesPath,
45
+ /** usage path if `--templates` option is not set */
46
+ original: originalTemplatesPath,
47
+ /** custom path to templates (`--templates`) */
48
+ custom: customTemplatesPath,
49
+ };
50
+ };
51
+
52
+ cropExtension = (path) =>
53
+ this.config.templateExtensions.reduce((path, ext) => (_.endsWith(path, ext) ? path.replace(ext, "") : path), path);
54
+
55
+ getTemplateFullPath = (path, fileName) => {
56
+ const raw = resolve(path, "./", this.cropExtension(fileName));
57
+ const pathVariants = this.config.templateExtensions.map((extension) => `${raw}${extension}`);
58
+
59
+ return pathVariants.find((variant) => !!this.fileSystem.pathIsExist(variant));
60
+ };
61
+
62
+ requireFnFromTemplate = (packageOrPath) => {
63
+ const isPath = _.startsWith(packageOrPath, "./") || _.startsWith(packageOrPath, "../");
64
+
65
+ if (isPath) {
66
+ return require(path.resolve(this.config.templates, packageOrPath));
67
+ }
68
+
69
+ return require(packageOrPath);
70
+ };
71
+
72
+ getTemplate = ({ fileName, name, path }) => {
73
+ const { templatePaths } = this.config;
74
+
75
+ if (path) {
76
+ return this.fileSystem.getFileContent(path);
77
+ }
78
+
79
+ if (!fileName) return "";
80
+
81
+ const customFullPath = this.getTemplateFullPath(templatePaths.custom, fileName);
82
+ let fileContent = customFullPath && this.fileSystem.getFileContent(customFullPath);
83
+
84
+ if (!fileContent) {
85
+ const baseFullPath = this.getTemplateFullPath(templatePaths.base, fileName);
86
+
87
+ if (baseFullPath) {
88
+ fileContent = this.fileSystem.getFileContent(baseFullPath);
89
+ } else {
90
+ this.logger.warn(
91
+ `${_.lowerCase(name)} template not found in ${customFullPath}`,
92
+ `\nCode generator will use the default template`,
93
+ );
94
+ }
95
+
96
+ const originalFullPath = this.getTemplateFullPath(templatePaths.original, fileName);
97
+
98
+ if (originalFullPath) {
99
+ fileContent = this.fileSystem.getFileContent(originalFullPath);
100
+ }
101
+ }
102
+
103
+ return fileContent;
104
+ };
105
+
106
+ getTemplates = ({ templatePaths }) => {
107
+ this.logger.log(`try to read templates from directory "${templatePaths.custom}"`);
108
+
109
+ return _.reduce(
110
+ this.config.templateInfos,
111
+ (acc, { fileName, name }) => ({
112
+ ...acc,
113
+ [name]: this.getTemplate({ fileName, name }),
114
+ }),
115
+ {},
116
+ );
117
+ };
118
+
119
+ getTemplateContent = (path) => {
120
+ const foundTemplatePathKey = _.keys(this.config.templatePaths).find((key) => _.startsWith(path, `@${key}`));
121
+
122
+ const findPathWithExt = (path) => {
123
+ const raw = this.cropExtension(path);
124
+ const pathVariants = this.config.templateExtensions.map((extension) => `${raw}${extension}`);
125
+ return pathVariants.find((variant) => this.fileSystem.pathIsExist(variant));
126
+ };
127
+
128
+ const rawPath = resolve(
129
+ _.replace(path, `@${foundTemplatePathKey}`, this.config.templatePaths[foundTemplatePathKey]),
130
+ );
131
+ const fixedPath = findPathWithExt(rawPath);
132
+
133
+ if (fixedPath) {
134
+ return this.fileSystem.getFileContent(fixedPath);
135
+ }
136
+
137
+ const customPath = findPathWithExt(resolve(this.config.templatePaths.custom, path));
138
+
139
+ if (customPath) {
140
+ return this.fileSystem.getFileContent(customPath);
141
+ }
142
+
143
+ const originalPath = findPathWithExt(resolve(this.config.templatePaths.original, path));
144
+
145
+ if (originalPath) {
146
+ return this.fileSystem.getFileContent(originalPath);
147
+ }
148
+
149
+ return "";
150
+ };
151
+
152
+ renderTemplate = (template, configuration, options) => {
153
+ if (!template) return "";
154
+
155
+ return Eta.render(
156
+ template,
157
+ {
158
+ ...this.getRenderTemplateData(),
159
+ ...configuration,
160
+ },
161
+ {
162
+ async: false,
163
+ ...(options || {}),
164
+ includeFile: (path, payload, options) => {
165
+ return this.renderTemplate(this.getTemplateContent(path), payload, options);
166
+ },
167
+ },
168
+ );
169
+ };
170
+ }
171
+
172
+ module.exports = {
173
+ Templates,
174
+ };
@@ -7,20 +7,9 @@ function translate(fileName, content, options) {
7
7
  const originalSourceFileGet = host.getSourceFile.bind(host);
8
8
  host.getSourceFile = (sourceFileName, languageVersion, onError, shouldCreateNewSourceFile) => {
9
9
  if (sourceFileName !== fileName)
10
- return originalSourceFileGet(
11
- sourceFileName,
12
- languageVersion,
13
- onError,
14
- shouldCreateNewSourceFile,
15
- );
16
-
17
- return ts.createSourceFile(
18
- sourceFileName,
19
- content,
20
- languageVersion,
21
- true,
22
- ts.ScriptKind.External,
23
- );
10
+ return originalSourceFileGet(sourceFileName, languageVersion, onError, shouldCreateNewSourceFile);
11
+
12
+ return ts.createSourceFile(sourceFileName, content, languageVersion, true, ts.ScriptKind.External);
24
13
  };
25
14
 
26
15
  host.writeFile = (fileName, contents) => {
@@ -0,0 +1,79 @@
1
+ const _ = require("lodash");
2
+
3
+ class TypeName {
4
+ /** @type {Map<string, string>} */
5
+ formattedModelNamesMap = new Map();
6
+
7
+ /** @type {Configuration} */
8
+ config;
9
+
10
+ /** @type {Logger} */
11
+ logger;
12
+
13
+ constructor(config, logger) {
14
+ this.config = config;
15
+ this.logger = logger;
16
+ }
17
+
18
+ /**
19
+ * @param name
20
+ * @param options {{ ignorePrefix?: boolean, ignoreSuffix?: boolean }}
21
+ * @return {string}
22
+ */
23
+ format = (name, options) => {
24
+ const typePrefix = options && options.ignorePrefix ? "" : this.config.typePrefix;
25
+ const typeSuffix = options && options.ignoreSuffix ? "" : this.config.typeSuffix;
26
+ const hashKey = `${typePrefix}_${name}_${typeSuffix}`;
27
+
28
+ if (typeof name !== "string") {
29
+ this.logger.warn("wrong name of the model name", name);
30
+ return name;
31
+ }
32
+
33
+ if (/^([A-Z_]{1,})$/g.test(name)) {
34
+ return _.compact([typePrefix, name, typeSuffix]).join("_");
35
+ }
36
+
37
+ if (this.formattedModelNamesMap.has(hashKey)) {
38
+ return this.formattedModelNamesMap.get(hashKey);
39
+ }
40
+
41
+ const fixedModelName = fixModelName(name);
42
+
43
+ const formattedModelName = _.replace(_.startCase(`${typePrefix}_${fixedModelName}_${typeSuffix}`), /\s/g, "");
44
+ const modelName = this.config.hooks.onFormatTypeName(formattedModelName, name) || formattedModelName;
45
+
46
+ this.formattedModelNamesMap.set(hashKey, modelName);
47
+
48
+ return modelName;
49
+ };
50
+
51
+ isValidName = isValidName;
52
+ }
53
+
54
+ const isValidName = (name) => /^([A-Za-z$_]{1,})$/g.test(name);
55
+
56
+ const fixModelName = (name) => {
57
+ if (!isValidName(name)) {
58
+ if (!/^[a-zA-Z_$]/g.test(name)) {
59
+ name = `Type ${name}`;
60
+ }
61
+
62
+ // specific replaces for TSOA 3.x
63
+ if (name.includes("."))
64
+ name = name
65
+ .replace(/Exclude_keyof[A-Za-z]{1,}/g, (match) => "ExcludeKeys")
66
+ .replace(/%22\~AND\~%22/g, "And")
67
+ .replace(/%22\~OR\~%22/g, "Or")
68
+ .replace(/(\.?%22)|\./g, "_")
69
+ .replace(/__+$/, "");
70
+
71
+ if (name.includes("-")) name = _.startCase(name).replace(/ /g, "");
72
+ }
73
+
74
+ return name;
75
+ };
76
+
77
+ module.exports = {
78
+ TypeName,
79
+ };