@vkontakte/api-schema-typescript-generator 0.13.2 → 0.14.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.
package/.eslintrc.json CHANGED
@@ -24,6 +24,9 @@
24
24
  "@typescript-eslint/no-magic-numbers": "off",
25
25
  "@typescript-eslint/no-extra-parens": "off",
26
26
 
27
+ "@typescript-eslint/quotes": "off",
28
+ "@typescript-eslint/indent": "off",
29
+
27
30
  "no-shadow": "off"
28
31
  },
29
32
  "overrides": [
package/.prettierrc.js ADDED
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ printWidth: 100,
3
+ bracketSpacing: true,
4
+ bracketSameLine: false,
5
+ singleQuote: true,
6
+ trailingComma: 'all',
7
+ arrowParens: 'always',
8
+ semi: true,
9
+ quoteProps: 'consistent',
10
+ };
@@ -26,13 +26,14 @@ class APITypingsGenerator {
26
26
  this.methodsList = options.methodsDefinitions.methods || [];
27
27
  this.objects = this.convertJSONSchemaDictionary(options.objects);
28
28
  this.responses = this.convertJSONSchemaDictionary(options.responses);
29
+ this.errors = options.errors;
29
30
  this.visitedRefs = {};
30
31
  this.generatedObjects = {};
31
32
  this.methodFilesMap = {};
32
33
  this.exports = {};
33
34
  this.ignoredResponses = {
34
35
  'storage.get': {
35
- 'keysResponse': true,
36
+ keysResponse: true,
36
37
  },
37
38
  };
38
39
  this.resultFiles = {};
@@ -44,6 +45,7 @@ class APITypingsGenerator {
44
45
  methodsList;
45
46
  objects;
46
47
  responses;
48
+ errors;
47
49
  visitedRefs;
48
50
  generatedObjects;
49
51
  methodFilesMap;
@@ -80,10 +82,7 @@ class APITypingsGenerator {
80
82
  ...methodFile.imports,
81
83
  ...imports,
82
84
  },
83
- codeBlocks: [
84
- ...methodFile.codeBlocks,
85
- ...codeBlocks,
86
- ],
85
+ codeBlocks: [...methodFile.codeBlocks, ...codeBlocks],
87
86
  };
88
87
  }
89
88
  collectAllOf(object, deep = 0) {
@@ -133,10 +132,7 @@ class APITypingsGenerator {
133
132
  additionalProperties = this.getObjectProperties(refObject, deep + 1);
134
133
  }
135
134
  if (additionalProperties.length) {
136
- properties = [
137
- ...properties,
138
- ...additionalProperties,
139
- ];
135
+ properties = [...properties, ...additionalProperties];
140
136
  }
141
137
  });
142
138
  }
@@ -192,10 +188,7 @@ class APITypingsGenerator {
192
188
  });
193
189
  });
194
190
  return {
195
- codeBlocks: [
196
- ...codeBlocks,
197
- codeBlock,
198
- ],
191
+ codeBlocks: [...codeBlocks, codeBlock],
199
192
  imports,
200
193
  value: '',
201
194
  };
@@ -298,7 +291,9 @@ class APITypingsGenerator {
298
291
  properties: [],
299
292
  });
