nope/lib/helpers/generateSchemas.ts

215 lines
5.6 KiB
TypeScript
Raw Normal View History

2020-11-06 08:10:30 +00:00
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2020-11-06 08:53:40
* @modify date 2020-11-06 08:53:41
* @desc [description]
*/
2020-08-24 11:35:32 +00:00
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';
2020-08-24 11:35:32 +00:00
import { IJsonSchema } from "../../types/IJSONSchema";
import { analyzeFiles, defaultClassFilter, defaultFunctionFilter, defaultPropFilter } from "./analyzeTypescriptFiles";
2020-08-25 22:11:26 +00:00
import { createFile, createPath } from "./fileMethods";
import { flattenSchema } from "./jsonSchemaMethods";
2020-08-24 11:35:32 +00:00
/**
* Generate the Client Templates.
* @param options
*/
export async function generateSchemas(options: {
2020-09-07 21:23:46 +00:00
pathToClassSchemaTemplate: string,
pathToFunctionSchemaTemplate: string,
2020-08-24 11:35:32 +00:00
tempDir: string,
inputDir: string,
tsConfigFilePath: string,
logger?: Logger,
2020-08-24 11:35:32 +00:00
}) {
// 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({
2020-09-07 21:23:46 +00:00
functionDecorator: 'exportFunctionToOpenAPI'
}),
2020-08-24 11:35:32 +00:00
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.
2020-09-07 21:23:46 +00:00
const classSchemaTemplate = await readFile(options.pathToClassSchemaTemplate, {
2020-08-24 11:35:32 +00:00
encoding: 'utf-8'
})
// Renderfuncting
2020-09-07 21:23:46 +00:00
const renderClassSchema = handlebars.compile(classSchemaTemplate);
2020-08-24 11:35:32 +00:00
// Generate the Files.
2020-09-07 21:23:46 +00:00
const classFiles: {
2020-08-24 11:35:32 +00:00
className: string,
name: string,
content: string,
}[] = result.classes.map(item => {
2020-08-24 11:35:32 +00:00
return {
className: item.className,
name: item.className + 'Schema',
2020-09-07 21:23:46 +00:00
content: renderClassSchema(item)
2020-08-24 11:35:32 +00:00
}
});
2020-09-07 21:23:46 +00:00
// load the File.
const classFunctionTemplate = await readFile(options.pathToFunctionSchemaTemplate, {
encoding: 'utf-8'
})
// Renderfuncting
const renderFunctionSchema = handlebars.compile(classFunctionTemplate);
// Generate the Files.
const functionFiles: {
name: string,
content: string,
className: string,
}[] = result.functions.map(item => {
return {
className: item.name,
name: item.name + 'Schema',
content: renderFunctionSchema(item)
}
});
2020-09-07 21:23:46 +00:00
for (const file of classFiles) {
// Generate the Path.
const fileName = join(options.tempDir, 'classes', file.name + '.ts');
2020-08-24 11:35:32 +00:00
await createFile(
fileName,
2020-08-24 11:35:32 +00:00
file.content
);
if (options.logger) {
options.logger.info('Generated -> ' + fileName);
}
2020-08-24 11:35:32 +00:00
}
2020-09-07 21:23:46 +00:00
for (const file of functionFiles) {
// Generate the Path.
const fileName = join(options.tempDir, 'functions', file.name + '.ts');
await createFile(
fileName,
file.content
);
if (options.logger) {
options.logger.info('Generated -> ' + fileName);
}
}
2020-08-24 11:35:32 +00:00
// After all files has been written => Generate the Schemas:
const _settings: TJS.PartialArgs = {
required: true,
2020-08-24 11:35:32 +00:00
};
// Options for the TJS.Compiler;
const compilerOptions: TJS.CompilerOptions = {
strictNullChecks: true,
skipLibCheck: true
};
const schemaMapping: { [index: string]: IJsonSchema } = {};
2020-09-07 21:23:46 +00:00
for (const file of classFiles) {
2020-08-24 11:35:32 +00:00
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)
2020-08-24 11:35:32 +00:00
// Receive the Element
schemaMapping[file.className] = _flattendSchema;
// Generate the Path.
const fileName = join(options.tempDir, 'schema', file.name + '.json')
2020-08-24 11:35:32 +00:00
// Write down the Schema:
await createFile(
fileName,
JSON.stringify(_flattendSchema, undefined, 4)
2020-08-24 11:35:32 +00:00
);
if (options.logger) {
options.logger.info('Generated -> ' + fileName);
}
2020-08-24 11:35:32 +00:00
}
2020-09-07 21:23:46 +00:00
for (const file of functionFiles) {
const _program = TJS.getProgramFromFiles(
[join(options.tempDir, 'functions', 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);
}
}
2020-08-24 21:15:26 +00:00
return {
schemaMapping,
analysis: result
};
2020-08-24 11:35:32 +00:00
}