creating functionality to write the results into files.
This commit is contained in:
parent
2926dcf46a
commit
5418c837d3
@ -37,6 +37,7 @@ export type MethodInformation = {
|
||||
isImplementation: boolean;
|
||||
returnType: TypeInformation;
|
||||
head: string;
|
||||
authorDescription: string;
|
||||
}
|
||||
|
||||
export type DecoratorInformation = {
|
||||
@ -46,6 +47,25 @@ export type DecoratorInformation = {
|
||||
decoratorSettings: { [index: string]: { [index: string]: any }}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for the Analyzing Result
|
||||
*/
|
||||
export interface IAnalyzeResult {
|
||||
// Name of the Class
|
||||
className: string,
|
||||
// Decorators of the Class
|
||||
classDecorator: DecoratorInformation,
|
||||
// Methods of the Class
|
||||
methods: (MethodInformation & DecoratorInformation)[],
|
||||
// Properties of the Class
|
||||
properties: (PropertyInformation & DecoratorInformation)[],
|
||||
// Imports of the Class (contians external Files)
|
||||
imports: {
|
||||
content: string,
|
||||
required: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
export type PropertyInformation = ModifierInformation & TypeInformation & { name: string; declaration: PropertyDeclaration; };
|
||||
|
||||
/**
|
||||
@ -363,7 +383,12 @@ export function getDescription(declaration: PropertyDeclaration | InterfaceDecla
|
||||
|
||||
// Use the Regex to remove the Imports from the Head
|
||||
const regex = /import\(.+?\)./g
|
||||
const head = declaration.getType().getText().replace(regex, '');
|
||||
// Define the Head
|
||||
let head = declaration.getType().getText().replace(regex, '');
|
||||
head = head.slice(0, head.length - ('=> '+ returnType.simplifiedType).length)
|
||||
|
||||
// Extract the Description of the Author.
|
||||
const authorDescription = declaration.getLeadingCommentRanges().map(comment => comment.getText()).join('\n');
|
||||
|
||||
return {
|
||||
declaration,
|
||||
@ -374,7 +399,8 @@ export function getDescription(declaration: PropertyDeclaration | InterfaceDecla
|
||||
isAsync,
|
||||
isGenerator,
|
||||
isImplementation,
|
||||
returnType
|
||||
returnType,
|
||||
authorDescription
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -717,25 +743,6 @@ export function getDeclarationByName(files: { [index: string]: SourceFile }, fil
|
||||
throw Error('Declaration "' + filePath + '" not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for the Analyzing Result
|
||||
*/
|
||||
export interface IAnalyzeResult {
|
||||
// Name of the Class
|
||||
className: string,
|
||||
// Decorators of the Class
|
||||
classDecorator: DecoratorInformation,
|
||||
// Methods of the Class
|
||||
methods: (MethodInformation & DecoratorInformation)[],
|
||||
// Properties of the Class
|
||||
properties: (PropertyInformation & DecoratorInformation)[],
|
||||
// Imports of the Class (contians external Files)
|
||||
imports: {
|
||||
content: string,
|
||||
required: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function, that will create the imported Type classes based on source-Files.
|
||||
* @param sourceFiles
|
||||
|
@ -1,120 +1,74 @@
|
||||
import { SourceFile } from "ts-morph";
|
||||
import { createFileMapping, analyzeClasses, getDeclarationByName } from "./analyzeTypescriptFiles";
|
||||
import { Project } from "ts-morph";
|
||||
import { analyzeFiles } from "./analyzeTypescriptFiles";
|
||||
import * as handlebars from 'handlebars';
|
||||
import { readFile, copyFile } from "fs/promises";
|
||||
import { join } from 'path';
|
||||
import { createFile, createPath } from "./fileHelpers";
|
||||
|
||||
/**
|
||||
* Function, that will create the imported Type classes based on source-Files.
|
||||
* @param sourceFiles
|
||||
* @param options Options, to Controll the generation.
|
||||
* Generate the Client Templates.
|
||||
* @param options
|
||||
*/
|
||||
export function transformClasses(sourceFiles: SourceFile[], options: {
|
||||
classDecorator: string,
|
||||
classInterface: string,
|
||||
methodDecorator: string,
|
||||
propertyType: string,
|
||||
propertyDecorator: string,
|
||||
} = {
|
||||
classDecorator: 'exportsElementsToDispatcher',
|
||||
classInterface: '',
|
||||
methodDecorator: 'exportMethodToDispatcher',
|
||||
propertyType: 'nopeObservable',
|
||||
propertyDecorator: 'exportPropertyToDispatcher'
|
||||
export async function generateClientTemplate(options: {
|
||||
pathToTemplate: string,
|
||||
outputDir: string,
|
||||
inputDir: string,
|
||||
tsConfigFilePath: string,
|
||||
}) {
|
||||
const fileMapping = createFileMapping(sourceFiles);
|
||||
const classes = analyzeClasses(sourceFiles, options);
|
||||
|
||||
// Create the Output dir (if it doenst exists)
|
||||
await createPath(options.outputDir);
|
||||
|
||||
|
||||
// Iterate over the Classes
|
||||
for (const relevantClass of classes){
|
||||
|
||||
const requiredImports = new Set<string>();
|
||||
const mappingTypeToImport: {
|
||||
[index: string]: Set<string>
|
||||
} = {}
|
||||
|
||||
// Iterate over the Properties
|
||||
for (const prop of relevantClass.properties){
|
||||
if (!prop.isBaseType){
|
||||
for (const {identifier: type, path} of (prop.typeImports || [])){
|
||||
|
||||
// Only if the import isnt the Base Type, add it to the List.
|
||||
if (type !== options.propertyType) {
|
||||
// Check if the Imported Type has been Adden multiple Times.
|
||||
if (mappingTypeToImport[type] === undefined) {
|
||||
mappingTypeToImport[type] = new Set<string>();
|
||||
}
|
||||
|
||||
mappingTypeToImport[type].add(path);
|
||||
requiredImports.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the Methods
|
||||
for (const method of relevantClass.methods){
|
||||
if (!method.returnType.isBaseType) {
|
||||
for (const {identifier, path} of (method.returnType.typeImports || [])){
|
||||
|
||||
// Only if the import isnt the Base Type, add it to the List.
|
||||
if (identifier !== options.propertyType) {
|
||||
// Check if the Imported Type has been Adden multiple Times.
|
||||
if (mappingTypeToImport[identifier] === undefined) {
|
||||
mappingTypeToImport[identifier] = new Set<string>();
|
||||
}
|
||||
|
||||
mappingTypeToImport[identifier].add(path);
|
||||
requiredImports.add(identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const parm of method.params){
|
||||
if (!parm.isBaseType){
|
||||
for (const {identifier, path} of (parm.typeImports || [])){
|
||||
|
||||
// Only if the import isnt the Base Type, add it to the List.
|
||||
if (identifier !== options.propertyType) {
|
||||
// Check if the Imported Type has been Adden multiple Times.
|
||||
if (mappingTypeToImport[identifier] === undefined) {
|
||||
mappingTypeToImport[identifier] = new Set<string>();
|
||||
}
|
||||
|
||||
mappingTypeToImport[identifier].add(path);
|
||||
requiredImports.add(identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fileWithTypesForClass = `// Automatic extracted Interfaces for the Class "` + relevantClass.className + `"\n// Generated on: ` + (new Date()).toISOString();
|
||||
|
||||
// List containing the already used Types
|
||||
const importedBaseTypes = new Set<string>();
|
||||
|
||||
// Iterate over the Imports
|
||||
for (const reqType of requiredImports) {
|
||||
if (mappingTypeToImport[reqType] && mappingTypeToImport[reqType].size === 1) {
|
||||
// Extract the Path of the File
|
||||
const pathToFile = Array.from(mappingTypeToImport[reqType].values())[0] + '.ts';
|
||||
|
||||
const declarations = getDeclarationByName(fileMapping, pathToFile, reqType).filter(item => !importedBaseTypes.has(item.baseType));
|
||||
declarations.map(item => importedBaseTypes.add(item.baseType));
|
||||
|
||||
fileWithTypesForClass += declarations.map(item =>
|
||||
item.originalCode
|
||||
).reduce(
|
||||
(prev, current, idx) => prev + '\n\n' + current, ''
|
||||
// Firstly copy the nopeDispatcher
|
||||
await copyFile(
|
||||
join(__dirname,'..','..','..','lib','dispatcher','nopeDispatcher.ts'),
|
||||
join(options.outputDir,'nopeDispatcher.ts')
|
||||
);
|
||||
|
||||
} else if (mappingTypeToImport[reqType].size > 1) {
|
||||
// Multiple Items are using the Same Name.
|
||||
// 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);
|
||||
|
||||
// load the File.
|
||||
const template = await readFile(options.pathToTemplate, {
|
||||
encoding: 'utf-8'
|
||||
})
|
||||
|
||||
// Renderfuncting
|
||||
const render = handlebars.compile(template);
|
||||
|
||||
// Generate the Files.
|
||||
const files: {
|
||||
name: string,
|
||||
content: string,
|
||||
}[] = result.map(item => {
|
||||
|
||||
item.className = item.className + 'ClientInterface'
|
||||
|
||||
return {
|
||||
name: item.className + '.ts',
|
||||
content: render(item)
|
||||
}
|
||||
});
|
||||
|
||||
for (const file of files){
|
||||
await createFile(
|
||||
// Generate the Path.
|
||||
join(options.outputDir,'clients',file.name),
|
||||
file.content
|
||||
)
|
||||
}
|
||||
|
||||
console.log(fileWithTypesForClass)
|
||||
}
|
||||
|
||||
|
||||
// Compile the Template and parse the Code.
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue
Block a user