swagger-typescript-api 11.1.3 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,6 +28,10 @@ class SchemaRoutes {
28
28
  * @type {SchemaParser}
29
29
  */
30
30
  schemaParser;
31
+ /**
32
+ * @type {SchemaUtils}
33
+ */
34
+ schemaUtils;
31
35
  /**
32
36
  * @type {TypeName}
33
37
  */
@@ -55,14 +59,15 @@ class SchemaRoutes {
55
59
  constructor(config, schemaParser, schemaComponentMap, logger, templates, typeName) {
56
60
  this.config = config;
57
61
  this.schemaParser = schemaParser;
62
+ this.schemaUtils = this.schemaParser.schemaUtils;
58
63
  this.typeName = typeName;
59
64
  this.schemaComponentMap = schemaComponentMap;
60
65
  this.logger = logger;
61
66
  this.templates = templates;
62
67
 
63
68
  this.FORM_DATA_TYPES = _.uniq([
64
- this.schemaParser.getTypeAlias({ type: "string", format: "file" }),
65
- this.schemaParser.getTypeAlias({ type: "string", format: "binary" }),
69
+ this.schemaParser.getSchemaType({ type: "string", format: "file" }),
70
+ this.schemaParser.getSchemaType({ type: "string", format: "binary" }),
66
71
  ]);
67
72
  }
68
73
 
@@ -87,7 +92,9 @@ class SchemaRoutes {
87
92
  );
88
93
  };
89
94
 
90
- parseRouteName = (routeName) => {
95
+ parseRouteName = (originalRouteName) => {
96
+ const routeName = this.config.hooks.onPreBuildRoutePath(originalRouteName) || originalRouteName;
97
+
91
98
  const pathParamMatches = (routeName || "").match(
92
99
  /({(([a-zA-Z]-?_?\.?){1,})([0-9]{1,})?})|(:(([a-zA-Z]-?_?\.?){1,})([0-9]{1,})?:?)/g,
93
100
  );
@@ -123,8 +130,9 @@ class SchemaRoutes {
123
130
 
124
131
  let fixedRoute = _.reduce(
125
132
  pathParams,
126
- (fixedRoute, pathParam) => {
127
- return _.replace(fixedRoute, pathParam.$match, `\${${pathParam.name}}`);
133
+ (fixedRoute, pathParam, i, arr) => {
134
+ const insertion = this.config.hooks.onInsertPathParam(pathParam.name, i, arr, fixedRoute) || pathParam.name;
135
+ return _.replace(fixedRoute, pathParam.$match, `\${${insertion}}`);
128
136
  },
129
137
  routeName || "",
130
138
  );
@@ -161,12 +169,14 @@ class SchemaRoutes {
161
169
  });
162
170
  }
163
171
 
164
- return {
165
- originalRoute: routeName || "",
172
+ const result = {
173
+ originalRoute: originalRouteName || "",
166
174
  route: fixedRoute,
167
175
  pathParams,
168
176
  queryParams,
169
177
  };
178
+
179
+ return this.config.hooks.onBuildRoutePath(result) || result;
170
180
  };
171
181
 
172
182
  getRouteParams = (routeInfo, pathParamsFromRouteName, queryParamsFromRouteName) => {
@@ -182,7 +192,7 @@ class SchemaRoutes {
182
192
  };
183
193
 
184
194
  _.each(parameters, (parameter) => {
185
- const refTypeInfo = this.schemaParser.getRefType(parameter);
195
+ const refTypeInfo = this.schemaParser.schemaUtils.getSchemaRefType(parameter);
186
196
  let routeParam = null;
187
197
 
188
198
  if (refTypeInfo && refTypeInfo.rawTypeData.in && refTypeInfo.rawTypeData) {
@@ -266,9 +276,7 @@ class SchemaRoutes {
266
276
  return CONTENT_KIND.IMAGE;
267
277
  }
268
278
 
269
- if (
270
- _.some(contentTypes, (contentType) => _.startsWith(contentType, "text/"))
271
- ) {
279
+ if (_.some(contentTypes, (contentType) => _.startsWith(contentType, "text/"))) {
272
280
  return CONTENT_KIND.TEXT;
273
281
  }
274
282
 
@@ -303,7 +311,7 @@ class SchemaRoutes {
303
311
  getTypeFromRequestInfo = ({ requestInfo, parsedSchemas, operationId, defaultType, typeName }) => {
304
312
  // TODO: make more flexible pick schema without content type
305
313
  const schema = this.getSchemaFromRequestType(requestInfo);
306
- const refTypeInfo = this.schemaParser.getRefType(requestInfo);
314
+ const refTypeInfo = this.schemaParser.schemaUtils.getSchemaRefType(requestInfo);
307
315
 
308
316
  if (schema) {
309
317
  const content = this.schemaParser.getInlineParseContent(schema, typeName);
@@ -357,7 +365,7 @@ class SchemaRoutes {
357
365
  ...(requestInfo || {}),
358
366
  contentTypes: contentTypes,
359
367
  contentKind: this.getContentKind(contentTypes),
360
- type: this.schemaParser.checkAndAddNull(
368
+ type: this.schemaParser.schemaUtils.safeAddNullToType(
361
369
  requestInfo,
362
370
  this.getTypeFromRequestInfo({
363
371
  requestInfo,
@@ -398,7 +406,7 @@ class SchemaRoutes {
398
406
  }
399
407
  const headerTypes = Object.fromEntries(
400
408
  Object.entries(src).map(([k, v]) => {
401
- return [k, this.schemaParser.getType(v)];
409
+ return [k, this.schemaParser.getSchemaType(v)];
402
410
  }),
403
411
  );
404
412
  const r = `headers: { ${Object.entries(headerTypes)
@@ -467,11 +475,11 @@ class SchemaRoutes {
467
475
  let typeName = null;
468
476
 
469
477
  if (this.config.extractRequestBody) {
470
- typeName = this.config.componentTypeNameResolver.resolve([
471
- pascalCase(`${routeName.usage} Payload`),
472
- pascalCase(`${routeName.usage} Body`),
473
- pascalCase(`${routeName.usage} Input`),
474
- ]);
478
+ typeName = this.schemaUtils.resolveTypeName(
479
+ routeName.usage,
480
+ this.config.extractingOptions.requestBodySuffix,
481
+ this.config.extractingOptions.requestBodyNameResolver,
482
+ );
475
483
  }
476
484
 
477
485
  if (routeParams.formData.length) {
@@ -483,7 +491,7 @@ class SchemaRoutes {
483
491
  type = this.schemaParser.getInlineParseContent(schema, typeName);
484
492
  } else if (requestBody) {
485
493
  schema = this.getSchemaFromRequestType(requestBody);
486
- type = this.schemaParser.checkAndAddNull(
494
+ type = this.schemaParser.schemaUtils.safeAddNullToType(
487
495
  requestBody,
488
496
  this.getTypeFromRequestInfo({
489
497
  requestInfo: requestBody,
@@ -568,7 +576,11 @@ class SchemaRoutes {
568
576
  if (fixedSchema) return fixedSchema;
569
577
 
570
578
  if (extractRequestParams) {
571
- const typeName = this.config.componentTypeNameResolver.resolve([pascalCase(`${routeName.usage} Params`)]);
579
+ const typeName = this.schemaUtils.resolveTypeName(
580
+ routeName.usage,
581
+ this.config.extractingOptions.requestParamsSuffix,
582
+ this.config.extractingOptions.requestParamsNameResolver,
583
+ );
572
584
 
573
585
  return this.schemaComponentMap.createComponent("schemas", typeName, { ...schema });
574
586
  }
@@ -578,11 +590,11 @@ class SchemaRoutes {
578
590
 
579
591
  extractResponseBodyIfItNeeded = (routeInfo, responseBodyInfo, routeName) => {
580
592
  if (responseBodyInfo.responses.length && responseBodyInfo.success && responseBodyInfo.success.schema) {
581
- const typeName = this.config.componentTypeNameResolver.resolve([
582
- pascalCase(`${routeName.usage} Data`),
583
- pascalCase(`${routeName.usage} Result`),
584
- pascalCase(`${routeName.usage} Output`),
585
- ]);
593
+ const typeName = this.schemaUtils.resolveTypeName(
594
+ routeName.usage,
595
+ this.config.extractingOptions.responseBodySuffix,
596
+ this.config.extractingOptions.responseBodyNameResolver,
597
+ );
586
598
 
587
599
  const idx = responseBodyInfo.responses.indexOf(responseBodyInfo.success.schema);
588
600
 
@@ -605,14 +617,11 @@ class SchemaRoutes {
605
617
 
606
618
  extractResponseErrorIfItNeeded = (routeInfo, responseBodyInfo, routeName) => {
607
619
  if (responseBodyInfo.responses.length && responseBodyInfo.error.schemas && responseBodyInfo.error.schemas.length) {
608
- const typeName = this.config.componentTypeNameResolver.resolve([
609
- pascalCase(`${routeName.usage} Error`),
610
- pascalCase(`${routeName.usage} Fail`),
611
- pascalCase(`${routeName.usage} Fails`),
612
- pascalCase(`${routeName.usage} ErrorData`),
613
- pascalCase(`${routeName.usage} HttpError`),
614
- pascalCase(`${routeName.usage} BadResponse`),
615
- ]);
620
+ const typeName = this.schemaUtils.resolveTypeName(
621
+ routeName.usage,
622
+ this.config.extractingOptions.responseErrorSuffix,
623
+ this.config.extractingOptions.responseErrorNameResolver,
624
+ );
616
625
 
617
626
  const errorSchemas = responseBodyInfo.error.schemas.map(this.getSchemaFromRequestType).filter(Boolean);
618
627
 
@@ -762,13 +771,13 @@ class SchemaRoutes {
762
771
  const pathType = routeParams.path.length ? this.schemaParser.getInlineParseContent(pathObjectSchema) : null;
763
772
  const headersType = routeParams.header.length ? this.schemaParser.getInlineParseContent(headersObjectSchema) : null;
764
773
 
765
- const nameResolver = new SpecificArgNameResolver(pathArgsNames);
774
+ const nameResolver = new SpecificArgNameResolver(this.logger, pathArgsNames);
766
775
 
767
776
  const specificArgs = {
768
777
  query: queryType
769
778
  ? {
770
779
  name: nameResolver.resolve(RESERVED_QUERY_ARG_NAMES),
771
- optional: this.schemaParser.parseSchema(queryObjectSchema, null).allFieldsAreOptional,
780
+ optional: this.schemaParser.parseSchema(queryObjectSchema).allFieldsAreOptional,
772
781
  type: queryType,
773
782
  }
774
783
  : void 0,
@@ -782,14 +791,14 @@ class SchemaRoutes {
782
791
  pathParams: pathType
783
792
  ? {
784
793
  name: nameResolver.resolve(RESERVED_PATH_ARG_NAMES),
785
- optional: this.schemaParser.parseSchema(pathObjectSchema, null).allFieldsAreOptional,
794
+ optional: this.schemaParser.parseSchema(pathObjectSchema).allFieldsAreOptional,
786
795
  type: pathType,
787
796
  }
788
797
  : void 0,
789
798
  headers: headersType
790
799
  ? {
791
800
  name: nameResolver.resolve(RESERVED_HEADER_ARG_NAMES),
792
- optional: this.schemaParser.parseSchema(headersObjectSchema, null).allFieldsAreOptional,
801
+ optional: this.schemaParser.parseSchema(headersObjectSchema).allFieldsAreOptional,
793
802
  type: headersType,
794
803
  }
795
804
  : void 0,
@@ -0,0 +1,165 @@
1
+ const _ = require("lodash");
2
+ const { SCHEMA_TYPES } = require("../constants");
3
+ const { internalCase } = require("../util/internal-case");
4
+ const { pascalCase } = require("../util/pascal-case");
5
+
6
+ class SchemaUtils {
7
+ /**
8
+ * @type {CodeGenConfig}
9
+ */
10
+ config;
11
+ /**
12
+ * @type {SchemaComponentsMap}
13
+ */
14
+ schemaComponentsMap;
15
+
16
+ constructor(config, schemaComponentsMap) {
17
+ this.config = config;
18
+ this.schemaComponentsMap = schemaComponentsMap;
19
+ }
20
+
21
+ getRequiredProperties = (schema) => {
22
+ return _.uniq((schema && _.isArray(schema.required) && schema.required) || []);
23
+ };
24
+
25
+ isRefSchema = (schema) => {
26
+ return !!(schema && schema["$ref"]);
27
+ };
28
+
29
+ getEnumNames = (schema) => {
30
+ return schema["x-enumNames"] || schema["xEnumNames"] || schema["x-enumnames"] || schema["x-enum-varnames"];
31
+ };
32
+
33
+ getSchemaRefType = (schema) => {
34
+ if (!this.isRefSchema(schema)) return null;
35
+ return this.schemaComponentsMap.get(schema.$ref);
36
+ };
37
+
38
+ isPropertyRequired = (name, propertySchema, rootSchema) => {
39
+ if (propertySchema["x-omitempty"] === false) {
40
+ return true;
41
+ }
42
+
43
+ const isRequired = _.isBoolean(propertySchema.required)
44
+ ? !!propertySchema.required
45
+ : _.isArray(rootSchema.required)
46
+ ? rootSchema.required.includes(name)
47
+ : !!rootSchema.required;
48
+
49
+ if (this.config.convertedFromSwagger2) {
50
+ return typeof propertySchema.nullable === this.config.Ts.Keyword.Undefined
51
+ ? isRequired
52
+ : !propertySchema.nullable;
53
+ }
54
+ return isRequired;
55
+ };
56
+
57
+ isNullMissingInType = (schema, type) => {
58
+ const { nullable, type: schemaType } = schema || {};
59
+ return (
60
+ (nullable || !!_.get(schema, "x-nullable") || schemaType === this.config.Ts.Keyword.Null) &&
61
+ _.isString(type) &&
62
+ !type.includes(` ${this.config.Ts.Keyword.Null}`) &&
63
+ !type.includes(`${this.config.Ts.Keyword.Null} `)
64
+ );
65
+ };
66
+
67
+ safeAddNullToType = (schema, type) => {
68
+ if (this.isNullMissingInType(schema, type)) {
69
+ return this.config.Ts.UnionType([type, this.config.Ts.Keyword.Null]);
70
+ }
71
+ return type;
72
+ };
73
+
74
+ getSchemaPrimitiveType = (rawSchema) => {
75
+ const schema = rawSchema || {};
76
+
77
+ if (schema.type) {
78
+ return internalCase(schema.type);
79
+ }
80
+ if (schema.enum) {
81
+ const enumFieldType = typeof schema.enum[0];
82
+ if (enumFieldType === this.config.Ts.Keyword.Undefined) return;
83
+
84
+ return internalCase(enumFieldType);
85
+ }
86
+ if (_.keys(schema.properties).length) {
87
+ return SCHEMA_TYPES.OBJECT;
88
+ }
89
+ if (!!schema.items) {
90
+ return SCHEMA_TYPES.ARRAY;
91
+ }
92
+
93
+ return null;
94
+ };
95
+
96
+ checkAndAddRequiredKeys = (schema, resultType) => {
97
+ if ("$$requiredKeys" in schema && schema.$$requiredKeys.length) {
98
+ this.config.update({
99
+ internalTemplateOptions: {
100
+ addUtilRequiredKeysType: true,
101
+ },
102
+ });
103
+ return this.config.Ts.TypeWithGeneric(this.config.Ts.CodeGenKeyword.UtilRequiredKeys, [
104
+ resultType,
105
+ this.config.Ts.UnionType(schema.$$requiredKeys.map(this.config.Ts.StringValue)),
106
+ ]);
107
+ }
108
+
109
+ return resultType;
110
+ };
111
+
112
+ makeAddRequiredToChildSchema = (parentSchema, childSchema) => {
113
+ if (!childSchema) return childSchema;
114
+
115
+ const required = _.uniq([...this.getRequiredProperties(parentSchema), ...this.getRequiredProperties(childSchema)]);
116
+
117
+ const refData = this.getSchemaRefType(childSchema);
118
+
119
+ if (refData) {
120
+ const refObjectProperties = _.keys((refData.rawTypeData && refData.rawTypeData.properties) || {});
121
+ const existedRequiredKeys = refObjectProperties.filter((key) => required.includes(key));
122
+
123
+ if (!existedRequiredKeys.length) return childSchema;
124
+
125
+ return {
126
+ ...childSchema,
127
+ $$requiredKeys: existedRequiredKeys,
128
+ };
129
+ } else if (childSchema.properties) {
130
+ const childSchemaProperties = _.keys(childSchema.properties);
131
+ const existedRequiredKeys = childSchemaProperties.filter((key) => required.includes(key));
132
+
133
+ if (!existedRequiredKeys.length) return childSchema;
134
+
135
+ return {
136
+ required: _.uniq([...this.getRequiredProperties(childSchema), ...existedRequiredKeys]),
137
+ ...childSchema,
138
+ };
139
+ }
140
+
141
+ return childSchema;
142
+ };
143
+
144
+ filterSchemaContents = (contents, filterFn) => {
145
+ return _.uniq(_.filter(contents, (type) => filterFn(type)));
146
+ };
147
+
148
+ resolveTypeName = (typeName, suffixes, resolver) => {
149
+ if (resolver) {
150
+ return this.config.componentTypeNameResolver.resolve((reserved) => {
151
+ const variant = resolver(pascalCase(typeName), reserved);
152
+ if (variant == null) return variant;
153
+ return pascalCase(variant);
154
+ });
155
+ } else {
156
+ return this.config.componentTypeNameResolver.resolve(
157
+ suffixes.map((suffix) => pascalCase(`${typeName} ${suffix}`)),
158
+ );
159
+ }
160
+ };
161
+ }
162
+
163
+ module.exports = {
164
+ SchemaUtils,
165
+ };
package/src/templates.js CHANGED
@@ -164,8 +164,8 @@ class Templates {
164
164
  {
165
165
  async: false,
166
166
  ...(options || {}),
167
- includeFile: (path, payload, options) => {
168
- return this.renderTemplate(this.getTemplateContent(path), payload, options);
167
+ includeFile: (path, configuration, options) => {
168
+ return this.renderTemplate(this.getTemplateContent(path), configuration, options);
169
169
  },
170
170
  },
171
171
  );
package/src/type-name.js CHANGED
@@ -1,5 +1,9 @@
1
1
  const _ = require("lodash");
2
2
 
3
+ /**
4
+ * @typedef {"enum-key" | "type-name"} FormattingSchemaType
5
+ */
6
+
3
7
  class TypeName {
4
8
  /** @type {Map<string, string>} */
5
9
  formattedModelNamesMap = new Map();
@@ -17,12 +21,20 @@ class TypeName {
17
21
 
18
22
  /**
19
23
  * @param name
20
- * @param options {{ ignorePrefix?: boolean, ignoreSuffix?: boolean }}
24
+ * @param options {{ type?: FormattingSchemaType }}
21
25
  * @return {string}
22
26
  */
23
27
  format = (name, options) => {
24
- const typePrefix = options && options.ignorePrefix ? "" : this.config.typePrefix;
25
- const typeSuffix = options && options.ignoreSuffix ? "" : this.config.typeSuffix;
28
+ options = options || {};
29
+
30
+ /**
31
+ * @type {FormattingSchemaType}
32
+ */
33
+ const schemaType = options.type || "type-name";
34
+
35
+ const typePrefix = schemaType === "enum-key" ? this.config.enumKeyPrefix : this.config.typePrefix;
36
+ const typeSuffix = schemaType === "enum-key" ? this.config.enumKeySuffix : this.config.typeSuffix;
37
+
26
38
  const hashKey = `${typePrefix}_${name}_${typeSuffix}`;
27
39
 
28
40
  if (typeof name !== "string") {
@@ -38,41 +50,48 @@ class TypeName {
38
50
  return this.formattedModelNamesMap.get(hashKey);
39
51
  }
40
52
 
41
- const fixedModelName = fixModelName(name);
53
+ const fixedModelName = this.fixModelName(name, { type: schemaType });
42
54
 
43
- const formattedModelName = _.replace(_.startCase(`${typePrefix}_${fixedModelName}_${typeSuffix}`), /\s/g, "");
44
- const modelName = this.config.hooks.onFormatTypeName(formattedModelName, name) || formattedModelName;
55
+ const formattedName = _.replace(_.startCase(`${typePrefix}_${fixedModelName}_${typeSuffix}`), /\s/g, "");
56
+ const formattedResultName = this.config.hooks.onFormatTypeName(formattedName, name, schemaType) || formattedName;
45
57
 
46
- this.formattedModelNamesMap.set(hashKey, modelName);
58
+ this.formattedModelNamesMap.set(hashKey, formattedResultName);
47
59
 
48
- return modelName;
60
+ return formattedResultName;
49
61
  };
50
62
 
51
- isValidName = isValidName;
52
- }
53
-
54
- const isValidName = (name) => /^([A-Za-z$_]{1,})$/g.test(name);
63
+ isValidName = (name) => /^([A-Za-z$_]{1,})$/g.test(name);
55
64
 
56
- const fixModelName = (name) => {
57
- if (!isValidName(name)) {
58
- if (!/^[a-zA-Z_$]/g.test(name)) {
59
- name = `Type ${name}`;
65
+ /**
66
+ * @param name
67
+ * @param options {{ type?: FormattingSchemaType }}
68
+ * @return {string}
69
+ */
70
+ fixModelName = (name, options) => {
71
+ if (!this.isValidName(name)) {
72
+ if (!/^[a-zA-Z_$]/g.test(name)) {
73
+ const fixPrefix =
74
+ options && options.type === "enum-key"
75
+ ? this.config.fixInvalidEnumKeyPrefix
76
+ : this.config.fixInvalidTypeNamePrefix;
77
+ name = `${fixPrefix} ${name}`;
78
+ }
79
+
80
+ // specific replaces for TSOA 3.x
81
+ if (name.includes("."))
82
+ name = name
83
+ .replace(/Exclude_keyof[A-Za-z]{1,}/g, (match) => "ExcludeKeys")
84
+ .replace(/%22\~AND\~%22/g, "And")
85
+ .replace(/%22\~OR\~%22/g, "Or")
86
+ .replace(/(\.?%22)|\./g, "_")
87
+ .replace(/__+$/, "");
88
+
89
+ if (name.includes("-")) name = _.startCase(name).replace(/ /g, "");
60
90
  }
61
91
 
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
- };
92
+ return name;
93
+ };
94
+ }
76
95
 
77
96
  module.exports = {
78
97
  TypeName,
@@ -12,7 +12,7 @@ class Logger {
12
12
  this.config = config;
13
13
  }
14
14
 
15
- createLogMessage = ({ type, emojiName, messages }) => {
15
+ createLogMessage = ({ type, emojiName, messages, raw }) => {
16
16
  if (this.config.silent) return;
17
17
 
18
18
  const emoji = emojify(emojiName);
@@ -26,6 +26,11 @@ class Logger {
26
26
  );
27
27
  }
28
28
 
29
+ if (raw) {
30
+ console.log(...raw);
31
+ return;
32
+ }
33
+
29
34
  console[type](
30
35
  emoji,
31
36
  " ",
@@ -93,6 +98,19 @@ class Logger {
93
98
  emojiName: ":exclamation:",
94
99
  messages,
95
100
  });
101
+
102
+ /**
103
+ *
104
+ * @param messages {any[]}
105
+ * @return {void}
106
+ */
107
+ debug = (...messages) => {
108
+ if (!this.config.debug) return;
109
+
110
+ this.createLogMessage({
111
+ raw: messages,
112
+ });
113
+ };
96
114
  }
97
115
 
98
116
  module.exports = {
@@ -3,19 +3,24 @@ const { getRandomInt } = require("./random.js");
3
3
 
4
4
  class NameResolver {
5
5
  reservedNames = [];
6
- getDefaultName = null;
6
+ getFallbackName = null;
7
7
 
8
8
  /**
9
- *
9
+ * @type {Logger}
10
+ */
11
+ logger;
12
+
13
+ /**
14
+ * @param {Logger} logger;
10
15
  * @param {string[]} reservedNames
11
16
  */
12
- constructor(reservedNames, getDefaultName) {
13
- this.getDefaultName = getDefaultName;
17
+ constructor(logger, reservedNames, getFallbackName) {
18
+ this.logger = logger;
19
+ this.getFallbackName = getFallbackName;
14
20
  this.reserve(reservedNames);
15
21
  }
16
22
 
17
23
  /**
18
- *
19
24
  * @param {string[]} names
20
25
  */
21
26
  reserve(names) {
@@ -32,44 +37,59 @@ class NameResolver {
32
37
 
33
38
  /**
34
39
  *
35
- * @param {string[]} variants
36
- * @param {((variant: string) => string) | undefined} onSelectMutation
40
+ * @param {(string[]) | ((reserved: string[]) => string)} variantsOrResolver
37
41
  * @returns {string | null}
38
42
  */
39
- resolve(variants, onSelectMutation) {
40
- let usageName = null;
41
- const uniqVariants = _.uniq(_.compact(variants));
42
-
43
- _.forEach(uniqVariants, (variant) => {
44
- const mutatedVariant = onSelectMutation ? onSelectMutation(variant) : variant;
45
- if (!usageName && !this.isReserved(mutatedVariant)) {
46
- usageName = mutatedVariant;
43
+ resolve(variantsOrResolver) {
44
+ this.logger.debug("resolving name with using", variantsOrResolver);
45
+ if (Array.isArray(variantsOrResolver)) {
46
+ const variants = variantsOrResolver;
47
+ let usageName = null;
48
+ const uniqVariants = _.uniq(_.compact(variants));
49
+
50
+ _.forEach(uniqVariants, (variant) => {
51
+ if (!usageName && !this.isReserved(variant)) {
52
+ usageName = variant;
53
+ }
54
+ });
55
+
56
+ if (usageName) {
57
+ this.reserve([usageName]);
58
+ return usageName;
47
59
  }
48
- });
49
60
 
50
- if (usageName) {
51
- this.reserve([usageName]);
52
- return usageName;
53
- }
61
+ this.logger.debug("trying to resolve name with using fallback name generator");
62
+ return this.resolve(this.getFallbackName);
63
+ } else if (typeof variantsOrResolver === "function") {
64
+ let usageName = null;
65
+ while (usageName === null) {
66
+ const variant = variantsOrResolver(this.reservedNames);
54
67
 
55
- const defaultName = this.getDefaultName && this.getDefaultName(variants);
68
+ if (variant === undefined) {
69
+ this.logger.warn("unable to resolve name. current reserved names: ", this.reservedNames);
70
+ return null;
71
+ }
72
+ if (!this.isReserved(variant)) {
73
+ usageName = variant;
74
+ }
75
+ }
56
76
 
57
- if (defaultName) {
58
- this.reserve([onSelectMutation ? onSelectMutation(defaultName) : defaultName]);
59
- return defaultName;
77
+ this.reserve([usageName]);
78
+ return usageName;
60
79
  }
61
80
 
81
+ this.logger.debug("problem with reserving names. current reserved names: ", this.reservedNames);
62
82
  return null;
63
83
  }
64
84
  }
65
85
 
66
86
  class SpecificArgNameResolver extends NameResolver {
67
87
  /**
68
- *
88
+ * @param {Logger} logger;
69
89
  * @param {string[]} reservedNames
70
90
  */
71
- constructor(reservedNames) {
72
- super(reservedNames, (variants) => {
91
+ constructor(logger, reservedNames) {
92
+ super(logger, reservedNames, (variants) => {
73
93
  return (variants[0] && `${variants[0]}${getRandomInt(1, 10)}`) || `arg${getRandomInt(1, 10)}`;
74
94
  });
75
95
  }
@@ -77,18 +97,17 @@ class SpecificArgNameResolver extends NameResolver {
77
97
 
78
98
  class ComponentTypeNameResolver extends NameResolver {
79
99
  /**
80
- *
100
+ * @param {Logger} logger;
81
101
  * @param {string[]} reservedNames
82
102
  */
83
- constructor(reservedNames) {
84
- super(reservedNames, (variants) => {
103
+ constructor(logger, reservedNames) {
104
+ super(logger, reservedNames, (variants) => {
85
105
  return (variants[0] && `${variants[0]}${getRandomInt(1, 10)}`) || `ComponentType${getRandomInt(1, 10)}`;
86
106
  });
87
107
  }
88
108
  }
89
109
 
90
110
  module.exports = {
91
- NameResolver,
92
111
  SpecificArgNameResolver,
93
112
  ComponentTypeNameResolver,
94
113
  };