@vkontakte/api-schema-typescript-generator
Version:
VK API TypeScript generator
202 lines (166 loc) • 5.61 kB
text/typescript
import fs, { promises as fsPromises } from 'fs';
import path from 'path';
import { capitalizeFirstLetter, trimArray } from './utils';
import { newLineChar, primitiveTypes, spaceChar } from './constants';
import { Dictionary } from './types';
import { consoleLogErrorAndExit } from './log';
import prettier from 'prettier';
export async function readJSONFile(path: string): Promise<any> {
const content = await fsPromises.readFile(path, 'utf-8');
return JSON.parse(content);
}
function deleteDirectoryRecursive(directoryPath: string) {
if (fs.existsSync(directoryPath)) {
fs.readdirSync(directoryPath).forEach((file) => {
const currentPath = path.join(directoryPath, file);
if (fs.lstatSync(currentPath).isDirectory()) {
deleteDirectoryRecursive(currentPath);
} else {
fs.unlinkSync(currentPath);
}
});
fs.rmdirSync(directoryPath);
}
}
export function prepareBuildDirectory(directoryPath: string) {
deleteDirectoryRecursive(directoryPath);
fs.mkdirSync(directoryPath, { recursive: true });
}
export function writeFile(filePath: string, code: string, insertAutoGeneratedNote = true) {
if (insertAutoGeneratedNote) {
code =
[
'/**',
" * This is auto-generated file, don't modify this file manually",
' */',
// '/* eslint-disable max-len */',
// '/* eslint-disable @typescript-eslint/no-empty-interface */',
].join(newLineChar) +
newLineChar.repeat(2) +
code.trim();
}
code = prettier.format(code, {
semi: true,
singleQuote: true,
trailingComma: 'all',
quoteProps: 'consistent',
parser: 'typescript',
});
fs.mkdirSync(filePath.replace(path.basename(filePath), ''), {
recursive: true,
});
fs.writeFileSync(filePath, code.trim() + newLineChar);
}
export function prepareMethodsPattern(methodsPattern: string): Dictionary<boolean> {
if (!methodsPattern) {
consoleLogErrorAndExit('methodsPattern is empty. Pass "*" to generate all methods');
}
return methodsPattern
.replace(/\s+/g, '')
.split(',')
.reduce<Dictionary<boolean>>((acc, pattern) => {
acc[pattern] = true;
return acc;
}, {});
}
export function isMethodNeeded(methodsPattern: Dictionary<boolean>, method: string): boolean {
const [methodSection, methodName] = method.split('.');
return Object.keys(methodsPattern).some((pattern) => {
const [patternSection, patternMethod] = pattern.split('.');
if (patternSection === '*') {
return true;
}
if (patternSection === methodSection) {
return patternMethod === '*' || patternMethod === methodName;
}
return false;
});
}
export function getMethodSection(methodName: string): string {
return methodName.split('.')[0];
}
export function getInterfaceName(name: string): string {
name = name
.replace(/\.|(\s+)|_/g, ' ')
.split(' ')
.map((v) => capitalizeFirstLetter(v))
.join('');
return capitalizeFirstLetter(name);
}
export function getEnumPropertyName(name: string): string {
return name.toUpperCase().replace(/\s+/g, '_').replace(/-/g, '_').replace(/\./g, '_');
}
export function getObjectNameByRef(ref: string): string {
const parts = ref.split('/');
return parts[parts.length - 1];
}
export function getSectionFromObjectName(name: string): string {
return name.split('_')[0];
}
export function isPatternProperty(name: string): boolean {
return name.startsWith('[key: ');
}
export function areQuotesNeededForProperty(name: string | number): boolean {
name = String(name);
if (isPatternProperty(name)) {
return false;
}
if (/[&-]/.test(name)) {
return true;
}
return !(/^[a-z_]([a-z0-9_])+$/i.test(name) || /^[a-z_]/i.test(name));
}
export function transformPatternPropertyName(name: string): string {
if (name === '^[0-9]+$') {
return '[key: number]';
}
return '[key: string] /* default pattern property name */';
}
export function joinCommentLines(indent = 2, ...description: Array<string | string[]>): string[] {
let descriptionLines: string[] = [];
description.forEach((entry) => {
if (typeof entry === 'string') {
descriptionLines = [
...descriptionLines,
...trimArray((entry || '').trim().split(newLineChar)),
];
} else if (Array.isArray(entry)) {
descriptionLines = [...descriptionLines, ...entry];
}
});
descriptionLines = trimArray(descriptionLines);
if (!descriptionLines.length) {
return [];
}
const indentSpaces = spaceChar.repeat(indent);
return [
`${indentSpaces}/**`,
...descriptionLines.map((line) => {
return indentSpaces + ' ' + `* ${line}`.trim();
}),
`${indentSpaces} */`,
];
}
export function joinOneOfValues(values: Array<string | number>, primitive?: boolean) {
const joined = values.join(' | ');
if (joined.length > 120) {
const spacesCount = primitive ? 2 : 4;
return values.join(` |${newLineChar}${spaceChar.repeat(spacesCount)}`);
} else {
return joined;
}
}
export function formatArrayDepth(value: string, depth: number) {
if (value.endsWith("'") || value.includes('|')) {
return `Array<${value}>` + '[]'.repeat(depth - 1); // Need decrement depth value because of Array<T> has its own depth
} else {
return value + '[]'.repeat(depth);
}
}
export function resolvePrimitiveTypesArray(types: string[]): string | null {
const isEveryTypePrimitive = types.every((type) => !!primitiveTypes[type]);
if (isEveryTypePrimitive) {
return types.map((type) => primitiveTypes[type]).join(' | ');
}
return null;
}