nope/lib/helpers/generateSchemas.ts
2020-09-07 20:12:19 +02:00

144 lines
3.8 KiB
TypeScript

import { readFile } from "fs/promises";
import * as handlebars from 'handlebars';
import { join } from 'path';
import { Project } from "ts-morph";
import * as TJS from "typescript-json-schema";
import { Logger } from 'winston';
import { IJsonSchema } from "../../types/IJSONSchema";
import { analyzeFiles, defaultClassFilter, defaultFunctionFilter, defaultPropFilter } from "./analyzeTypescriptFiles";
import { createFile, createPath } from "./fileMethods";
import { flattenSchema } from "./jsonSchemaMethods";
/**
* Generate the Client Templates.
* @param options
*/
export async function generateSchemas(options: {
pathToSchemaTemplate: string,
tempDir: string,
inputDir: string,
tsConfigFilePath: string,
logger?: Logger,
}) {
// Create the Output dir (if it doenst exists)
await createPath(options.tempDir);
// Function to Determine new project files.
const project = new Project({
tsConfigFilePath: options.tsConfigFilePath,
addFilesFromTsConfig: false,
});
project.addSourceFilesAtPaths(options.inputDir);
// Readin the Source-Files.
const sourceFiles = project.getSourceFiles();
// Generate the Files
const result = analyzeFiles(sourceFiles, {
classDecorator: 'exportsElementsToOpenAPI',
methodDecorator: 'exportMethodToOpenAPI',
propertyDecorator: 'exportPropertyToOpenAPI',
filterClasses: defaultClassFilter({
classDecorator: 'exportsElementsToOpenAPI',
classInterface: ''
}),
filterFunctions: defaultFunctionFilter({
functionDecorator: 'TODO'
}),
filterMethods: (cl, method) => {
return method.isImplementation && method.isAsync && method.params.filter(param => param.baseType === 'function').length === 0
},
filterProperties: defaultPropFilter({
propertyDecorator: 'exportPropertyToDispatcher',
propertyType: 'nopeObservable'
}),
checkImport: type => type !== 'nopeObservable'
}
);
// load the File.
const schemaTemplate = await readFile(options.pathToSchemaTemplate, {
encoding: 'utf-8'
})
// Renderfuncting
const renderSchema = handlebars.compile(schemaTemplate);
// Generate the Files.
const files: {
className: string,
name: string,
content: string,
}[] = result.classes.map(item => {
return {
className: item.className,
name: item.className + 'Schema',
content: renderSchema(item)
}
});
for (const file of files) {
// Generate the Path.
const fileName = join(options.tempDir, 'classes', file.name + '.ts');
await createFile(
fileName,
file.content
);
if (options.logger) {
options.logger.info('Generated -> ' + fileName);
}
}
// After all files has been written => Generate the Schemas:
const _settings: TJS.PartialArgs = {
required: true,
};
// Options for the TJS.Compiler;
const compilerOptions: TJS.CompilerOptions = {
strictNullChecks: true,
skipLibCheck: true
};
const schemaMapping: { [index: string]: IJsonSchema } = {};
for (const file of files) {
const _program = TJS.getProgramFromFiles(
[join(options.tempDir, 'classes', file.name + '.ts')],
compilerOptions
);
// We can either get the schema for one file and one type...
const _schema = TJS.generateSchema(_program, "*", _settings);
// Flatten the Schema.
const _flattendSchema = flattenSchema(_schema as any)
// Receive the Element
schemaMapping[file.className] = _flattendSchema;
// Generate the Path.
const fileName = join(options.tempDir, 'schema', file.name + '.json')
// Write down the Schema:
await createFile(
fileName,
JSON.stringify(_flattendSchema, undefined, 4)
);
if (options.logger) {
options.logger.info('Generated -> ' + fileName);
}
}
return {
schemaMapping,
analysis: result
};
}