JSON_DSL is the json based DSL which provide the condition base transformation of the json data . JSON_DSL store each of operation which is going to performed on json DATA in array when there specific conditions is get satisfied and in last all the operation is performed on the json DATA. Currently, I am using recursion, which may have some side effects. However, I am confident that I can mitigate them using asynchronous programming.
-
Recursive Traverser : As name suggest this method traverser from the json data according to the traverse method provided in the “Path” attribute in the rule
-
Controller : Controller is responsible for the checking of the condition and then call method for performing the operation on the part of the json at which condition get true
-
Operation Performer : This method is perform all the operation provided in the rule on the target part of the json , it call the methods which are available in the “Operations methods” for performing the operations .
-
Conditions Performer : This method perform the conditions provided in the rule using the methods available in the “Conditions methods”
-
Condition Methods : This is the collection of the methods which have the return type of the boolean
-
Operation Methods : This is the collection of the methods which have the return type of the json object which actually is the updated object
-
Getters Methods : After the condition method there is still need to one more collection of the methods which provide some other functionalities will be explain using the example in this Rough DOCS 😀
-
Getter Resolver : This method which resolves the getter method if it is present in the json rules , each and every method call the getter resolver to resolve there parameters .
-
Storage : In this DSL there is the functionality to creat variables which is get store in the same object and can be accessed by using the “getStorage” which is the one of the methods of the “Getters Methods” so that can be used in from any stage , currently i just made this feature for the “ValueIterator” which is one of the method of the Operation methods will be explain later.
const transformRule = [
{
path: "*",
condOperMapper: [
{
conditions: [{ "isKey": { key: "$schema" } }],
operations: { "updateValue": { value: "https://json-schema.org/draft/2020-12/schema" } }
}
]
}
]
this is the one of example of the rule for DSL , in this
- Transformation rule must be the array in which each element represent the rule going to perform in that iteration which represent by
path
, new element in the array represent the new condition and operations on json data which perform with fresh new iteration on the json data - Path represent the the way we want to traverse from the JSON "*" represent the recursive there are 2 more options "#" and specific path, will explain later
- condOperMapper , elements which represent the condtion and operation specific operation only perform when condtions get true
- Overall it change the value of the kye "$schema" to the "https://json-schema.org/draft/2020-12/schema"
In this path represent the target where we want to do the transformation , path can be of 3 type
- specific : in this type we provide the specific path where we want to perform the transformation EX : "something/something2"
- hashSpef (#) : this type is use to perform the transformation rule on the only on the one level of json data (no recursion ) EX : "something/something2/#" this path is perform the operation on the something2 object (no recursion just on the root level )
- recursive (*) : this type is use to perform the transfromation rule recursivly EX : path : "*" apply the rule on whole json recursivly , path : "something/something2/*" this will apply the transformation rule on the something2 recursivly
- Walkers : JSON_DSL have type to traverse from the json scheam just for temparory purpose ( for qulification Task ) using the walkers provided in the alterschema .
this is the transformation rule for the transition of 2019-09 to 2020-12
[
{
"path": { "walkers": "jsonschema-2019-09" },
"condOperMapper": [
{
"conditions": [
{ "isKey": { "key": "$recursiveAnchor" } }
],
"operations": {
"updateValue": {
"value": "anchor"
},
"editKey": {
"key": "$dynamicAnchor"
}
}
},
{
"conditions": [
{ "isKey": { "key": "$recursiveRef" } }
],
"operations": {
"updateValue": {
"value": "#anchor"
},
"editKey": {
"key": "$dynamicRef"
}
}
},
{
"conditions": [
{ "isKey": { "key": "items" } }
],
"operations": {
"editKey": {
"key": "prefixItems"
}
}
},
{
"conditions": [
{ "isKey": { "key": "additionalItems" } }
],
"operations": {
"editKey": {
"key": "items"
}
}
},
{
"conditions": [
{ "isKey": { "key": "$schema" } }
],
"operations": {
"updateValue": {
"value": "https://json-schema.org/draft/2020-12/schema"
}
}
}
]
},
{
"path": { "walkers": "jsonschema-2020-12" },
"condOperMapper": [
{
"conditions": [
{ "isKey": { "key": "$ref" }, "valuePattern": ".*\\bitems\\b.*" },
{ "isKey": { "key": "$ref" }, "valuePattern": ".*\\badditionalItems\\b.*" }
],
"operations": {
"valueIterator": {
"targetValue": { "getFragmentUri": null },
"type": "string",
"splitBy": "/",
"defineStorage": {
"path": {
"current": { "getConcatinate": [{ "getUriWithoutFragment": null }, "#"] },
"updater": [
{
"conditions": [
{ "isEqual": { "value1": "items", "value2": { "getStorage": "_$value_" } } },
{ "isValidPath": { "getConcatinate": [{ "getStorage": "path" }, "/", "prefixItems"] } }
],
"getters": {
"getConcatinate": [{ "getStorage": "path" }, "/prefixItems"]
}
},
{
"conditions": [
{ "isEqual": { "value1": "additionalItems", "value2": { "getStorage": "_$value_" } } },
{ "isValidPath": { "getConcatinate": [{ "getStorage": "path" }, "/", "items"] } }
],
"getters": {
"getConcatinate": [{ "getStorage": "path" }, "/items"]
}
},
{ "getters": { "getConcatinate": [{ "getStorage": "path" }, "/", { "getStorage": "_$value_" }] } }
]
}
},
"operations": {
"updateValue": { "value": { "getStorage": "path" } }
}
}
}
}
]
}
]
In this rule there are 2 transformation object in array first for the tranformation of all the 2019 keywords to the specific keyword of 2020 draft in which jsonschema is iterate using the walkers "jsonschema-2019-09" and 2nd transformation object is for the transformation of the $ref
on the bases of the updated keyword in which json scheam is iterate using the walekrs "jsonschema-2020-12" (as accept $ref whole schema is transform into the 2020-12 draft).
Each tranformation object in array is performed with the different iteration on the JSON data and next transformation object is perfomred after the all the operations of the previous transformation object is performed on the json data
NOTE : Empty conditions
array or not provided conditions
is resolve to the True , so this DSL can be used as the normal DSL like json merge and json patch . For the conditions of json schema Transformation we can use the AJV as done in the alterschema.
valueIterator
is the one of the method from OperationsMethod
it iterate from the value of the key which filter from the
conditions: [{ "isKey": { key: "$ref" }, "valuePattern": ".*\\/items\\/.*" }]
condtions will filter out the element which have the key $ref
and its value follow the json schema pattern .*\\/items\\/.*
- Condtions is the array of the
Condtion methods
- In condtions all the methods present in the same
{ }
somethign like this[{method1 , method2}]
will be performed with the AND operations between them , means if single methods get return false no next conditions is going to be check - All the methods present in the difference
{ }
something like this[{method1} , {method2}]
then OR operations is perform between all the condtions , means if single method return true no next condtions is going to be check
- It iterate from the value of type
string
,array
andobject
splitBy
is the property which is used for the string which is used to split the string form the specific char , if not given then value is iterate from the all characters of the string- For
array
andobject
it iterate from noramlly from the element - Value Iterator maintain the variable
_$value_
and_$key_
which represent the current value and key of the iteration which can be accessed using thegetStorage
method which is the one of the method of theGetters methods
targetValue
is the value on which iteration is performdefineStorage
is the one of the property of the Value Iterator which is used to define the Varaibles , in example keys are the name of the varaibels and value have the property which is used by the valueIterator to update the variables.Current
is the property of the each of the defined variable it's value is used to set the initial value of the variable.updater
is the property which performed for every iteration to update the current value of the variable , it is the array of the object in each object 2 proeprties are therecondtion
andgetters
only one updater is performed (which is under thegetters
) from theupdater
array on the satisfaction of its respective condtion.- Finally
condtions
andopertions
are the properties of thevalueiterator
which is use to perform final operation on the target which is filter from the first conditon (line 65 of above code ) when thecondtions
is satisfied ( we can leave this condtion if we want uncondtional operation )
- This method is use to resolve the ref pointers of the json schema and also provide to realtivly get the reference with respect to the current reference
- This method have 2 property
path
represent the uri or the path WRT to the current reference , In above example getReference is used in the current property of the prevReference variable in this we are using the chain of the getters method let start with in to out.getValue
method used to get the value of the current key value for which we are under this operation method in our case it is$ref
getRootUri
this method give the root (absolute) uri without its fragment, for the input uri in uri property , EX : uri = "/something#/foo/some" this uri is resolve to "https://..../something" under the hood this method is use the base uri which is the nearest$id
WRT to the target ($ref) to resolve the realtive urigetReference
Now this method resolve the uri which get from thegetRootUri
method and return its reference, under the hood JSON_DSL maintian the obj which have all refernce map with there respective$id
(or we can say full URI of them ) , id itself resolve from the previous id as the base uri . This obj is usefull to resolve the case like bunduled schema with difference IDs so in this type of case schemas referenced using the realtive URI , example
- isValidPath : this is the condition method which check weather the path provided is valid or not (can be resolved or not )
- isEqual : this is the condition method which check weather the value1 and value2 is equal or not
- getCocatinate : this is the getters method which concatinate all the value provided in the array by resolvoing it .
this are the updaters of the path variable which update the path variable
------------------------------item to prefixItems----------------------------------------
{
"conditions": [
{ "isEqual": { "value1": "items", "value2": { "getStorage": "_$value_" } } },
{ "isValidPath": { "getConcatinate": [{ "getStorage": "path" }, "/", "prefixItems"] } }
],
"getters": {
"getConcatinate": [{ "getStorage": "path" }, "/prefixItems"]
}
},
-------------------------------additionalItems to items ----------------------------------
{
"conditions": [
{ "isEqual": { "value1": "additionalItems", "value2": { "getStorage": "_$value_" } } },
{ "isValidPath": { "getConcatinate": [{ "getStorage": "path" }, "/", "items"] } }
],
"getters": {
"getConcatinate": [{ "getStorage": "path" }, "/items"]
}
},
---------------------------------Defult-----------------------------------------------------
{
"getters": {
"getConcatinate": [{ "getStorage": "path" }, "/", { "getStorage": "_$value_" }]
}
}
In the rule for the items to prefixItems ,we are cheking 2 conditions first isEqual
check weather _$value_
variable is equal to the items or not and 2nd conditions isValidPath
check weather the path provided is valid or not ( can be resolved or not )
isValidPath
have the value of getters method which resolve in this way
- first
getStorage
method get the value of thepath
- then
getConcatinate
method concatinate thepath
value with the "/" and "prefixItems" (as keyword is alredy transform into the 2020 draft specific ) - then the resolved path is checked by
isValidPath
weather the path is valid or not
when the conditions get satisfied getters
property update the value of path by resolving this
json "getConcatinate": [{ "getStorage": "path" }, "/items"]
Last object is the conditionLess getters which perform for the keys which not require to chagne and for which no other update is perfomred .
In last Operation
perform the operation on the $ref
by updating its value to the path
variable
IN summery : we are checking weather the $ref path is valid or not and then change the path according to it
There analysis phase of the json schema in which one object is created which have the all the reference of the object of Subscheam which have different base URI ( cause by $id , anchor and others ) Explained here .
This object is used by the isValidPath
to resolve the subscheam which have different base URI and then fragment part of the path is resolved using the normal iteration from that reference if referecer resolved succesfully from the path given , then this method return True else False .
- This method is used to get the value/reference(if Object) of the path given in the
path
attribute - If path is startWith #.../ then path is resolve wth respect to the current element for which conditions is checking or operation is performing
- It have
from
property which is the object from where we need to get the path resolve , iffrom
property is given then path must start with the '#' - If
from
attibute is not given and even path is not start with '#.../' in that case getReference resolve the path using base URI ( nearest $id , $anchore or etc ) and that resolved path which is the full URI is searched on the OBJECT which is made in the analysis state of the DSL which have all the reference to the Object map with the uri where baseUri get change.