diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/src/OpenApiGenerator.ts b/src/OpenApiGenerator.ts index c455246..2f1164a 100644 --- a/src/OpenApiGenerator.ts +++ b/src/OpenApiGenerator.ts @@ -1,6 +1,5 @@ import { OpenAPIV3 } from "openapi-types"; -import { Description } from "./app"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; type APISchemas = { [key: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject; diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/src/OpenApiGenerator.ts b/src/OpenApiGenerator.ts index c455246..2f1164a 100644 --- a/src/OpenApiGenerator.ts +++ b/src/OpenApiGenerator.ts @@ -1,6 +1,5 @@ import { OpenAPIV3 } from "openapi-types"; -import { Description } from "./app"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; type APISchemas = { [key: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject; diff --git a/src/UtilGenerator.ts b/src/UtilGenerator.ts index 66de2ff..2cbf118 100644 --- a/src/UtilGenerator.ts +++ b/src/UtilGenerator.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,4 +127,34 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: \`String value doesn't equal '\${targetValue}'.\`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; `; diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/src/OpenApiGenerator.ts b/src/OpenApiGenerator.ts index c455246..2f1164a 100644 --- a/src/OpenApiGenerator.ts +++ b/src/OpenApiGenerator.ts @@ -1,6 +1,5 @@ import { OpenAPIV3 } from "openapi-types"; -import { Description } from "./app"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; type APISchemas = { [key: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject; diff --git a/src/UtilGenerator.ts b/src/UtilGenerator.ts index 66de2ff..2cbf118 100644 --- a/src/UtilGenerator.ts +++ b/src/UtilGenerator.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,4 +127,34 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: \`String value doesn't equal '\${targetValue}'.\`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; `; diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index 396678e..0000000 --- a/src/app.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Description } from "./types"; -import { join } from "path"; -import * as fs from "fs"; -import { generateModel } from "./ModelGenerator"; -import { generateDataAccess } from "./DataAccessGenerator"; -import { generateOpenAPI } from "./OpenApiGenerator"; -import { generateMiddlewares } from "./MiddlewareGenerator"; -import { UtilCode } from "./UtilGenerator"; - -interface Options { - typeScriptOutputFolder: string; - openapiOutput: string; -} -export interface FileWrite { - location: string; - content: string; -} - -function describeTestOutput(): Description { - return { - collections: [ - { - name: "Characters" - , entities: { - name: "Character", - properties: [ - { key: "name", type: "string", isNullable: false }, - { key: "backstory", type: "string", isNullable: false } - ] - } - } - ] - } -} - -/** - * Central function, that contains all the (pure) logic. - * @param options parameters for the generators - * @param description The supplied data model description - */ -function generate(options: Options, description: Description): FileWrite[] { - // generate model files - const modelWrites = generateModel(description.collections); - modelWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate data access files - const dataAccessWrites = generateDataAccess(description.collections); - dataAccessWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate openapi file - const openapiDoc = generateOpenAPI(description); - const openapiWrites: FileWrite = { location: options.openapiOutput, content: JSON.stringify(openapiDoc, null, "\t") }; - - // generate middleware file - const middlewareWrites = generateMiddlewares(description); - middlewareWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - const utilWrite: FileWrite = { - location: join(options.typeScriptOutputFolder, "util.ts"), - content: UtilCode, - }; - - // TODO create json schema file for the storage - - return [ - ...modelWrites, - ...dataAccessWrites, - ...middlewareWrites, - openapiWrites, - utilWrite, - ]; -} - -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(); diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/src/OpenApiGenerator.ts b/src/OpenApiGenerator.ts index c455246..2f1164a 100644 --- a/src/OpenApiGenerator.ts +++ b/src/OpenApiGenerator.ts @@ -1,6 +1,5 @@ import { OpenAPIV3 } from "openapi-types"; -import { Description } from "./app"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; type APISchemas = { [key: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject; diff --git a/src/UtilGenerator.ts b/src/UtilGenerator.ts index 66de2ff..2cbf118 100644 --- a/src/UtilGenerator.ts +++ b/src/UtilGenerator.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,4 +127,34 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: \`String value doesn't equal '\${targetValue}'.\`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; `; diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index 396678e..0000000 --- a/src/app.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Description } from "./types"; -import { join } from "path"; -import * as fs from "fs"; -import { generateModel } from "./ModelGenerator"; -import { generateDataAccess } from "./DataAccessGenerator"; -import { generateOpenAPI } from "./OpenApiGenerator"; -import { generateMiddlewares } from "./MiddlewareGenerator"; -import { UtilCode } from "./UtilGenerator"; - -interface Options { - typeScriptOutputFolder: string; - openapiOutput: string; -} -export interface FileWrite { - location: string; - content: string; -} - -function describeTestOutput(): Description { - return { - collections: [ - { - name: "Characters" - , entities: { - name: "Character", - properties: [ - { key: "name", type: "string", isNullable: false }, - { key: "backstory", type: "string", isNullable: false } - ] - } - } - ] - } -} - -/** - * Central function, that contains all the (pure) logic. - * @param options parameters for the generators - * @param description The supplied data model description - */ -function generate(options: Options, description: Description): FileWrite[] { - // generate model files - const modelWrites = generateModel(description.collections); - modelWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate data access files - const dataAccessWrites = generateDataAccess(description.collections); - dataAccessWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate openapi file - const openapiDoc = generateOpenAPI(description); - const openapiWrites: FileWrite = { location: options.openapiOutput, content: JSON.stringify(openapiDoc, null, "\t") }; - - // generate middleware file - const middlewareWrites = generateMiddlewares(description); - middlewareWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - const utilWrite: FileWrite = { - location: join(options.typeScriptOutputFolder, "util.ts"), - content: UtilCode, - }; - - // TODO create json schema file for the storage - - return [ - ...modelWrites, - ...dataAccessWrites, - ...middlewareWrites, - openapiWrites, - utilWrite, - ]; -} - -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(); diff --git a/src/characters.model.json b/src/characters.model.json new file mode 100644 index 0000000..3e05037 --- /dev/null +++ b/src/characters.model.json @@ -0,0 +1,15 @@ +{ + "$schema": "./server-generator.schema.json", + "collections": [ + { + "name": "Characters", + "entities": { + "name": "Character", + "properties": [ + { "key": "name", "type": "string", "isNullable": false }, + { "key": "backstory", "type": "string", "isNullable": false } + ] + } + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/src/OpenApiGenerator.ts b/src/OpenApiGenerator.ts index c455246..2f1164a 100644 --- a/src/OpenApiGenerator.ts +++ b/src/OpenApiGenerator.ts @@ -1,6 +1,5 @@ import { OpenAPIV3 } from "openapi-types"; -import { Description } from "./app"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; type APISchemas = { [key: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject; diff --git a/src/UtilGenerator.ts b/src/UtilGenerator.ts index 66de2ff..2cbf118 100644 --- a/src/UtilGenerator.ts +++ b/src/UtilGenerator.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,4 +127,34 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: \`String value doesn't equal '\${targetValue}'.\`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; `; diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index 396678e..0000000 --- a/src/app.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Description } from "./types"; -import { join } from "path"; -import * as fs from "fs"; -import { generateModel } from "./ModelGenerator"; -import { generateDataAccess } from "./DataAccessGenerator"; -import { generateOpenAPI } from "./OpenApiGenerator"; -import { generateMiddlewares } from "./MiddlewareGenerator"; -import { UtilCode } from "./UtilGenerator"; - -interface Options { - typeScriptOutputFolder: string; - openapiOutput: string; -} -export interface FileWrite { - location: string; - content: string; -} - -function describeTestOutput(): Description { - return { - collections: [ - { - name: "Characters" - , entities: { - name: "Character", - properties: [ - { key: "name", type: "string", isNullable: false }, - { key: "backstory", type: "string", isNullable: false } - ] - } - } - ] - } -} - -/** - * Central function, that contains all the (pure) logic. - * @param options parameters for the generators - * @param description The supplied data model description - */ -function generate(options: Options, description: Description): FileWrite[] { - // generate model files - const modelWrites = generateModel(description.collections); - modelWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate data access files - const dataAccessWrites = generateDataAccess(description.collections); - dataAccessWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate openapi file - const openapiDoc = generateOpenAPI(description); - const openapiWrites: FileWrite = { location: options.openapiOutput, content: JSON.stringify(openapiDoc, null, "\t") }; - - // generate middleware file - const middlewareWrites = generateMiddlewares(description); - middlewareWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - const utilWrite: FileWrite = { - location: join(options.typeScriptOutputFolder, "util.ts"), - content: UtilCode, - }; - - // TODO create json schema file for the storage - - return [ - ...modelWrites, - ...dataAccessWrites, - ...middlewareWrites, - openapiWrites, - utilWrite, - ]; -} - -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(); diff --git a/src/characters.model.json b/src/characters.model.json new file mode 100644 index 0000000..3e05037 --- /dev/null +++ b/src/characters.model.json @@ -0,0 +1,15 @@ +{ + "$schema": "./server-generator.schema.json", + "collections": [ + { + "name": "Characters", + "entities": { + "name": "Character", + "properties": [ + { "key": "name", "type": "string", "isNullable": false }, + { "key": "backstory", "type": "string", "isNullable": false } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/input-parser.ts b/src/input-parser.ts new file mode 100644 index 0000000..06109b0 --- /dev/null +++ b/src/input-parser.ts @@ -0,0 +1,45 @@ +import { andThen, compose, parseArray, parseBoolean, parseNotNull, ParseObject, parseObject, parseRequiredMember, parseString, parseStringValue, resolve, Result } from "./ExampleOutput/util"; +import { Collection, Description, Entity, Property } from "./types"; + +export function parseDescription(data: unknown): Result { + const obj = andThen(parseObject)(parseNotNull(data)); + const collectionObj = andThen(parseRequiredMember("collections"))(obj); + const collectionResult = andThen(parseArray(parseCollection))(collectionObj); + if (collectionResult.isSuccessful) { + return { + isSuccessful: true, + value: { collections: collectionResult.value }, + }; + } + else { + return collectionResult; + } +} + +function parseCollection(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + name: andThen(compose(parseRequiredMember("name"), parseString))(obj), + entities: andThen(compose(parseRequiredMember("entities"), parseEntity))(obj), + } + return resolve(result); +} + +function parseEntity(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + name: andThen(compose(parseRequiredMember("name"), parseString))(obj), + properties: andThen(compose(parseRequiredMember("properties"), parseArray(parseProperty)))(obj), + }; + return resolve(result); +} + +function parseProperty(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + key: andThen(compose(parseRequiredMember("key"), parseString))(obj), + isNullable: andThen(compose(parseRequiredMember("isNullable"), parseBoolean))(obj), + type: andThen(compose(compose(parseRequiredMember("type"), parseString), parseStringValue("string")))(obj), + }; + return resolve(result); +} diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/src/OpenApiGenerator.ts b/src/OpenApiGenerator.ts index c455246..2f1164a 100644 --- a/src/OpenApiGenerator.ts +++ b/src/OpenApiGenerator.ts @@ -1,6 +1,5 @@ import { OpenAPIV3 } from "openapi-types"; -import { Description } from "./app"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; type APISchemas = { [key: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject; diff --git a/src/UtilGenerator.ts b/src/UtilGenerator.ts index 66de2ff..2cbf118 100644 --- a/src/UtilGenerator.ts +++ b/src/UtilGenerator.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,4 +127,34 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: \`String value doesn't equal '\${targetValue}'.\`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; `; diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index 396678e..0000000 --- a/src/app.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Description } from "./types"; -import { join } from "path"; -import * as fs from "fs"; -import { generateModel } from "./ModelGenerator"; -import { generateDataAccess } from "./DataAccessGenerator"; -import { generateOpenAPI } from "./OpenApiGenerator"; -import { generateMiddlewares } from "./MiddlewareGenerator"; -import { UtilCode } from "./UtilGenerator"; - -interface Options { - typeScriptOutputFolder: string; - openapiOutput: string; -} -export interface FileWrite { - location: string; - content: string; -} - -function describeTestOutput(): Description { - return { - collections: [ - { - name: "Characters" - , entities: { - name: "Character", - properties: [ - { key: "name", type: "string", isNullable: false }, - { key: "backstory", type: "string", isNullable: false } - ] - } - } - ] - } -} - -/** - * Central function, that contains all the (pure) logic. - * @param options parameters for the generators - * @param description The supplied data model description - */ -function generate(options: Options, description: Description): FileWrite[] { - // generate model files - const modelWrites = generateModel(description.collections); - modelWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate data access files - const dataAccessWrites = generateDataAccess(description.collections); - dataAccessWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate openapi file - const openapiDoc = generateOpenAPI(description); - const openapiWrites: FileWrite = { location: options.openapiOutput, content: JSON.stringify(openapiDoc, null, "\t") }; - - // generate middleware file - const middlewareWrites = generateMiddlewares(description); - middlewareWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - const utilWrite: FileWrite = { - location: join(options.typeScriptOutputFolder, "util.ts"), - content: UtilCode, - }; - - // TODO create json schema file for the storage - - return [ - ...modelWrites, - ...dataAccessWrites, - ...middlewareWrites, - openapiWrites, - utilWrite, - ]; -} - -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(); diff --git a/src/characters.model.json b/src/characters.model.json new file mode 100644 index 0000000..3e05037 --- /dev/null +++ b/src/characters.model.json @@ -0,0 +1,15 @@ +{ + "$schema": "./server-generator.schema.json", + "collections": [ + { + "name": "Characters", + "entities": { + "name": "Character", + "properties": [ + { "key": "name", "type": "string", "isNullable": false }, + { "key": "backstory", "type": "string", "isNullable": false } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/input-parser.ts b/src/input-parser.ts new file mode 100644 index 0000000..06109b0 --- /dev/null +++ b/src/input-parser.ts @@ -0,0 +1,45 @@ +import { andThen, compose, parseArray, parseBoolean, parseNotNull, ParseObject, parseObject, parseRequiredMember, parseString, parseStringValue, resolve, Result } from "./ExampleOutput/util"; +import { Collection, Description, Entity, Property } from "./types"; + +export function parseDescription(data: unknown): Result { + const obj = andThen(parseObject)(parseNotNull(data)); + const collectionObj = andThen(parseRequiredMember("collections"))(obj); + const collectionResult = andThen(parseArray(parseCollection))(collectionObj); + if (collectionResult.isSuccessful) { + return { + isSuccessful: true, + value: { collections: collectionResult.value }, + }; + } + else { + return collectionResult; + } +} + +function parseCollection(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + name: andThen(compose(parseRequiredMember("name"), parseString))(obj), + entities: andThen(compose(parseRequiredMember("entities"), parseEntity))(obj), + } + return resolve(result); +} + +function parseEntity(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + name: andThen(compose(parseRequiredMember("name"), parseString))(obj), + properties: andThen(compose(parseRequiredMember("properties"), parseArray(parseProperty)))(obj), + }; + return resolve(result); +} + +function parseProperty(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + key: andThen(compose(parseRequiredMember("key"), parseString))(obj), + isNullable: andThen(compose(parseRequiredMember("isNullable"), parseBoolean))(obj), + type: andThen(compose(compose(parseRequiredMember("type"), parseString), parseStringValue("string")))(obj), + }; + return resolve(result); +} diff --git a/src/server-generator.schema.json b/src/server-generator.schema.json index 053687d..2f719b1 100644 --- a/src/server-generator.schema.json +++ b/src/server-generator.schema.json @@ -8,7 +8,7 @@ "properties": { "$schema": { "type": "string", - "enum": ["https://infinity.synoikos.de/schemata/server-generator.schema.json"] + "enum": ["https://infinity.synoikos.de/schemata/server-generator.schema.json", "./server-generator.schema.json"] }, "collections": { "type": "array", diff --git a/package.json b/package.json index ac501c3..6c75a7a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "dist/server.js", "scripts": { - "generate": "npm run build-generator && node --inspect ./dist/app.js", + "generate": "npm run build-generator && node --inspect ./dist/server-generator.js", "build-generator": "tsc && node dist/CopyCodeFile.js && tsc", "debug-server": "tsc && node --inspect=9229 ./dist/server.js", "eslint": "eslint . --ext .ts", diff --git a/src/CopyCodeFile.ts b/src/CopyCodeFile.ts index d56f2d4..a28b2a0 100644 --- a/src/CopyCodeFile.ts +++ b/src/CopyCodeFile.ts @@ -3,7 +3,7 @@ const codeFileName = join(__dirname, "..", "src", "ExampleOutput", "util.ts"); let code = fs.readFileSync(codeFileName).toString(); -code = code.replace(/`/g, "\\`").replace("$", "\\$"); +code = code.replace(/`/g, "\\`").replace(/\$/g, "\\$"); const utilGenerator = `export const UtilCode = \`${code}\`;\n`; const outputFileName = join(__dirname, "..", "src", "UtilGenerator.ts"); fs.writeFileSync(outputFileName, utilGenerator); diff --git a/src/DataAccessGenerator.ts b/src/DataAccessGenerator.ts index acece01..ffe2a3a 100644 --- a/src/DataAccessGenerator.ts +++ b/src/DataAccessGenerator.ts @@ -1,5 +1,5 @@ -import { Collection, Entity, Property } from "./MySchema"; -import { FileWrite } from "./app"; +import { Collection, Entity, Property } from "./types"; +import { FileWrite } from "./server-generator"; import { modelModuleName } from "./ModelGenerator"; export function generateDataAccess(collections: Collection[]): FileWrite[] { diff --git a/src/ExampleOutput/util.ts b/src/ExampleOutput/util.ts index 39c85a4..e426413 100644 --- a/src/ExampleOutput/util.ts +++ b/src/ExampleOutput/util.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,3 +127,33 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: `String value doesn't equal '${targetValue}'.`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; diff --git a/src/MiddlewareGenerator.ts b/src/MiddlewareGenerator.ts index 6d6baf6..1af9a58 100644 --- a/src/MiddlewareGenerator.ts +++ b/src/MiddlewareGenerator.ts @@ -1,7 +1,7 @@ -import { Description, FileWrite } from "./app"; +import { FileWrite } from "./server-generator"; import { dataAccessModuleName } from "./DataAccessGenerator"; import { modelModuleName } from "./ModelGenerator"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function middlewareModuleName(collection: Collection): string { @@ -123,7 +123,7 @@ } function definePropertyParser(entity: Entity, property: Property): string { - if(property.type === "string") { + if (property.type === "string") { return defineStringPropertyParser(entity.name, property.key, property.isNullable); } else { diff --git a/src/ModelGenerator.ts b/src/ModelGenerator.ts index 2ca7487..a36da70 100644 --- a/src/ModelGenerator.ts +++ b/src/ModelGenerator.ts @@ -1,5 +1,5 @@ -import { FileWrite } from "./app"; -import { Collection, Entity } from "./MySchema"; +import { FileWrite } from "./server-generator"; +import { Collection, Entity } from "./types"; import { collectionRoute } from "./OpenApiGenerator"; export function generateModel(collections: Collection[]): FileWrite[] diff --git a/src/OpenApiGenerator.ts b/src/OpenApiGenerator.ts index c455246..2f1164a 100644 --- a/src/OpenApiGenerator.ts +++ b/src/OpenApiGenerator.ts @@ -1,6 +1,5 @@ import { OpenAPIV3 } from "openapi-types"; -import { Description } from "./app"; -import { Collection, Entity, Property } from "./MySchema"; +import { Collection, Description, Entity, Property } from "./types"; type APISchemas = { [key: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject; diff --git a/src/UtilGenerator.ts b/src/UtilGenerator.ts index 66de2ff..2cbf118 100644 --- a/src/UtilGenerator.ts +++ b/src/UtilGenerator.ts @@ -59,6 +59,11 @@ else return { isSuccessful: false, errorMessage: "Value is not a string." }; } +export function parseBoolean(data: any): Result { + if (data == null || typeof data === "boolean") return { isSuccessful: true, value: data }; + else return { isSuccessful: false, errorMessage: "Value is not a boolean." }; +} + export type ParseObject = { [P in keyof T]: Result }; @@ -122,4 +127,34 @@ return false; } } + +function isStringValue(targetValue: T, value: string): value is T { + return targetValue === value; +} + +export const parseStringValue = (targetValue: T) => (data: string): Result => { + if(isStringValue(targetValue, data)) { + return { isSuccessful: true, value: data }; + } + else { + return { isSuccessful: false, errorMessage: \`String value doesn't equal '\${targetValue}'.\`} + } +} + +export const parseArray = (itemParser: (d: unknown) => Result) => (data: unknown): Result => { + if (Array.isArray(data)) { + const output: T[] = []; + for (const itemObj of data) { + const itemRes = itemParser(itemObj); + if (itemRes.isSuccessful) { + output.push(itemRes.value); + } + else { + return { isSuccessful: false, errorMessage: "Item could not be parsed: " + itemRes.errorMessage }; + } + } + return { isSuccessful: true, value: output }; + } + return { isSuccessful: false, errorMessage: "Input is not an array." }; +}; `; diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index 396678e..0000000 --- a/src/app.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Description } from "./types"; -import { join } from "path"; -import * as fs from "fs"; -import { generateModel } from "./ModelGenerator"; -import { generateDataAccess } from "./DataAccessGenerator"; -import { generateOpenAPI } from "./OpenApiGenerator"; -import { generateMiddlewares } from "./MiddlewareGenerator"; -import { UtilCode } from "./UtilGenerator"; - -interface Options { - typeScriptOutputFolder: string; - openapiOutput: string; -} -export interface FileWrite { - location: string; - content: string; -} - -function describeTestOutput(): Description { - return { - collections: [ - { - name: "Characters" - , entities: { - name: "Character", - properties: [ - { key: "name", type: "string", isNullable: false }, - { key: "backstory", type: "string", isNullable: false } - ] - } - } - ] - } -} - -/** - * Central function, that contains all the (pure) logic. - * @param options parameters for the generators - * @param description The supplied data model description - */ -function generate(options: Options, description: Description): FileWrite[] { - // generate model files - const modelWrites = generateModel(description.collections); - modelWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate data access files - const dataAccessWrites = generateDataAccess(description.collections); - dataAccessWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - // generate openapi file - const openapiDoc = generateOpenAPI(description); - const openapiWrites: FileWrite = { location: options.openapiOutput, content: JSON.stringify(openapiDoc, null, "\t") }; - - // generate middleware file - const middlewareWrites = generateMiddlewares(description); - middlewareWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); - - const utilWrite: FileWrite = { - location: join(options.typeScriptOutputFolder, "util.ts"), - content: UtilCode, - }; - - // TODO create json schema file for the storage - - return [ - ...modelWrites, - ...dataAccessWrites, - ...middlewareWrites, - openapiWrites, - utilWrite, - ]; -} - -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(); diff --git a/src/characters.model.json b/src/characters.model.json new file mode 100644 index 0000000..3e05037 --- /dev/null +++ b/src/characters.model.json @@ -0,0 +1,15 @@ +{ + "$schema": "./server-generator.schema.json", + "collections": [ + { + "name": "Characters", + "entities": { + "name": "Character", + "properties": [ + { "key": "name", "type": "string", "isNullable": false }, + { "key": "backstory", "type": "string", "isNullable": false } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/input-parser.ts b/src/input-parser.ts new file mode 100644 index 0000000..06109b0 --- /dev/null +++ b/src/input-parser.ts @@ -0,0 +1,45 @@ +import { andThen, compose, parseArray, parseBoolean, parseNotNull, ParseObject, parseObject, parseRequiredMember, parseString, parseStringValue, resolve, Result } from "./ExampleOutput/util"; +import { Collection, Description, Entity, Property } from "./types"; + +export function parseDescription(data: unknown): Result { + const obj = andThen(parseObject)(parseNotNull(data)); + const collectionObj = andThen(parseRequiredMember("collections"))(obj); + const collectionResult = andThen(parseArray(parseCollection))(collectionObj); + if (collectionResult.isSuccessful) { + return { + isSuccessful: true, + value: { collections: collectionResult.value }, + }; + } + else { + return collectionResult; + } +} + +function parseCollection(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + name: andThen(compose(parseRequiredMember("name"), parseString))(obj), + entities: andThen(compose(parseRequiredMember("entities"), parseEntity))(obj), + } + return resolve(result); +} + +function parseEntity(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + name: andThen(compose(parseRequiredMember("name"), parseString))(obj), + properties: andThen(compose(parseRequiredMember("properties"), parseArray(parseProperty)))(obj), + }; + return resolve(result); +} + +function parseProperty(data: unknown): Result { + const obj = compose(parseNotNull, parseObject)(data); + const result: ParseObject = { + key: andThen(compose(parseRequiredMember("key"), parseString))(obj), + isNullable: andThen(compose(parseRequiredMember("isNullable"), parseBoolean))(obj), + type: andThen(compose(compose(parseRequiredMember("type"), parseString), parseStringValue("string")))(obj), + }; + return resolve(result); +} diff --git a/src/server-generator.schema.json b/src/server-generator.schema.json index 053687d..2f719b1 100644 --- a/src/server-generator.schema.json +++ b/src/server-generator.schema.json @@ -8,7 +8,7 @@ "properties": { "$schema": { "type": "string", - "enum": ["https://infinity.synoikos.de/schemata/server-generator.schema.json"] + "enum": ["https://infinity.synoikos.de/schemata/server-generator.schema.json", "./server-generator.schema.json"] }, "collections": { "type": "array", diff --git a/src/server-generator.ts b/src/server-generator.ts new file mode 100644 index 0000000..b8ddd3f --- /dev/null +++ b/src/server-generator.ts @@ -0,0 +1,79 @@ +import { Description } from "./types"; +import { join } from "path"; +import * as fs from "fs"; +import { generateModel } from "./ModelGenerator"; +import { generateDataAccess } from "./DataAccessGenerator"; +import { generateOpenAPI } from "./OpenApiGenerator"; +import { generateMiddlewares } from "./MiddlewareGenerator"; +import { UtilCode } from "./UtilGenerator"; +import { parseDescription } from "./input-parser"; + +interface Options { + typeScriptOutputFolder: string; + openapiOutput: string; +} +export interface FileWrite { + location: string; + content: string; +} + +/** + * Central function, that contains all the (pure) logic. + * @param options parameters for the generators + * @param description The supplied data model description + */ +function generate(options: Options, description: Description): FileWrite[] { + // generate model files + const modelWrites = generateModel(description.collections); + modelWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); + + // generate data access files + const dataAccessWrites = generateDataAccess(description.collections); + dataAccessWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); + + // generate openapi file + const openapiDoc = generateOpenAPI(description); + const openapiWrites: FileWrite = { location: options.openapiOutput, content: JSON.stringify(openapiDoc, null, "\t") }; + + // generate middleware file + const middlewareWrites = generateMiddlewares(description); + middlewareWrites.forEach(w => { w.location = join(options.typeScriptOutputFolder, w.location) }); + + const utilWrite: FileWrite = { + location: join(options.typeScriptOutputFolder, "util.ts"), + content: UtilCode, + }; + + // TODO create json schema file for the storage + + return [ + ...modelWrites, + ...dataAccessWrites, + ...middlewareWrites, + openapiWrites, + utilWrite, + ]; +} + +function execute() { + const modelContent = fs.readFileSync(join(__dirname, "..", "src", "characters.model.json")).toString(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const rawModelObject = JSON.parse(modelContent); + const modelResult = parseDescription(rawModelObject); + if(!modelResult.isSuccessful) { + console.error(modelResult.errorMessage); + return; + } + const model:Description = modelResult.value; + const options: Options = { + openapiOutput: join(__dirname, "..", "src", "TestOutput", "openapi.json"), + typeScriptOutputFolder: join(__dirname, "..", "src", "TestOutput") + }; + const writes = generate(options, model); + for (const write of writes) { + fs.writeFileSync(write.location, write.content); + console.log(`Written file '${write.location}'`) + } +} + +execute();