300
293
  methodInfo.parameters.forEach((property) => {
301
- const { imports: newImports, value, codeBlocks: newCodeBlocks, } = typeString_1.generateTypeString(property, this.objects, { needEnumNamesConstant: false });
294
+ const { imports: newImports, value, codeBlocks: newCodeBlocks, } = typeString_1.generateTypeString(property, this.objects, {
295
+ needEnumNamesConstant: false,
296
+ });
302
297
  imports = { ...imports, ...newImports };
303
298
  codeBlocks = [...codeBlocks, ...newCodeBlocks];
304
299
  codeBlock.addProperty({
@@ -323,12 +318,10 @@ class APITypingsGenerator {
323
318
  let imports = {};
324
319
  if (object.enum) {
325
320
  const { codeBlocks: newCodeBlocks } = enums_1.generateEnumAsUnionType(object);
326
- codeBlocks = [
327
- ...newCodeBlocks,
328
- ];
321
+ codeBlocks = [...newCodeBlocks];
329
322
  }
330
323
  else {
331
- const { imports: newImports, value, codeBlocks: newCodeBlocks } = typeString_1.generateTypeString(object, this.objects);
324
+ const { imports: newImports, value, codeBlocks: newCodeBlocks, } = typeString_1.generateTypeString(object, this.objects);
332
325
  const codeBlock = new TypeCodeBlock_1.TypeCodeBlock({
333
326
  type: TypeCodeBlock_1.TypeScriptCodeTypes.Type,
334
327
  refName: object.name,
@@ -339,11 +332,7 @@ class APITypingsGenerator {
339
332
  value,
340
333
  });
341
334
  imports = newImports;
342
- codeBlocks = [
343
- ...codeBlocks,
344
- ...newCodeBlocks,
345
- codeBlock,
346
- ];
335
+ codeBlocks = [...codeBlocks, ...newCodeBlocks, codeBlock];
347
336
  }
348
337
  return {
349
338
  codeBlocks,
@@ -352,26 +341,20 @@ class APITypingsGenerator {
352
341
  };
353
342
  }
354
343
  getResponseCodeBlockAsType(object, response) {
355
- const { imports, value, codeBlocks, description, } = typeString_1.generateTypeString(response, this.objects, {
344
+ const { imports, value, codeBlocks, description } = typeString_1.generateTypeString(response, this.objects, {
356
345
  objectParentName: ' ', // TODO: Refactor
357
346
  });
358
347
  const codeBlock = new TypeCodeBlock_1.TypeCodeBlock({
359
348
  type: TypeCodeBlock_1.TypeScriptCodeTypes.Type,
360
349
  refName: object.name,
361
350
  interfaceName: helpers_1.getInterfaceName(object.name),
362
- description: [
363
- object.description,
364
- description || '',
365
- ].join(constants_1.newLineChar),
351
+ description: [object.description, description || ''].join(constants_1.newLineChar),
366
352
  needExport: true,
367
353
  properties: [],
368
354
  value,
369
355
  });
370
356
  return {
371
- codeBlocks: [
372
- ...codeBlocks,
373
- codeBlock,
374
- ],
357
+ codeBlocks: [...codeBlocks, codeBlock],
375
358
  imports,
376
359
  value: '',
377
360
  description,
@@ -441,13 +424,10 @@ class APITypingsGenerator {
441
424
  // Comment with method name for visual sections in file
442
425
  const methodNameComment = new CommentCodeBlock_1.CommentCodeBlock([methodName]);
443
426
  if (method.description) {
444
- methodNameComment.appendLines([
445
- '',
446
- method.description,
447
- ]);
427
+ methodNameComment.appendLines(['', method.description]);
448
428
  }
449
429
  this.appendToFileMap(section, {}, [methodNameComment]);
450
- const { method: normalizedMethod, parameterRefs, } = methods_1.normalizeMethodInfo(method);
430
+ const { method: normalizedMethod, parameterRefs } = methods_1.normalizeMethodInfo(method);
451
431
  method = normalizedMethod;
452
432
  this.generateObjectsFromRefs(parameterRefs);
453
433
  this.generateMethodParams(new SchemaObject_1.SchemaObject(method.name, method));
@@ -473,13 +453,35 @@ class APITypingsGenerator {
473
453
  this.registerExport(`./methods/${section}`, codeBlock.interfaceName);
474
454
  }
475
455
  });
476
- const code = [
477
- generator_1.generateImportsBlock(imports, null),
478
- ...codeBlocks,
479
- ];
456
+ const code = [generator_1.generateImportsBlock(imports, null), ...codeBlocks];
480
457
  this.registerResultFile(path_1.default.join('methods', `${section}.ts`), code.join(constants_1.newLineChar.repeat(2)));
481
458
  });
482
459
  }
460
+ generateErrors() {
461
+ log_1.consoleLogInfo('creating errors...');
462
+ const code = [];
463
+ Object.entries(this.errors)
464
+ .reduce((acc, [name, error]) => {
465
+ acc.push({ name, ...error });
466
+ return acc;
467
+ }, [])
468
+ .sort((errorA, errorB) => {
469
+ return errorA.code - errorB.code;
470
+ })
471
+ .forEach((error) => {
472
+ const errorConstantName = error.name.toUpperCase();
473
+ code.push(new TypeCodeBlock_1.TypeCodeBlock({
474
+ type: TypeCodeBlock_1.TypeScriptCodeTypes.Const,
475
+ interfaceName: errorConstantName,
476
+ needExport: true,
477
+ value: String(error.code),
478
+ properties: [],
479
+ description: [error.description, error.$comment || ''].join(constants_1.newLineChar.repeat(2)),
480
+ }).toString());
481
+ this.registerExport('./common/errors', errorConstantName);
482
+ });
483
+ this.registerResultFile(path_1.default.join('common', 'errors.ts'), code.join(constants_1.newLineChar.repeat(2)));
484
+ }
483
485
  createCommonTypes() {
484
486
  log_1.consoleLogInfo('creating common types...');
485
487
  const code = [];
@@ -545,6 +547,7 @@ class APITypingsGenerator {
545
547
  generate() {
546
548
  log_1.consoleLogInfo('generate');
547
549
  this.generateMethods();
550
+ this.generateErrors();
548
551
  if (this.needEmit) {
549
552
  this.createCommonTypes();
550
553
  this.createIndexExports();
@@ -10,18 +10,11 @@ class CommentCodeBlock extends BaseCodeBlock_1.BaseCodeBlock {
10
10
  }
11
11
  lines;
12
12
  appendLines(lines) {
13
- this.lines = [
14
- ...this.lines,
15
- ...lines,
16
- ];
13
+ this.lines = [...this.lines, ...lines];
17
14
  }
18
15
  toString() {
19
16
  const inner = this.lines.map((line) => constants_1.spaceChar + `* ${line}`.trim());
20
- return [
21
- '/**',
22
- ...inner,
23
- ' */',
24
- ].join(constants_1.newLineChar);
17
+ return ['/**', ...inner, ' */'].join(constants_1.newLineChar);
25
18
  }
26
19
  }
27
20
  exports.CommentCodeBlock = CommentCodeBlock;
@@ -7,7 +7,11 @@ const log_1 = require("../log");
7
7
  class SchemaObject {
8
8
  constructor(name, object, parentName) {
9
9
  if (!utils_1.isObject(object)) {
10
- log_1.consoleLogErrorAndExit(`[SchemaObject] "${name}" is not an object.`, { name, object, parentName });
10
+ log_1.consoleLogErrorAndExit(`[SchemaObject] "${name}" is not an object.`, {
11
+ name,
12
+ object,
13
+ parentName,
14
+ });
11
15
  return;
12
16
  }
13
17
  this.name = name;
@@ -12,6 +12,7 @@ var TypeScriptCodeTypes;
12
12
  TypeScriptCodeTypes["Enum"] = "enum";
13
13
  TypeScriptCodeTypes["ConstantObject"] = "constant_object";
14
14
  TypeScriptCodeTypes["Type"] = "type";
15
+ TypeScriptCodeTypes["Const"] = "const";
15
16
  })(TypeScriptCodeTypes = exports.TypeScriptCodeTypes || (exports.TypeScriptCodeTypes = {}));
16
17
  class TypeCodeBlock extends BaseCodeBlock_1.BaseCodeBlock {
17
18
  constructor(options) {
@@ -39,8 +40,11 @@ class TypeCodeBlock extends BaseCodeBlock_1.BaseCodeBlock {
39
40
  this.properties.push(property);
40
41
  }
41
42
  getPropertiesCode() {
42
- const quoteChar = this.properties.some((property) => helpers_1.areQuotesNeededForProperty(property.name)) ? '\'' : '';
43
- return this.properties.map((property) => {
43
+ const quoteChar = this.properties.some((property) => helpers_1.areQuotesNeededForProperty(property.name))
44
+ ? "'"
45
+ : '';
46
+ return this.properties
47
+ .map((property) => {
44
48
  let divider = '';
45
49
  let lineEnd = '';
46
50
  switch (this.type) {
@@ -68,7 +72,8 @@ class TypeCodeBlock extends BaseCodeBlock_1.BaseCodeBlock {
68
72
  }
69
73
  }
70
74
  return propertyCode.join(constants_1.newLineChar);
71
- }).join(constants_1.newLineChar);
75
+ })
76
+ .join(constants_1.newLineChar);
72
77
  }
73
78
  toString() {
74
79
  const hasProperties = this.properties.length > 0;
@@ -80,10 +85,7 @@ class TypeCodeBlock extends BaseCodeBlock_1.BaseCodeBlock {
80
85
  before.push(`// ${this.refName}`);
81
86
  }
82
87
  if (this.description) {
83
- before = [
84
- ...before,
85
- ...helpers_1.joinCommentLines(0, this.description),
86
- ];
88
+ before = [...before, ...helpers_1.joinCommentLines(0, this.description)];
87
89
  }
88
90
  switch (this.type) {
89
91
  case TypeScriptCodeTypes.Interface: {
@@ -92,15 +94,12 @@ class TypeCodeBlock extends BaseCodeBlock_1.BaseCodeBlock {
92
94
  propertiesCode = '';
93
95
  }
94
96
  else {
95
- propertiesCode = [
96
- ' // empty interface',
97
- ' [key: string]: any;',
98
- ].join(constants_1.newLineChar);
97
+ propertiesCode = [' // empty interface', ' [key: string]: any;'].join(constants_1.newLineChar);
99
98
  }
100
99
  }
101
- const extendsInterfaces = Array.isArray(this.extendsInterfaces) && this.extendsInterfaces.length ?
102
- this.extendsInterfaces.join(', ') :
103
- '';
100
+ const extendsInterfaces = Array.isArray(this.extendsInterfaces) && this.extendsInterfaces.length
101
+ ? this.extendsInterfaces.join(', ')
102
+ : '';
104
103
  code = [
105
104
  utils_1.trimStringDoubleSpaces(`${exportKeyword} interface ${this.interfaceName} ${extendsInterfaces} {`),
106
105
  propertiesCode,
@@ -130,11 +129,16 @@ class TypeCodeBlock extends BaseCodeBlock_1.BaseCodeBlock {
130
129
  utils_1.trimStringDoubleSpaces(`${exportKeyword} type ${this.interfaceName} = ${this.value};`),
131
130
  ].join(constants_1.newLineChar);
132
131
  break;
132
+ case TypeScriptCodeTypes.Const:
133
+ if (!this.value) {
134
+ log_1.consoleLogErrorAndExit(`"${this.interfaceName}" type has empty value`);
135
+ }
136
+ code = [
137
+ utils_1.trimStringDoubleSpaces(`${exportKeyword} const ${this.interfaceName} = ${this.value};`),
138
+ ].join(constants_1.newLineChar);
139
+ break;
133
140
  }
134
- return [
135
- before.join(constants_1.newLineChar),
136
- code,
137
- ].join(constants_1.newLineChar).trim();
141
+ return [before.join(constants_1.newLineChar), code].join(constants_1.newLineChar).trim();
138
142
  }
139
143
  }
140
144
  exports.TypeCodeBlock = TypeCodeBlock;
@@ -46,10 +46,7 @@ function generateEnumAsUnionType(object) {
46
46
  type: TypeCodeBlock_1.TypeScriptCodeTypes.Type,
47
47
  refName: object.name,
48
48
  interfaceName: helpers_1.getInterfaceName(object.name),
49
- description: [
50
- object.description,
51
- description,
52
- ].join(constants_1.newLineChar),
49
+ description: [object.description, description].join(constants_1.newLineChar),
53
50
  needExport: true,
54
51
  properties: [],
55
52
  value,
@@ -79,7 +76,7 @@ function getEnumNames(object) {
79
76
  };
80
77
  }
81
78
  function generateInlineEnum(object, options = {}) {
82
- const { isNumericEnum, enumNames, needEnumNamesDescription, } = getEnumNames(object);
79
+ const { isNumericEnum, enumNames, needEnumNamesDescription } = getEnumNames(object);
83
80
  options = {
84
81
  needEnumNamesConstant: isNumericEnum,
85
82
  ...options,
@@ -28,9 +28,9 @@ function normalizeMethodInfo(method) {
28
28
  if (parameter.items && parameter.items.$ref) {
29
29
  const ref = parameter.items?.$ref;
30
30
  parameterRefs[ref] = types_1.RefsDictionaryType.Generate;
31
- parameter.description += constants_1.newLineChar.repeat(2) + [
32
- `@see ${helpers_1.getInterfaceName(helpers_1.getObjectNameByRef(ref))} (${ref})`,
33
- ].join(constants_1.newLineChar);
31
+ parameter.description +=
32
+ constants_1.newLineChar.repeat(2) +
33
+ [`@see ${helpers_1.getInterfaceName(helpers_1.getObjectNameByRef(ref))} (${ref})`].join(constants_1.newLineChar);
34
34
  }
35
35
  });
36
36
  return {
package/dist/helpers.js CHANGED
@@ -28,6 +28,7 @@ const path_1 = __importDefault(require("path"));
28
28
  const utils_1 = require("./utils");
29
29
  const constants_1 = require("./constants");
30
30
  const log_1 = require("./log");
31
+ const prettier_1 = __importDefault(require("prettier"));
31
32
  async function readJSONFile(path) {
32
33
  const content = await fs_1.promises.readFile(path, 'utf-8');
33
34
  return JSON.parse(content);
@@ -54,15 +55,27 @@ function prepareBuildDirectory(directoryPath) {
54
55
  exports.prepareBuildDirectory = prepareBuildDirectory;
55
56
  function writeFile(filePath, code, insertAutoGeneratedNote = true) {
56
57
  if (insertAutoGeneratedNote) {
57
- code = [
58
- '/**',
59
- ' * This is auto-generated file, don\'t modify this file manually',
60
- ' */',
61
- // '/* eslint-disable max-len */',
62
- // '/* eslint-disable @typescript-eslint/no-empty-interface */',
63
- ].join(constants_1.newLineChar) + constants_1.newLineChar.repeat(2) + code.trim();
58
+ code =
59
+ [
60
+ '/**',
61
+ " * This is auto-generated file, don't modify this file manually",
62
+ ' */',
63
+ // '/* eslint-disable max-len */',
64
+ // '/* eslint-disable @typescript-eslint/no-empty-interface */',
65
+ ].join(constants_1.newLineChar) +
66
+ constants_1.newLineChar.repeat(2) +
67
+ code.trim();
64
68
  }
65
- fs_1.default.mkdirSync(filePath.replace(path_1.default.basename(filePath), ''), { recursive: true });
69
+ code = prettier_1.default.format(code, {
70
+ semi: true,
71
+ singleQuote: true,
72
+ trailingComma: 'all',
73
+ quoteProps: 'consistent',
74
+ parser: 'typescript',
75
+ });
76
+ fs_1.default.mkdirSync(filePath.replace(path_1.default.basename(filePath), ''), {
77
+ recursive: true,
78
+ });
66
79
  fs_1.default.writeFileSync(filePath, code.trim() + constants_1.newLineChar);
67
80
  }
68
81
  exports.writeFile = writeFile;
@@ -70,7 +83,10 @@ function prepareMethodsPattern(methodsPattern) {
70
83
  if (!methodsPattern) {
71
84
  log_1.consoleLogErrorAndExit('methodsPattern is empty. Pass "*" to generate all methods');
72
85
  }
73
- return methodsPattern.replace(/\s+/g, '').split(',').reduce((acc, pattern) => {
86
+ return methodsPattern
87
+ .replace(/\s+/g, '')
88
+ .split(',')
89
+ .reduce((acc, pattern) => {
74
90
  acc[pattern] = true;
75
91
  return acc;
76
92
  }, {});
@@ -95,17 +111,16 @@ function getMethodSection(methodName) {
95
111
  }
96
112
  exports.getMethodSection = getMethodSection;
97
113
  function getInterfaceName(name) {
98
- name = name.replace(/\.|(\s+)|_/g, ' ')
114
+ name = name
115
+ .replace(/\.|(\s+)|_/g, ' ')
99
116
  .split(' ')
100
- .map((v) => utils_1.capitalizeFirstLetter(v)).join('');
117
+ .map((v) => utils_1.capitalizeFirstLetter(v))
118
+ .join('');
101
119
  return utils_1.capitalizeFirstLetter(name);
102
120
  }
103
121
  exports.getInterfaceName = getInterfaceName;
104
122
  function getEnumPropertyName(name) {
105
- return name.toUpperCase()
106
- .replace(/\s+/g, '_')
107
- .replace(/-/g, '_')
108
- .replace(/\./g, '_');
123
+ return name.toUpperCase().replace(/\s+/g, '_').replace(/-/g, '_').replace(/\./g, '_');
109
124
  }
110
125
  exports.getEnumPropertyName = getEnumPropertyName;
111
126
  function getObjectNameByRef(ref) {
@@ -149,10 +164,7 @@ function joinCommentLines(indent = 2, ...description) {
149
164
  ];
150
165
  }
151
166
  else if (Array.isArray(entry)) {
152
- descriptionLines = [
153
- ...descriptionLines,
154
- ...entry,
155
- ];
167
+ descriptionLines = [...descriptionLines, ...entry];
156
168
  }
157
169
  });
158
170
  descriptionLines = utils_1.trimArray(descriptionLines);
@@ -181,7 +193,7 @@ function joinOneOfValues(values, primitive) {
181
193
  }
182
194
  exports.joinOneOfValues = joinOneOfValues;
183
195
  function formatArrayDepth(value, depth) {
184
- if (value.endsWith('\'') || value.includes('|')) {
196
+ if (value.endsWith("'") || value.includes('|')) {
185
197
  return `Array<${value}>` + '[]'.repeat(depth - 1); // Need decrement depth value because of Array<T> has its own depth
186
198
  }
187
199
  else {
package/dist/index.js CHANGED
@@ -24,8 +24,8 @@ const helpMessage = `
24
24
 
25
25
  ${chalk_1.default.greenBright('--methods')} List of methods to generate responses and all needed objects.
26
26
  Example:
27
- - ${chalk_1.default.bold('\'*\'')} - to generate all responses and objects.
28
- - ${chalk_1.default.bold('\'messages.*, users.get, groups.isMember\'')} - to generate all methods from messages section, users.get and groups.isMember.
27
+ - ${chalk_1.default.bold("'*'")} - to generate all responses and objects.
28
+ - ${chalk_1.default.bold("'messages.*, users.get, groups.isMember'")} - to generate all methods from messages section, users.get and groups.isMember.
29
29
  `;
30
30
  async function main() {
31
31
  console.log(chalk_1.default.bold('VK API Schema TypeScript generator'));
@@ -52,7 +52,7 @@ async function main() {
52
52
  schemaDir = path_1.default.resolve(schemaDir);
53
53
  outDir = outDir ? path_1.default.resolve(outDir) : '';
54
54
  // Read and check required schema files
55
- const [methodsDefinitions, { definitions: responsesDefinitions }, { definitions: objectsDefinitions },] = await Promise.all([
55
+ const [methodsDefinitions, { definitions: responsesDefinitions }, { definitions: objectsDefinitions }, { errors: errorsDefinitions },] = await Promise.all([
56
56
  helpers_1.readJSONFile(path_1.default.resolve(schemaDir, 'methods.json')),
57
57
  helpers_1.readJSONFile(path_1.default.resolve(schemaDir, 'responses.json')),
58
58
  helpers_1.readJSONFile(path_1.default.resolve(schemaDir, 'objects.json')),
@@ -77,6 +77,7 @@ async function main() {
77
77
  methodsDefinitions,
78
78
  objects: objectsDefinitions,
79
79
  responses: responsesDefinitions,
80
+ errors: errorsDefinitions,
80
81
  methodsPattern: methods.join(','),
81
82
  });
82
83
  generator.generate();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/api-schema-typescript-generator",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "license": "MIT",
5
5
  "description": "VK API TypeScript generator",
6
6
  "author": {
@@ -33,14 +33,16 @@
33
33
  "clear": "rimraf dist/*",
34
34
  "build": "yarn clear && tsc",
35
35
  "watch": "yarn clear && tsc --watch",
36
- "test": "jest && tsc --noEmit && eslint src --ext .ts"
36
+ "prettier": "prettier --write \"src/**/*.ts\"",
37
+ "test": "jest && tsc --noEmit && eslint src --ext .ts && yarn prettier"
37
38
  },
38
39
  "pre-commit": [
39
40
  "test"
40
41
  ],
41
42
  "dependencies": {
42
43
  "arg": "^4.1.3",
43
- "chalk": "4.1.0"
44
+ "chalk": "4.1.0",
45
+ "prettier": "^2.7.1"
44
46
  },
45
47
  "devDependencies": {
46
48
  "@types/jest": "^28.1.5",
package/src/generator.ts CHANGED
@@ -3,7 +3,11 @@ import { getInterfaceName, getSectionFromObjectName } from './helpers';
3
3
  import { Dictionary, ObjectType, RefsDictionary, RefsDictionaryType } from './types';
4
4
  import { sortArrayAlphabetically, uniqueArray } from './utils';
5
5
 
6
- export function generateImportsBlock(refs: RefsDictionary, section: string | null, type?: ObjectType): string {
6
+ export function generateImportsBlock(
7
+ refs: RefsDictionary,
8
+ section: string | null,
9
+ type?: ObjectType,
10
+ ): string {
7
11
  let importRefs = Object.entries(refs)
8
12
  .filter(([, type]) => type === RefsDictionaryType.GenerateAndImport)
9
13
  .map(([key]) => key);
@@ -1,15 +1,16 @@
1
1
  import * as Schema from '../types/schema';
2
- import {
3
- Dictionary,
4
- ObjectType,
5
- RefsDictionary,
6
- } from '../types';
2
+ import { Dictionary, ObjectType, RefsDictionary } from '../types';
7
3
  import { generateEnumAsUnionType } from './enums';
8
4
  import { normalizeMethodInfo } from './methods';
9
5
  import { SchemaObject } from './SchemaObject';
10
6
  import {
11
- getInterfaceName, getMethodSection, getObjectNameByRef,
12
- getSectionFromObjectName, isMethodNeeded, isPatternProperty, prepareBuildDirectory,
7
+ getInterfaceName,
8
+ getMethodSection,
9
+ getObjectNameByRef,
10
+ getSectionFromObjectName,
11
+ isMethodNeeded,
12
+ isPatternProperty,
13
+ prepareBuildDirectory,
13
14
  prepareMethodsPattern,
14
15
  writeFile,
15
16
  } from '../helpers';
@@ -20,7 +21,8 @@ import {
20
21
  baseAPIParamsInterfaceName,
21
22
  baseBoolIntRef,
22
23
  baseOkResponseRef,
23
- basePropertyExistsRef, DEFAULT_API_VERSION,
24
+ basePropertyExistsRef,
25
+ DEFAULT_API_VERSION,
24
26
  newLineChar,
25
27
  } from '../constants';
26
28
  import path from 'path';
@@ -28,6 +30,7 @@ import { CommentCodeBlock } from './CommentCodeBlock';
28
30
  import { consoleLogError, consoleLogErrorAndExit, consoleLogInfo } from '../log';
29
31
  import { generateImportsBlock } from '../generator';
30
32
  import { generateTypeString } from './typeString';
33
+ import { ErrorInterface } from '../types/schema';
31
34
 
32
35
  interface APITypingsGeneratorOptions {
33
36
  needEmit: boolean;
@@ -47,6 +50,7 @@ interface APITypingsGeneratorOptions {
47
50
  methodsDefinitions: Schema.API;
48
51
  objects: Dictionary<SchemaObject>;
49
52
  responses: Dictionary<SchemaObject>;
53
+ errors: Dictionary<ErrorInterface>;
50
54
  }
51
55
 
52
56
  export class APITypingsGenerator {
@@ -59,6 +63,7 @@ export class APITypingsGenerator {
59
63
  this.methodsList = options.methodsDefinitions.methods || [];
60
64
  this.objects = this.convertJSONSchemaDictionary(options.objects);
61
65
  this.responses = this.convertJSONSchemaDictionary(options.responses);
66
+ this.errors = options.errors;
62
67
 
63
68
  this.visitedRefs = {};
64
69
  this.generatedObjects = {};
@@ -68,7 +73,7 @@ export class APITypingsGenerator {
68
73
 
69
74
  this.ignoredResponses = {
70
75
  'storage.get': {
71
- 'keysResponse': true,
76
+ keysResponse: true,
72
77
  },
73
78
  };
74
79
 
@@ -83,6 +88,7 @@ export class APITypingsGenerator {
83
88
  methodsList!: NonNullable<Schema.API['methods']>;
84
89
  objects!: Dictionary<SchemaObject>;
85
90
  responses!: Dictionary<SchemaObject>;
91
+ errors!: Dictionary<ErrorInterface>;
86
92
 
87
93
  visitedRefs!: Dictionary<boolean>;
88
94
  generatedObjects!: Dictionary<boolean>;
@@ -129,10 +135,7 @@ export class APITypingsGenerator {
129
135
  ...methodFile.imports,
130
136
  ...imports,
131
137
  },
132
- codeBlocks: [
133
- ...methodFile.codeBlocks,
134
- ...codeBlocks,
135
- ],
138
+ codeBlocks: [...methodFile.codeBlocks, ...codeBlocks],
136
139
  };
137
140
  }
138
141
 
@@ -192,10 +195,7 @@ export class APITypingsGenerator {
192
195
  }
193
196
 
194
197
  if (additionalProperties.length) {
195
- properties = [
196
- ...properties,
197
- ...additionalProperties,
198
- ];
198
+ properties = [...properties, ...additionalProperties];
199
199
  }
200
200
  });
201
201
  }
@@ -265,10 +265,7 @@ export class APITypingsGenerator {
265
265
  });
266
266
 
267
267
  return {
268
- codeBlocks: [
269
- ...codeBlocks,
270
- codeBlock,
271
- ],
268
+ codeBlocks: [...codeBlocks, codeBlock],
272
269
  imports,
273
270
  value: '',
274
271
  };
@@ -338,12 +335,18 @@ export class APITypingsGenerator {
338
335
 
339
336
  if (stringCodeBlocks.length > 0) {
340
337
  const code = stringCodeBlocks.join(newLineChar.repeat(2));
341
- this.registerResultFile(path.join('objects', section, `${getInterfaceName(object.name)}.ts`), code);
338
+ this.registerResultFile(
339
+ path.join('objects', section, `${getInterfaceName(object.name)}.ts`),
340
+ code,
341
+ );
342
342
  }
343
343
 
344
344
  codeBlocks.forEach((codeBlock) => {
345
345
  if (codeBlock instanceof TypeCodeBlock && codeBlock.needExport && codeBlock.interfaceName) {
346
- this.registerExport(`./objects/${section}/${getInterfaceName(object.name)}.ts`, codeBlock.interfaceName);
346
+ this.registerExport(
347
+ `./objects/${section}/${getInterfaceName(object.name)}.ts`,
348
+ codeBlock.interfaceName,
349
+ );
347
350
  }
348
351
  });
349
352
 
@@ -399,7 +402,9 @@ export class APITypingsGenerator {
399
402
  imports: newImports,
400
403
  value,
401
404
  codeBlocks: newCodeBlocks,
402
- } = generateTypeString(property, this.objects, { needEnumNamesConstant: false });
405
+ } = generateTypeString(property, this.objects, {
406
+ needEnumNamesConstant: false,
407
+ });
403
408
 
404
409
  imports = { ...imports, ...newImports };
405
410
  codeBlocks = [...codeBlocks, ...newCodeBlocks];
@@ -432,11 +437,13 @@ export class APITypingsGenerator {
432
437
 
433
438
  if (object.enum) {
434
439
  const { codeBlocks: newCodeBlocks } = generateEnumAsUnionType(object);
435
- codeBlocks = [
436
- ...newCodeBlocks,
437
- ];
440
+ codeBlocks = [...newCodeBlocks];
438
441
  } else {
439
- const { imports: newImports, value, codeBlocks: newCodeBlocks } = generateTypeString(object, this.objects);
442
+ const {
443
+ imports: newImports,
444
+ value,
445
+ codeBlocks: newCodeBlocks,
446
+ } = generateTypeString(object, this.objects);
440
447
  const codeBlock = new TypeCodeBlock({
441
448
  type: TypeScriptCodeTypes.Type,
442
449
  refName: object.name,
@@ -448,11 +455,7 @@ export class APITypingsGenerator {
448
455
  });
449
456
 
450
457
  imports = newImports;
451
- codeBlocks = [
452
- ...codeBlocks,
453
- ...newCodeBlocks,
454
- codeBlock,
455
- ];
458
+ codeBlocks = [...codeBlocks, ...newCodeBlocks, codeBlock];
456
459
  }
457
460
 
458
461
  return {
@@ -462,13 +465,11 @@ export class APITypingsGenerator {
462
465
  };
463
466
  }
464
467
 
465
- private getResponseCodeBlockAsType(object: SchemaObject, response: SchemaObject): GeneratorResultInterface | false {
466
- const {
467
- imports,
468
- value,
469
- codeBlocks,
470
- description,
471
- } = generateTypeString(response, this.objects, {
468
+ private getResponseCodeBlockAsType(
469
+ object: SchemaObject,
470
+ response: SchemaObject,
471
+ ): GeneratorResultInterface | false {
472
+ const { imports, value, codeBlocks, description } = generateTypeString(response, this.objects, {
472
473
  objectParentName: ' ', // TODO: Refactor
473
474
  });
474
475
 
@@ -476,20 +477,14 @@ export class APITypingsGenerator {
476
477
  type: TypeScriptCodeTypes.Type,
477
478
  refName: object.name,
478
479
  interfaceName: getInterfaceName(object.name),
479
- description: [
480
- object.description,
481
- description || '',
482
- ].join(newLineChar),
480
+ description: [object.description, description || ''].join(newLineChar),
483
481
  needExport: true,
484
482
  properties: [],
485
483
  value,
486
484
  });
487
485
 
488
486
  return {
489
- codeBlocks: [
490
- ...codeBlocks,
491
- codeBlock,
492
- ],
487
+ codeBlocks: [...codeBlocks, codeBlock],
493
488
  imports,
494
489
  value: '',
495
490
  description,
@@ -576,17 +571,11 @@ export class APITypingsGenerator {
576
571
  // Comment with method name for visual sections in file
577
572
  const methodNameComment = new CommentCodeBlock([methodName]);
578
573
  if (method.description) {
579
- methodNameComment.appendLines([
580
- '',
581
- method.description,
582
- ]);
574
+ methodNameComment.appendLines(['', method.description]);
583
575
  }
584
576
  this.appendToFileMap(section, {}, [methodNameComment]);
585
577
 
586
- const {
587
- method: normalizedMethod,
588
- parameterRefs,
589
- } = normalizeMethodInfo(method);
578
+ const { method: normalizedMethod, parameterRefs } = normalizeMethodInfo(method);
590
579
 
591
580
  method = normalizedMethod;
592
581
  this.generateObjectsFromRefs(parameterRefs);
@@ -619,15 +608,48 @@ export class APITypingsGenerator {
619
608
  this.registerExport(`./methods/${section}`, codeBlock.interfaceName);
620
609
  }
621
610
  });
622
- const code = [
623
- generateImportsBlock(imports, null),
624
- ...codeBlocks,
625
- ];
611
+ const code = [generateImportsBlock(imports, null), ...codeBlocks];
626
612
 
627
- this.registerResultFile(path.join('methods', `${section}.ts`), code.join(newLineChar.repeat(2)));
613
+ this.registerResultFile(
614
+ path.join('methods', `${section}.ts`),
615
+ code.join(newLineChar.repeat(2)),
616
+ );
628
617
  });
629
618
  }
630
619
 
620
+ private generateErrors() {
621
+ consoleLogInfo('creating errors...');
622
+
623
+ const code: string[] = [];
624
+
625
+ Object.entries(this.errors)
626
+ .reduce<Array<ErrorInterface & { name: string }>>((acc, [name, error]) => {
627
+ acc.push({ name, ...error });
628
+ return acc;
629
+ }, [])
630
+ .sort((errorA, errorB) => {
631
+ return errorA.code - errorB.code;
632
+ })
633
+ .forEach((error) => {
634
+ const errorConstantName = error.name.toUpperCase();
635
+
636
+ code.push(
637
+ new TypeCodeBlock({
638
+ type: TypeScriptCodeTypes.Const,
639
+ interfaceName: errorConstantName,
640
+ needExport: true,
641
+ value: String(error.code),
642
+ properties: [],
643
+ description: [error.description, error.$comment || ''].join(newLineChar.repeat(2)),
644
+ }).toString(),
645
+ );
646
+
647
+ this.registerExport('./common/errors', errorConstantName);
648
+ });
649
+
650
+ this.registerResultFile(path.join('common', 'errors.ts'), code.join(newLineChar.repeat(2)));
651
+ }
652
+
631
653
  private createCommonTypes() {
632
654
  consoleLogInfo('creating common types...');
633
655
  const code: string[] = [];
@@ -708,6 +730,7 @@ export class APITypingsGenerator {
708
730
  consoleLogInfo('generate');
709
731
 
710
732
  this.generateMethods();
733
+ this.generateErrors();
711
734
 
712
735
  if (this.needEmit) {
713
736
  this.createCommonTypes();
@@ -10,19 +10,12 @@ export class CommentCodeBlock extends BaseCodeBlock {
10
10
  lines: string[];
11
11
 
12
12
  appendLines(lines: string[]) {
13
- this.lines = [
14
- ...this.lines,
15
- ...lines,
16
- ];
13
+ this.lines = [...this.lines, ...lines];
17
14
  }
18
15
 
19
16
  toString(): string {
20
17
  const inner = this.lines.map((line) => spaceChar + `* ${line}`.trim());
21
18
 
22
- return [
23
- '/**',
24
- ...inner,
25
- ' */',
26
- ].join(newLineChar);
19
+ return ['/**', ...inner, ' */'].join(newLineChar);
27
20
  }
28
21
  }
@@ -1,14 +1,16 @@
1
1
  import { EnumLikeArray } from '../types';
2
2
  import { isObject, isString } from '../utils';
3
- import {
4
- transformPatternPropertyName,
5
- } from '../helpers';
3
+ import { transformPatternPropertyName } from '../helpers';
6
4
  import { consoleLogErrorAndExit } from '../log';
7
5
 
8
6
  export class SchemaObject {
9
7
  constructor(name: string, object: any, parentName?: string) {
10
8
  if (!isObject(object)) {
11
- consoleLogErrorAndExit(`[SchemaObject] "${name}" is not an object.`, { name, object, parentName });
9
+ consoleLogErrorAndExit(`[SchemaObject] "${name}" is not an object.`, {
10
+ name,
11
+ object,
12
+ parentName,
13
+ });
12
14
  return;
13
15
  }
14
16
 
@@ -67,9 +69,13 @@ export class SchemaObject {
67
69
  }
68
70
 
69
71
  if (object.patternProperties) {
70
- Object.entries(object.patternProperties).forEach(([propertyName, property]: [string, any]) => {
71
- this.properties.push(new SchemaObject(transformPatternPropertyName(propertyName), property, name));
72
- });
72
+ Object.entries(object.patternProperties).forEach(
73
+ ([propertyName, property]: [string, any]) => {
74
+ this.properties.push(
75
+ new SchemaObject(transformPatternPropertyName(propertyName), property, name),
76
+ );
77
+ },
78
+ );
73
79
  }
74
80
 
75
81
  if (isObject(object.items)) {
@@ -112,6 +118,9 @@ export class SchemaObject {
112
118
  }
113
119
 
114
120
  public clone() {
115
- return Object.assign(Object.create(Object.getPrototypeOf(this)), this) as NonNullable<SchemaObject>;
121
+ return Object.assign(
122
+ Object.create(Object.getPrototypeOf(this)),
123
+ this,
124
+ ) as NonNullable<SchemaObject>;
116
125
  }
117
126
  }
@@ -9,6 +9,7 @@ export enum TypeScriptCodeTypes {
9
9
  Enum = 'enum',
10
10
  ConstantObject = 'constant_object',
11
11
  Type = 'type',
12
+ Const = 'const',
12
13
  }
13
14
 
14
15
  export interface TypeCodeBlockProperty {
@@ -63,41 +64,45 @@ export class TypeCodeBlock extends BaseCodeBlock {
63
64
  }
64
65
 
65
66
  private getPropertiesCode() {
66
- const quoteChar = this.properties.some((property) => areQuotesNeededForProperty(property.name)) ? '\'' : '';
67
-
68
- return this.properties.map((property) => {
69
- let divider = '';
70
- let lineEnd = '';
71
-
72
- switch (this.type) {
73
- case TypeScriptCodeTypes.Interface:
74
- divider = property.isRequired ? ':' : '?:';
75
- lineEnd = ';';
76
- break;
77
- case TypeScriptCodeTypes.ConstantObject:
78
- divider = ':';
79
- lineEnd = ',';
80
- break;
81
- case TypeScriptCodeTypes.Enum:
82
- divider = ' =';
83
- lineEnd = ',';
84
- break;
85
- }
67
+ const quoteChar = this.properties.some((property) => areQuotesNeededForProperty(property.name))
68
+ ? "'"
69
+ : '';
70
+
71
+ return this.properties
72
+ .map((property) => {
73
+ let divider = '';
74
+ let lineEnd = '';
75
+
76
+ switch (this.type) {
77
+ case TypeScriptCodeTypes.Interface:
78
+ divider = property.isRequired ? ':' : '?:';
79
+ lineEnd = ';';
80
+ break;
81
+ case TypeScriptCodeTypes.ConstantObject:
82
+ divider = ':';
83
+ lineEnd = ',';
84
+ break;
85
+ case TypeScriptCodeTypes.Enum:
86
+ divider = ' =';
87
+ lineEnd = ',';
88
+ break;
89
+ }
86
90
 
87
- let value = property.wrapValue ? quoteJavaScriptValue(property.value) : property.value;
88
- let propertyCode = [
89
- ` ${quoteChar}${property.name}${quoteChar}${divider} ${value}${lineEnd}`,
90
- ];
91
+ let value = property.wrapValue ? quoteJavaScriptValue(property.value) : property.value;
92
+ let propertyCode = [
93
+ ` ${quoteChar}${property.name}${quoteChar}${divider} ${value}${lineEnd}`,
94
+ ];
91
95
 
92
- if (property.description) {
93
- const commentLines = joinCommentLines(2, property.description);
94
- if (commentLines.length) {
95
- propertyCode.unshift(commentLines.join(newLineChar));
96
+ if (property.description) {
97
+ const commentLines = joinCommentLines(2, property.description);
98
+ if (commentLines.length) {
99
+ propertyCode.unshift(commentLines.join(newLineChar));
100
+ }
96
101
  }
97
- }
98
102
 
99
- return propertyCode.join(newLineChar);
100
- }).join(newLineChar);
103
+ return propertyCode.join(newLineChar);
104
+ })
105
+ .join(newLineChar);
101
106
  }
102
107
 
103
108
  toString(): string {
@@ -113,10 +118,7 @@ export class TypeCodeBlock extends BaseCodeBlock {
113
118
  }
114
119
 
115
120
  if (this.description) {
116
- before = [
117
- ...before,
118
- ...joinCommentLines(0, this.description),
119
- ];
121
+ before = [...before, ...joinCommentLines(0, this.description)];
120
122
  }
121
123
 
122
124
  switch (this.type) {
@@ -125,19 +127,19 @@ export class TypeCodeBlock extends BaseCodeBlock {
125
127
  if (this.options.allowEmptyInterface) {
126
128
  propertiesCode = '';
127
129
  } else {
128
- propertiesCode = [
129
- ' // empty interface',
130
- ' [key: string]: any;',
131
- ].join(newLineChar);
130
+ propertiesCode = [' // empty interface', ' [key: string]: any;'].join(newLineChar);
132
131
  }
133
132
  }
134
133
 
135
- const extendsInterfaces = Array.isArray(this.extendsInterfaces) && this.extendsInterfaces.length ?
136
- this.extendsInterfaces.join(', ') :
137
- '';
134
+ const extendsInterfaces =
135
+ Array.isArray(this.extendsInterfaces) && this.extendsInterfaces.length
136
+ ? this.extendsInterfaces.join(', ')
137
+ : '';
138
138
 
139
139
  code = [
140
- trimStringDoubleSpaces(`${exportKeyword} interface ${this.interfaceName} ${extendsInterfaces} {`),
140
+ trimStringDoubleSpaces(
141
+ `${exportKeyword} interface ${this.interfaceName} ${extendsInterfaces} {`,
142
+ ),
141
143
  propertiesCode,
142
144
  '}',
143
145
  ].join(propertiesCode.length ? newLineChar : '');
@@ -169,11 +171,18 @@ export class TypeCodeBlock extends BaseCodeBlock {
169
171
  trimStringDoubleSpaces(`${exportKeyword} type ${this.interfaceName} = ${this.value};`),
170
172
  ].join(newLineChar);
171
173
  break;
174
+
175
+ case TypeScriptCodeTypes.Const:
176
+ if (!this.value) {
177
+ consoleLogErrorAndExit(`"${this.interfaceName}" type has empty value`);
178
+ }
179
+
180
+ code = [
181
+ trimStringDoubleSpaces(`${exportKeyword} const ${this.interfaceName} = ${this.value};`),
182
+ ].join(newLineChar);
183
+ break;
172
184
  }
173
185
 
174
- return [
175
- before.join(newLineChar),
176
- code,
177
- ].join(newLineChar).trim();
186
+ return [before.join(newLineChar), code].join(newLineChar).trim();
178
187
  }
179
188
  }
@@ -18,7 +18,11 @@ export function getEnumNamesIdentifier(name: string) {
18
18
  return `${name} enumNames`.trim();
19
19
  }
20
20
 
21
- export function generateEnumConstantObject(object: SchemaObject, objectName: string, enumNames: Array<string | number>) {
21
+ export function generateEnumConstantObject(
22
+ object: SchemaObject,
23
+ objectName: string,
24
+ enumNames: Array<string | number>,
25
+ ) {
22
26
  const enumInterfaceName = getInterfaceName(objectName);
23
27
 
24
28
  const codeBlock = new TypeCodeBlock({
@@ -52,10 +56,7 @@ export function generateEnumAsUnionType(object: SchemaObject): GeneratorResultIn
52
56
  type: TypeScriptCodeTypes.Type,
53
57
  refName: object.name,
54
58
  interfaceName: getInterfaceName(object.name),
55
- description: [
56
- object.description,
57
- description,
58
- ].join(newLineChar),
59
+ description: [object.description, description].join(newLineChar),
59
60
  needExport: true,
60
61
  properties: [],
61
62
  value,
@@ -97,12 +98,11 @@ interface GenerateInlineEnumOptions {
97
98
  refName?: string;
98
99
  }
99
100
 
100
- export function generateInlineEnum(object: SchemaObject, options: GenerateInlineEnumOptions = {}): GeneratorResultInterface {
101
- const {
102
- isNumericEnum,
103
- enumNames,
104
- needEnumNamesDescription,
105
- } = getEnumNames(object);
101
+ export function generateInlineEnum(
102
+ object: SchemaObject,
103
+ options: GenerateInlineEnumOptions = {},
104
+ ): GeneratorResultInterface {
105
+ const { isNumericEnum, enumNames, needEnumNamesDescription } = getEnumNames(object);
106
106
 
107
107
  options = {
108
108
  needEnumNamesConstant: isNumericEnum,
@@ -37,9 +37,9 @@ export function normalizeMethodInfo(method: Schema.Method): NormalizeMethodInfoR
37
37
  const ref = parameter.items?.$ref;
38
38
  parameterRefs[ref] = RefsDictionaryType.Generate;
39
39
 
40
- parameter.description += newLineChar.repeat(2) + [
41
- `@see ${getInterfaceName(getObjectNameByRef(ref))} (${ref})`,
42
- ].join(newLineChar);
40
+ parameter.description +=
41
+ newLineChar.repeat(2) +
42
+ [`@see ${getInterfaceName(getObjectNameByRef(ref))} (${ref})`].join(newLineChar);
43
43
  }
44
44
  });
45
45
 
@@ -28,7 +28,10 @@ interface GenerateTypeStringOptions {
28
28
  needEnumNamesConstant?: boolean;
29
29
  }
30
30
 
31
- function generateBaseType(object: SchemaObject, options: GenerateTypeStringOptions): GeneratorResultInterface {
31
+ function generateBaseType(
32
+ object: SchemaObject,
33
+ options: GenerateTypeStringOptions,
34
+ ): GeneratorResultInterface {
32
35
  let codeBlocks: CodeBlocksArray = [];
33
36
  let typeString = 'any /* default type */';
34
37
  let imports: RefsDictionary = {};
package/src/helpers.ts CHANGED
@@ -4,6 +4,7 @@ import { capitalizeFirstLetter, trimArray } from './utils';
4
4
  import { newLineChar, primitiveTypes, spaceChar } from './constants';
5
5
  import { Dictionary } from './types';
6
6
  import { consoleLogErrorAndExit } from './log';
7
+ import prettier from 'prettier';
7
8
 
8
9
  export async function readJSONFile(path: string): Promise<any> {
9
10
  const content = await fsPromises.readFile(path, 'utf-8');
@@ -31,16 +32,29 @@ export function prepareBuildDirectory(directoryPath: string) {
31
32
 
32
33
  export function writeFile(filePath: string, code: string, insertAutoGeneratedNote = true) {
33
34
  if (insertAutoGeneratedNote) {
34
- code = [
35
- '/**',
36
- ' * This is auto-generated file, don\'t modify this file manually',
37
- ' */',
38
- // '/* eslint-disable max-len */',
39
- // '/* eslint-disable @typescript-eslint/no-empty-interface */',
40
- ].join(newLineChar) + newLineChar.repeat(2) + code.trim();
35
+ code =
36
+ [
37
+ '/**',
38
+ " * This is auto-generated file, don't modify this file manually",
39
+ ' */',
40
+ // '/* eslint-disable max-len */',
41
+ // '/* eslint-disable @typescript-eslint/no-empty-interface */',
42
+ ].join(newLineChar) +
43
+ newLineChar.repeat(2) +
44
+ code.trim();
41
45
  }
42
46
 
43
- fs.mkdirSync(filePath.replace(path.basename(filePath), ''), { recursive: true });
47
+ code = prettier.format(code, {
48
+ semi: true,
49
+ singleQuote: true,
50
+ trailingComma: 'all',
51
+ quoteProps: 'consistent',
52
+ parser: 'typescript',
53
+ });
54
+
55
+ fs.mkdirSync(filePath.replace(path.basename(filePath), ''), {
56
+ recursive: true,
57
+ });
44
58
  fs.writeFileSync(filePath, code.trim() + newLineChar);
45
59
  }
46
60
 
@@ -49,10 +63,13 @@ export function prepareMethodsPattern(methodsPattern: string): Dictionary<boolea
49
63
  consoleLogErrorAndExit('methodsPattern is empty. Pass "*" to generate all methods');
50
64
  }
51
65
 
52
- return methodsPattern.replace(/\s+/g, '').split(',').reduce<Dictionary<boolean>>((acc, pattern) => {
53
- acc[pattern] = true;
54
- return acc;
55
- }, {});
66
+ return methodsPattern
67
+ .replace(/\s+/g, '')
68
+ .split(',')
69
+ .reduce<Dictionary<boolean>>((acc, pattern) => {
70
+ acc[pattern] = true;
71
+ return acc;
72
+ }, {});
56
73
  }
57
74
 
58
75
  export function isMethodNeeded(methodsPattern: Dictionary<boolean>, method: string): boolean {
@@ -77,18 +94,17 @@ export function getMethodSection(methodName: string): string {
77
94
  }
78
95
 
79
96
  export function getInterfaceName(name: string): string {
80
- name = name.replace(/\.|(\s+)|_/g, ' ')
97
+ name = name
98
+ .replace(/\.|(\s+)|_/g, ' ')
81
99
  .split(' ')
82
- .map((v) => capitalizeFirstLetter(v)).join('');
100
+ .map((v) => capitalizeFirstLetter(v))
101
+ .join('');
83
102
 
84
103
  return capitalizeFirstLetter(name);
85
104
  }
86
105
 
87
106
  export function getEnumPropertyName(name: string): string {
88
- return name.toUpperCase()
89
- .replace(/\s+/g, '_')
90
- .replace(/-/g, '_')
91
- .replace(/\./g, '_');
107
+ return name.toUpperCase().replace(/\s+/g, '_').replace(/-/g, '_').replace(/\./g, '_');
92
108
  }
93
109
 
94
110
  export function getObjectNameByRef(ref: string): string {
@@ -136,10 +152,7 @@ export function joinCommentLines(indent = 2, ...description: Array<string | stri
136
152
  ...trimArray((entry || '').trim().split(newLineChar)),
137
153
  ];
138
154
  } else if (Array.isArray(entry)) {
139
- descriptionLines = [
140
- ...descriptionLines,
141
- ...entry,
142
- ];
155
+ descriptionLines = [...descriptionLines, ...entry];
143
156
  }
144
157
  });
145
158
 
@@ -171,7 +184,7 @@ export function joinOneOfValues(values: Array<string | number>, primitive?: bool
171
184
  }
172
185
 
173
186
  export function formatArrayDepth(value: string, depth: number) {
174
- if (value.endsWith('\'') || value.includes('|')) {
187
+ if (value.endsWith("'") || value.includes('|')) {
175
188
  return `Array<${value}>` + '[]'.repeat(depth - 1); // Need decrement depth value because of Array<T> has its own depth
176
189
  } else {
177
190
  return value + '[]'.repeat(depth);
package/src/index.ts CHANGED
@@ -11,16 +11,24 @@ const helpMessage = `
11
11
 
12
12
  ${chalk.greenBright('--help')} Shows this help.
13
13
 
14
- ${chalk.greenBright('--schemaDir')} The relative path to directory with ${chalk.bold('methods.json')}, ${chalk.bold('objects.json')} and ${chalk.bold('responses.json')} files.
14
+ ${chalk.greenBright('--schemaDir')} The relative path to directory with ${chalk.bold(
15
+ 'methods.json',
16
+ )}, ${chalk.bold('objects.json')} and ${chalk.bold('responses.json')} files.
15
17
 
16
18
  ${chalk.greenBright('--outDir')} The directory where the files will be generated.
17
19
  If you skip this param, script will work in linter mode without emitting files to file system.
18
- ${chalk.bold('Please note')} that this folder will be cleared after starting the generation.
20
+ ${chalk.bold(
21
+ 'Please note',
22
+ )} that this folder will be cleared after starting the generation.
19
23
 
20
- ${chalk.greenBright('--methods')} List of methods to generate responses and all needed objects.
24
+ ${chalk.greenBright(
25
+ '--methods',
26
+ )} List of methods to generate responses and all needed objects.
21
27
  Example:
22
- - ${chalk.bold('\'*\'')} - to generate all responses and objects.
23
- - ${chalk.bold('\'messages.*, users.get, groups.isMember\'')} - to generate all methods from messages section, users.get and groups.isMember.
28
+ - ${chalk.bold("'*'")} - to generate all responses and objects.
29
+ - ${chalk.bold(
30
+ "'messages.*, users.get, groups.isMember'",
31
+ )} - to generate all methods from messages section, users.get and groups.isMember.
24
32
  `;
25
33
 
26
34
  export async function main() {
@@ -61,6 +69,7 @@ export async function main() {
61
69
  methodsDefinitions,
62
70
  { definitions: responsesDefinitions },
63
71
  { definitions: objectsDefinitions },
72
+ { errors: errorsDefinitions },
64
73
  ] = await Promise.all([
65
74
  readJSONFile(path.resolve(schemaDir, 'methods.json')),
66
75
  readJSONFile(path.resolve(schemaDir, 'responses.json')),
@@ -91,6 +100,7 @@ export async function main() {
91
100
  methodsDefinitions,
92
101
  objects: objectsDefinitions,
93
102
  responses: responsesDefinitions,
103
+ errors: errorsDefinitions,
94
104
  methodsPattern: methods.join(','),
95
105
  });
96
106
 
@@ -150,3 +150,10 @@ export interface Response {
150
150
  };
151
151
  additionalProperties?: boolean;
152
152
  }
153
+
154
+ export interface ErrorInterface {
155
+ code: number;
156
+ description: string;
157
+ $comment?: string;
158
+ subcodes?: Array<{ $ref: string }>;
159
+ }