Skip to content

Commit

Permalink
JSON2Schema updated with propertyOrder auto inserted for preserving t…
Browse files Browse the repository at this point in the history
…he defined property order in other browsers like Chrome, that seem to ignore the order in which the key-value-pairs are generated internally. propertyOrdner fixes the browser inconsitency of Chrome. So propertyOrder is added the JSON2Schema generator.
  • Loading branch information
Engelbert Niehaus committed May 16, 2018
1 parent 2f24116 commit 2db9c22
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 36 deletions.
130 changes: 114 additions & 16 deletions docs/plugins/dbedit/js/json2schema.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@

function onClickSchema4JSON(pInputID,pOutputID) {
function onClickSchema4JSON(pInputID,pOutputID,pTitleID) {
var vRootTitle = getValueDOM(pTitleID);

var vStringJSON = getEditorValue(pInputID);
var vJSON = getJSON4String(vStringJSON);
if (vJSON) {
var vSchema = getSchema4JSON(vJSON);
var vSchema = getSchema4JSON(vJSON,vRootTitle);
vSchema["title"] = vRootTitle;
var vStringSchema = JSON.stringify(vSchema,null,4);
//write2value(pOutputID,vStringSchema);
setEditorValue(pOutputID,vStringSchema);
Expand All @@ -13,13 +16,15 @@ function onClickSchema4JSON(pInputID,pOutputID) {
}
}

function getSchema4JSON(pJSON) {
function getSchema4JSON(pJSON,pTitle) {
// getSchema4JSON is called for the root element of the JSON file
var vTitle = pTitle || "MyJSON";
console.log("getSchema4JSON(pJSON,'"+vTitle+"')");
var vPath = "";
var vSchema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"additionalProperties": true,
"title":"MyJSON",
"title":vTitle,
"definitions": {
"comment": {
"title": "Comment:",
Expand All @@ -44,7 +49,7 @@ function getSchema4JSON(pJSON) {
// in a recursive way.
var vEditorPath = "root";
// path is keeping track of the JSON schema
convertJSON2Schema(pJSON,vPath,vSchema,vTypeTree,vEditorPath);
convertJSON2Schema(pJSON,vPath,vSchema,vTypeTree,vEditorPath,vTitle);
//return vTypeTree;
return vSchema;
};
Expand All @@ -59,6 +64,84 @@ function getTypeTree4JSON(pJSON) {
return vTypeTree;
};

function toUpperCase1Char(pString) {
// converts first character to uppercase.
var vString = pString || "undefined_string";
if (vString.indexOf("/")>=0) {
vString = vString.slice(vString.lastIndexOf("/")+1);
};
vString = vString.replace(/[^A-Za-z0-9]/g,"_"); // remove illegial characters in variable name
return vString.charAt(0).toUpperCase() + vString.slice(1);
};


function getID4EditorPath(pPath) {
var vID = pPath;
var vSlashPos = vID.lastIndexOf(".")
if (vSlashPos>0) {
vID = pPath.substring(vSlashPos+1);
};
return vID;
}

function getTitle4EditorPath(pPath,pRootTitle) {
var vTitle = getID4EditorPath(pPath);
if (vTitle.length>0) {
vTitle = var2title(vTitle);
};
//e.g. pPath = root.* vTitle = "*"
if (vTitle == "*") {
pPath = pPath.substr(0,pPath.lastIndexOf("."));
vTitle = getTitle4EditorPath(pPath);
};
if (vTitle == "Root") {
if (pRootTitle) {
vTitle = pRootTitle;
};
};
vTitle = var2title(vTitle);
return vTitle;
}

function var2title(pName) {
var vName = "undefined var";
if (pName) {
vName = pName;
vName = vName.replace(/[^A-Za-z9-9äöüÄÖÜ]+/g," ");
var vNameArr = vName.split(" ");
for (var i = 0; i < vNameArr.length; i++) {
vNameArr[i] = toUpperCase1Char(vNameArr[i]);
};
vName = vNameArr.join(" ");
};
return vName;
}

function getDescription4EditorPath(pPath,pType,pDescription) {
var vDescription = "Description for '"+getID4Path(pPath)+"' Type: '"+pType+"' Path: '"+pPath+"'";
//vDescription = "";
if (pDescription) {
if (pDescription != "") {
vDescription = pDescription;
} else {
};
};
return vDescription;
}


function getTitle4JSON(pEditorPath,pType,pTitle) {
var vTitle = "Title of '"+pEditorPath+"' Type: '"+pType+"'";
if (pTitle) {
if (pTitle != "") {
vTitle = pTitle;
} else {
vTitle = getTitle4EditorPath(pEditorPath);
};
};
return vTitle;
};

function createTypeTree4JSON(pJSON,pTypeTree) {
var vType = getType4JSON(pJSON);
var vSubType = "";
Expand Down Expand Up @@ -102,7 +185,9 @@ function getID4Path(pPath) {
return vID;
}

function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath,pTitle) {
console.log("convertJSON2Schema('"+pPath+"') pTitle='"+pTitle+"'");
var vTitle = pTitle || "Default Schema Title";
// pTypeTree is need for checking deep equal for "oneOf" definition in arrays
var vType = getType4JSON(pJSON);
//---set Type and ID---
Expand All @@ -118,7 +203,9 @@ function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
switch (vType) {
//---- OBJECT/HASH -------
case "object":
pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
//pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
pSchema["title"] = getTitle4EditorPath(pEditorPath,vType,vTitle);
console.log("Title for Object='"+vTitle+"'");
pSchema["options"] = {
"disable_collapse": false,
"disable_edit_json": false,
Expand All @@ -129,6 +216,7 @@ function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
break;
//---- ARRAY -------------
case "array":
pSchema["title"] = getTitle4EditorPath(pEditorPath,vType,vTitle);
pSchema["format"] = "tabs";
pSchema["options"] = {
"disable_collapse": false,
Expand All @@ -142,17 +230,20 @@ function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
break;
//---- STRING ------------
case "string":
pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
//pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
pSchema["title"] = getTitle4EditorPath(pEditorPath,vType,vTitle);
pSchema["default"] = pJSON; //"Default text of "+vType+" variable";
pSchema["format"] = determineFormat4String(pJSON);
pSchema["description"] = "A description for '"+getID4Path(pPath)+"' Type: '"+vType+"'";
pSchema["description"] = getDescription4EditorPath(pPath,vType);
//"A description for '"+getID4Path(pPath)+"' Type: '"+vType+"'";
pSchema["options"] = {
"hidden": false
};
break;
//---- NUMBER ------------
case "number":
pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
//pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
pSchema["title"] = getTitle4EditorPath(pEditorPath,vType,vTitle);
pSchema["default"] = pJSON;
pSchema["description"] = "A description for '"+getID4Path(pPath)+"' Type: '"+vType+"'";
pSchema["options"] = {
Expand All @@ -161,7 +252,8 @@ function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
break;
//---- INTEGER ------------
case "integer":
pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
//pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
pSchema["title"] = getTitle4EditorPath(pEditorPath,vType,vTitle);
pSchema["default"] = pJSON;
pSchema["description"] = "A description for '"+getID4Path(pPath)+"' Type: '"+vType+"'";
pSchema["options"] = {
Expand All @@ -170,7 +262,8 @@ function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
break;
//---- BOOLEAN ------------
case "boolean":
pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
//pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
pSchema["title"] = getTitle4EditorPath(pEditorPath,vType,vTitle);
pSchema["format"] = "checkbox";
pSchema["default"] = pJSON;
pSchema["description"] = "A description for '"+getID4Path(pPath)+"' Type: '"+vType+"'";
Expand All @@ -179,13 +272,16 @@ function convertJSON2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
};
break;
default:
pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
//pSchema["title"] = "Title of '"+pEditorPath+"' Type: '"+vType+"'";
pSchema["title"] = getTitle4EditorPath(pEditorPath,vType,vTitle);
pSchema["default"] = null;
pSchema["description"] = "A description for '"+getID4Path(pPath)+"' Type: '"+vType+"'";
pSchema["options"] = {
"hidden": false
};
};

console.log("SchemaGen - Path: '"+pPath+"' Type='"+vType+"' Title='"+pSchema["title"]+"'");
};

function convertObject2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
Expand All @@ -204,15 +300,15 @@ function convertObject2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
// now call convertJSON2Schema() on sub-structure of JSON
convertJSON2Schema(pJSON[key],pPath+"/properties/"+key,pSchema["properties"][key],pTypeTree[key],pEditorPath+"."+key);
pSchema["properties"][key]["propertyOrder"] = order_index;
order_index += order_increment;
order_index += order_increment;
};
};
};

function convertArray2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
var vID = "";
pSchema["items"] = {};
pSchema["items"]["headerTemplate"] = "{{i1}}";
pSchema["items"]["headerTemplate"] = "Record {{i1}}";
var vItems = [];
var vDefaults = [];
for (var i = 0; i < pJSON.length; i++) {
Expand All @@ -223,6 +319,7 @@ function convertArray2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
// check if previous elements of array are deep equal
var vDeepEqual = false;
console.log("Compare JSON1:\n"+JSON.stringify(pTypeTree[i],null,4));
/* Deep Equal Check
for (var k = 0; k < i; k++) {
console.log("Compare JSON2["+k+"]:\n"+JSON.stringify(pTypeTree[k],null,4));
if(_.isEqual(pTypeTree[k], pTypeTree[i])){
Expand All @@ -231,14 +328,15 @@ function convertArray2Schema(pJSON,pPath,pSchema,pTypeTree,pEditorPath) {
};
// if subTypeTree of vHash4ID is not deep equal to previous array elements
// push the new schema for the element and store the SubTypeTree
*/
if (vDeepEqual == false) {
vItems.push(vHash4ID);
};
};
// if more than one vItems are present in array, use "oneOf" for schema.
if (vItems.length > 1) {
for (var i = 0; i < vItems.length; i++) {
vItems[i]["id"] = pPath+"/arr"+i;
vItems[i]["id"] = pPath+"/oneof"+i;
vItems[i]["title"] = "Title array"+i+" "+pPath;
};
pSchema["items"]["oneOf"] = vItems;
Expand Down
11 changes: 9 additions & 2 deletions docs/plugins/json2schema.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,21 @@ <h4>
</h4>
</div>
<hr>
<h3>Schema Title</h3>
<b>Title:</b> <input type="text" id="tTitleSchema" value="My Schema Title">
<hr>
<h3>JSON Input</h3>
<textarea id="jsoninput" rows="5" cols="20" style="display:none">
{
"myid": 1,
"book": "A green door",
"authors": [
"Mary Myers",
"Bert Bond"
{
"name":"Bert Bond",
"age":65
}

],
"prices": {
"buy": 12.5,
Expand All @@ -98,7 +105,7 @@ <h3>JSON Input</h3>
<iframe src="ace/ace.html?domid=jsoninput&mode=json" id="iACEinput" width="90%" height="150px"></iframe>
</div>
<p id="pConverter">
<button id='bCreateSchema' onclick="onClickSchema4JSON('iACEinput','iACEoutput')">Create JSON Schema</button>
<button id='bCreateSchema' onclick="onClickSchema4JSON('iACEinput','iACEoutput','tTitleSchema')">Create JSON Schema</button>
<button id='bExportJSON' onclick="saveFile2HDD('myjson.json',getEditorValue('iACEinput'))">Export JSON</button>
</p>
<div id="pSchemaOutput" style="display:none">
Expand Down

0 comments on commit 2db9c22

Please sign in to comment.