@vkontakte/api-schema-typescript-generator 0.9.0 → 0.13.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.
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateInlineEnum = exports.generateEnumAsUnionType = exports.generateEnumConstantObject = exports.getEnumNamesIdentifier = exports.isNumericEnum = void 0;
4
+ const constants_1 = require("../constants");
5
+ const helpers_1 = require("../helpers");
6
+ const utils_1 = require("../utils");
7
+ const TypeCodeBlock_1 = require("./TypeCodeBlock");
8
+ function isNumericEnum(object) {
9
+ return object.enum.some((value) => !!+value);
10
+ }
11
+ exports.isNumericEnum = isNumericEnum;
12
+ function getEnumNamesIdentifier(name) {
13
+ if (!name) {
14
+ throw new Error('[getEnumNamesIdentifier] empty name');
15
+ }
16
+ return `${name} enumNames`.trim();
17
+ }
18
+ exports.getEnumNamesIdentifier = getEnumNamesIdentifier;
19
+ function generateEnumConstantObject(object, objectName, enumNames) {
20
+ const enumInterfaceName = helpers_1.getInterfaceName(objectName);
21
+ const codeBlock = new TypeCodeBlock_1.TypeCodeBlock({
22
+ type: TypeCodeBlock_1.TypeScriptCodeTypes.ConstantObject,
23
+ refName: objectName,
24
+ interfaceName: enumInterfaceName,
25
+ needExport: true,
26
+ properties: [],
27
+ });
28
+ enumNames.forEach((name, index) => {
29
+ codeBlock.addProperty({
30
+ name: helpers_1.getEnumPropertyName(name.toString()),
31
+ value: object.enum[index],
32
+ wrapValue: true,
33
+ });
34
+ });
35
+ return codeBlock;
36
+ }
37
+ exports.generateEnumConstantObject = generateEnumConstantObject;
38
+ /**
39
+ * Generates enum as union type with constant object if necessary
40
+ */
41
+ function generateEnumAsUnionType(object) {
42
+ const { codeBlocks, value, description } = generateInlineEnum(object, {
43
+ refName: getEnumNamesIdentifier(object.name),
44
+ });
45
+ const unionType = new TypeCodeBlock_1.TypeCodeBlock({
46
+ type: TypeCodeBlock_1.TypeScriptCodeTypes.Type,
47
+ refName: object.name,
48
+ interfaceName: helpers_1.getInterfaceName(object.name),
49
+ description: [
50
+ object.description,
51
+ description,
52
+ ].join(constants_1.newLineChar),
53
+ needExport: true,
54
+ properties: [],
55
+ value,
56
+ });
57
+ codeBlocks.push(unionType);
58
+ return {
59
+ codeBlocks,
60
+ imports: {},
61
+ value: '',
62
+ };
63
+ }
64
+ exports.generateEnumAsUnionType = generateEnumAsUnionType;
65
+ function getEnumNames(object) {
66
+ let { enumNames } = object;
67
+ const isNumeric = isNumericEnum(object);
68
+ const needEnumNamesDescription = !!enumNames;
69
+ if (!enumNames) {
70
+ const canUseEnumNames = !isNumeric;
71
+ if (canUseEnumNames) {
72
+ enumNames = [...object.enum];
73
+ }
74
+ }
75
+ return {
76
+ isNumericEnum: isNumeric,
77
+ needEnumNamesDescription,
78
+ enumNames: Array.isArray(enumNames) && enumNames.length ? enumNames : undefined,
79
+ };
80
+ }
81
+ function generateInlineEnum(object, options = {}) {
82
+ const { isNumericEnum, enumNames, needEnumNamesDescription, } = getEnumNames(object);
83
+ options = {
84
+ needEnumNamesConstant: isNumericEnum,
85
+ ...options,
86
+ };
87
+ const codeBlocks = [];
88
+ let descriptionLines = [];
89
+ if (enumNames) {
90
+ if (needEnumNamesDescription) {
91
+ if (isNumericEnum && options.refName) {
92
+ descriptionLines.push('');
93
+ descriptionLines.push('@note This enum have auto-generated constant with keys and values');
94
+ descriptionLines.push(`@see ${helpers_1.getInterfaceName(options.refName)}`);
95
+ }
96
+ descriptionLines.push('');
97
+ enumNames.forEach((name, index) => {
98
+ const value = object.enum[index];
99
+ if (needEnumNamesDescription) {
100
+ descriptionLines.push(`\`${value}\` — ${name}`);
101
+ }
102
+ });
103
+ }
104
+ if (isNumericEnum && options.needEnumNamesConstant) {
105
+ const enumName = getEnumNamesIdentifier(`${options.objectParentName || ''} ${object.name}`);
106
+ const codeBlock = generateEnumConstantObject(object, enumName, enumNames);
107
+ codeBlocks.push(codeBlock);
108
+ }
109
+ }
110
+ const values = object.enum.map((value) => utils_1.quoteJavaScriptValue(value));
111
+ return {
112
+ codeBlocks,
113
+ imports: {},
114
+ value: helpers_1.joinOneOfValues(values, true),
115
+ description: descriptionLines.join(constants_1.newLineChar),
116
+ };
117
+ }
118
+ exports.generateInlineEnum = generateInlineEnum;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeMethodInfo = void 0;
4
+ const constants_1 = require("../constants");
5
+ const helpers_1 = require("../helpers");
6
+ const types_1 = require("../types");
7
+ /**
8
+ * Patches for method definition
9
+ */
10
+ function normalizeMethodInfo(method) {
11
+ const parameterRefs = {};
12
+ method.parameters?.forEach((parameter) => {
13
+ // For method params "boolean" type means 1 or 0
14
+ // Real "false" boolean value will be detected by API as true
15
+ if (parameter.type === 'boolean') {
16
+ delete parameter.type;
17
+ parameter.$ref = constants_1.baseBoolIntRef;
18
+ }
19
+ // For parameters of the "array" type, VK API still accepts only a comma-separated string
20
+ // This may change in the future when the VK API starts accepting a json body
21
+ if (parameter.type === 'array') {
22
+ parameter.type = 'string';
23
+ }
24
+ if (!parameter.description) {
25
+ parameter.description = '';
26
+ }
27
+ if (parameter.items && parameter.items.$ref) {
28
+ const ref = parameter.items?.$ref;
29
+ parameterRefs[ref] = types_1.RefsDictionaryType.Generate;
30
+ parameter.description += constants_1.newLineChar.repeat(2) + [
31
+ `@see ${helpers_1.getInterfaceName(helpers_1.getObjectNameByRef(ref))} (${ref})`,
32
+ ].join(constants_1.newLineChar);
33
+ }
34
+ });
35
+ return {
36
+ method,
37
+ parameterRefs,
38
+ };
39
+ }
40
+ exports.normalizeMethodInfo = normalizeMethodInfo;
@@ -1,22 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateTypeString = void 0;
4
- const helpers_1 = require("../helpers");
5
4
  const constants_1 = require("../constants");
