-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fab4cee
commit 3a0edc4
Showing
7 changed files
with
885 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,3 +102,5 @@ dist | |
|
||
# TernJS port file | ||
.tern-port | ||
|
||
.DS_Store |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#!/usr/bin/env node | ||
|
||
const postmanToOpenApi = require("postman-to-openapi"); | ||
const YAML = require("yamljs"); | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const _ = require("lodash"); | ||
const $RefParser = require("json-schema-ref-parser"); | ||
const colors = require("colors"); | ||
|
||
const openapiJSONPath = "./openapi.json"; | ||
|
||
const importSchemas = async (obj) => { | ||
const jsonFiles = fs | ||
.readdirSync(path.resolve("schemas")) | ||
.filter((filename) => filename.endsWith(".json")); | ||
|
||
console.log( | ||
`${jsonFiles.length} files found on the schemas directory`.italic.underline | ||
); | ||
|
||
await Promise.all( | ||
jsonFiles.map(async (jsonFile) => { | ||
const content = require(path.resolve("schemas", jsonFile)); | ||
|
||
const refsJSON = await $RefParser.dereference(content); | ||
|
||
for (const nestedPath in refsJSON) { | ||
_.set(obj, nestedPath, { | ||
..._.get(obj, nestedPath), | ||
...refsJSON[nestedPath], | ||
}); | ||
} | ||
}) | ||
); | ||
|
||
return obj; | ||
}; | ||
|
||
const writeToJSONFile = (data, filePath) => | ||
fs.writeFileSync( | ||
path.resolve(path.join(filePath)), | ||
JSON.stringify(data, null, 2) | ||
); | ||
|
||
module.exports = async (postmanCollectionPath, config) => { | ||
const rawOpenapiYAML = await postmanToOpenApi( | ||
path.resolve(postmanCollectionPath), | ||
null, | ||
config | ||
); | ||
|
||
const rawOpenapiJSON = YAML.parse(rawOpenapiYAML); | ||
const openapiJSON = await importSchemas(rawOpenapiJSON); | ||
|
||
writeToJSONFile(openapiJSON, openapiJSONPath); | ||
|
||
console.log( | ||
"\n[✓] Build the OpenAPI spec file and saved in `openapi.json` file".green, | ||
"\n" | ||
); | ||
}; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#!/usr/bin/env node | ||
|
||
const flatten = require("obj-flatten"); | ||
const postmanToOpenApi = require("postman-to-openapi"); | ||
const YAML = require("yamljs"); | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const _ = require("lodash"); | ||
const GenerateSchema = require("generate-schema"); | ||
const colors = require("colors"); | ||
const SCHEMA_DIR = "schemas"; | ||
|
||
const extractedJSONPath = "./schemas/_extracted.json"; | ||
|
||
const isValidPath = (p) => { | ||
const regexs = [ | ||
/paths.*.requestBody.*.application\/json.schema.type/, | ||
/paths.*.responses.*.application\/json.schema.type/, | ||
]; | ||
return regexs.map((re) => re.test(p)).some((v) => v === true); | ||
}; | ||
|
||
const writeToJSONFile = (data, filePath) => | ||
fs.writeFileSync( | ||
path.resolve(path.join(filePath)), | ||
JSON.stringify(data, null, 2) | ||
); | ||
|
||
const getExsistingPaths = () => { | ||
const jsonFiles = fs | ||
.readdirSync(path.join(SCHEMA_DIR)) | ||
.filter((filename) => filename.endsWith(".json")); | ||
|
||
let exsitingPaths = []; | ||
jsonFiles.forEach((jsonFile) => { | ||
const content = require(path.resolve("schemas", jsonFile)); | ||
exsitingPaths = [...exsitingPaths, ...Object.keys(content)]; | ||
}); | ||
|
||
return exsitingPaths; | ||
}; | ||
|
||
module.exports = async (postmanCollectionPath) => { | ||
if (!fs.existsSync(path.resolve(SCHEMA_DIR))) { | ||
fs.mkdirSync(path.resolve(SCHEMA_DIR)); | ||
} | ||
|
||
const exsitingPaths = getExsistingPaths(); | ||
|
||
const rawOpenapiYAML = await postmanToOpenApi(postmanCollectionPath, null, { | ||
defaultTag: "General", | ||
}); | ||
|
||
const rawOpenapiJSON = YAML.parse(rawOpenapiYAML); | ||
|
||
const targetPaths = Object.keys(flatten(rawOpenapiJSON)) | ||
.filter(isValidPath) | ||
.map((p) => p.split(".").slice(0, -1).join(".")); | ||
|
||
let differencePaths = targetPaths.filter((x) => !exsitingPaths.includes(x)); | ||
console.log(`${differencePaths.length} paths found!`.italic.underline); | ||
|
||
const pathsWithExampleSchema = {}; | ||
differencePaths.forEach((p) => { | ||
const requestExample = _.get(rawOpenapiJSON, `${p}.example`); | ||
const responseExample = _.get( | ||
rawOpenapiJSON, | ||
`${p.split(".").slice(0, -1).join(".")}.example` | ||
); | ||
|
||
if (requestExample) { | ||
pathsWithExampleSchema[p] = { | ||
...GenerateSchema.json(requestExample), | ||
$schema: undefined, | ||
}; | ||
} else if (responseExample) { | ||
pathsWithExampleSchema[p] = { | ||
...GenerateSchema.json(responseExample), | ||
$schema: undefined, | ||
}; | ||
} else { | ||
pathsWithExampleSchema[p] = {}; | ||
} | ||
}); | ||
|
||
writeToJSONFile(pathsWithExampleSchema, extractedJSONPath); | ||
console.log( | ||
"\n[✓] Saved the extracted paths with schemas from examples at: schemas/_extracted.json" | ||
.green, | ||
"\n[⚈] Remove/Rename the file before you run `extract` for the next time or it'll get reset" | ||
.blue, | ||
"\n[ ] Run `p2ojx build` to compile the complete OpenAPI specfile".yellow, | ||
"\n", | ||
"\nGood to know:".gray, | ||
"\n[?] You can break up the whole list of extracted schemas into smaller files. Make sure, they're present in the schemas directory" | ||
.gray, | ||
"\n[?] You can use JSON refs in your schemas".gray, | ||
"\n" | ||
); | ||
}; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#!/usr/bin/env node | ||
|
||
const { Command } = require("commander"); | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const extract = require("./extract"); | ||
const colors = require("colors"); | ||
const build = require("./build"); | ||
const NOT_FOUND = "NOT_FOUND"; | ||
|
||
const program = new Command(); | ||
program.version("0.0.1"); | ||
|
||
program | ||
.command("extract") | ||
.description( | ||
"Extract requests and responses schemas from the postman collection" | ||
) | ||
.argument("[input file path]", "The postman_collection.json file") | ||
.action(async (postmanCollectionPath) => { | ||
if (!postmanCollectionPath) { | ||
const avaliableCollection = fs | ||
.readdirSync(path.resolve()) | ||
.filter((file) => file.endsWith(".postman_collection.json"))[0]; | ||
|
||
if (!avaliableCollection) { | ||
console.error("No postman collection found!".red); | ||
return; | ||
} | ||
postmanCollectionPath = avaliableCollection; | ||
} | ||
|
||
console.log(`Postman collection: ${postmanCollectionPath}`.magenta); | ||
await extract(postmanCollectionPath); | ||
}); | ||
|
||
program | ||
.command("build") | ||
.description( | ||
"Build the OpenAPI specs file with the extended schemas specified" | ||
) | ||
.option("-p <postmanCollectionPath>", "Pass the postman_collection.json file") | ||
.option( | ||
"-c <configPath>", | ||
"Pass the additional configurations as a `.p2ojx.json` file. See: https://joolfe.github.io/postman-to-openapi/#options" | ||
) | ||
.action(async ({ p: postmanCollectionPath, c: configPath }) => { | ||
if (!postmanCollectionPath) { | ||
const avaliableCollection = fs | ||
.readdirSync(path.resolve()) | ||
.filter((file) => file.endsWith(".postman_collection.json"))[0]; | ||
|
||
if (!avaliableCollection) { | ||
console.error("No postman collection found!".red); | ||
return; | ||
} | ||
postmanCollectionPath = avaliableCollection; | ||
} | ||
|
||
if (!configPath) { | ||
const availableConfigFile = fs | ||
.readdirSync(path.resolve()) | ||
.filter((file) => file.endsWith(".p2ojx.json"))[0]; | ||
|
||
if (!availableConfigFile) { | ||
configPath = {}; | ||
} else { | ||
configPath = path.resolve(availableConfigFile); | ||
} | ||
} | ||
|
||
const config = require(configPath); | ||
|
||
console.log(`Postman collection: ${postmanCollectionPath}`.magenta); | ||
console.log(`Configuration: ${configPath}`.magenta); | ||
|
||
await build(postmanCollectionPath, config); | ||
}); | ||
|
||
program.parse(process.argv); |
Oops, something went wrong.