diff --git a/.gitignore b/.gitignore index 7cd6f9b..2e2fe17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.js.map dist *.user +src/TestOutput diff --git a/.gitignore b/.gitignore index 7cd6f9b..2e2fe17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.js.map dist *.user +src/TestOutput diff --git a/.vscode/launch.json b/.vscode/launch.json index 7dc4d32..c3e92a3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,19 @@ "version": "0.2.0", "configurations": [ { + "name": "Launch generate", + "request": "launch", + "runtimeArgs": [ + "run-script", + "generate" + ], + "runtimeExecutable": "npm", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { "type": "chrome", "request": "launch", "name": "Launch Chrome", diff --git a/.gitignore b/.gitignore index 7cd6f9b..2e2fe17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.js.map dist *.user +src/TestOutput diff --git a/.vscode/launch.json b/.vscode/launch.json index 7dc4d32..c3e92a3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,19 @@ "version": "0.2.0", "configurations": [ { + "name": "Launch generate", + "request": "launch", + "runtimeArgs": [ + "run-script", + "generate" + ], + "runtimeExecutable": "npm", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { "type": "chrome", "request": "launch", "name": "Launch Chrome", diff --git a/package.json b/package.json index 969d061..f58fd95 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { - "name": "ServerGenerator", + "name": "server-generator", "version": "1.0.0", "description": "", "main": "dist/server.js", "scripts": { - "debug": "tsc && node --inspect-brk=9229 ./dist/server.js", + "generate": "tsc && node --inspect ./dist/app.js", + "debug": "tsc && node --inspect=9229 ./dist/server.js", "start": "npm run build && npm run watch", "build": "npm run build-ts && npm run tslint", "watch-node": "nodemon --inspect ./dist/server.js", diff --git a/.gitignore b/.gitignore index 7cd6f9b..2e2fe17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.js.map dist *.user +src/TestOutput diff --git a/.vscode/launch.json b/.vscode/launch.json index 7dc4d32..c3e92a3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,19 @@ "version": "0.2.0", "configurations": [ { + "name": "Launch generate", + "request": "launch", + "runtimeArgs": [ + "run-script", + "generate" + ], + "runtimeExecutable": "npm", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { "type": "chrome", "request": "launch", "name": "Launch Chrome", diff --git a/package.json b/package.json index 969d061..f58fd95 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { - "name": "ServerGenerator", + "name": "server-generator", "version": "1.0.0", "description": "", "main": "dist/server.js", "scripts": { - "debug": "tsc && node --inspect-brk=9229 ./dist/server.js", + "generate": "tsc && node --inspect ./dist/app.js", + "debug": "tsc && node --inspect=9229 ./dist/server.js", "start": "npm run build && npm run watch", "build": "npm run build-ts && npm run tslint", "watch-node": "nodemon --inspect ./dist/server.js", diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts new file mode 100644 index 0000000..29550ef --- /dev/null +++ b/src/ModelGenerator.ts @@ -0,0 +1,58 @@ +import { FileWrite } from "./app"; +import { Collection, Entity } from "./MySchema"; + +export function generateModel(collections: Collection[]): FileWrite[] +{ + return collections.map(generateModelFile); +} + +function generateModelFile(collection: Collection): FileWrite +{ + const fileName = collection.name + "Model.ts"; + const definitions: string[] = [ + defineCollection(collection), + defineEntity(collection.entities), + definePayload(collection), + defineFindFunction(collection), + ]; + return { + location: fileName, + content: definitions.join("\n\n") + "\n", + }; +} + +function defineCollection(collection: Collection): string { + return `export interface ${collection.name} { + nodes: ${collection.entities.name}[]; + nextId: number; +}`; +} + +function defineEntity(entity: Entity): string +{ + const propDefinitions = entity.properties.map(p => `\t${p.key}: ${p.type};`).join("\n"); + return `export interface ${entity.name} { + id: number; +${propDefinitions} +}`; +} + +function definePayload(collection: Collection): string { + const entity = collection.entities; + return `export interface ${entity.name}Payload extends ${entity.name} { + ref: string; +} + +export function toPayload(node: ${entity.name}): ${entity.name}Payload { + return { + ...node, + ref: \`/${collection.name.toLowerCase()}/\${node.id}\`, + } +}`; +} + +function defineFindFunction(collection: Collection): string { + return `export function findSingle(graph: ${collection.name}, id: number) { + return graph.nodes.find(n => n.id === id); +}`; +} diff --git a/.gitignore b/.gitignore index 7cd6f9b..2e2fe17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.js.map dist *.user +src/TestOutput diff --git a/.vscode/launch.json b/.vscode/launch.json index 7dc4d32..c3e92a3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,19 @@ "version": "0.2.0", "configurations": [ { + "name": "Launch generate", + "request": "launch", + "runtimeArgs": [ + "run-script", + "generate" + ], + "runtimeExecutable": "npm", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { "type": "chrome", "request": "launch", "name": "Launch Chrome", diff --git a/package.json b/package.json index 969d061..f58fd95 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { - "name": "ServerGenerator", + "name": "server-generator", "version": "1.0.0", "description": "", "main": "dist/server.js", "scripts": { - "debug": "tsc && node --inspect-brk=9229 ./dist/server.js", + "generate": "tsc && node --inspect ./dist/app.js", + "debug": "tsc && node --inspect=9229 ./dist/server.js", "start": "npm run build && npm run watch", "build": "npm run build-ts && npm run tslint", "watch-node": "nodemon --inspect ./dist/server.js", diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts new file mode 100644 index 0000000..29550ef --- /dev/null +++ b/src/ModelGenerator.ts @@ -0,0 +1,58 @@ +import { FileWrite } from "./app"; +import { Collection, Entity } from "./MySchema"; + +export function generateModel(collections: Collection[]): FileWrite[] +{ + return collections.map(generateModelFile); +} + +function generateModelFile(collection: Collection): FileWrite +{ + const fileName = collection.name + "Model.ts"; + const definitions: string[] = [ + defineCollection(collection), + defineEntity(collection.entities), + definePayload(collection), + defineFindFunction(collection), + ]; + return { + location: fileName, + content: definitions.join("\n\n") + "\n", + }; +} + +function defineCollection(collection: Collection): string { + return `export interface ${collection.name} { + nodes: ${collection.entities.name}[]; + nextId: number; +}`; +} + +function defineEntity(entity: Entity): string +{ + const propDefinitions = entity.properties.map(p => `\t${p.key}: ${p.type};`).join("\n"); + return `export interface ${entity.name} { + id: number; +${propDefinitions} +}`; +} + +function definePayload(collection: Collection): string { + const entity = collection.entities; + return `export interface ${entity.name}Payload extends ${entity.name} { + ref: string; +} + +export function toPayload(node: ${entity.name}): ${entity.name}Payload { + return { + ...node, + ref: \`/${collection.name.toLowerCase()}/\${node.id}\`, + } +}`; +} + +function defineFindFunction(collection: Collection): string { + return `export function findSingle(graph: ${collection.name}, id: number) { + return graph.nodes.find(n => n.id === id); +}`; +} diff --git a/src/MySchema.ts b/src/MySchema.ts index ae312de..ddfd6de 100644 --- a/src/MySchema.ts +++ b/src/MySchema.ts @@ -5,7 +5,7 @@ export interface Entity { name: string; - properties: Property; + properties: Property[]; } export interface Property { diff --git a/.gitignore b/.gitignore index 7cd6f9b..2e2fe17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.js.map dist *.user +src/TestOutput diff --git a/.vscode/launch.json b/.vscode/launch.json index 7dc4d32..c3e92a3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,19 @@ "version": "0.2.0", "configurations": [ { + "name": "Launch generate", + "request": "launch", + "runtimeArgs": [ + "run-script", + "generate" + ], + "runtimeExecutable": "npm", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { "type": "chrome", "request": "launch", "name": "Launch Chrome", diff --git a/package.json b/package.json index 969d061..f58fd95 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { - "name": "ServerGenerator", + "name": "server-generator", "version": "1.0.0", "description": "", "main": "dist/server.js", "scripts": { - "debug": "tsc && node --inspect-brk=9229 ./dist/server.js", + "generate": "tsc && node --inspect ./dist/app.js", + "debug": "tsc && node --inspect=9229 ./dist/server.js", "start": "npm run build && npm run watch", "build": "npm run build-ts && npm run tslint", "watch-node": "nodemon --inspect ./dist/server.js", diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts new file mode 100644 index 0000000..29550ef --- /dev/null +++ b/src/ModelGenerator.ts @@ -0,0 +1,58 @@ +import { FileWrite } from "./app"; +import { Collection, Entity } from "./MySchema"; + +export function generateModel(collections: Collection[]): FileWrite[] +{ + return collections.map(generateModelFile); +} + +function generateModelFile(collection: Collection): FileWrite +{ + const fileName = collection.name + "Model.ts"; + const definitions: string[] = [ + defineCollection(collection), + defineEntity(collection.entities), + definePayload(collection), + defineFindFunction(collection), + ]; + return { + location: fileName, + content: definitions.join("\n\n") + "\n", + }; +} + +function defineCollection(collection: Collection): string { + return `export interface ${collection.name} { + nodes: ${collection.entities.name}[]; + nextId: number; +}`; +} + +function defineEntity(entity: Entity): string +{ + const propDefinitions = entity.properties.map(p => `\t${p.key}: ${p.type};`).join("\n"); + return `export interface ${entity.name} { + id: number; +${propDefinitions} +}`; +} + +function definePayload(collection: Collection): string { + const entity = collection.entities; + return `export interface ${entity.name}Payload extends ${entity.name} { + ref: string; +} + +export function toPayload(node: ${entity.name}): ${entity.name}Payload { + return { + ...node, + ref: \`/${collection.name.toLowerCase()}/\${node.id}\`, + } +}`; +} + +function defineFindFunction(collection: Collection): string { + return `export function findSingle(graph: ${collection.name}, id: number) { + return graph.nodes.find(n => n.id === id); +}`; +} diff --git a/src/MySchema.ts b/src/MySchema.ts index ae312de..ddfd6de 100644 --- a/src/MySchema.ts +++ b/src/MySchema.ts @@ -5,7 +5,7 @@ export interface Entity { name: string; - properties: Property; + properties: Property[]; } export interface Property { diff --git a/src/app.ts b/src/app.ts index 143394d..46ec548 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,23 +1,59 @@ import { Collection } from "./MySchema"; +import { join } from "path"; +import * as fs from "fs"; +import { generateModel } from "./ModelGenerator"; interface Options { typeScriptOutputFolder: string; openapiOutput: string; } -interface Description { +export interface Description { collections: Collection[]; } -interface FileWrite { +export interface FileWrite { location: string; content: string; } -export function generate(options: Options, description: Description): FileWrite[] -{ +function describeTestOutput(): Description { + return { + collections: [ + { + name: "Characters" + , entities: { + name: "Character", + properties: [ + { key: "name", type: "string", isNullable: false }, + { key: "backstory", type: "string", isNullable: false } + ] + } + } + ] + } +} + +function generate(options: Options, description: Description): FileWrite[] { // generate model files // generate data access files // generate middleware file // generate openapi file // -> see https://swagger.io/docs/specification/describing-responses/ - return []; -} \ No newline at end of file + const writes = generateModel(description.collections); + writes.forEach(w => {w.location = join(options.typeScriptOutputFolder, w.location)}) + return writes; +} + +function execute() { + const example = describeTestOutput(); + const options: Options = { + openapiOutput: join(__dirname, "..", "src", "TestOutput", "openapi.json"), + typeScriptOutputFolder: join(__dirname, "..", "src", "TestOutput") + }; + const writes = generate(options, example); + for (const write of writes) { + fs.writeFileSync(write.location, write.content); + console.log(`Written file '${write.location}'`) + } +} + +execute();