mirror of
https://github.com/LukeHagar/openapi-definition-generator.git
synced 2025-12-06 04:20:23 +00:00
357 lines
8.9 KiB
Svelte
357 lines
8.9 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
|
|
//@ts-ignore
|
|
import { stringify } from 'yaml';
|
|
let inJSON: any;
|
|
let inputJSON = '';
|
|
let outSwagger = '';
|
|
|
|
let requestExamples: boolean;
|
|
let noInt: boolean;
|
|
let yamlOut: boolean;
|
|
let tabCount: number;
|
|
let indentator: string;
|
|
let nullType: string;
|
|
let parseErr: Error | null;
|
|
let timeOut: any;
|
|
|
|
const trigger = (evt: Event) => {
|
|
clearTimeout(timeOut);
|
|
timeOut = setTimeout(() => convert(), 100);
|
|
};
|
|
|
|
const convert = () => {
|
|
localStorage.setItem('inputJSON', inputJSON);
|
|
try {
|
|
inJSON = JSON.parse(inputJSON);
|
|
parseErr = null;
|
|
} catch (e: any) {
|
|
parseErr = e;
|
|
return;
|
|
}
|
|
//For recursive functions to keep track of the tab spacing
|
|
tabCount = 0;
|
|
indentator = '\n';
|
|
// ---- Begin definitions ----
|
|
outSwagger = '{';
|
|
changeIndentation(1);
|
|
//For each object inside the JSON
|
|
for (let obj in inJSON) {
|
|
// ---- Begin schema scope ----
|
|
outSwagger += indentator + '"' + obj + '": {';
|
|
conversorSelection(inJSON[obj]);
|
|
outSwagger += indentator + '},';
|
|
// ---- End schema scope ----
|
|
}
|
|
//Remove last comma
|
|
outSwagger = outSwagger.substring(0, outSwagger.length - 1);
|
|
// ---- End definitions ----
|
|
changeIndentation(tabCount - 1);
|
|
outSwagger += indentator + '}';
|
|
|
|
outSwagger = format(outSwagger);
|
|
};
|
|
|
|
function changeIndentation(count: number) {
|
|
/*
|
|
Assign 'indentator' a string beginning with newline and followed by 'count' tabs
|
|
Updates variable 'tabCount' with the number of tabs used
|
|
Global variables updated:
|
|
-indentator
|
|
-tabCount
|
|
*/
|
|
|
|
let i;
|
|
if (count >= tabCount) {
|
|
i = tabCount;
|
|
} else {
|
|
i = 0;
|
|
indentator = '\n';
|
|
}
|
|
for (; i < count; i++) {
|
|
indentator += '\t';
|
|
}
|
|
//Update tabCount
|
|
tabCount = count;
|
|
}
|
|
|
|
function conversorSelection(obj: any) {
|
|
/*
|
|
Selects which conversion method to call based on given obj
|
|
Global variables updated:
|
|
-outSwagger
|
|
*/
|
|
|
|
changeIndentation(tabCount + 1);
|
|
if (typeof obj === 'number') {
|
|
//attribute is a number
|
|
convertNumber(obj);
|
|
} else if (Object.prototype.toString.call(obj) === '[object Array]') {
|
|
//attribute is an array
|
|
convertArray(obj);
|
|
} else if (typeof obj === 'object') {
|
|
//attribute is an object
|
|
convertObject(obj);
|
|
} else if (typeof obj === 'string') {
|
|
//attribute is a string
|
|
convertString(obj);
|
|
} else if (typeof obj === 'boolean') {
|
|
// attribute is a boolean
|
|
outSwagger += indentator + '"type": "boolean"';
|
|
} else {
|
|
// not a valid Swagger type
|
|
alert('Property type "' + typeof obj + '" not valid for Swagger definitions');
|
|
}
|
|
changeIndentation(tabCount - 1);
|
|
}
|
|
|
|
function convertNumber(num: number) {
|
|
/*
|
|
Append to 'outSwagger' string with Swagger schema attributes relative to given number
|
|
Global variables updated:
|
|
-outSwagger
|
|
*/
|
|
|
|
if (num % 1 === 0 && !noInt) {
|
|
outSwagger += indentator + '"type": "integer",';
|
|
if (num < 2147483647 && num > -2147483647) {
|
|
outSwagger += indentator + '"format": "int32"';
|
|
} else if (Number.isSafeInteger(num)) {
|
|
outSwagger += indentator + '"format": "int64"';
|
|
} else {
|
|
outSwagger += indentator + '"format": "unsafe"';
|
|
}
|
|
} else {
|
|
outSwagger += indentator + '"type": "number"';
|
|
}
|
|
if (requestExamples) {
|
|
//Log example if checkbox is checked
|
|
outSwagger += ',' + indentator + '"example": "' + num + '"';
|
|
}
|
|
}
|
|
|
|
//date is ISO8601 format - https://xml2rfc.tools.ietf.org/public/rfc/html/rfc3339.html#anchor14
|
|
function convertString(str: string) {
|
|
/*
|
|
Append to 'outSwagger' string with Swagger schema attributes relative to given string
|
|
Global variables updated:
|
|
-outSwagger
|
|
*/
|
|
|
|
let regxDate = /^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/,
|
|
regxDateTime =
|
|
/^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]).([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\.[0-9]{1,3})?(Z|(\+|\-)([0-1][0-9]|2[0-3]):[0-5][0-9])$/;
|
|
|
|
outSwagger += indentator + '"type": "string"';
|
|
if (regxDateTime.test(str)) {
|
|
outSwagger += ',';
|
|
outSwagger += indentator + '"format": "date-time"';
|
|
} else if (regxDate.test(str)) {
|
|
outSwagger += ',';
|
|
outSwagger += indentator + '"format": "date"';
|
|
}
|
|
if (requestExamples) {
|
|
//Log example if checkbox is checked
|
|
outSwagger += ',' + indentator + '"example": "' + str + '"';
|
|
}
|
|
}
|
|
|
|
function convertArray(obj: any[]) {
|
|
/*
|
|
Append to 'outSwagger' string with Swagger schema attributes relative to given array
|
|
Global variables updated:
|
|
-outSwagger
|
|
*/
|
|
let schema: any = {};
|
|
let examples = new Set();
|
|
for (const entry of obj) {
|
|
for (const key of Object.keys(entry)) {
|
|
if (!Object.keys(schema).includes(key)) {
|
|
examples.add(entry);
|
|
schema[key] = entry[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
outSwagger += indentator + '"type": "array",';
|
|
// ---- Begin items scope ----
|
|
outSwagger += indentator + '"items": {';
|
|
conversorSelection(schema);
|
|
outSwagger += indentator + '}';
|
|
// ---- End items scope ----
|
|
// ---- Begin example scope ----
|
|
if (requestExamples) {
|
|
outSwagger += ',' + indentator + '"example": ' + JSON.stringify([...examples], null, '\t');
|
|
}
|
|
}
|
|
|
|
function convertObject(obj: any) {
|
|
/*
|
|
Append to 'outSwagger' string with Swagger schema attributes relative to given object
|
|
Global variables updated:
|
|
-outSwagger
|
|
*/
|
|
|
|
//Convert null attributes to given type
|
|
if (obj === null) {
|
|
outSwagger += indentator + '"type": "' + nullType + '",';
|
|
outSwagger += indentator + '"format": "nullable"';
|
|
return;
|
|
}
|
|
// ---- Begin properties scope ----
|
|
outSwagger += indentator + '"type": "object",';
|
|
outSwagger += indentator + '"properties": {';
|
|
changeIndentation(tabCount + 1);
|
|
//For each attribute inside that object
|
|
for (var prop in obj) {
|
|
// ---- Begin property type scope ----
|
|
outSwagger += indentator + '"' + prop + '": {';
|
|
conversorSelection(obj[prop]);
|
|
outSwagger += indentator + '},';
|
|
// ---- End property type scope ----
|
|
}
|
|
|
|
changeIndentation(tabCount - 1);
|
|
if (Object.keys(obj).length > 0) {
|
|
//At least 1 property inserted
|
|
outSwagger = outSwagger.substring(0, outSwagger.length - 1); //Remove last comma
|
|
outSwagger += indentator + '}';
|
|
} else {
|
|
// No property inserted
|
|
outSwagger += ' }';
|
|
}
|
|
}
|
|
|
|
function format(value: string) {
|
|
/*
|
|
Convert JSON to YAML if yaml checkbox is checked
|
|
Global variables updated:
|
|
NONE
|
|
*/
|
|
|
|
value = JSON.stringify(JSON.parse(value), null, '\t');
|
|
|
|
if (yamlOut) {
|
|
return stringify(JSON.parse(value));
|
|
} else {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
onMount(() => {
|
|
let tempJSON = localStorage.getItem('inputJSON');
|
|
if (tempJSON !== null && tempJSON !== '') {
|
|
inputJSON = tempJSON;
|
|
} else {
|
|
inputJSON = `{
|
|
"numbersMock": {
|
|
"smallInt": -20,
|
|
"bigInt": 2147483647,
|
|
"unsafeInt": 9999999999999999,
|
|
"notInt": 12.2
|
|
},
|
|
"stringsMock": {
|
|
"stringTest": "Hello World",
|
|
"isoDate": "1999-12-31",
|
|
"isoDateTime": "1999-12-31T23:59:59Z"
|
|
},
|
|
"objectsMock": {
|
|
"child": {"child": true},
|
|
"childList": [{"child": true}],
|
|
"childMatrix": [[{"child": true}]],
|
|
"nullable": null
|
|
}
|
|
}`;
|
|
}
|
|
convert();
|
|
});
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<meta charset="UTF-8" />
|
|
<title>Swagger Generator</title>
|
|
</svelte:head>
|
|
|
|
<p class="text-center p-8 relative">
|
|
Add your JSON mock to generate Swagger definitions.
|
|
{#if parseErr && inputJSON != ''}
|
|
<aside class="alert variant-filled-warning absolute m-4 center inset-0">
|
|
<h3>Error in JSON</h3>
|
|
<p>{parseErr}</p>
|
|
</aside>
|
|
{/if}
|
|
</p>
|
|
<div class="flex flex-row justify-between p-2 gap-2">
|
|
<textarea
|
|
id="JSON"
|
|
rows="35"
|
|
cols="85"
|
|
class="grow textarea"
|
|
placeholder="Type your JSON"
|
|
contenteditable
|
|
on:input={trigger}
|
|
on:paste
|
|
bind:value={inputJSON}
|
|
/>
|
|
|
|
<textarea
|
|
readonly
|
|
id="Swagger"
|
|
rows="35"
|
|
cols="85"
|
|
class="grow textarea"
|
|
placeholder="Here is your Swagger"
|
|
bind:value={outSwagger}
|
|
/>
|
|
</div>
|
|
<div class="flex flex-row justify-center px-4 gap-24">
|
|
<label class="label">
|
|
Convert null values to:
|
|
<select bind:value={nullType} on:change={() => convert()} class="select" id="nullType">
|
|
<option value="string" selected>String</option>
|
|
<option value="number">Number</option>
|
|
<option value="integer">Integer</option>
|
|
<option value="boolean">Boolean</option>
|
|
</select>
|
|
</label>
|
|
<div>
|
|
<label>
|
|
Add values as examples:
|
|
<input
|
|
bind:checked={requestExamples}
|
|
on:change={() => convert()}
|
|
class="checkbox"
|
|
type="checkbox"
|
|
id="requestExamples"
|
|
/>
|
|
</label>
|
|
<label>
|
|
Convert integer values to number:
|
|
<input
|
|
bind:checked={noInt}
|
|
on:change={() => convert()}
|
|
class="checkbox"
|
|
type="checkbox"
|
|
id="noInt"
|
|
/>
|
|
</label>
|
|
<label>
|
|
Output as YAML:
|
|
<input
|
|
bind:checked={yamlOut}
|
|
on:change={() => convert()}
|
|
class="checkbox"
|
|
type="checkbox"
|
|
id="yamlOut"
|
|
/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<p class="text-center pt-4">
|
|
Feel like collaborating? Clone the repository at <a
|
|
target="_blank"
|
|
href="https://github.com/Roger13/SwaggerGenerator">GitHub</a
|
|
>
|
|
</p>
|