6
- const utils_1 = require("../utils");
5
+ const enums_1 = require("./enums");
6
+ const helpers_1 = require("../helpers");
7
7
  const log_1 = require("../log");
8
- const generator_1 = require("../generator");
8
+ const types_1 = require("../types");
9
+ const utils_1 = require("../utils");
9
10
  function generateBaseType(object, options) {
10
11
  let codeBlocks = [];
11
12
  let typeString = 'any /* default type */';
12
13
  let imports = {};
13
14
  let description = '';
14
15
  if (object.enum) {
15
- const { value, codeBlocks: newCodeBlocks, description: newDescription, } = generator_1.generateInlineEnum(object, {
16
+ const { value, codeBlocks: newCodeBlocks, description: newDescription, } = enums_1.generateInlineEnum(object, {
16
17
  // TODO: Refactor
17
18
  // section_object_name -> property_name -> items => section_object_name_property_name_items enumNames
18
19
  objectParentName: options.objectParentName || object.parentObjectName,
19
- skipEnumNamesConstant: options.skipEnumNamesConstant,
20
+ needEnumNamesConstant: options.needEnumNamesConstant,
20
21
  });
21
22
  typeString = value;
22
23
  codeBlocks = newCodeBlocks;
@@ -47,6 +48,10 @@ function generateTypeString(object, objects, options = {}) {
47
48
  let typeString = 'any /* default type */';
48
49
  let imports = {};
49
50
  let description = '';
51
+ options = {
52
+ needEnumNamesConstant: true,
53
+ ...options,
54
+ };
50
55
  if (object.oneOf) {
51
56
  const values = object.oneOf.map((oneOfObject) => {
52
57
  const { value, imports: newImports } = generateTypeString(oneOfObject, objects);
@@ -74,8 +79,8 @@ function generateTypeString(object, objects, options = {}) {
74
79
  if (!refObject) {
75
80
  log_1.consoleLogErrorAndExit(`Error, object for "${refName}" ref is not found.`);
76
81
  }
77
- imports[refName] = true;
78
- typeString = helpers_1.getInterfaceName(refName) + '[]'.repeat(depth);
82
+ imports[refName] = types_1.RefsDictionaryType.GenerateAndImport;
83
+ typeString = helpers_1.formatArrayDepth(helpers_1.getInterfaceName(refName), depth);
79
84
  }
80
85
  else {
81
86
  const { value, description: newDescription, imports: newImports, codeBlocks: newCodeBlocks, } = generateBaseType(items, {
@@ -83,20 +88,12 @@ function generateTypeString(object, objects, options = {}) {
83
88
  // TODO: Refactor
84
89
  objectParentName: object.parentObjectName,
85
90
  });
86
- if (value.endsWith('\'') || value.includes('|')) {
87
- typeString = `Array<${value}>` + '[]'.repeat(depth - 1); // Need decrement depth value because of Array<T> has its own depth
88
- }
89
- else {
90
- typeString = value + '[]'.repeat(depth);
91
- }
91
+ typeString = helpers_1.formatArrayDepth(value, depth);
92
92
  description = newDescription;
93
93
  imports = { ...imports, ...newImports };
94
94
  codeBlocks = [...codeBlocks, ...newCodeBlocks];
95
95
  }
96
96
  }
97
- else if (object.type) {
98
- return generateBaseType(object, options);
99
- }
100
97
  else if (object.ref) {
101
98
  const refName = helpers_1.getObjectNameByRef(object.ref);
102
99
  switch (refName) {
@@ -113,7 +110,7 @@ function generateTypeString(object, objects, options = {}) {
113
110
  log_1.consoleLogErrorAndExit(`Error, object for "${refName}" ref is not found.`);
114
111
  }
115
112
  if (refObject.enum) {
116
- imports[refName] = true;
113
+ imports[refName] = types_1.RefsDictionaryType.GenerateAndImport;
117
114
  typeString = helpers_1.getInterfaceName(refName);
118
115
  }
119
116
  else if (refObject.oneOf) {
@@ -128,12 +125,15 @@ function generateTypeString(object, objects, options = {}) {
128
125
  typeString = constants_1.scalarTypes[refObject.type];
129
126
  }
130
127
  else {
131
- imports[refName] = true;
128
+ imports[refName] = types_1.RefsDictionaryType.GenerateAndImport;
132
129
  typeString = helpers_1.getInterfaceName(refName);
133
130
  }
134
131
  }
135
132
  }
136
133
  }
134
+ else if (object.type) {
135
+ return generateBaseType(object, options);
136
+ }
137
137
  return {
138
138
  codeBlocks,
139
139
  imports,
package/dist/helpers.js CHANGED
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
23
  };
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.resolvePrimitiveTypesArray = exports.joinOneOfValues = exports.transformPatternPropertyName = exports.areQuotesNeededForProperty = exports.isPatternProperty = exports.getSectionFromObjectName = exports.getObjectNameByRef = exports.getEnumPropertyName = exports.getInterfaceName = exports.getMethodSection = exports.isMethodNeeded = exports.prepareMethodsPattern = exports.writeFile = exports.prepareBuildDirectory = exports.readJSONFile = void 0;
25
+ exports.resolvePrimitiveTypesArray = exports.formatArrayDepth = exports.joinOneOfValues = exports.joinCommentLines = exports.transformPatternPropertyName = exports.areQuotesNeededForProperty = exports.isPatternProperty = exports.getSectionFromObjectName = exports.getObjectNameByRef = exports.getEnumPropertyName = exports.getInterfaceName = exports.getMethodSection = exports.isMethodNeeded = exports.prepareMethodsPattern = exports.writeFile = exports.prepareBuildDirectory = exports.readJSONFile = void 0;
26
26
  const fs_1 = __importStar(require("fs"));
27
27
  const path_1 = __importDefault(require("path"));
28
28
  const utils_1 = require("./utils");
@@ -137,6 +137,36 @@ function transformPatternPropertyName(name) {
137
137
  return '[key: string] /* default pattern property name */';
138
138
  }
139
139
  exports.transformPatternPropertyName = transformPatternPropertyName;
140
+ function joinCommentLines(indent = 2, ...description) {
141
+ let descriptionLines = [];
142
+ description.forEach((entry) => {
143
+ if (typeof entry === 'string') {
144
+ descriptionLines = [
145
+ ...descriptionLines,
146
+ ...utils_1.trimArray((entry || '').trim().split(constants_1.newLineChar)),
147
+ ];
148
+ }
149
+ else if (Array.isArray(entry)) {
150
+ descriptionLines = [
151
+ ...descriptionLines,
152
+ ...entry,
153
+ ];
154
+ }
155
+ });
156
+ descriptionLines = utils_1.trimArray(descriptionLines);
157
+ if (!descriptionLines.length) {
158
+ return [];
159
+ }
160
+ const indentSpaces = constants_1.spaceChar.repeat(indent);
161
+ return [
162
+ `${indentSpaces}/**`,
163
+ ...descriptionLines.map((line) => {
164
+ return indentSpaces + ' ' + `* ${line}`.trim();
165
+ }),
166
+ `${indentSpaces} */`,
167
+ ];
168
+ }
169
+ exports.joinCommentLines = joinCommentLines;
140
170
  function joinOneOfValues(values, primitive) {
141
171
  const joined = values.join(' | ');
142
172
  if (joined.length > 120) {
@@ -148,6 +178,15 @@ function joinOneOfValues(values, primitive) {
148
178
  }
149
179
  }
150
180
  exports.joinOneOfValues = joinOneOfValues;
181
+ function formatArrayDepth(value, depth) {
182
+ if (value.endsWith('\'') || value.includes('|')) {
183
+ return `Array<${value}>` + '[]'.repeat(depth - 1); // Need decrement depth value because of Array<T> has its own depth
184
+ }
185
+ else {
186
+ return value + '[]'.repeat(depth);
187
+ }
188
+ }
189
+ exports.formatArrayDepth = formatArrayDepth;
151
190
  function resolvePrimitiveTypesArray(types) {
152
191
  const isEveryTypePrimitive = types.every((type) => !!constants_1.primitiveTypes[type]);
153
192
  if (isEveryTypePrimitive) {
package/dist/log.js CHANGED
@@ -11,7 +11,7 @@ function getInspectArgs(args) {
11
11
  if (typeof arg === 'object') {
12
12
  return util_1.inspect(arg, {
13
13
  showHidden: false,
14
- depth: null,
14
+ depth: 10,
15
15
  colors: true,
16
16
  });
17
17
  }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/types.js CHANGED
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ObjectType = void 0;
3
+ exports.ObjectType = exports.RefsDictionaryType = void 0;
4
+ var RefsDictionaryType;
5
+ (function (RefsDictionaryType) {
6
+ RefsDictionaryType[RefsDictionaryType["GenerateAndImport"] = 0] = "GenerateAndImport";
7
+ RefsDictionaryType[RefsDictionaryType["Generate"] = 1] = "Generate";
8
+ })(RefsDictionaryType = exports.RefsDictionaryType || (exports.RefsDictionaryType = {}));
4
9
  var ObjectType;
5
10
  (function (ObjectType) {
6
11
  ObjectType["Object"] = "object";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/api-schema-typescript-generator",
3
- "version": "0.9.0",
3
+ "version": "0.13.0",
4
4
  "license": "MIT",
5
5
  "description": "VK API TypeScript generator",
6
6
  "author": {
@@ -31,6 +31,7 @@
31
31
  "scripts": {
32
32
  "clear": "rimraf dist/*",
33
33
  "build": "yarn clear && tsc",
34
+ "watch": "yarn clear && tsc --watch",
34
35
  "test": "tsc --noEmit && eslint src --ext .ts"
35
36
  },
36
37
  "pre-commit": [
package/src/generator.ts CHANGED
@@ -1,16 +1,17 @@
1
- import { Dictionary, ObjectType } from './types';
2
- import { quoteJavaScriptValue, sortArrayAlphabetically, uniqueArray } from './utils';
3
1
  import { newLineChar } from './constants';
4
- import { getEnumPropertyName, getInterfaceName, getSectionFromObjectName, joinOneOfValues } from './helpers';
5
- import { CodeBlocksArray, GeneratorResultInterface } from './generators/BaseCodeBlock';
6
- import { TypeCodeBlock, TypeScriptCodeTypes } from './generators/TypeCodeBlock';
7
- import { SchemaObject } from './generators/SchemaObject';
2
+ import { getInterfaceName, getSectionFromObjectName } from './helpers';
3
+ import { Dictionary, ObjectType, RefsDictionary, RefsDictionaryType } from './types';
4
+ import { sortArrayAlphabetically, uniqueArray } from './utils';
8
5
 
9
- export function generateImportsBlock(imports: Dictionary<boolean>, section: string | null, type?: ObjectType): string {
10
- const objectsToImport = uniqueArray(Object.keys(imports));
11
- const paths: Dictionary<string[]> = {};
6
+ export function generateImportsBlock(refs: RefsDictionary, section: string | null, type?: ObjectType): string {
7
+ let importRefs = Object.entries(refs)
8
+ .filter(([, type]) => type === RefsDictionaryType.GenerateAndImport)
9
+ .map(([key]) => key);
10
+
11
+ importRefs = uniqueArray(importRefs);
12
12
 
13
- objectsToImport.forEach((objectName) => {
13
+ const paths: Dictionary<string[]> = {};
14
+ importRefs.forEach((objectName) => {
14
15
  const importSection = getSectionFromObjectName(objectName);
15
16
  const interfaceName = getInterfaceName(objectName);
16
17
  let path;
@@ -40,127 +41,3 @@ export function generateImportsBlock(imports: Dictionary<boolean>, section: stri
40
41
 
41
42
  return importLines.join(newLineChar);
42
43
  }
43
-
44
- function getEnumNames(object: SchemaObject) {
45
- let { enumNames } = object;
46
-
47
- const needEnumNamesDescription = !!enumNames;
48
-
49
- if (!enumNames) {
50
- const canUseEnumNames = !object.enum.some((value) => !!+value);
51
- if (canUseEnumNames) {
52
- enumNames = [...object.enum];
53
- }
54
- }
55
-
56
- return {
57
- needEnumNamesDescription,
58
- enumNames: Array.isArray(enumNames) && enumNames.length ? enumNames : undefined,
59
- };
60
- }
61
-
62
- interface GenerateInlineEnumOptions {
63
- objectParentName?: string;
64
- skipEnumNamesConstant?: boolean;
65
- }
66
-
67
- export function generateInlineEnum(object: SchemaObject, options: GenerateInlineEnumOptions = {}): GeneratorResultInterface {
68
- const {
69
- enumNames,
70
- needEnumNamesDescription,
71
- } = getEnumNames(object);
72
-
73
- const codeBlocks: CodeBlocksArray = [];
74
- let descriptionLines: string[] = [];
75
-
76
- if (enumNames) {
77
- const enumName = options.objectParentName ? `${options.objectParentName} ${object.name} enumNames` : object.name;
78
- const enumInterfaceName = getInterfaceName(enumName);
79
-
80
- const codeBlock = new TypeCodeBlock({
81
- type: TypeScriptCodeTypes.ConstantObject,
82
- refName: enumName,
83
- interfaceName: enumInterfaceName,
84
- needExport: true,
85
- properties: [],
86
- });
87
-
88
- if (needEnumNamesDescription) {
89
- descriptionLines.push('');
90
- }
91
-
92
- enumNames.forEach((name, index) => {
93
- const value = object.enum[index];
94
-
95
- codeBlock.addProperty({
96
- name: getEnumPropertyName(name.toString()),
97
- value,
98
- wrapValue: true,
99
- });
100
-
101
- if (needEnumNamesDescription) {
102
- descriptionLines.push(`\`${value}\` — ${name}`);
103
- }
104
- });
105
-
106
- if (!options.skipEnumNamesConstant) {
107
- codeBlocks.push(codeBlock);
108
- }
109
- }
110
-
111
- const values = object.enum.map((value) => quoteJavaScriptValue(value));
112
-
113
- return {
114
- codeBlocks,
115
- imports: {},
116
- value: joinOneOfValues(values, true),
117
- description: descriptionLines.join(newLineChar),
118
- };
119
- }
120
-
121
- interface GenerateStandaloneEnumOptions {
122
- objectParentName?: string;
123
- }
124
-
125
- export function generateStandaloneEnum(object: SchemaObject, options: GenerateStandaloneEnumOptions = {}): GeneratorResultInterface {
126
- const {
127
- enumNames,
128
- } = getEnumNames(object);
129
-
130
- if (enumNames) {
131
- const enumName = options.objectParentName ? `${options.objectParentName} ${object.name} enum` : object.name;
132
- const enumInterfaceName = getInterfaceName(enumName);
133
-
134
- const codeBlock = new TypeCodeBlock({
135
- type: TypeScriptCodeTypes.Enum,
136
- refName: enumName,
137
- interfaceName: enumInterfaceName,
138
- needExport: true,
139
- properties: [],
140
- });
141
-
142
- enumNames.forEach((name, index) => {
143
- codeBlock.addProperty({
144
- name: getEnumPropertyName(name.toString()),
145
- value: object.enum[index],
146
- wrapValue: true,
147
- });
148
- });
149
-
150
- return {
151
- codeBlocks: [
152
- codeBlock,
153
- ],
154
- imports: {},
155
- value: enumInterfaceName,
156
- };
157
- } else {
158
- const values = object.enum.map((value) => quoteJavaScriptValue(value));
159
-
160
- return {
161
- codeBlocks: [],
162
- imports: {},
163
- value: joinOneOfValues(values, true),
164
- };
165
- }
166
- }