-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/dev', v1.1.0
- Loading branch information
Showing
9 changed files
with
654 additions
and
15 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
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
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
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
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
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,188 @@ | ||
const Utils = require('./utils.js'); | ||
|
||
/** | ||
* Utilities to parse process specs and JSON schemas. | ||
* | ||
* @class | ||
*/ | ||
class ProcessUtils { | ||
|
||
/** | ||
* From a "complex" JSON Schema with allOf/anyOf/oneOf, make separate schemas. | ||
* | ||
* So afterwards each schema has it's own array entry. | ||
* It merges allOf, resolves anyOf/oneOf into separate schemas. | ||
* May also split the JSON Schema type arrays into separate entries by setting `splitTypes` to `true`. | ||
* | ||
* @param {object|array} schemas - The JSON Schema(s) to convert | ||
* @returns {array} | ||
*/ | ||
static normalizeJsonSchema(schemas, splitTypes = false) { | ||
// Make schemas always an array | ||
if (Utils.isObject(schemas)) { | ||
schemas = [schemas]; | ||
} | ||
else if (Array.isArray(schemas)) { | ||
schemas = schemas; | ||
} | ||
else { | ||
schemas = []; | ||
} | ||
|
||
// Merge allOf, resolve anyOf/oneOf into separate schemas | ||
let normalized = []; | ||
for(let schema of schemas) { | ||
if (Array.isArray(schema.allOf)) { | ||
normalized.push(Object.assign({}, ...schema.allOf)); | ||
} | ||
else if (Array.isArray(schema.oneOf) || Array.isArray(schema.anyOf)) { | ||
let copy = Utils.omitFromObject(schema, ['oneOf', 'anyOf']); | ||
let subSchemas = schema.oneOf || schema.anyOf; | ||
for(let subSchema of subSchemas) { | ||
normalized.push(Object.assign({}, copy, subSchema)); | ||
} | ||
} | ||
else { | ||
normalized.push(schema); | ||
} | ||
} | ||
|
||
if (!splitTypes) { | ||
return normalized; | ||
} | ||
|
||
// Split type field into separate schemas | ||
schemas = []; | ||
for(let schema of normalized) { | ||
if (Array.isArray(schema.type)) { | ||
/* jshint ignore:start */ | ||
schemas = schemas.concat(schema.type.map(type => Object.assign({}, schema, {type: type}))); | ||
/* jshint ignore:end */ | ||
} | ||
else { | ||
schemas.push(schema); | ||
} | ||
} | ||
|
||
return schemas; | ||
} | ||
|
||
/** | ||
* Returns the callback parameters for a given process parameter. | ||
* | ||
* @param {object} processParameter - The process parameter spec to parse. | ||
* @returns {array} | ||
* @throws {Error} | ||
*/ | ||
static getCallbackParameters(processParameter) { | ||
if (!Utils.isObject(processParameter) || !processParameter.schema) { | ||
return []; | ||
} | ||
|
||
let schemas = ProcessUtils.normalizeJsonSchema(processParameter.schema); | ||
|
||
let cbParams = []; | ||
for(let schema of schemas) { | ||
if (Array.isArray(schema.parameters)) { | ||
if (cbParams.length > 0 && !Utils.equals(cbParams, schema.parameters)) { | ||
throw new Error("Multiple schemas with different callback parameters found."); | ||
} | ||
cbParams = schema.parameters; | ||
} | ||
} | ||
|
||
return cbParams; | ||
} | ||
|
||
/** | ||
* Returns the callback parameters for a given process parameter from a full process spec. | ||
* | ||
* @param {object} process - The process to parse. | ||
* @param {string} parameterName - The name of the parameter to get the callback parameters for. | ||
* @returns {array} | ||
* @throws {Error} | ||
*/ | ||
static getCallbackParametersForProcess(process, parameterName) { | ||
if (!Utils.isObject(process) || !Array.isArray(process.parameters)) { | ||
return []; | ||
} | ||
|
||
let param = process.parameters.find(p => p.name === parameterName); | ||
return ProcessUtils.getCallbackParameters(param); | ||
} | ||
|
||
/** | ||
* Returns *all* the native JSON data types allowed for the schema. | ||
* | ||
* @param {object} schema | ||
* @param {boolean} anyIsEmpty | ||
* @returns {array} | ||
*/ | ||
static getNativeTypesForJsonSchema(schema, anyIsEmpty = false) { | ||
if (Utils.isObject(schema) && Array.isArray(schema.type)) { | ||
// Remove duplicate and invalid types | ||
let validTypes = Utils.unique(schema.type).filter(type => ProcessUtils.JSON_SCHEMA_TYPES.includes(type)); | ||
if (validTypes.length > 0 && validTypes.length < ProcessUtils.JSON_SCHEMA_TYPES.length) { | ||
return validTypes; | ||
} | ||
else { | ||
return anyIsEmpty ? [] : ProcessUtils.JSON_SCHEMA_TYPES; | ||
} | ||
} | ||
else if (Utils.isObject(schema) && typeof schema.type === 'string' && ProcessUtils.JSON_SCHEMA_TYPES.includes(schema.type)) { | ||
return [schema.type]; | ||
} | ||
else { | ||
return anyIsEmpty ? [] : ProcessUtils.JSON_SCHEMA_TYPES; | ||
} | ||
} | ||
|
||
/** | ||
* Returns the schema for a property of an object or an element of an array. | ||
* | ||
* If you want to retrieve the schema for a specific key, use the parameter `key`. | ||
* | ||
* @param {object} schema - The JSON schema to parse. | ||
* @param {string|integer|null} key - If you want to retrieve the schema for a specific key, otherwise null. | ||
* @returns {object} - JSON Schema | ||
*/ | ||
static getElementJsonSchema(schema, key = null) { | ||
let types = ProcessUtils.getNativeTypesForJsonSchema(schema); | ||
if (Utils.isObject(schema) && types.includes('array') && typeof key !== 'string') { | ||
if (Utils.isObject(schema.items)) { | ||
// Array with one schema for all items: https://json-schema.org/understanding-json-schema/reference/array.html#id5 | ||
return schema.items; | ||
} | ||
else if (Array.isArray(schema.items)) { | ||
// Tuple validation: https://json-schema.org/understanding-json-schema/reference/array.html#id6 | ||
if (key !== null && Utils.isObject(schema.items[key])) { | ||
return schema.items[key]; | ||
} | ||
else if (Utils.isObject(schema.additionalItems)) { | ||
return schema.additionalItems; | ||
} | ||
} | ||
} | ||
if (Utils.isObject(schema) && types.includes('object')) { | ||
if (key !== null && Utils.isObject(schema.properties) && Utils.isObject(schema.properties[key])) { | ||
return schema.properties[key]; | ||
} | ||
else if (Utils.isObject(schema.additionalProperties)) { | ||
return schema.additionalProperties; | ||
} | ||
// ToDo: No support for patternProperties yet | ||
} | ||
|
||
return {}; | ||
} | ||
|
||
} | ||
|
||
/** | ||
* A list of all allowed JSON Schema type values. | ||
* | ||
* @type {array} | ||
*/ | ||
ProcessUtils.JSON_SCHEMA_TYPES = ['string', 'number', 'integer', 'boolean', 'array', 'object', 'null']; | ||
|
||
module.exports = ProcessUtils; |
Oops, something went wrong.