json-schema-transducer

Generate a function using JMESPath to convert from a data to another data which a JSON Schema defines

Usage no npm install needed!

<script type="module">
  import jsonSchemaTransducer from 'https://cdn.skypack.dev/json-schema-transducer';
</script>

README

json-schema-transducer

This module generates a function using JMESPath to convert from a data to another data which a JSON Schema defines.

If a data which a JSON schema defines becomes assigned from another data, there needs a mapper, a converter or a transducer. This module generates such a transducer function from a JMESPath query in the JSON Schema description to describe how to extract and transform the value from an input data. Thus, a JSON Schema remains valid, and there is no need to prepare other resource or code to implement a transducer.

JMESPath Query in JSON Schema Description

The query to extract the JSON value from an input data is describe in Extended Markdown code block syntax at a JSON Schema descrption. The query must be in JMESPath. The value of the element which has such a description is a result to evaluate the JMESPath query for the input data.

The query in a description must have the prefix "query:". The body of the query must be enclosed a single backtick (`) or three backtick (```).

Example:

{
  "title": "json-schema-transducer sample",
  "description": "This description does not include a query because each elements are extracted individually.",
  "type": "object",
  "properties": {
    "address": {
      "description": "\"address\" is derived by query:`User.Address.Name`",
      "type": "string"
    },
    "country-name": {
      "description": "query:```User.Country``` equals to country-name",
      "type": "string"
    }
  }
}

The above example includes two properties, "address" and "country-name". "address" has the description which has a JMESPath query User.Address.Name. And also "country-name" has the description which has a JMESPath query User.Country. This JSON Schema generates a function to transduce from a User object to a json-schema-transducer sample data:

const transducer = require('json-schema-transducer');

try {
  const transduce = await transducer(schema);
} catch (e) {
  // failed to generate a transducer.
  console.log(e);
}

console.log(
  tranceduce(
    {
      "User": {
        "Name": {
          "First": "John",
          "Last": "Coltrane",
        },
        "Address": {
          "Name": "Village Vanguard",
          "Code": "AS-42"
        },
        "Country": "US"
      }
    }
  )
);
// {
//   "address": "Village Vanguard",
//   "country-name": "US"
// }

Relative JMEPath

If there exists queries at the different layers in a schema, the JMESPath expressions of the children must be relative.

{
  "title": "Pets",
  "description": "query:`[*]`",
  "type": "array",
  "properties": {
    "Pet": {
      "type": "object",
      "properties": {
        "HouseNumber": {
          "type": "number",
          "description": "pet.house_number"
        }
      }
    }
  }
}

In the above example, the Pets (not Pets) are extracted from the element objects in Pets ([*]). Therefore, Pet has an extension like pet.house_number, not [*].pet.house_number.

Extract and Transform of oneOf, anyOf, and allOf

A result of oneOf, anyOf, or allOf is extracted as follows:

  1. try to get a result of an item of oneOf, anyOf, or allOf array.
  2. copy the properties in the result to one new object by Object.assign.
  3. cleanup the result object (to delete null and not to delete empty object {}, empty array [] and empty string '').
  4. In the case oneOf or allOf, if the new object is not null, the new object is returned. In the case anyOf, go back to the first.

Complied with this manner, please construct JMESPath expressions of all items to be suitable for what the schema expect. For example, see Or Expressions or And Expressions in JMESPath. Note that this module search the first item of allOf conditions which has type and try to extract the value by the query which the condition has.

Example

Please see __tests__.

Not Supported

  • Object:
    • Property names and Pattern Properties: This module does not support Property names and Pattern Properties directly because the transducer can not determine the property name. However, a JMESPath expression in the same layer of type: "object", not in propertyNames or patternProperties, can generate an object which will match the pattern as a result.
    • Property dependencie and Schema dependencies: Currently, there is no reasonable representation by JMESPath expressions in different layers which describe the dependencies.
  • Combining schemas:
    • not: There does not exists reasonable representation.

License

MIT