Last active
June 30, 2020 21:51
-
-
Save NicolasDurant/0fbe0601e2f226199532e681646897aa to your computer and use it in GitHub Desktop.
[Node - MirageJS to Swagger-Generator] A script that can sit in the MirageJS-Folder and generate as much documentation as possible out of the factories configuration. Filepaths might need tweaking according to paths. Can be run with `node swagger-generator.js` #MirageJS #JavaScript #Swagger #yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const readline = require('readline'); | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout, | |
}); | |
const opt = 'utf8'; | |
const routes = fs.readFileSync('./routes.js', opt); | |
rl.question('Want to generate Swagger Info Object (y/n)? ', (answer) => { | |
if (answer === 'y') { | |
startReadingFiles(true); | |
} else { | |
startReadingFiles(false); | |
} | |
rl.close(); | |
}); | |
function startReadingFiles(infoObject) { | |
fs.readFile('./server.js', opt, (error, serverData) => { | |
if (error) return error; | |
let fileContent = serverData; | |
let modelsStart = fileContent.indexOf('models'); | |
if (modelsStart === -1) { | |
console.error('Couldnt find any model definition in the server.js file'); | |
} else { | |
const models = getModelsAsArray(fileContent, modelsStart); | |
if (models) { | |
fs.readFile('./factories.js', opt, (error, factoriesData) => { | |
if (error) return error; | |
writingSwaggerFile(infoObject, models, factoriesData); | |
}); | |
} | |
} | |
}); | |
} | |
function writingSwaggerFile(infoObject, models, factoriesData) { | |
console.log('>>> CREATING FILE swagger.yml'); | |
let stream = fs.createWriteStream('./swagger.yml'); | |
stream.once('open', function(fd) { | |
if (infoObject) { | |
console.log('>>>>>> WRITING SWAGGER INFO OBJECT'); | |
stream.write(INFO_OBJECT); | |
} | |
generateSchematas(models, factoriesData, stream); | |
generatePaths(models, stream); | |
stream.end(); | |
}); | |
} | |
function generateSchematas(models, factoriesData, stream) { | |
console.log('>>>>>> CREATING SWAGGER SCHEMATA'); | |
stream.write(SCHEMATAS); | |
console.log('>>>>>> CREATING DEFAULT ERROR SCHEMATA'); | |
stream.write(SCHEMA_ERROR); | |
models.forEach((element) => { | |
let fieldNames = analyseFactories(factoriesData, element); | |
if (fieldNames !== -1) { | |
console.log('>>>>>>>>> WRITING SWAGGER SCHEMA ' + element); | |
let els = element + 's'; | |
let elCamel = element.charAt(0).toUpperCase() + element.slice(1); | |
let elCamels = element.charAt(0).toUpperCase() + element.slice(1) + 's'; | |
let spr = SCHEMA_PLACEHOLDER_REQUIRED.replace('{Placeholder}', elCamel); | |
console.log('>>>>>>>>> WRITING SWAGGER SCHEMA REQUIRED FIELDS '); | |
stream.write(spr); | |
fieldNames.forEach((field) => { | |
let f = SCHEMA_PLACEHOLDER_REQUIRED_FIELD.replace( | |
'{placeholder}', | |
field | |
); | |
stream.write(f); | |
}); | |
stream.write(SCHEMA_PLACEHOLDER_PROPERTIES); | |
console.log('>>>>>>>>> WRITING SWAGGER SCHEMA PROPERTIES FIELDS '); | |
fieldNames.forEach((field) => { | |
let f = SCHEMA_PLACEHOLDER_PROPERTIES_FIELD.replace( | |
'{placeholder}', | |
field | |
); | |
stream.write(f); | |
}); | |
console.log('>>>>>>>>> WRITING SWAGGER SCHEMA ' + els); | |
let spl = SCHEMA_PLACEHOLDER_LIST.replace( | |
'{Placeholder}', | |
elCamel | |
).replace('{Placeholders}', elCamels); | |
stream.write(spl); | |
} | |
}); | |
} | |
function generatePaths(models, stream) { | |
console.log('>>>>>> CREATING SWAGGER PATHS'); | |
stream.write(PATHS); | |
models.forEach((element) => { | |
console.log('>>>>>>>>> WRITING SWAGGER PATHS ' + element); | |
let els = element + 's'; | |
let elCamel = element.charAt(0).toUpperCase() + element.slice(1); | |
let elCamels = element.charAt(0).toUpperCase() + element.slice(1) + 's'; | |
let pp = PATHS_PLACEHOLDER.replace(/\{Placeholder\}/g, elCamel) | |
.replace(/\{Placeholders\}/g, elCamels) | |
.replace(/\{placeholder\}/g, element) | |
.replace(/\{placeholders\}/g, els); | |
stream.write(pp); | |
}); | |
} | |
function getModelsAsArray(fileContent, modelsStart) { | |
console.log('>>> PARSING MODELS FROM server.js'); | |
let modelsObjectStart = fileContent.indexOf('{', modelsStart); | |
let modelsObjectEnd = fileContent.indexOf('}', modelsStart); | |
let modelsString = fileContent.slice(modelsObjectStart + 1, modelsObjectEnd); | |
let models = modelsString.replace(/ |\n|Model,/g, '').split(':'); | |
models.pop(); | |
if (models.length > 0) { | |
models = models.sort(); | |
console.log('>>> FOUND MODELS:'); | |
models.forEach((element) => { | |
console.log('>>>>>> ' + element); | |
}); | |
return models; | |
} else { | |
console.log('>>> NO MODELS DEFINED'); | |
return -1; | |
} | |
} | |
function analyseFactories(fileContent, element) { | |
console.log('>>> SEARCHING MODEL ' + element + ' IN factories.js'); | |
let modelsStart = fileContent.indexOf(element + ':'); | |
if (modelsStart === -1) { | |
console.error( | |
'Couldnt find the model ' + element + ' in the factories.js file' | |
); | |
} else { | |
console.log('>>> FOUND MODEL ' + element + ' IN factories.js'); | |
let modelsObjectStart = fileContent.indexOf('({', modelsStart); | |
let modelsObjectEnd = fileContent.indexOf('}),', modelsStart); | |
let modelsString = fileContent.slice( | |
modelsObjectStart + 2, | |
modelsObjectEnd | |
); | |
let indecisOfFieldNames = []; | |
let fieldNames = []; | |
let regex = /\s{3}[A-Z|a-z]+[(]{1}[)]{1}/gi; | |
let result; | |
while ((result = regex.exec(modelsString))) { | |
indecisOfFieldNames.push(result.index); | |
} | |
if (indecisOfFieldNames.length > 0) { | |
console.log('>>> FOUND FIELDNAMES:'); | |
indecisOfFieldNames.forEach((index) => { | |
fieldEnd = modelsString.indexOf('()', index); | |
fieldStart = index + 3; | |
let value = modelsString.slice(fieldStart, fieldEnd); | |
console.log('>>>>>> ' + value); | |
fieldNames.push(value); | |
}); | |
return fieldNames; | |
} else { | |
return -1; | |
} | |
} | |
} | |
const INFO_OBJECT = ` | |
openapi: 3.0.0 | |
info: | |
title: PWA Aicovo | |
description: The OpenAPI Specification (OAS) for the PWA Aicovo project. This API is based on the Miragejs Mockdata Service used in the student project and can be added on or modified. | |
version: 1.0.0 | |
contact: | |
name: Nicolas Durant | |
email: [email protected] | |
servers: | |
- url: http://localhost:8080/api/v1/ | |
description: Local Development | |
- url: https://pwa-aicovo-dev.web.app/api/v1/ | |
description: Staging | |
- url: https://aicovo.de/api/v1/ | |
description: Production | |
`; | |
const SCHEMATAS = ` | |
components: | |
schemas:`; | |
const SCHEMA_ERROR = ` | |
Error: | |
type: object | |
required: | |
- code | |
- message | |
properties: | |
code: | |
type: integer | |
format: int32 | |
message: | |
type: string`; | |
const SCHEMA_PLACEHOLDER_REQUIRED = ` | |
{Placeholder}: | |
required:`; | |
const SCHEMA_PLACEHOLDER_REQUIRED_FIELD = ` | |
- {placeholder}`; | |
const SCHEMA_PLACEHOLDER_PROPERTIES = ` | |
properties:`; | |
const SCHEMA_PLACEHOLDER_PROPERTIES_FIELD = ` | |
{placeholder}: | |
type: string`; | |
const SCHEMA_PLACEHOLDER_LIST = ` | |
{Placeholders}: | |
type: array | |
items: | |
$ref: "#/components/schemas/{Placeholder}"`; | |
const PATHS = ` | |
paths:`; | |
const PATHS_PLACEHOLDER = ` | |
/{placeholders}: | |
get: | |
summary: List all {placeholders} | |
operationId: list{Placeholders} | |
tags: | |
- {placeholders} | |
parameters: | |
- name: limit | |
in: query | |
description: How many items to return at one time (max 100) | |
required: false | |
schema: | |
type: integer | |
format: int32 | |
responses: | |
"200": | |
description: A paged array of {placeholders} | |
headers: | |
x-next: | |
description: A link to the next page of responses | |
schema: | |
type: string | |
content: | |
application/json: | |
schema: | |
$ref: "#/components/schemas/{Placeholders}" | |
default: | |
description: unexpected error | |
content: | |
application/json: | |
schema: | |
$ref: "#/components/schemas/Error" | |
post: | |
summary: Create an {placeholder} | |
operationId: create{Placeholders} | |
tags: | |
- {placeholders} | |
parameters: | |
- name: {placeholder} | |
in: path | |
required: true | |
description: The {placeholder} object | |
schema: | |
$ref: "#/components/schemas/{Placeholder}" | |
responses: | |
"201": | |
description: {Placeholder} created | |
default: | |
description: unexpected error | |
content: | |
application/json: | |
schema: | |
$ref: "#/components/schemas/Error" | |
/{placeholders}/{id}: | |
get: | |
summary: Info for a specific {placeholder} | |
operationId: show{Placeholder}ById | |
tags: | |
- {placeholders} | |
parameters: | |
- name: id | |
in: path | |
required: true | |
description: The id of the {placeholder} to retrieve | |
schema: | |
type: integer | |
format: int64 | |
responses: | |
"200": | |
description: {Placeholder} retrieved | |
content: | |
application/json: | |
schema: | |
$ref: "#/components/schemas/{Placeholder}" | |
default: | |
description: unexpected error | |
content: | |
application/json: | |
schema: | |
$ref: "#/components/schemas/Error" | |
put: | |
summary: Update an {placeholder} | |
operationId: update{Placeholders} | |
tags: | |
- {placeholders} | |
parameters: | |
- name: id | |
in: path | |
description: ID of {placeholder} to delete | |
required: true | |
schema: | |
type: integer | |
format: int64 | |
- name: {placeholder} | |
in: header | |
required: true | |
description: The {placeholder} object | |
schema: | |
$ref: "#/components/schemas/{Placeholder}" | |
responses: | |
"201": | |
description: {Placeholder} updated | |
default: | |
description: unexpected error | |
content: | |
application/json: | |
schema: | |
$ref: "#/components/schemas/Error" | |
delete: | |
summary: Deletes a single {placeholder} | |
operationId: delete{Placeholder} | |
tags: | |
- {placeholders} | |
parameters: | |
- name: id | |
in: path | |
description: ID of {placeholder} to delete | |
required: true | |
schema: | |
type: integer | |
format: int64 | |
responses: | |
"204": | |
description: {Placeholder} deleted | |
default: | |
description: unexpected error | |
content: | |
application/json: | |
schema: | |
$ref: "#/components/schemas/Error"`; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment