nope/lib/helpers/generateTemplate.ts

120 lines
4.7 KiB
TypeScript

import { SourceFile } from "ts-morph";
import { createFileMapping, analyzeClasses, getDeclarationByName } from "./analyzeTypescriptFiles";
/**
* Function, that will create the imported Type classes based on source-Files.
* @param sourceFiles
* @param options Options, to Controll the generation.
*/
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'
}){
const fileMapping = createFileMapping(sourceFiles);
const classes = analyzeClasses(sourceFiles, options);
// 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, ''
);
} else if (mappingTypeToImport[reqType].size > 1) {
// Multiple Items are using the Same Name.
}
}
console.log(fileWithTypesForClass)
}
}