Fixing creation of functions

This commit is contained in:
Martin Karkowski 2020-09-08 10:46:52 +02:00
parent a54625e53a
commit 87311beab9
10 changed files with 2703 additions and 758 deletions

View File

@ -3,14 +3,14 @@ set DIR=%~dp0
cd "%DIR%" cd "%DIR%"
SETLOCAL SETLOCAL
echo Compiling Backend echo Compiling Backend
(npx tsc -p ./tsconfigBackend.json --noEmit --pretty) && ( (npx tsc -p ./tsconfigBackend.json --pretty) && (
echo Generating API-Interface echo Generating API-Interface
@echo on @echo on
node ./dist/lib/cli/generateFiles node ./dist/lib/cli/generateFiles
echo Generating API-Interface echo Generating API-Interface
@echo off @echo off
echo Compiling FrontendFiles echo Compiling FrontendFiles
(npx tsc -p ./tsconfigBackend.json --noEmit --pretty) && ( (npx tsc -p ./tsconfigBackend.json --pretty) && (
echo Done echo Done
) || ( ) || (
echo Done echo Done
@ -22,7 +22,7 @@ echo Compiling Backend
echo Generating API-Interface echo Generating API-Interface
@echo off @echo off
echo Compiling FrontendFiles echo Compiling FrontendFiles
(npx tsc -p ./tsconfigBackend.json --noEmit --pretty) && ( (npx tsc -p ./tsconfigBackend.json --pretty) && (
echo Done echo Done
) || ( ) || (
echo Done echo Done

View File

@ -11,8 +11,9 @@ import { createFile, createPath } from "./fileMethods";
* @param options * @param options
*/ */
export async function generateClientTemplate(options: { export async function generateClientTemplate(options: {
pathToClientTemplate: string, pathToClassInterfaceTemplate: string,
pathToInterfaceTemplate: string, pathToFunctionInterfaceTemplate: string,
pathToBackendInterfaceTemplate: string,
outputDir: string, outputDir: string,
inputDir: string, inputDir: string,
tsConfigFilePath: string, tsConfigFilePath: string,
@ -20,11 +21,13 @@ export async function generateClientTemplate(options: {
logger?: Logger logger?: Logger
}) { }) {
// If there is a Logger Show a hint of the folders.
if (options.logger) { if (options.logger) {
options.logger.info('Templates will be stored in ' + options.outputDir); options.logger.info('Templates will be stored in ' + options.outputDir);
} }
// Define an Array containing elements that should be copied
// Copying the stuff is relevant for
const filesToCopy: { const filesToCopy: {
src: string[], src: string[],
name: string, name: string,
@ -35,11 +38,6 @@ export async function generateClientTemplate(options: {
path: ['dispatcher'], path: ['dispatcher'],
src: ['lib', 'dispatcher'] src: ['lib', 'dispatcher']
}, },
// {
// name: 'nopeObservable.ts',
// path: ['observables'],
// src: ['lib', 'observables']
// },
{ {
name: 'nopeRemoteObservable.ts', name: 'nopeRemoteObservable.ts',
path: ['observables'], path: ['observables'],
@ -47,6 +45,7 @@ export async function generateClientTemplate(options: {
} }
]; ];
// Copy the Files.
for (const file of filesToCopy) { for (const file of filesToCopy) {
// Create the Output dir (if it doenst exists) // Create the Output dir (if it doenst exists)
await createPath(join(options.outputDir, ...file.path)); await createPath(join(options.outputDir, ...file.path));
@ -58,7 +57,7 @@ export async function generateClientTemplate(options: {
); );
if (options.logger) { if (options.logger) {
options.logger.info('Copied -> ' + file.name); options.logger.info('Copied -> ' + join(options.outputDir, ...file.path, file.name));
} }
} }
@ -68,6 +67,7 @@ export async function generateClientTemplate(options: {
addFilesFromTsConfig: false, addFilesFromTsConfig: false,
}); });
// Readin the Sources of the Dir.
project.addSourceFilesAtPaths(options.inputDir); project.addSourceFilesAtPaths(options.inputDir);
// Readin the Source-Files. // Readin the Source-Files.
@ -76,25 +76,14 @@ export async function generateClientTemplate(options: {
// Generate the Files // Generate the Files
const result = analyzeFiles(sourceFiles); const result = analyzeFiles(sourceFiles);
// load the File. // Enrich the Information.
const clientTemplate = await readFile(options.pathToClientTemplate, { result.classes = result.classes.map(item => {
encoding: 'utf-8'
})
// Renderfuncting
const renderClient = handlebars.compile(clientTemplate);
// Generate the Files.
const files: {
name: string,
content: string,
}[] = result.classes.map(item => {
// Extract the Class uri // Extract the Class uri
const classUri = item.classDecorator.decoratorSettings.exportsElementsToDispatcher ? item.classDecorator.decoratorSettings.exportsElementsToDispatcher.uri || item.className : item.className; const classUri = item.classDecorator.decoratorSettings.exportsElementsToDispatcher ? item.classDecorator.decoratorSettings.exportsElementsToDispatcher.uri || item.className : item.className;
(item as any).orginalName = item.className; (item as any).orginalName = item.className;
item.className = item.className + 'ClientInterface'; (item as any).fileName = item.className + '_ClientInterface';
item.className = item.className + '_ClientInterface';
item.methods = item.methods.map(m => { item.methods = item.methods.map(m => {
const methodUri = m.decoratorSettings.exportMethodToDispatcher ? m.decoratorSettings.exportMethodToDispatcher.uri || m.name : m.name; const methodUri = m.decoratorSettings.exportMethodToDispatcher ? m.decoratorSettings.exportMethodToDispatcher.uri || m.name : m.name;
@ -113,14 +102,56 @@ export async function generateClientTemplate(options: {
return p; return p;
}); });
return item;
});
result.functions = result.functions.map(item => {
// Adding a generatorName
(item as any).generatorName = 'generate_' + item.name + '_Accessor';
(item as any).orginalName = item.name;
(item as any).fileName = item.name + '_ClientInterface';
return item;
});
// load the File.
const clientTemplate = await readFile(options.pathToClassInterfaceTemplate, {
encoding: 'utf-8'
})
// Renderfuncting
const renderClientInterface = handlebars.compile(clientTemplate);
// Generate the Files.
const classFiles: {
name: string,
content: string,
}[] = result.classes.map(item => {
return { return {
name: item.className + '.ts', name: (item as any).fileName + '.ts',
content: renderClient(item) content: renderClientInterface(item)
} }
}); });
// load the File. // load the File.
const interfaceTemplate = await readFile(options.pathToInterfaceTemplate, { const functionTemplate = await readFile(options.pathToFunctionInterfaceTemplate, {
encoding: 'utf-8'
})
// Renderfuncting
const renderFunctionInterface = handlebars.compile(functionTemplate);
const functionFiles: {
name: string,
content: string,
}[] = result.functions.map(func => {
return {
name: (func as any).fileName + '.ts',
content: renderFunctionInterface(func)
}
});
// load the File.
const interfaceTemplate = await readFile(options.pathToBackendInterfaceTemplate, {
encoding: 'utf-8' encoding: 'utf-8'
}) })
@ -130,25 +161,56 @@ export async function generateClientTemplate(options: {
await createFile( await createFile(
// Generate the Path. // Generate the Path.
join(options.outputDir, 'BackendInterface.ts'), join(options.outputDir, 'BackendInterface.ts'),
renderInterface({ classes: result }) renderInterface(result)
); );
if (options.logger) { if (options.logger) {
options.logger.info('Generated -> BackendInterface.ts'); options.logger.info('Generated -> ' + join(options.outputDir, 'BackendInterface.ts'));
} }
for (const file of files) { for (const file of classFiles) {
// Define the File Name: // Define the File Name:
const fileName = join(options.outputDir, 'clients', file.name); const fileName = join(options.outputDir, 'clients', file.name);
await createFile( await createFile(
// Generate the Path. // Generate the Path.
join(options.outputDir, 'clients', file.name), fileName,
file.content file.content
); );
if (options.logger) { if (options.logger) {
options.logger.info('Generated -> ' + join('clients', fileName)); options.logger.info('Generated -> ' + fileName);
}
// Function to Determine new project files.
const project = new Project({
tsConfigFilePath: options.tsConfigFilePath,
addFilesFromTsConfig: false,
});
project.addSourceFileAtPath(fileName);
// Readin the Source-Files.
const sourceFiles = project.getSourceFiles();
for (const file of sourceFiles) {
file.formatText();
await file.save();
}
}
for (const file of functionFiles) {
// Define the File Name:
const fileName = join(options.outputDir, 'functions', file.name);
await createFile(
// Generate the Path.
fileName,
file.content
);
if (options.logger) {
options.logger.info('Generated -> ' + fileName);
} }
// Function to Determine new project files. // Function to Determine new project files.

View File

@ -34,6 +34,10 @@ export class {{className}} {
public {{name}}: nopeRemoteObservable<{{{simplifiedSubType}}}> public {{name}}: nopeRemoteObservable<{{{simplifiedSubType}}}>
{{/each}} {{/each}}
/**
* Creates an instance of the Class.
* @param _dispatcher The Dispatcher to use.
*/
constructor(protected _dispatcher: nopeDispatcher){ constructor(protected _dispatcher: nopeDispatcher){
{{#each properties}} {{#each properties}}
this.{{name}} = new nopeRemoteObservable(_dispatcher,{ this.{{name}} = new nopeRemoteObservable(_dispatcher,{
@ -42,21 +46,15 @@ export class {{className}} {
{{/each}} {{/each}}
} }
{{!-- {{!--
declaration: MethodDeclaration; Iterate over the Methods and create the Function Interface
params: ParameterInformation[];
isAbstract: boolean;
name: string;
isAsync: boolean;
isGenerator: boolean;
isImplementation: boolean;
returnType: TypeInformation;
head: string;
--}} --}}
{{#each methods}} {{#each methods}}
{{!-- Use the Docu of the Author --}}
{{{authorDescription}}} {{{authorDescription}}}
public async {{name}}{{{head}}}{ public async {{name}}{{{head}}}{
// Perform the Method // Perform the Method via the Dispatcher.
{{!-- Perform the Dispather-Call --}}
return await this._dispatcher.performCall<{{{returnType.simplifiedSubType}}}>('{{uri}}', [{{#each params}}{{name}}{{#unless @last}}, {{/unless}}{{/each}}]) return await this._dispatcher.performCall<{{{returnType.simplifiedSubType}}}>('{{uri}}', [{{#each params}}{{name}}{{#unless @last}}, {{/unless}}{{/each}}])
} }
{{/each}} {{/each}}

View File

@ -0,0 +1,17 @@
// Automatic Genearted File for Backendclass: "{{className}}"
// To update run `npm run build:backend`
import { nopeDispatcher } from "../dispatcher/nopeDispatcher"
{{!-- Define the Imports. --}}
{{#if imports.required}}
{{{imports.content}}}
{{/if}}
export function {{generatorName}}(_dispatcher: nopeDispatcher){
return async ({{#each params}}{{#if isBaseType}}{{name}}{{#if isOptional}}?{{/if}}: {{{originalCode}}}{{/if}}{{#unless isBaseType}}{{name}}{{#if isOptional}}?{{/if}}: {{{simplifiedType}}}{{/unless}}{{#unless @last}}, {{/unless}}{{/each}}) => {
// Perform the Method via the Dispatcher.
{{!-- Perform the Dispather-Call --}}
return await _dispatcher.performCall<{{{returnType.simplifiedSubType}}}>('{{uri}}', [{{#each params}}{{name}}{{#unless @last}}, {{/unless}}{{/each}}])
}
}

View File

@ -3,18 +3,29 @@
import { nopeDispatcher } from "./dispatcher/nopeDispatcher" import { nopeDispatcher } from "./dispatcher/nopeDispatcher"
{{#each classes}} {{#each classes}}
import { {{className}} } from "./clients/{{className}}"; import { {{className}} } from "./clients/{{fileName}}";
{{/each}}
{{#each functions}}
import { {{generatorName}} } from "./functions/{{fileName}}";
{{/each}} {{/each}}
export class BackendInterface { export class BackendInterface {
{{#each classes}} {{#each classes}}
public {{orginalName}}: {{className}}; public readonly {{orginalName}}: {{className}};
{{/each}}
{{#each functions}}
public readonly {{orginalName}}: ({{#each params}}{{#if isBaseType}}{{name}}{{#if isOptional}}?{{/if}}: {{{originalCode}}}{{/if}}{{#unless isBaseType}}{{name}}{{#if isOptional}}?{{/if}}: import("./functions/{{../fileName}}").{{{simplifiedType}}}{{/unless}}{{#unless @last}}, {{/unless}}{{/each}}) => Promise<{{{returnType.simplifiedSubType}}}>;
{{/each}} {{/each}}
constructor(protected _dispatcher: nopeDispatcher){ constructor(protected _dispatcher: nopeDispatcher){
{{#each classes}} {{#each classes}}
this.{{orginalName}} = new {{className}}(_dispatcher); this.{{orginalName}} = new {{className}}(_dispatcher);
{{/each}} {{/each}}
{{#each functions}}
this.{{orginalName}} = {{generatorName}}(_dispatcher);
{{/each}}
} }
} }

View File

@ -2,8 +2,9 @@
"dispatcher": { "dispatcher": {
"inputDir": "./test/*.ts", "inputDir": "./test/*.ts",
"outputDir": "./resources/backend-api", "outputDir": "./resources/backend-api",
"pathToClientTemplate": "./lib/templates/clientInterface.handlebars", "pathToClassInterfaceTemplate": "./lib/templates/backendClassInterface.handlebars",
"pathToInterfaceTemplate": "./lib/templates/backendInterface.handlebars", "pathToFunctionInterfaceTemplate": "./lib/templates/backendFunctionInterface.handlebars",
"pathToBackendInterfaceTemplate": "./lib/templates/backendInterface.handlebars",
"tsConfigFilePath": "./tsconfigBackend.json" "tsConfigFilePath": "./tsconfigBackend.json"
}, },
"openapi": { "openapi": {

3243
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -32,38 +32,39 @@
"bootstrap": "^4.5.2", "bootstrap": "^4.5.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.17.1", "express": "^4.17.1",
"express-openapi": "^7.0.0", "express-openapi": "^7.0.1",
"handlebars": "^4.7.6", "handlebars": "^4.7.6",
"inquirer": "^7.3.3", "inquirer": "^7.3.3",
"inquirer-fuzzy-path": "^2.3.0", "inquirer-fuzzy-path": "^2.3.0",
"inversify": "^5.0.1", "inversify": "^5.0.1",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"mqtt-pattern": "^1.2.0", "mqtt-pattern": "^1.2.0",
"next": "^9.5.2", "next": "^9.5.3",
"node-ads": "^1.5.1", "node-ads": "^1.5.1",
"react": "^16.13.1", "react": "^16.13.1",
"react-bootstrap": "^1.3.0", "react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-icons": "^3.11.0", "react-icons": "^3.11.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rxjs": "^6.6.2", "rxjs": "^6.6.3",
"socket.io": "^2.3.0", "socket.io": "^2.3.0",
"socket.io-client": "^2.3.0", "socket.io-client": "^2.3.0",
"swagger-ui-react": "^3.32.4", "swagger-ui-react": "^3.32.5",
"ts-morph": "^7.3.0", "ts-morph": "^8.1.0",
"typescript-json-schema": "^0.43.0", "typescript-json-schema": "^0.43.0",
"uuid": "^8.3.0", "uuid": "^8.3.0",
"winston": "^3.3.3" "winston": "^3.3.3"
}, },
"devDependencies": { "devDependencies": {
"@openapitools/openapi-generator-cli": "^1.0.15-4.3.1", "@openapitools/openapi-generator-cli": "^1.0.18-4.3.1",
"@types/express": "^4.17.7", "@types/express": "^4.17.8",
"@types/lodash": "^4.14.159", "@types/lodash": "^4.14.161",
"@types/node": "^14.6.0", "@types/node": "^14.6.4",
"@types/react": "^16.9.46", "@types/react": "^16.9.49",
"@types/socket.io": "^2.1.11", "@types/socket.io": "^2.1.11",
"@types/socket.io-client": "^1.4.33", "@types/socket.io-client": "^1.4.33",
"openapi-typescript-codegen": "^0.4.10", "npm-check-updates": "^8.1.1",
"typescript": "^3.9.7" "openapi-typescript-codegen": "^0.4.11",
"typescript": "^4.0.2"
} }
} }

View File

@ -18,7 +18,8 @@
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "preserve",
"downlevelIteration": true, "downlevelIteration": true,
"experimentalDecorators": true "experimentalDecorators": true,
"noImplicitAny": false
}, },
"include": [ "include": [
"next-env.d.ts", "next-env.d.ts",

View File

@ -17,7 +17,8 @@
"removeComments": true, "removeComments": true,
"rootDir": "./", "rootDir": "./",
"stripInternal": true, "stripInternal": true,
"downlevelIteration": true "downlevelIteration": true,
"noImplicitAny": false
}, },
"include": [ "include": [
"next-env.d.ts", "next-env.d.ts",