@openeo/js-commons
Advanced tools
Comparing version 0.4.0-beta.2 to 0.4.0
1885
dist/main.js
@@ -1,1 +0,1884 @@ | ||
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("ajv"));else if("function"==typeof define&&define.amd)define(["ajv"],t);else{var r="object"==typeof exports?t(require("ajv")):t(e.ajv);for(var s in r)("object"==typeof exports?exports:e)[s]=r[s]}}(window,function(e){return function(e){var t={};function r(s){if(t[s])return t[s].exports;var a=t[s]={i:s,l:!1,exports:{}};return e[s].call(a.exports,a,a.exports,r),a.l=!0,a.exports}return r.m=e,r.c=t,r.d=function(e,t,s){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(r.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)r.d(s,a,function(t){return e[t]}.bind(null,a));return s},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=7)}([function(e,t,r){const s=r(9);var a={compareVersion(e,t){try{return s(e,t)}catch(e){return null}},isObject:e=>"object"==typeof e&&e===Object(e)&&!Array.isArray(e),size:e=>"object"==typeof e&&null!==e?Array.isArray(e)?e.length:Object.keys(e).length:0,replacePlaceholders(e,t={}){if("string"==typeof e&&this.isObject(t))for(var r in t)e=e.replace("{"+r+"}",t[r]);return e},mergeDeep(e,...t){if(!t.length)return e;const r=t.shift();if(this.isObject(e)&&this.isObject(r))for(const t in r)this.isObject(r[t])?(e[t]||(e[t]={}),this.mergeDeep(e[t],r[t])):e[t]=r[t];return this.mergeDeep(e,...t)}};e.exports=a},function(e,t,r){const s=r(0),a={MultipleResultNodes:"Multiple result nodes specified for process graph.",StartNodeMissing:"No start nodes found for process graph.",ResultNodeMissing:"No result node found for process graph.",MultipleResultNodesCallback:"Multiple result nodes specified for the callback in the process '{process_id}' (node: '{node_id}').",StartNodeMissingCallback:"No start nodes found for the callback in the process '{process_id}' (node: '{node_id}')'.",ResultNodeMissingCallback:"No result node found for the callback in the process '{process_id}' (node: '{node_id}').",ReferencedNodeMissing:"Referenced node '{node_id}' doesn't exist.",NodeIdInvalid:"Invalid node id specified in process graph.",NodeInvalid:"Process graph node '{node_id}' is not a valid object.",ProcessIdMissing:"Process graph node '{node_id}' doesn't contain a process id.",CallbackArgumentInvalid:"Invalid callback argument '{argument}' requested in the process '{process_id}' (node: '{node_id}').",ProcessUnsupported:"Process '{process}' is not supported.",ProcessArgumentUnsupported:"Process '{process}' does not support argument '{argument}'.",ProcessArgumentRequired:"Process '{process}' requires argument '{argument}'.",ProcessArgumentInvalid:"The argument '{argument}' in process '{process}' is invalid: {reason}",VariableValueMissing:"No value specified for process graph variable '{variable_id}'.",VariableDefaultValueTypeInvalid:"The default value specified for the process graph variable '{variable_id}' is not of type '{type}'.",VariableValueTypeInvalid:"The value specified for the process graph variable '{variable_id}' is not of type '{type}'.",VariableIdInvalid:"A specified variable ID is not valid.",VariableTypeInvalid:"The data type specified for the process graph variable '{variable_id}' is invalid. Must be one of: string, boolean, number, array or object."};e.exports=class extends Error{constructor(e,t={}){super(),this.code=e,this.variables=t,"string"==typeof a[e]&&(this.message=s.replacePlaceholders(a[e],t))}toJSON(){return{code:this.code,message:this.message}}}},function(e,t,r){const s=r(1),a=r(0);e.exports=class e{constructor(e,t,r){if("string"!=typeof t||0===t.length)throw new s("NodeIdInvalid");if(!a.isObject(e))throw new s("NodeInvalid",{node_id:t});if("string"!=typeof e.process_id)throw new s("ProcessIdMissing",{node_id:t});this.id=t,this.processGraph=r,this.process_id=e.process_id,this.arguments=e.arguments||{},this.isResultNode=e.result||!1,this.expectsFrom=[],this.passesTo=[],this.result=null,this.resultsAvailableFrom=[]}getProcessGraph(){return this.processGraph}getArgumentNames(){return Object.keys(this.arguments)}hasArgument(e){return e in this.arguments}getArgumentType(t){return e.getType(this.arguments[t])}getRawArgument(e){return this.arguments[e]}getRawArgumentValue(t){var r=this.arguments[t];switch(e.getType(r)){case"result":return r.from_node;case"callback":return r.callback;case"callback-argument":return r.from_argument;default:return r}}getArgument(e,t){return void 0===this.arguments[e]?t:this.processArgument(this.arguments[e])}processArgument(t){switch(e.getType(t)){case"result":return this.processGraph.getNode(t.from_node).getResult();case"callback":return t.callback;case"callback-argument":return this.processGraph.getParameter(t.from_argument);case"variable":return this.processGraph.getVariableValue(t.variable_id);case"array":case"object":for(var r in t)t[r]=this.processArgument(t[r]);return t;default:return t}}static getType(e,t="null"){return"object"==typeof e?null===e?t:Array.isArray(e)?"array":e.hasOwnProperty("callback")?"callback":e.hasOwnProperty("variable_id")?"variable":e.hasOwnProperty("from_node")?"result":e.hasOwnProperty("from_argument")?"callback-argument":"object":typeof e}isStartNode(){return 0===this.expectsFrom.length}addPreviousNode(e){this.expectsFrom.push(e)}getPreviousNodes(){return this.expectsFrom}addNextNode(e){this.passesTo.push(e)}getNextNodes(){return this.passesTo}reset(){this.result=null,this.resultsAvailableFrom=[]}setResult(e){this.result=e}getResult(){return this.result}solveDependency(e){return null!==e&&this.expectsFrom.includes(e)&&this.resultsAvailableFrom.push(e),this.expectsFrom.length===this.resultsAvailableFrom.length}}},function(e,t,r){const s=r(4),a=r(1),i=r(2),o=r(5),n=r(0);e.exports=class{constructor(e,t=null){this.schema=e,this.jsonSchema=null===t?new s:t}async validate(e){var t=e.getArgumentNames().filter(e=>void 0===this.schema.parameters[e]);if(t.length>0)throw new a("ProcessArgumentUnsupported",{process:this.schema.id,argument:t[0]});for(let t in this.schema.parameters){let r=this.schema.parameters[t],s=e.getRawArgument(t);if(await this.validateArgument(s,e,t,r))continue;let i=await this.jsonSchema.validateJson(s,r.schema);if(i.length>0)throw new a("ProcessArgumentInvalid",{process:this.schema.id,argument:t,reason:i.join("; ")})}}async validateArgument(e,t,r,l){let c=i.getType(e);if(e instanceof o)return await e.validate(!0),!0;switch(c){case"undefined":if(l.required)throw new a("ProcessArgumentRequired",{process:this.schema.id,argument:r});return!0;case"callback-argument":var d=t.getProcessGraph().getCallbackParameters();if(n.isObject(d)&&d.hasOwnProperty(e.from_argument))return s.isSchemaCompatible(l.schema,d[e.from_argument]);throw new a("CallbackArgumentInvalid",{argument:e.from_argument,node_id:t.id,process_id:this.schema.id});case"variable":var p={type:e.type||"string"};return s.isSchemaCompatible(l.schema,p);case"result":try{var u=t.getProcessGraph(),h=u.getNode(e.from_node).process_id,v=u.getProcess(h);return s.isSchemaCompatible(l.schema,v.schema.returns.schema)}catch(e){}break;case"array":case"object":for(var g in e)await this.validateArgument(e[g],t,r);return!0}return!1}async execute(e){throw"execute not implemented yet"}test(){throw"test not implemented yet"}}},function(e,t,r){const s=r(12),a=r(0);e.exports=class e{constructor(e){var t={schemaId:"auto",format:"full",formats:{"band-name":{type:"string",validate:this.validateBandName.bind(this)},"bounding-box":{type:"object",validate:this.validateBoundingBox.bind(this)},callback:{type:"object",validate:this.validateCallback.bind(this)},"collection-id":{type:"string",validate:this.validateCollectionId.bind(this)},"epsg-code":{type:"integer",validate:this.validateEpsgCode.bind(this)},geojson:{type:"object",validate:this.validateGeoJson.bind(this)},"job-id":{type:"string",async:!0,validate:this.validateJobId.bind(this)},kernel:{type:"array",validate:this.validateKernel.bind(this)},"output-format":{type:"string",validate:this.validateOutputFormat.bind(this)},"output-format-options":{type:"array",validate:this.validateOutputFormatOptions.bind(this)},"process-graph-id":{type:"string",async:!0,validate:this.validateProcessGraphId.bind(this)},"process-graph-variables":{type:"array",validate:this.validateProcessGraphVariables.bind(this)},"proj-definition":{type:"string",validate:this.validateProjDefinition.bind(this)},"raster-cube":{type:"object",validate:this.validateRasterCube.bind(this)},"temporal-interval":{type:"array",validate:this.validateTemporalInterval.bind(this)},"temporal-intervals":{type:"array",validate:this.validateTemporalIntervals.bind(this)},"vector-cube":{type:"object",validate:this.validateVectorCube.bind(this)}}};this.ajv=new s(t),this.ajv.addKeyword("parameters",{dependencies:["type","format"],metaSchema:{type:"object",additionalProperties:{type:"object"}},valid:!0,errors:!0}),a.isObject(e)&&(this.collectionResolver=e.collectionResolver||null,this.jobResolver=e.jobResolver||null,this.pgResolver=e.pgResolver||null,this.outputFormats=e.outputFormats||null)}async validateJson(e,t){var r=Object.assign({},t);r.$async=!0,void 0===t.$schema&&(r.$schema="http://json-schema.org/draft-07/schema#");try{return await this.ajv.validate(r,e),[]}catch(e){if(Array.isArray(e.errors))return e.errors.map(e=>e.message);throw e}}validateJsonSchema(e){void 0===e.$schema&&((e=Object.assign({},e)).$schema="http://json-schema.org/draft-07/schema#");return this.ajv.compile(e).errors||[]}setCollectionResolver(e){this.collectionResolver=e}setJobResolver(e){this.jobResolver=e}setStoredProcessGraphResolver(e){this.pgResolver=e}setOutputFormats(e){for(var t in this.outputFormats={},e)this.outputFormats[t.toUpperCase()]=e[t]}validateBandName(e){return!0}validateBoundingBox(e){return!0}validateCallback(e){return!0}async validateCollectionId(e){return"function"!=typeof this.collectionResolver||this.collectionResolver(e)}validateEpsgCode(e){return!0}validateGeoJson(e){if("string"!=typeof e.type)throw new s.ValidationError([{message:"Invalid GeoJSON specified (no type property)."}]);return!0}async validateJobId(e){return"function"!=typeof this.jobResolver||this.jobResolver(e)}validateKernel(e){return!0}validateOutputFormat(e){return!a.isObject(this.outputFormats)||e.toUpperCase()in this.outputFormats}validateOutputFormatOptions(e){return!0}async validateProcessGraphId(e){if("function"==typeof this.pgResolver)return this.pgResolver(e)}validateProcessGraphVariables(e){return!0}validateProjDefinition(e){return!0}validateRasterCube(e){return!0}validateTemporalInterval(e){return!0}validateTemporalIntervals(e){return!0}validateVectorCube(e){return!0}static isSchemaCompatible(e,t){return!0}static async getTypeForValue(t,r){var s=new e,a=[];for(var i in t){0===(await s.validateJson(r,t[i])).length&&a.push(i)}return a.length>1?a:a[0]}}},function(e,t,r){const s=r(6),a=r(1),i=r(2),o=r(0),n=["string","number","boolean","array","object"];e.exports=class e{constructor(e,t){this.json=o.mergeDeep({},e),this.processRegistry=t,this.nodes=[],this.startNodes={},this.resultNode=null,this.childrenProcessGraphs=[],this.parentNode=null,this.parentParameterName=null,this.variables={},this.parsed=!1,this.validated=!1,this.errors=new s,this.parameters={}}toJSON(){return this.json}createNodeInstance(e,t,r){return new i(e,t,r)}createProcessGraphInstance(t){return new e(t,this.processRegistry)}setParent(e,t){this.parentNode=e,this.parentParameterName=t}isValid(){return this.validated&&0===this.errors.count()}addError(e){this.errors.add(e)}parse(){if(!this.parsed){for(var e in this.json)this.nodes[e]=this.createNodeInstance(this.json[e],e,this);for(var e in this.nodes){var t=this.nodes[e];if(t.isResultNode){if(null!==this.resultNode)throw this.parentNode?new a("MultipleResultNodesCallback",{node_id:this.parentNode.id,process_id:this.parentNode.process_id}):new a("MultipleResultNodes");this.resultNode=t}this.parseArguments(e,t)}if(!this.findStartNodes())throw this.parentNode?new a("StartNodeMissingCallback",{node_id:this.parentNode.id,process_id:this.parentNode.process_id}):new a("StartNodeMissing");if(null===this.resultNode)throw this.parentNode?new a("ResultNodeMissingCallback",{node_id:this.parentNode.id,process_id:this.parentNode.process_id}):new a("ResultNodeMissing");this.parsed=!0}}async validate(e=!0){if(this.validated)return null;this.validated=!0;try{this.parse()}catch(e){this.addError(e)}return await this.validateNodes(this.getStartNodes(),e),this.errors}async execute(e=null){return await this.validate(),this.reset(),this.setParameters(e),await this.executeNodes(this.getStartNodes()),this.getResultNode()}async validateNodes(e,t,r=null){if(0!==e.length){var a=e.map(async e=>{if(e.solveDependency(r)){try{await this.validateNode(e)}catch(e){if(e instanceof s){if(this.errors.merge(e),t)throw e.first()}else if(this.addError(e),t)throw e}await this.validateNodes(e.getNextNodes(),t,e)}});await Promise.all(a)}}async validateNode(e){var t=this.getProcess(e);return await t.validate(e)}async executeNodes(e,t=null){if(0!==e.length){var r=e.map(async e=>{if(e.solveDependency(t)){var r=await this.executeNode(e);e.setResult(r),await this.executeNodes(e.getNextNodes(),e)}});return Promise.all(r)}}async executeNode(e){var t=this.getProcess(e);return await t.execute(e)}parseArguments(e,t,r){for(var s in void 0===r&&(r=t.arguments),r){var a=r[s];switch(i.getType(a)){case"result":this.connectNodes(t,a.from_node);break;case"variable":this.parseVariable(a);break;case"callback":a.callback=this.createProcessGraph(a.callback,t,s);break;case"callback-argument":this.parseCallbackArgument(t,a.from_argument);break;case"array":case"object":this.parseArguments(e,t,a)}}}parseCallbackArgument(e,t){}createProcessGraph(e,t,r){var s=this.createProcessGraphInstance(e);return s.setParent(t,r),s.parse(),this.childrenProcessGraphs.push(s),s}parseVariable(e){if("string"!=typeof e.variable_id)throw new a("VariableIdInvalid");var t={};if(void 0!==e.type&&!n.includes(e.type))throw new a("VariableTypeInvalid",e);t.type=void 0!==e.type?e.type:"string";var r=i.getType(e.default);if("undefined"!==r){if(r!==t.type)throw new a("VariableDefaultValueTypeInvalid",e);t.value=e.default}}setParameters(e){"object"==typeof e&&null!==e&&(this.parameters=e)}getParameter(e){return this.parameters[e]}setVariableValues(e){for(var t in e)this.setVariable(t,e[t])}setVariableValue(e,t){"object"!=typeof this.variables[e]&&(this.variables[e]={}),this.variables[e].value=t}getVariableValue(e){var t=this.variables[e];if("object"!=typeof t||void 0===t.value)throw new a("VariableValueMissing",{variable_id:e});if(i.getType(t.value)!==t.type)throw new a("VariableValueTypeInvalid",{variable_id:e,type:t.type});return this.variables[e].value}connectNodes(e,t){var r=this.nodes[t];if(void 0===r)throw new a("ReferencedNodeMissing",{node_id:t});e.addPreviousNode(r),r.addNextNode(e)}findStartNodes(){var e=!1;for(var t in this.nodes){var r=this.nodes[t];r.isStartNode()&&(this.startNodes[t]=r,e=!0)}return e}reset(){for(var e in this.nodes)this.nodes[e].reset();this.childrenProcessGraphs.forEach(e=>e.reset())}getResultNode(){return this.resultNode}getStartNodes(){return Object.values(this.startNodes)}getStartNodeIds(){return Object.keys(this.startNodes)}getNode(e){return this.nodes[e]}getNodes(){return this.nodes}getJson(){return this.json}getErrors(){return this.errors}getProcess(e){var t=this.processRegistry.get(e.process_id);if(null===t)throw new a("ProcessUnsupported",{process:e.process_id});return t}getCallbackParameters(){if(!this.parentNode||!this.parentParameterName)return{};var e=this.getProcess(this.parentNode).schema.parameters[this.parentParameterName].schema;if(o.isObject(e.parameters))return e.parameters;var t={},r=e.anyOf||e.oneOf||e.allOf;if(Array.isArray(r))for(let e in r){var s=r[e];o.isObject(s.parameters)&&Object.assign(t,s.parameters)}return t}}},function(e,t){e.exports=class{constructor(){this.errors=[]}first(){return this.errors[0]}merge(e){this.errors.concat(e.getAll())}add(e){this.errors.push(e)}count(){return this.errors.length}toJSON(){return this.errors.map(e=>"function"==typeof e.toJSON?e.toJSON():{code:"InternalError",message:e.message})}getMessage(){var e="";for(var t in this.errors)e+=parseInt(t)+1+". "+this.errors[t].message+"\r\n";return e.trim()}getAll(){return this.errors}}},function(e,t,r){const s=r(8),a=r(10),i=r(11),o=r(3),n=r(4),l=r(5),c=r(1),d=r(2),p=r(13),u=r(6),h=r(14),v=r(0);e.exports={MigrateCapabilities:s,MigrateCollections:a,MigrateProcesses:i,BaseProcess:o,JsonSchemaValidator:n,ProcessGraph:l,ProcessGraphError:c,ProcessGraphNode:d,ProcessRegistry:p,ErrorList:u,FeatureList:h,Utils:v}},function(e,t,r){const s=r(0);var a={guessApiVersion:e=>"string"==typeof e.version?e.version:"string"==typeof e.api_version?e.api_version:e.backend_version||e.title||e.description||e.links?"0.4":"0.3",convertCapabilitiesToLatestSpec:function(e,t=null,r="Unknown"){var a=Object.assign({},e);return null===t&&(t=this.guessApiVersion(a)),0===s.compareVersion(t,"0.3.x")&&void 0!==a.version&&delete a.version,void 0!==a.billing&&(a.billing=this.convertBillingToLatestSpec(a.billing,t)),a.endpoints=this.convertEndpointsToLatestSpec(a.endpoints,t),"string"!=typeof a.api_version&&(a.api_version="0.4.0"),"string"!=typeof a.backend_version&&(a.backend_version="Unknown"),"string"!=typeof a.title&&(a.title=r),"string"!=typeof a.description&&(a.description="No description provided."),a},convertBillingToLatestSpec:function(e,t){var r=Object.assign({},e);return 0===s.compareVersion(t,"0.3.x")&&Array.isArray(r.plans)&&(r.plans=r.plans.map(e=>("boolean"!=typeof e.paid&&(e.paid=!0,"string"==typeof e.name&&e.name.toLowerCase().includes("free")&&(e.paid=!1)),e))),r},convertEndpointsToLatestSpec:function(e,t){var r=[];return Array.isArray(e)&&(r=e.slice(0)),s.compareVersion(t,"0.3.x"),r},convertOutputFormatsToLatestSpec:function(e,t){var r=Object.assign({},e);return 0===s.compareVersion(t,"0.3.x")&&"object"==typeof r.formats&&null!==r.formats?r.formats:r},convertServiceTypesToLatestSpec:function(e,t){var r=Object.assign({},e);return s.compareVersion(t,"0.3.x"),r}};e.exports=a},function(e,t,r){var s,a,i;a=[],void 0===(i="function"==typeof(s=function(){var e=/^v?(?:\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+))?(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;function t(e){var t,r,s=e.replace(/^v/,"").replace(/\+.*$/,""),a=(r="-",-1===(t=s).indexOf(r)?t.length:t.indexOf(r)),i=s.substring(0,a).split(".");return i.push(s.substring(a+1)),i}function r(e){return isNaN(Number(e))?e:Number(e)}function s(t){if("string"!=typeof t)throw new TypeError("Invalid argument expected string");if(!e.test(t))throw new Error("Invalid argument not valid semver ('"+t+"' received)")}return function(e,a){[e,a].forEach(s);for(var i=t(e),o=t(a),n=0;n<Math.max(i.length-1,o.length-1);n++){var l=parseInt(i[n]||0,10),c=parseInt(o[n]||0,10);if(l>c)return 1;if(c>l)return-1}var d=i[i.length-1],p=o[o.length-1];if(d&&p){var u=d.split(".").map(r),h=p.split(".").map(r);for(n=0;n<Math.max(u.length,h.length);n++){if(void 0===u[n]||"string"==typeof h[n]&&"number"==typeof u[n])return-1;if(void 0===h[n]||"string"==typeof u[n]&&"number"==typeof h[n])return 1;if(u[n]>h[n])return 1;if(h[n]>u[n])return-1}}else if(d||p)return d?-1:1;return 0}})?s.apply(t,a):s)||(e.exports=i)},function(e,t,r){const s=r(0);var a={guessCollectionSpecVersion(e){var t="0.4";return void 0===e.id&&void 0!==e.name&&(t="0.3"),t},convertCollectionToLatestSpec:function(e,t=null){var r=Object.assign({},e);if(!Object.keys(r).length)return r;if(null===t&&(t=this.guessCollectionSpecVersion(r)),0===s.compareVersion(t,"0.3.x")){if(r.id=r.name,delete r.name,r.stac_version="0.6.1",Array.isArray(r.provider)&&(r.providers=r.provider,delete r.provider),"object"!=typeof r.properties&&(r.properties={}),null!==r["eo:bands"]&&"object"==typeof r["eo:bands"]&&!Array.isArray(r["eo:bands"])){var a=[];for(var i in r["eo:bands"]){var o=Object.assign({},r["eo:bands"][i]);o.name=i,void 0!==o.resolution&&void 0===o.gsd&&(o.gsd=o.resolution,delete o.resolution),void 0!==o.wavelength&&void 0===o.center_wavelength&&(o.center_wavelength=o.wavelength,delete o.wavelength),a.push(o)}r["eo:bands"]=a}for(var i in r)i.includes(":")&&(r.properties[i]=r[i],delete r[i])}return r}};e.exports=a},function(e,t,r){const s=r(0);var a={guessProcessSpecVersion(e){var t="0.4";return void 0===e.id&&void 0!==e.name&&(t="0.3"),t},convertProcessToLatestSpec:function(e,t=null){var r=Object.assign({},e);if(null===t&&(t=this.guessProcessSpecVersion(r)),0===s.compareVersion(t,"0.3.x")){if(r.id=r.name,delete r.name,"object"==typeof r.parameters)for(var a in r.parameters)if(void 0!==r.parameters[a].mime_type){var i=Object.assign({},r.parameters[a]);i.media_type=i.mime_type,delete i.mime_type,r.parameters[a]=i}if("object"==typeof r.returns&&void 0!==r.returns.mime_type&&(r.returns.media_type=r.returns.mime_type,delete r.returns.mime_type),"object"==typeof r.exceptions)for(var a in r.exceptions){var o=r.exceptions[a];void 0===o.message&&(r.exceptions[a]=Object.assign({},o,{message:o.description}))}if("object"==typeof r.examples){var n=[];for(var a in r.examples){var l=r.examples[a],c={title:l.summary||a,description:l.description};l.process_graph&&(c.process_graph=l.process_graph),n.push(c)}r.examples=n}if("object"==typeof r.parameters&&!Array.isArray(r.parameter_order)){var d=Object.keys(r.parameters);d.length>1&&(r.parameter_order=d)}}return r}};e.exports=a},function(t,r){t.exports=e},function(e,t,r){const s=r(3),a=r(0);e.exports=class{constructor(){this.processes={}}addFromResponse(e){for(var t in e.processes){var r=e.processes[t];this.processes[r.id]=new s(r)}}count(){return a.size(this.processes)}get(e){var t=e.toLowerCase();return void 0!==this.processes[t]?this.processes[t]:null}getProcessSchemas(){return Object.values(this.processes).map(e=>e.schema)}}},function(e,t,r){const s=r(0);var a={features:{"Basic functionality":["get /collections","get /collections/{}","get /processes","get /output_formats"],"Authenticate with HTTP Basic":["get /credentials/basic"],"Authenticate with OpenID Connect":["get /credentials/oidc"],"Batch processing":["get /jobs","post /jobs","get /jobs/{}","delete /jobs/{}","get /jobs/{}/results","post /jobs/{}/results"],"Estimate processing costs":["get /jobs/{}/estimate"],"Preview processing results":["post /result"],"Secondary web services":["get /service_types","get /services","post /services","get /services/{}","delete /services/{}"],"File storage":["get /files/{}","get /files/{}/{}","put /files/{}/{}","delete /files/{}/{}"],"Stored process graphs":["get /process_graphs","post /process_graphs","get /process_graphs/{}","delete /process_graphs/{}"],"Validate process graphs":["post /validation"],"Notifications and monitoring":["get /subscription"],"User defined functions (UDF)":["get /udf_runtimes"]},legacyFeatures:{"post /result":{"post /preview":["0.3.*"]}},getListForVersion(e){var t={};for(var r in this.features)for(var s in t[r]=[],this.features[r]){var a=this.findLegacyEndpoint(e,this.features[r][s]);t[r].push(a)}return t},findLegacyEndpoint(e,t,r=null){if(null!==r&&(t=this.endpointToString(r,t)),"object"==typeof this.legacyFeatures[t]){var a=this.legacyFeatures[t];for(var i in a)for(var o in a[i]){var n=a[i][o];if(0===s.compareVersion(e,n))return i}}return t},getFeatures(){return Object.keys(this.features)},getFeatureCount(){return Object.keys(this.features).length},endpointsToStringList(e){var t=[];for(let r in e)for(let s in e[r].methods)t.push(this.endpointToString(e[r].methods[s],e[r].path));return t},endpointToString:(e,t)=>(e+" "+t.replace(/{[^}]+}/g,"{}")).toLowerCase(),getReport(e,t,r=!0){var s=0,a=r?this.endpointsToStringList(e):e,i=this.getListForVersion(t);return Object.keys(i).forEach(e=>{let t=i[e];switch(t.filter(e=>!a.includes(e)).length){case 0:i[e]=2,s++;break;case t.length:i[e]=0;break;default:i[e]=1}}),{count:s,list:i}}};e.exports=a}])}); | ||
(function webpackUniversalModuleDefinition(root, factory) { | ||
if(typeof exports === 'object' && typeof module === 'object') | ||
module.exports = factory(require("ajv")); | ||
else if(typeof define === 'function' && define.amd) | ||
define(["ajv"], factory); | ||
else { | ||
var a = typeof exports === 'object' ? factory(require("ajv")) : factory(root["ajv"]); | ||
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; | ||
} | ||
})(window, function(__WEBPACK_EXTERNAL_MODULE__12__) { | ||
return /******/ (function(modules) { // webpackBootstrap | ||
/******/ // The module cache | ||
/******/ var installedModules = {}; | ||
/******/ | ||
/******/ // The require function | ||
/******/ function __webpack_require__(moduleId) { | ||
/******/ | ||
/******/ // Check if module is in cache | ||
/******/ if(installedModules[moduleId]) { | ||
/******/ return installedModules[moduleId].exports; | ||
/******/ } | ||
/******/ // Create a new module (and put it into the cache) | ||
/******/ var module = installedModules[moduleId] = { | ||
/******/ i: moduleId, | ||
/******/ l: false, | ||
/******/ exports: {} | ||
/******/ }; | ||
/******/ | ||
/******/ // Execute the module function | ||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||
/******/ | ||
/******/ // Flag the module as loaded | ||
/******/ module.l = true; | ||
/******/ | ||
/******/ // Return the exports of the module | ||
/******/ return module.exports; | ||
/******/ } | ||
/******/ | ||
/******/ | ||
/******/ // expose the modules object (__webpack_modules__) | ||
/******/ __webpack_require__.m = modules; | ||
/******/ | ||
/******/ // expose the module cache | ||
/******/ __webpack_require__.c = installedModules; | ||
/******/ | ||
/******/ // define getter function for harmony exports | ||
/******/ __webpack_require__.d = function(exports, name, getter) { | ||
/******/ if(!__webpack_require__.o(exports, name)) { | ||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); | ||
/******/ } | ||
/******/ }; | ||
/******/ | ||
/******/ // define __esModule on exports | ||
/******/ __webpack_require__.r = function(exports) { | ||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { | ||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
/******/ } | ||
/******/ Object.defineProperty(exports, '__esModule', { value: true }); | ||
/******/ }; | ||
/******/ | ||
/******/ // create a fake namespace object | ||
/******/ // mode & 1: value is a module id, require it | ||
/******/ // mode & 2: merge all properties of value into the ns | ||
/******/ // mode & 4: return value when already ns object | ||
/******/ // mode & 8|1: behave like require | ||
/******/ __webpack_require__.t = function(value, mode) { | ||
/******/ if(mode & 1) value = __webpack_require__(value); | ||
/******/ if(mode & 8) return value; | ||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; | ||
/******/ var ns = Object.create(null); | ||
/******/ __webpack_require__.r(ns); | ||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); | ||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); | ||
/******/ return ns; | ||
/******/ }; | ||
/******/ | ||
/******/ // getDefaultExport function for compatibility with non-harmony modules | ||
/******/ __webpack_require__.n = function(module) { | ||
/******/ var getter = module && module.__esModule ? | ||
/******/ function getDefault() { return module['default']; } : | ||
/******/ function getModuleExports() { return module; }; | ||
/******/ __webpack_require__.d(getter, 'a', getter); | ||
/******/ return getter; | ||
/******/ }; | ||
/******/ | ||
/******/ // Object.prototype.hasOwnProperty.call | ||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; | ||
/******/ | ||
/******/ // __webpack_public_path__ | ||
/******/ __webpack_require__.p = ""; | ||
/******/ | ||
/******/ | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(__webpack_require__.s = 7); | ||
/******/ }) | ||
/************************************************************************/ | ||
/******/ ([ | ||
/* 0 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const compareVersions = __webpack_require__(9); | ||
var Utils = { | ||
compareVersion(v1, v2) { | ||
try { | ||
return compareVersions(v1, v2); | ||
} catch (error) { | ||
return null; | ||
} | ||
}, | ||
isObject(obj) { | ||
return (typeof obj === 'object' && obj === Object(obj) && !Array.isArray(obj)); | ||
}, | ||
size(obj) { | ||
if (typeof obj === 'object' && obj !== null) { | ||
if (Array.isArray(obj)) { | ||
return obj.length; | ||
} | ||
else { | ||
return Object.keys(obj).length; | ||
} | ||
} | ||
return 0; | ||
}, | ||
replacePlaceholders(message, variables = {}) { | ||
if (typeof message === 'string' && this.isObject(variables)) { | ||
for(var placeholder in variables) { | ||
message = message.replace('{' + placeholder + '}', variables[placeholder]); | ||
} | ||
} | ||
return message; | ||
} | ||
}; | ||
module.exports = Utils; | ||
/***/ }), | ||
/* 1 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const Utils = __webpack_require__(0); | ||
const MESSAGES = { | ||
"MultipleResultNodes": "Multiple result nodes specified for process graph.", | ||
"StartNodeMissing": "No start nodes found for process graph.", | ||
"ResultNodeMissing": "No result node found for process graph.", | ||
"MultipleResultNodesCallback": "Multiple result nodes specified for the callback in the process '{process_id}' (node: '{node_id}').", | ||
"StartNodeMissingCallback": "No start nodes found for the callback in the process '{process_id}' (node: '{node_id}')'.", | ||
"ResultNodeMissingCallback": "No result node found for the callback in the process '{process_id}' (node: '{node_id}').", | ||
"ReferencedNodeMissing": "Referenced node '{node_id}' doesn't exist.", | ||
"NodeIdInvalid": "Invalid node id specified in process graph.", | ||
"NodeInvalid": "Process graph node '{node_id}' is not a valid object.", | ||
"ProcessIdMissing": "Process graph node '{node_id}' doesn't contain a process id.", | ||
"CallbackArgumentInvalid": "Invalid callback argument '{argument}' requested in the process '{process_id}' (node: '{node_id}').", | ||
"ProcessUnsupported": "Process '{process}' is not supported.", | ||
"ProcessArgumentUnsupported": "Process '{process}' does not support argument '{argument}'.", | ||
"ProcessArgumentRequired": "Process '{process}' requires argument '{argument}'.", | ||
"ProcessArgumentInvalid": "The argument '{argument}' in process '{process}' is invalid: {reason}", | ||
"VariableValueMissing": "No value specified for process graph variable '{variable_id}'.", | ||
"VariableDefaultValueTypeInvalid": "The default value specified for the process graph variable '{variable_id}' is not of type '{type}'.", | ||
"VariableValueTypeInvalid": "The value specified for the process graph variable '{variable_id}' is not of type '{type}'.", | ||
"VariableIdInvalid": "A specified variable ID is not valid.", | ||
"VariableTypeInvalid": "The data type specified for the process graph variable '{variable_id}' is invalid. Must be one of: string, boolean, number, array or object.", | ||
}; | ||
module.exports = class ProcessGraphError extends Error { | ||
constructor(codeOrMsg, variables = {}) { | ||
super(); | ||
this.variables = variables; | ||
if (typeof MESSAGES[codeOrMsg] === 'string') { | ||
this.code = codeOrMsg; | ||
this.message = Utils.replacePlaceholders(MESSAGES[codeOrMsg], variables); | ||
} | ||
else { | ||
this.code = codeOrMsg.replace(/[^\w\d]+/g, ''); | ||
this.message = codeOrMsg; | ||
} | ||
} | ||
toJSON() { | ||
return { | ||
code: this.code, | ||
message: this.message | ||
}; | ||
} | ||
}; | ||
/***/ }), | ||
/* 2 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const ProcessGraphError = __webpack_require__(1); | ||
const Utils = __webpack_require__(0); | ||
module.exports = class ProcessGraphNode { | ||
constructor(json, id, parent) { | ||
if (typeof id !== 'string' || id.length === 0) { | ||
throw new ProcessGraphError('NodeIdInvalid'); | ||
} | ||
if (!Utils.isObject(json)) { | ||
throw new ProcessGraphError('NodeInvalid', {node_id: id}); | ||
} | ||
if (typeof json.process_id !== 'string') { | ||
throw new ProcessGraphError('ProcessIdMissing', {node_id: id}); | ||
} | ||
this.id = id; | ||
this.processGraph = parent; | ||
this.process_id = json.process_id; | ||
this.arguments = Utils.isObject(json.arguments) ? JSON.parse(JSON.stringify(json.arguments)) : {}; | ||
this.isResultNode = json.result || false; | ||
this.expectsFrom = []; | ||
this.passesTo = []; | ||
this.result = null; | ||
this.resultsAvailableFrom = []; | ||
} | ||
getProcessGraph() { | ||
return this.processGraph; | ||
} | ||
getArgumentNames() { | ||
return Object.keys(this.arguments); | ||
} | ||
hasArgument(name) { | ||
return (name in this.arguments); | ||
} | ||
getArgumentType(name) { | ||
return ProcessGraphNode.getType(this.arguments[name]); | ||
} | ||
getRawArgument(name) { | ||
return this.arguments[name]; | ||
} | ||
getRawArgumentValue(name) { | ||
var arg = this.arguments[name]; | ||
switch(ProcessGraphNode.getType(arg)) { | ||
case 'result': | ||
return arg.from_node; | ||
case 'callback': | ||
return arg.callback; | ||
case 'callback-argument': | ||
return arg.from_argument; | ||
default: | ||
return arg; | ||
} | ||
} | ||
getArgument(name, defaultValue = undefined) { | ||
if (typeof this.arguments[name] === 'undefined') { | ||
return defaultValue; | ||
} | ||
return this.processArgument(this.arguments[name]); | ||
} | ||
processArgument(arg) { | ||
var type = ProcessGraphNode.getType(arg); | ||
switch(type) { | ||
case 'result': | ||
return this.processGraph.getNode(arg.from_node).getResult(); | ||
case 'callback': | ||
return arg.callback; | ||
case 'callback-argument': | ||
return this.processGraph.getParameter(arg.from_argument); | ||
case 'variable': | ||
return this.processGraph.getVariableValue(arg.variable_id); | ||
case 'array': | ||
case 'object': | ||
for(var i in arg) { | ||
arg[i] = this.processArgument(arg[i]); | ||
} | ||
return arg; | ||
default: | ||
return arg; | ||
} | ||
} | ||
static getType(obj, reportNullAs = 'null') { | ||
if (typeof obj === 'object') { | ||
if (obj === null) { | ||
return reportNullAs; | ||
} | ||
else if (Array.isArray(obj)) { | ||
return 'array'; | ||
} | ||
else if(obj.hasOwnProperty("callback")) { | ||
return 'callback'; | ||
} | ||
else if(obj.hasOwnProperty("variable_id")) { | ||
return 'variable'; | ||
} | ||
else if(obj.hasOwnProperty("from_node")) { | ||
return 'result'; | ||
} | ||
else if(obj.hasOwnProperty("from_argument")) { | ||
return 'callback-argument'; | ||
} | ||
else { | ||
return 'object'; | ||
} | ||
} | ||
return (typeof obj); | ||
} | ||
isStartNode() { | ||
return (this.expectsFrom.length === 0); | ||
} | ||
addPreviousNode(node) { | ||
this.expectsFrom.push(node); | ||
} | ||
getPreviousNodes() { | ||
return this.expectsFrom; | ||
} | ||
addNextNode(node) { | ||
this.passesTo.push(node); | ||
} | ||
getNextNodes() { | ||
return this.passesTo; | ||
} | ||
reset() { | ||
this.result = null; | ||
this.resultsAvailableFrom = []; | ||
} | ||
setResult(result) { | ||
this.result = result; | ||
} | ||
getResult() { | ||
return this.result; | ||
} | ||
solveDependency(dependencyNode) { | ||
if (dependencyNode !== null && this.expectsFrom.includes(dependencyNode)) { | ||
this.resultsAvailableFrom.push(dependencyNode); | ||
} | ||
return (this.expectsFrom.length === this.resultsAvailableFrom.length); // all dependencies solved? | ||
} | ||
}; | ||
/***/ }), | ||
/* 3 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const JsonSchemaValidator = __webpack_require__(4); | ||
const ProcessGraphError = __webpack_require__(1); | ||
const ProcessGraphNode = __webpack_require__(2); | ||
const ProcessGraph = __webpack_require__(5); | ||
module.exports = class BaseProcess { | ||
constructor(schema, validator = null) { | ||
this.schema = schema; | ||
if (validator === null) { | ||
this.jsonSchema = new JsonSchemaValidator(); | ||
} | ||
else { | ||
this.jsonSchema = validator; | ||
} | ||
} | ||
async validate(node) { | ||
// Check for arguments we don't support and throw error | ||
var unsupportedArgs = node.getArgumentNames().filter(name => (typeof this.schema.parameters[name] === 'undefined')); | ||
if (unsupportedArgs.length > 0) { | ||
throw new ProcessGraphError('ProcessArgumentUnsupported', { | ||
process: this.schema.id, | ||
argument: unsupportedArgs[0] | ||
}); | ||
} | ||
// Validate against JSON Schema | ||
for(let name in this.schema.parameters) { | ||
let param = this.schema.parameters[name]; | ||
let arg = node.getRawArgument(name); | ||
if (await this.validateArgument(arg, node, name, param)) { | ||
continue; | ||
} | ||
// Validate against JSON schema | ||
let errors = await this.jsonSchema.validateJson(arg, param.schema); | ||
if (errors.length > 0) { | ||
throw new ProcessGraphError('ProcessArgumentInvalid', { | ||
process: this.schema.id, | ||
argument: name, | ||
reason: errors.join("; ") | ||
}); | ||
} | ||
} | ||
} | ||
async validateArgument(arg, node, parameterName, param) { | ||
let argType = ProcessGraphNode.getType(arg); | ||
if (arg instanceof ProcessGraph) { | ||
await arg.validate(true); | ||
return true; | ||
} | ||
switch(argType) { | ||
// Check whether parameter is required | ||
case 'undefined': | ||
if (param.required) { | ||
throw new ProcessGraphError('ProcessArgumentRequired', { | ||
process: this.schema.id, | ||
argument: parameterName | ||
}); | ||
} | ||
return true; // Parameter not set, nothing to validate against | ||
case 'callback-argument': | ||
var cbParams = node.getProcessGraph().getCallbackParameters(); | ||
// No need for further checks, callback argument is validated in processgraph.js: see parseCallbackArgument() | ||
return JsonSchemaValidator.isSchemaCompatible(param.schema, cbParams[arg.from_argument]); | ||
case 'variable': | ||
var variableSchema = { | ||
type: arg.type || 'string' | ||
}; | ||
return JsonSchemaValidator.isSchemaCompatible(param.schema, variableSchema); | ||
case 'result': | ||
try { | ||
var pg = node.getProcessGraph(); | ||
var process_id = pg.getNode(arg.from_node).process_id; | ||
var process = pg.getProcess(process_id); | ||
return JsonSchemaValidator.isSchemaCompatible(param.schema, process.schema.returns.schema); | ||
} catch (e) {} | ||
break; | ||
case 'array': | ||
case 'object': | ||
// ToDo: Check how we can validate arrays and objects that have references to callback arguments, variables and node results in them... | ||
// See issue https://github.com/Open-EO/openeo-js-commons/issues/5 | ||
// for(var i in arg) { | ||
// await this.validateArgument(arg[i], node, parameterName, param); | ||
// } | ||
return true; | ||
} | ||
return false; | ||
} | ||
/* istanbul ignore next */ | ||
async execute(/*node*/) { | ||
throw "execute not implemented yet"; | ||
} | ||
/* istanbul ignore next */ | ||
test() { | ||
// Run the tests from the examples | ||
throw "test not implemented yet"; | ||
} | ||
}; | ||
/***/ }), | ||
/* 4 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const ajv = __webpack_require__(12); | ||
const Utils = __webpack_require__(0); | ||
module.exports = class JsonSchemaValidator { | ||
constructor() { | ||
var ajvOptions = { | ||
schemaId: 'auto', | ||
format: 'full', | ||
formats: { | ||
// See issue https://github.com/Open-EO/openeo-js-commons/issues/4 for information on why ajv doesn't support non-string validation | ||
'band-name': {type: 'string', async: true, validate: this.validateBandName.bind(this)}, | ||
'bounding-box': {type: 'object', async: true, validate: this.validateBoundingBox.bind(this)}, // Currently not supported by ajv 6.10 | ||
'callback': {type: 'object', async: true, validate: this.validateCallback.bind(this)}, // Currently not supported by ajv 6.10 | ||
'collection-id': {type: 'string', async: true, validate: this.validateCollectionId.bind(this)}, | ||
'epsg-code': {type: 'integer', async: true, validate: this.validateEpsgCode.bind(this)}, // Currently not supported by ajv 6.10 | ||
'geojson': {type: 'object', async: true, validate: this.validateGeoJson.bind(this)}, // Currently not supported by ajv 6.10 | ||
'job-id': {type: 'string', async: true, validate: this.validateJobId.bind(this)}, | ||
'kernel': {type: 'array', async: true, validate: this.validateKernel.bind(this)}, // Currently not supported by ajv 6.10 | ||
'output-format': {type: 'string', async: true, validate: this.validateOutputFormat.bind(this)}, | ||
'output-format-options': {type: 'array', async: true, validate: this.validateOutputFormatOptions.bind(this)}, // Currently not supported by ajv 6.10 | ||
'process-graph-id': {type: 'string', async: true, validate: this.validateProcessGraphId.bind(this)}, | ||
'process-graph-variables': {type: 'array', async: true, validate: this.validateProcessGraphVariables.bind(this)}, // Currently not supported by ajv 6.10 | ||
'proj-definition': {type: 'string', async: true, validate: this.validateProjDefinition.bind(this)}, | ||
'raster-cube': {type: 'object', async: true, validate: this.validateRasterCube.bind(this)}, // Currently not supported by ajv 6.10 | ||
'temporal-interval': {type: 'array', async: true, validate: this.validateTemporalInterval.bind(this)}, // Currently not supported by ajv 6.10 | ||
'temporal-intervals': {type: 'array', async: true, validate: this.validateTemporalIntervals.bind(this)}, // Currently not supported by ajv 6.10 | ||
'vector-cube': {type: 'object', async: true, validate: this.validateVectorCube.bind(this)} // Currently not supported by ajv 6.10 | ||
} | ||
}; | ||
this.ajv = new ajv(ajvOptions); | ||
this.ajv.addKeyword('parameters', { | ||
dependencies: [ | ||
"type", | ||
"format" | ||
], | ||
metaSchema: { | ||
type: "object", | ||
additionalProperties: { | ||
type: "object" | ||
} | ||
}, | ||
valid: true, | ||
errors: true | ||
}); | ||
this.outputFormats = null; | ||
this.geoJsonValidator = null; | ||
} | ||
async validateJson(json, schema) { | ||
// Make sure we don't alter the process registry | ||
var clonedSchema = Object.assign({}, schema); | ||
clonedSchema.$async = true; | ||
if (typeof clonedSchema.$schema === 'undefined') { | ||
// Set applicable JSON Schema draft version if not already set | ||
clonedSchema.$schema = "http://json-schema.org/draft-07/schema#"; | ||
} | ||
try { | ||
await this.ajv.validate(clonedSchema, json); | ||
return []; | ||
} catch (e) { | ||
if (Array.isArray(e.errors)) { | ||
return e.errors.map(e => e.message); | ||
} | ||
else { | ||
throw e; | ||
} | ||
} | ||
} | ||
validateJsonSchema(schema) { | ||
// Set applicable JSON SChema draft version if not already set | ||
if (typeof schema.$schema === 'undefined') { | ||
schema = Object.assign({}, schema); // Make sure we don't alter the process registry | ||
schema.$schema = "http://json-schema.org/draft-07/schema#"; | ||
} | ||
let result = this.ajv.compile(schema); | ||
return result.errors || []; | ||
} | ||
// Pass the content of https://geojson.org/schema/GeoJSON.json | ||
setGeoJsonSchema(schema) { | ||
var gjv = new ajv(); | ||
this.geoJsonValidator = gjv.compile(schema); | ||
} | ||
// Expects API compatible output formats (see GET /output_formats). | ||
setOutputFormats(outputFormats) { | ||
this.outputFormats = {}; | ||
for (var key in outputFormats) { | ||
this.outputFormats[key.toUpperCase()] = outputFormats[key]; | ||
} | ||
} | ||
/* istanbul ignore next */ | ||
async validateBandName(/*data*/) { | ||
// Can't validate band name without knowing/loading the data. | ||
// => To be overridden by end-user application. | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateBoundingBox(/*data*/) { | ||
// Nothing to validate, schema is (usually) delivered by processes. | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateCallback(/*data*/) { | ||
// This should be checked by process graph parsing automatically. | ||
// Otherwise to be overridden by end-user application. | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateCollectionId(/*data*/) { | ||
// To be overridden by end-user application. | ||
return true; | ||
} | ||
async validateEpsgCode(data) { | ||
// Rough check for valid numbers as we don't want to maintain a full epsg code list in this repo. | ||
// Fully validation to be implemented by end-user application by overriding this method. | ||
if (data >= 2000) { | ||
return true; | ||
} | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid EPSG code specified." | ||
}]); | ||
} | ||
async validateGeoJson(data) { | ||
if (this.geoJsonValidator !== null) { | ||
if (!this.geoJsonValidator(data)) { | ||
throw new ajv.ValidationError(ajv.errors); | ||
} | ||
return true; | ||
} | ||
else { | ||
// A very rough GeoJSON validation if no GeoJSON schema is available. | ||
if (typeof data.type !== 'string') { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (no type property)." | ||
}]); | ||
} | ||
switch(data.type) { | ||
case "Point": | ||
case "MultiPoint": | ||
case "LineString": | ||
case "MultiLineString": | ||
case "Polygon": | ||
case "MultiPolygon": | ||
if (!Array.isArray(data.coordinates)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (Geometry has no valid coordinates member)." | ||
}]); | ||
} | ||
return true; | ||
case "GeometryCollection": | ||
if (!Array.isArray(data.geometries)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (GeometryCollection has no valid geometries member)." | ||
}]); | ||
} | ||
return true; | ||
case "Feature": | ||
if (data.geometry !== null && !Utils.isObject(data.geometry)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (Feature has no valid geometry member)." | ||
}]); | ||
} | ||
if (data.properties !== null && !Utils.isObject(data.properties)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (Feature has no valid properties member)." | ||
}]); | ||
} | ||
return true; | ||
case "FeatureCollection": | ||
if (!Array.isArray(data.features)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (FeatureCollection has no valid features member)." | ||
}]); | ||
} | ||
return true; | ||
default: | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON type specified." | ||
}]); | ||
} | ||
} | ||
} | ||
/* istanbul ignore next */ | ||
async validateJobId(/*data*/) { | ||
// To be overridden by end-user application | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateKernel(/*data*/) { | ||
// ToDo? / To be overridden by end-user application | ||
return true; | ||
} | ||
async validateOutputFormat(data) { | ||
if (Utils.isObject(this.outputFormats) && !(data.toUpperCase() in this.outputFormats)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Output format not supported." | ||
}]); | ||
} | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateOutputFormatOptions(/*data*/) { | ||
// This depends on the output format specified and can't be fully validated without knowning the chosen output format. | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateProcessGraphId(/*data*/) { | ||
// To be overridden by end-user application | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateProcessGraphVariables(/*data*/) { | ||
// Nothing to validate against... | ||
return true; | ||
} | ||
async validateProjDefinition(data) { | ||
// To be overridden by end-user application, just doing a very basic check here. | ||
if (!data.toLowerCase().includes("+proj")) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid PROJ string specified (doesn't contain '+proj')." | ||
}]); | ||
} | ||
return true; | ||
} | ||
/* istanbul ignore next */ | ||
async validateRasterCube(/*data*/) { | ||
// This is usually a reference to a process result as we haven't specified any JSON encoding for raster cubes. | ||
return true; | ||
} | ||
async validateTemporalInterval(/*data*/) { | ||
// ToDo: Fully check against schema, most is already checked by JSON Schemas itself, but check for example that | ||
// both can't be null at the same time or the first element is > the second element. | ||
return true; | ||
} | ||
async validateTemporalIntervals(data) { | ||
var invalid = data.filter(x => !this.validateTemporalInterval(x)); | ||
return invalid.length === 0; | ||
} | ||
/* istanbul ignore next */ | ||
async validateVectorCube(/*data*/) { | ||
// This is usually a reference to a process result as we haven't specified any JSON encoding for raster cubes. | ||
return true; | ||
} | ||
// Checks whether the valueSchema is compatible to the paramSchema. | ||
// So would a value compatible with valueSchema be accepted by paramSchema? | ||
static isSchemaCompatible(paramSchema, valueSchema, strict = false) { | ||
var paramSchemas = this._convertSchemaToArray(paramSchema); | ||
var valueSchemas = this._convertSchemaToArray(valueSchema); | ||
var compatible = paramSchemas.filter(ps => { | ||
for(var i in valueSchemas) { | ||
var vs = valueSchemas[i]; | ||
if (typeof ps.type !== 'string' || (!strict && typeof vs.type !== 'string')) { // "any" type is always compatible | ||
return true; | ||
} | ||
else if (ps.type === vs.type || (ps.type === 'number' && vs.type === 'integer') || (!strict && ps.type === 'integer' && vs.type === 'number')) { | ||
if (ps.type === 'array' && Utils.isObject(ps.items) && Utils.isObject(vs.items)) { | ||
if (JsonSchemaValidator.isSchemaCompatible(ps.items, vs.items, strict)) { | ||
return true; | ||
} | ||
} | ||
else if (ps.type === 'object' && Utils.isObject(ps.properties) && Utils.isObject(vs.properties)) { | ||
// ToDo: Check properties, required properties etc. | ||
return true; | ||
} | ||
else if (!strict && (typeof ps.format !== 'string' || typeof vs.format !== 'string')) { | ||
return true; | ||
} | ||
else if (typeof ps.format !== 'string') { // types without format always accepts the same type with a format | ||
return true; | ||
} | ||
else if (ps.format === vs.format) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}); | ||
return compatible.length > 0; | ||
} | ||
static _convertSchemaToArray(schema) { | ||
var schemas = []; | ||
// ToDo: schema.not and schema.allOf is not supported - see also class constructor of ProcessSchema in processSchema.js of openeo-web-editor. | ||
if (schema.oneOf || schema.anyOf) { | ||
schemas = (schema.oneOf || schema.anyOf); | ||
} | ||
else if (Array.isArray(schema.type)) { | ||
schemas = schema.type.map(t => Object.assign({}, schema, {type: t})); | ||
} | ||
else { | ||
schemas = [schema]; | ||
} | ||
return schemas; | ||
} | ||
/** | ||
* Returns the indices of provided JSON Schemas that the provided values matches against. | ||
* | ||
* Returns a single index if a single type is mathcing. | ||
* Returns undefined if no valid type is found. | ||
* Returns an array of indices if multiple types are found. | ||
* | ||
* @param {Array} types - Array of JSON schemas | ||
* @param {*} value - A value | ||
* @return {(string[]|string|undefined)} - Returns matching indices, see description. | ||
*/ | ||
static async getTypeForValue(types, value) { | ||
var validator = new JsonSchemaValidator(); | ||
var potentialTypes = []; | ||
for(var i in types) { | ||
var errors = await validator.validateJson(value, types[i]); | ||
if (errors.length === 0) { | ||
potentialTypes.push(String(i)); | ||
} | ||
} | ||
return potentialTypes.length > 1 ? potentialTypes : potentialTypes[0]; | ||
} | ||
}; | ||
/***/ }), | ||
/* 5 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const ErrorList = __webpack_require__(6); | ||
const ProcessGraphError = __webpack_require__(1); | ||
const ProcessGraphNode = __webpack_require__(2); | ||
const Utils = __webpack_require__(0); | ||
const VARIABLE_TYPES = ['string', 'number', 'boolean', 'array', 'object']; | ||
module.exports = class ProcessGraph { | ||
constructor(jsonProcessGraph, processRegistry) { | ||
this.json = jsonProcessGraph; | ||
this.processRegistry = processRegistry; | ||
this.nodes = []; | ||
this.startNodes = {}; | ||
this.resultNode = null; | ||
this.childrenProcessGraphs = []; | ||
this.parentNode = null; | ||
this.parentParameterName = null; | ||
this.variables = {}; | ||
this.parsed = false; | ||
this.validated = false; | ||
this.errors = new ErrorList(); | ||
this.parameters = {}; | ||
} | ||
toJSON() { | ||
return this.json; | ||
} | ||
createNodeInstance(json, id, parent) { | ||
return new ProcessGraphNode(json, id, parent); | ||
} | ||
createProcessGraphInstance(json) { | ||
return new ProcessGraph(json, this.processRegistry); | ||
} | ||
setParent(node, parameterName) { | ||
this.parentNode = node; | ||
this.parentParameterName = parameterName; | ||
} | ||
isValid() { | ||
return this.validated && this.errors.count() === 0; | ||
} | ||
addError(error) { | ||
this.errors.add(error); | ||
} | ||
parse() { | ||
if (this.parsed) { | ||
return; | ||
} | ||
for(let id in this.json) { | ||
this.nodes[id] = this.createNodeInstance(this.json[id], id, this); | ||
} | ||
for(let id in this.nodes) { | ||
var node = this.nodes[id]; | ||
if (node.isResultNode) { | ||
if (this.resultNode !== null) { | ||
throw this.parentNode ? new ProcessGraphError('MultipleResultNodesCallback', {node_id: this.parentNode.id, process_id: this.parentNode.process_id}) : new ProcessGraphError('MultipleResultNodes'); | ||
} | ||
this.resultNode = node; | ||
} | ||
this.parseArguments(id, node); | ||
} | ||
if (!this.findStartNodes()) { | ||
throw this.parentNode ? new ProcessGraphError('StartNodeMissingCallback', {node_id: this.parentNode.id, process_id: this.parentNode.process_id}) : new ProcessGraphError('StartNodeMissing'); | ||
} | ||
if (this.resultNode === null) { | ||
throw this.parentNode ? new ProcessGraphError('ResultNodeMissingCallback', {node_id: this.parentNode.id, process_id: this.parentNode.process_id}) : new ProcessGraphError('ResultNodeMissing'); | ||
} | ||
this.parsed = true; | ||
} | ||
async validate(throwOnErrors = true) { | ||
if (this.validated) { | ||
return null; | ||
} | ||
this.validated = true; | ||
// Parse | ||
try { | ||
this.parse(); | ||
} catch (error) { | ||
this.addError(error); | ||
} | ||
// Validate | ||
await this.validateNodes(this.getStartNodes(), throwOnErrors); | ||
return this.errors; | ||
} | ||
async execute(parameters = null) { | ||
await this.validate(); | ||
this.reset(); | ||
this.setParameters(parameters); | ||
await this.executeNodes(this.getStartNodes()); | ||
return this.getResultNode(); | ||
} | ||
async validateNodes(nodes, throwsOnErrors, previousNode = null) { | ||
if (nodes.length === 0) { | ||
return; | ||
} | ||
var promises = nodes.map(async (node) => { | ||
// Validate this node after all dependencies are available | ||
if (!node.solveDependency(previousNode)) { | ||
return; | ||
} | ||
// Get process and validate | ||
try { | ||
await this.validateNode(node); | ||
} catch (e) { | ||
if (e instanceof ErrorList) { | ||
this.errors.merge(e); | ||
if (throwsOnErrors) { | ||
throw e.first(); | ||
} | ||
} | ||
else { | ||
this.addError(e); | ||
if (throwsOnErrors) { | ||
throw e; | ||
} | ||
} | ||
} | ||
await this.validateNodes(node.getNextNodes(), throwsOnErrors, node); | ||
}); | ||
await Promise.all(promises); | ||
} | ||
async validateNode(node) { | ||
var process = this.getProcess(node); | ||
return await process.validate(node); | ||
} | ||
async executeNodes(nodes, previousNode = null) { | ||
if (nodes.length === 0) { | ||
return; | ||
} | ||
var promises = nodes.map(async (node) => { | ||
// Execute this node after all dependencies are available | ||
if (!node.solveDependency(previousNode)) { | ||
return; | ||
} | ||
var result = await this.executeNode(node); | ||
node.setResult(result); | ||
// Execute next nodes in chain | ||
await this.executeNodes(node.getNextNodes(), node); | ||
}); | ||
return Promise.all(promises); | ||
} | ||
async executeNode(node) { | ||
var process = this.getProcess(node); | ||
return await process.execute(node); | ||
} | ||
parseArguments(nodeId, node, args) { | ||
if (typeof args === 'undefined') { | ||
args = node.arguments; | ||
} | ||
for(var argumentName in args) { | ||
var arg = args[argumentName]; | ||
var type = ProcessGraphNode.getType(arg); | ||
switch(type) { | ||
case 'result': | ||
this.connectNodes(node, arg.from_node); | ||
break; | ||
case 'variable': | ||
this.parseVariable(arg); | ||
break; | ||
case 'callback': | ||
arg.callback = this.createProcessGraph(arg.callback, node, argumentName); | ||
break; | ||
case 'callback-argument': | ||
this.parseCallbackArgument(node, arg.from_argument); | ||
break; | ||
case 'array': | ||
case 'object': | ||
this.parseArguments(nodeId, node, arg); | ||
break; | ||
} | ||
} | ||
} | ||
parseCallbackArgument(node, name) { | ||
var cbParams = this.getCallbackParameters(); | ||
if (!Utils.isObject(cbParams) || !cbParams.hasOwnProperty(name)) { | ||
throw new ProcessGraphError('CallbackArgumentInvalid', { | ||
argument: name, | ||
node_id: node.id, | ||
process_id: node.process_id | ||
}); | ||
} | ||
} | ||
createProcessGraph(json, node, argumentName) { | ||
var pg = this.createProcessGraphInstance(json); | ||
pg.setParent(node, argumentName); | ||
pg.parse(); | ||
this.childrenProcessGraphs.push(pg); | ||
return pg; | ||
} | ||
parseVariable(variable) { | ||
// Check whether the variable id is valid | ||
if (typeof variable.variable_id !== 'string') { | ||
throw new ProcessGraphError('VariableIdInvalid'); | ||
} | ||
var obj = {}; | ||
// Check whether the data type is valid | ||
if (typeof variable.type !== 'undefined' && !VARIABLE_TYPES.includes(variable.type)) { | ||
throw new ProcessGraphError('VariableTypeInvalid', variable); | ||
} | ||
obj.type = typeof variable.type !== 'undefined' ? variable.type : 'string'; | ||
// Check whether the defult value has the correct data type | ||
var defaultType = ProcessGraphNode.getType(variable.default); | ||
if (defaultType !== 'undefined') { | ||
if (defaultType !== obj.type) { | ||
throw new ProcessGraphError('VariableDefaultValueTypeInvalid', variable); | ||
} | ||
else { | ||
obj.value = variable.default; | ||
} | ||
} | ||
} | ||
setParameters(parameters) { | ||
if (typeof parameters === 'object' && parameters !== null) { | ||
this.parameters = parameters; | ||
} | ||
} | ||
getParameter(name) { | ||
return this.parameters[name]; | ||
} | ||
setVariableValues(variables) { | ||
for(var i in variables) { | ||
this.setVariable(i, variables[i]); | ||
} | ||
} | ||
setVariableValue(id, value) { | ||
if (typeof this.variables[id] !== 'object') { | ||
this.variables[id] = {}; | ||
} | ||
this.variables[id].value = value; | ||
} | ||
getVariableValue(id) { | ||
var variable = this.variables[id]; | ||
if (typeof variable !== 'object' || typeof variable.value === 'undefined') { | ||
throw new ProcessGraphError('VariableValueMissing', {variable_id: id}); | ||
} | ||
var type = ProcessGraphNode.getType(variable.value); | ||
if (type !== variable.type) { | ||
throw new ProcessGraphError('VariableValueTypeInvalid', {variable_id: id, type: variable.type}); | ||
} | ||
return this.variables[id].value; | ||
} | ||
connectNodes(node, prevNodeId) { | ||
var prevNode = this.nodes[prevNodeId]; | ||
if (typeof prevNode === 'undefined') { | ||
throw new ProcessGraphError('ReferencedNodeMissing', {node_id: prevNodeId}); | ||
} | ||
node.addPreviousNode(prevNode); | ||
prevNode.addNextNode(node); | ||
} | ||
findStartNodes() { | ||
var found = false; | ||
for(var id in this.nodes) { | ||
var node = this.nodes[id]; | ||
if (node.isStartNode()) { | ||
this.startNodes[id] = node; | ||
found = true; | ||
} | ||
} | ||
return found; | ||
} | ||
reset() { | ||
for(var id in this.nodes) { | ||
this.nodes[id].reset(); | ||
} | ||
this.childrenProcessGraphs.forEach(child => child.reset()); | ||
} | ||
getResultNode() { | ||
return this.resultNode; | ||
} | ||
getStartNodes() { | ||
return Object.values(this.startNodes); | ||
} | ||
getStartNodeIds() { | ||
return Object.keys(this.startNodes); | ||
} | ||
getNode(nodeId) { | ||
return this.nodes[nodeId]; | ||
} | ||
getNodes() { | ||
return this.nodes; | ||
} | ||
getErrors() { | ||
return this.errors; | ||
} | ||
getProcess(node) { | ||
var process = this.processRegistry.get(node.process_id); | ||
if (process === null) { | ||
throw new ProcessGraphError('ProcessUnsupported', {process: node.process_id}); | ||
} | ||
return process; | ||
} | ||
getCallbackParameters() { | ||
if (!this.parentNode || !this.parentParameterName) { | ||
return {}; | ||
} | ||
var process = this.getProcess(this.parentNode); | ||
var schema = process.schema.parameters[this.parentParameterName].schema; | ||
if (Utils.isObject(schema.parameters)) { | ||
return schema.parameters; | ||
} | ||
// ToDo: If a process parameter supports multiple different callbacks, i.e. reduce with either an array of two separate values, this | ||
// can't be separated accordingly and we just return all potential values. So it might happen that people get a successful validation | ||
// but they used the wrong callback parameters. | ||
// See issue https://github.com/Open-EO/openeo-js-commons/issues/6 | ||
var cbParams = {}; | ||
var choice = schema.anyOf || schema.oneOf || schema.allOf; | ||
if (Array.isArray(choice)) { | ||
for(let i in choice) { | ||
var p = choice[i]; | ||
if (Utils.isObject(p.parameters)) { | ||
Object.assign(cbParams, p.parameters); | ||
} | ||
} | ||
} | ||
return cbParams; | ||
} | ||
}; | ||
/***/ }), | ||
/* 6 */ | ||
/***/ (function(module, exports) { | ||
module.exports = class ErrorList { | ||
constructor() { | ||
this.errors = []; | ||
} | ||
first() { | ||
return this.errors[0] || null; | ||
} | ||
last() { | ||
return this.errors[this.errors.length-1] || null; | ||
} | ||
merge(errorList) { | ||
this.errors = this.errors.concat(errorList.getAll()); | ||
} | ||
add(error) { | ||
this.errors.push(error); | ||
} | ||
count() { | ||
return this.errors.length; | ||
} | ||
toJSON() { | ||
return this.errors.map(e => { | ||
if (typeof e.toJSON === 'function') { | ||
return e.toJSON(); | ||
} | ||
else { | ||
return { | ||
code: 'InternalError', | ||
message: e.message | ||
}; | ||
} | ||
}); | ||
} | ||
getMessage() { | ||
var msg = ''; | ||
for (var i in this.errors) { | ||
msg += (parseInt(i, 10)+1) + ". " + this.errors[i].message + "\r\n"; | ||
} | ||
return msg.trim(); | ||
} | ||
getAll() { | ||
return this.errors; | ||
} | ||
}; | ||
/***/ }), | ||
/* 7 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
// Migrations | ||
const MigrateCapabilities = __webpack_require__(8); | ||
const MigrateCollections = __webpack_require__(10); | ||
const MigrateProcesses = __webpack_require__(11); | ||
// Process graphs | ||
const BaseProcess = __webpack_require__(3); | ||
const JsonSchemaValidator = __webpack_require__(4); | ||
const ProcessGraph = __webpack_require__(5); | ||
const ProcessGraphError = __webpack_require__(1); | ||
const ProcessGraphNode = __webpack_require__(2); | ||
const ProcessRegistry = __webpack_require__(13); | ||
// Others | ||
const ErrorList = __webpack_require__(6); | ||
const FeatureList = __webpack_require__(14); | ||
const Utils = __webpack_require__(0); | ||
module.exports = { | ||
MigrateCapabilities, | ||
MigrateCollections, | ||
MigrateProcesses, | ||
BaseProcess, | ||
JsonSchemaValidator, | ||
ProcessGraph, | ||
ProcessGraphError, | ||
ProcessGraphNode, | ||
ProcessRegistry, | ||
ErrorList, | ||
FeatureList, | ||
Utils | ||
}; | ||
/***/ }), | ||
/* 8 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const Utils = __webpack_require__(0); | ||
var MigrateCapabilities = { | ||
guessApiVersion(capabilties) { | ||
if (typeof capabilties.version === 'string') { | ||
return capabilties.version; | ||
} | ||
else if (typeof capabilties.api_version === 'string') { | ||
return capabilties.api_version; | ||
} | ||
else if (capabilties.backend_version || capabilties.title || capabilties.description || capabilties.links) { | ||
return "0.4"; | ||
} | ||
else { | ||
// This is a wild guess | ||
return "0.3"; | ||
} | ||
}, | ||
// Always returns a copy of the input object | ||
convertCapabilitiesToLatestSpec(originalCapabilities, version = null, title = "Unknown") { | ||
var capabilities = Object.assign({}, originalCapabilities); | ||
if (version === null) { | ||
version = this.guessApiVersion(capabilities); | ||
} | ||
// convert v0.3 capabilities to v0.4 format | ||
if (Utils.compareVersion(version, "0.3.x") === 0) { | ||
// version => api_version | ||
if (typeof capabilities.version !== 'undefined') { | ||
delete capabilities.version; | ||
} | ||
} | ||
// Convert billing plans | ||
if (typeof capabilities.billing !== 'undefined') { | ||
capabilities.billing = this.convertBillingToLatestSpec(capabilities.billing, version); | ||
} | ||
// Convert endpoints | ||
capabilities.endpoints = this.convertEndpointsToLatestSpec(capabilities.endpoints, version); | ||
// Add missing fields with somewhat useful data | ||
if (typeof capabilities.api_version !== 'string') { | ||
capabilities.api_version = "0.4.0"; | ||
} | ||
if (typeof capabilities.backend_version !== 'string') { | ||
capabilities.backend_version = "Unknown"; | ||
} | ||
if (typeof capabilities.title !== 'string') { | ||
capabilities.title = title; | ||
} | ||
if (typeof capabilities.description !== 'string') { | ||
capabilities.description = "No description provided."; | ||
} | ||
return capabilities; | ||
}, | ||
// Always returns a copy of the input object | ||
convertBillingToLatestSpec(originalBilling, version) { | ||
var billing = Object.assign({}, originalBilling); | ||
// convert v0.3 billing info to v0.4 format | ||
if (Utils.compareVersion(version, "0.3.x") === 0) { | ||
// Add paid flag to billing plans | ||
if (Array.isArray(billing.plans)) { | ||
billing.plans = billing.plans.map(plan => { | ||
if (typeof plan.paid !== 'boolean') { | ||
plan.paid = true; | ||
if (typeof plan.name === 'string' && plan.name.toLowerCase().includes('free')) { | ||
plan.paid = false; | ||
} | ||
} | ||
return plan; | ||
}); | ||
} | ||
} | ||
return billing; | ||
}, | ||
// Always returns a copy of the input object | ||
convertEndpointsToLatestSpec(originalEndpoints, version) { | ||
var endpoints = []; | ||
if (Array.isArray(originalEndpoints)) { | ||
endpoints = originalEndpoints.slice(0); | ||
} | ||
// convert v0.3 service types to v0.4 format | ||
if (Utils.compareVersion(version, "0.3.x") === 0) { | ||
// Nothing to do as nothing has changed. | ||
} | ||
return endpoints; | ||
}, | ||
// Always returns a copy of the input object | ||
convertOutputFormatsToLatestSpec(originalFormats, version) { | ||
var formats = Object.assign({}, originalFormats); | ||
// convert v0.3 output formats to v0.4 format | ||
if (Utils.compareVersion(version, "0.3.x") === 0) { | ||
if (typeof formats.formats === 'object' && formats.formats !== null) { | ||
return formats.formats; | ||
} | ||
} | ||
return formats; | ||
}, | ||
// Always returns a copy of the input object | ||
convertServiceTypesToLatestSpec(originalTypes, version) { | ||
var types = Object.assign({}, originalTypes); | ||
// convert v0.3 service types to v0.4 format | ||
if (Utils.compareVersion(version, "0.3.x") === 0) { | ||
// Nothing to do as nothing has changed. | ||
} | ||
return types; | ||
} | ||
}; | ||
module.exports = MigrateCapabilities; | ||
/***/ }), | ||
/* 9 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* global define */ | ||
(function (root, factory) { | ||
/* istanbul ignore next */ | ||
if (true) { | ||
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), | ||
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? | ||
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), | ||
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); | ||
} else {} | ||
}(this, function () { | ||
var semver = /^v?(?:\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+))?(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i; | ||
function indexOrEnd(str, q) { | ||
return str.indexOf(q) === -1 ? str.length : str.indexOf(q); | ||
} | ||
function split(v) { | ||
var c = v.replace(/^v/, '').replace(/\+.*$/, ''); | ||
var patchIndex = indexOrEnd(c, '-'); | ||
var arr = c.substring(0, patchIndex).split('.'); | ||
arr.push(c.substring(patchIndex + 1)); | ||
return arr; | ||
} | ||
function tryParse(v) { | ||
return isNaN(Number(v)) ? v : Number(v); | ||
} | ||
function validate(version) { | ||
if (typeof version !== 'string') { | ||
throw new TypeError('Invalid argument expected string'); | ||
} | ||
if (!semver.test(version)) { | ||
throw new Error('Invalid argument not valid semver (\''+version+'\' received)'); | ||
} | ||
} | ||
return function compareVersions(v1, v2) { | ||
[v1, v2].forEach(validate); | ||
var s1 = split(v1); | ||
var s2 = split(v2); | ||
for (var i = 0; i < Math.max(s1.length - 1, s2.length - 1); i++) { | ||
var n1 = parseInt(s1[i] || 0, 10); | ||
var n2 = parseInt(s2[i] || 0, 10); | ||
if (n1 > n2) return 1; | ||
if (n2 > n1) return -1; | ||
} | ||
var sp1 = s1[s1.length - 1]; | ||
var sp2 = s2[s2.length - 1]; | ||
if (sp1 && sp2) { | ||
var p1 = sp1.split('.').map(tryParse); | ||
var p2 = sp2.split('.').map(tryParse); | ||
for (i = 0; i < Math.max(p1.length, p2.length); i++) { | ||
if (p1[i] === undefined || typeof p2[i] === 'string' && typeof p1[i] === 'number') return -1; | ||
if (p2[i] === undefined || typeof p1[i] === 'string' && typeof p2[i] === 'number') return 1; | ||
if (p1[i] > p2[i]) return 1; | ||
if (p2[i] > p1[i]) return -1; | ||
} | ||
} else if (sp1 || sp2) { | ||
return sp1 ? -1 : 1; | ||
} | ||
return 0; | ||
}; | ||
})); | ||
/***/ }), | ||
/* 10 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const Utils = __webpack_require__(0); | ||
var MigrateCollections = { | ||
guessCollectionSpecVersion(c) { | ||
var version = "0.4"; | ||
// Try to guess a version | ||
if (typeof c.id === 'undefined' && typeof c.name !== 'undefined') { // No id defined, probably v0.3 | ||
version = "0.3"; | ||
} | ||
return version; | ||
}, | ||
// Always returns a copy of the input collection object | ||
convertCollectionToLatestSpec(originalCollection, version = null) { | ||
var collection = Object.assign({}, originalCollection); | ||
if (!Object.keys(collection).length) { | ||
return collection; | ||
} | ||
if (version === null) { | ||
version = this.guessCollectionSpecVersion(collection); | ||
} | ||
// convert v0.3 processes to v0.4 format | ||
if (Utils.compareVersion(version, "0.3.x") === 0) { | ||
// name => id | ||
collection.id = collection.name; | ||
delete collection.name; | ||
// Add stac_version | ||
collection.stac_version = '0.6.1'; | ||
// Rename provider => providers | ||
if (Array.isArray(collection.provider)) { | ||
collection.providers = collection.provider; | ||
delete collection.provider; | ||
} | ||
if (typeof collection.properties !== 'object') { | ||
collection.properties = {}; | ||
} | ||
// Migrate eo:bands | ||
if (collection['eo:bands'] !== null && typeof collection['eo:bands'] === 'object' && !Array.isArray(collection['eo:bands'])) { | ||
var bands = []; | ||
for(let key in collection['eo:bands']) { | ||
var band = Object.assign({}, collection['eo:bands'][key]); | ||
band.name = key; | ||
if (typeof band.resolution !== 'undefined' && typeof band.gsd === 'undefined') { | ||
band.gsd = band.resolution; | ||
delete band.resolution; | ||
} | ||
if (typeof band.wavelength !== 'undefined' && typeof band.center_wavelength === 'undefined') { | ||
band.center_wavelength = band.wavelength; | ||
delete band.wavelength; | ||
} | ||
bands.push(band); | ||
} | ||
collection['eo:bands'] = bands; | ||
} | ||
// Move all other properties into properties. | ||
for (let key in collection) { | ||
if (key.includes(':')) { | ||
collection.properties[key] = collection[key]; | ||
delete collection[key]; | ||
} | ||
} | ||
} | ||
return collection; | ||
} | ||
}; | ||
module.exports = MigrateCollections; | ||
/***/ }), | ||
/* 11 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const Utils = __webpack_require__(0); | ||
var MigrateProcesses = { | ||
guessProcessSpecVersion(p) { | ||
var version = "0.4"; | ||
// Try to guess a version | ||
if (typeof p.id === 'undefined' && typeof p.name !== 'undefined') { // No id defined, probably v0.3 | ||
version = "0.3"; | ||
} | ||
return version; | ||
}, | ||
// Always returns a copy of the input process object | ||
convertProcessToLatestSpec(originalProcess, version = null) { | ||
var process = Object.assign({}, originalProcess); | ||
if (version === null) { | ||
version = this.guessProcessSpecVersion(process); | ||
} | ||
// convert v0.3 processes to v0.4 format | ||
if (Utils.compareVersion(version, "0.3.x") === 0) { | ||
// name => id | ||
process.id = process.name; | ||
delete process.name; | ||
// mime_type => media_type | ||
if (typeof process.parameters === 'object') { | ||
for(var key in process.parameters) { | ||
if (typeof process.parameters[key].mime_type !== 'undefined') { | ||
var param = Object.assign({}, process.parameters[key]); | ||
param.media_type = param.mime_type; | ||
delete param.mime_type; | ||
process.parameters[key] = param; | ||
} | ||
} | ||
} | ||
if (typeof process.returns === 'object' && typeof process.returns.mime_type !== 'undefined') { | ||
process.returns.media_type = process.returns.mime_type; | ||
delete process.returns.mime_type; | ||
} | ||
// exception object | ||
if (typeof process.exceptions === 'object') { | ||
for(let key in process.exceptions) { | ||
var e = process.exceptions[key]; | ||
if (typeof e.message === 'undefined') { | ||
process.exceptions[key] = Object.assign({}, e, { | ||
message: e.description | ||
}); | ||
} | ||
} | ||
} | ||
// examples object | ||
if (typeof process.examples === 'object') { | ||
var examples = []; | ||
for(let key in process.examples) { | ||
var old = process.examples[key]; | ||
var example = { | ||
title: old.summary || key, | ||
description: old.description | ||
}; | ||
if (old.process_graph) { | ||
example.process_graph = old.process_graph; | ||
} | ||
examples.push(example); | ||
} | ||
process.examples = examples; | ||
} | ||
// Fill parameter order | ||
if (typeof process.parameters === 'object' && !Array.isArray(process.parameter_order)) { | ||
var parameter_order = Object.keys(process.parameters); | ||
if (parameter_order.length > 1) { | ||
process.parameter_order = parameter_order; | ||
} | ||
} | ||
} | ||
return process; | ||
} | ||
}; | ||
module.exports = MigrateProcesses; | ||
/***/ }), | ||
/* 12 */ | ||
/***/ (function(module, exports) { | ||
module.exports = __WEBPACK_EXTERNAL_MODULE__12__; | ||
/***/ }), | ||
/* 13 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const BaseProcess = __webpack_require__(3); | ||
const Utils = __webpack_require__(0); | ||
module.exports = class ProcessRegistry { | ||
constructor() { | ||
// Keys added to this object must be lowercase! | ||
this.processes = {}; | ||
} | ||
addFromResponse(response) { | ||
for(var i in response.processes) { | ||
this.add(response.processes[i]); | ||
} | ||
} | ||
add(process) { | ||
this.processes[process.id] = new BaseProcess(process); | ||
} | ||
count() { | ||
return Utils.size(this.processes); | ||
} | ||
get(id) { | ||
var pid = id.toLowerCase(); | ||
if (typeof this.processes[pid] !== 'undefined') { | ||
return this.processes[pid]; | ||
} | ||
return null; | ||
} | ||
getSchema(id) { | ||
var p = this.get(id); | ||
return p !== null ? p.schema : null; | ||
} | ||
getProcessSchemas() { | ||
return Object.values(this.processes).map(impl => impl.schema); | ||
} | ||
}; | ||
/***/ }), | ||
/* 14 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const Utils = __webpack_require__(0); | ||
var FeatureList = { | ||
// Manual assignment of the endpoints above to individual features. | ||
// A functionality is considered supported when ALL of the corresponding endpoints are supported. | ||
features: { | ||
'Basic functionality': [ | ||
'get /collections', | ||
'get /collections/{}', | ||
'get /processes', | ||
'get /output_formats' | ||
], | ||
'Authenticate with HTTP Basic': [ // TODO: Remove later because this auth method should not be used | ||
'get /credentials/basic', | ||
// 'get /me' // not necessarily needed (just outputs metadata) | ||
], | ||
'Authenticate with OpenID Connect': [ // TODO: Remove later because the user doesn't care HOW the auth works | ||
'get /credentials/oidc', | ||
// 'get /me' // not necessarily needed (just outputs metadata) | ||
], | ||
'Batch processing': [ | ||
'get /jobs', | ||
'post /jobs', | ||
'get /jobs/{}', | ||
// 'patch /jobs/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
'delete /jobs/{}', | ||
'get /jobs/{}/results', | ||
'post /jobs/{}/results', | ||
// 'delete /jobs/{}/results' // not necessarily needed (can be deleted by deleting the entire job) | ||
], | ||
'Estimate processing costs': [ | ||
'get /jobs/{}/estimate' | ||
], | ||
'Preview processing results': [ | ||
'post /result' | ||
], | ||
'Secondary web services': [ | ||
'get /service_types', | ||
'get /services', | ||
'post /services', | ||
'get /services/{}', | ||
// 'patch /services/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
'delete /services/{}', | ||
], | ||
'File storage': [ | ||
'get /files/{}', | ||
'get /files/{}/{}', | ||
'put /files/{}/{}', | ||
'delete /files/{}/{}' | ||
], | ||
'Stored process graphs': [ | ||
'get /process_graphs', | ||
'post /process_graphs', | ||
'get /process_graphs/{}', | ||
// 'patch /process_graphs/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
'delete /process_graphs/{}' | ||
], | ||
'Validate process graphs': [ | ||
'post /validation', | ||
], | ||
'Notifications and monitoring': [ | ||
'get /subscription' | ||
], | ||
'User defined functions (UDF)': [ | ||
'get /udf_runtimes' | ||
] | ||
}, | ||
legacyFeatures: { | ||
'post /result': { | ||
'post /preview': ["0.3.*"] | ||
} | ||
}, | ||
getListForVersion(version) { | ||
var list = {}; | ||
for(var feature in this.features) { | ||
list[feature] = []; | ||
for(var i in this.features[feature]) { | ||
var endpoint = this.findLegacyEndpoint(version, this.features[feature][i]); | ||
list[feature].push(endpoint); | ||
} | ||
} | ||
return list; | ||
}, | ||
findLegacyEndpoint(version, endpoint, method = null) { | ||
if (method !== null) { | ||
endpoint = this.endpointToString(method, endpoint); | ||
} | ||
if (typeof this.legacyFeatures[endpoint] === 'object') { | ||
var legacy = this.legacyFeatures[endpoint]; | ||
for(var legacyEndpoint in legacy) { | ||
for(var i in legacy[legacyEndpoint]) { | ||
var legacyVersion = legacy[legacyEndpoint][i]; | ||
if (Utils.compareVersion(version, legacyVersion) === 0) { | ||
return legacyEndpoint; | ||
} | ||
} | ||
} | ||
} | ||
return endpoint; | ||
}, | ||
getFeatures() { | ||
return Object.keys(this.features); | ||
}, | ||
getFeatureCount() { | ||
return Object.keys(this.features).length; | ||
}, | ||
endpointsToStringList(endpoints) { | ||
var list = []; | ||
for(let i in endpoints) { | ||
for(let j in endpoints[i].methods) { | ||
list.push(this.endpointToString(endpoints[i].methods[j], endpoints[i].path)); | ||
} | ||
} | ||
return list; | ||
}, | ||
endpointToString(method, path) { | ||
// allow arbitrary parameter names => don't care about content in curly brackets | ||
let request = method + ' ' + path.replace(/{[^}]+}/g, '{}'); | ||
return request.toLowerCase(); | ||
}, | ||
getReport(endpoints, version, convert = true) { | ||
var supportedFeatureCount = 0; | ||
var supportedEndpoints = convert ? this.endpointsToStringList(endpoints) : endpoints; | ||
var status = this.getListForVersion(version); | ||
// Assign each functionality a supported flag (0 = none, 1 = partially, 2 = fully) | ||
Object.keys(status).forEach(key => { | ||
let requiredEndpoints = status[key]; | ||
// Get a list of unsupported, but required endpoints | ||
let unsupported = requiredEndpoints.filter(requiredEndpoint => !supportedEndpoints.includes(requiredEndpoint)); | ||
switch(unsupported.length) { | ||
// No unsupported endpoints => fully supported | ||
case 0: | ||
status[key] = 2; | ||
supportedFeatureCount++; | ||
break; | ||
// All endpoints are unsupported | ||
case requiredEndpoints.length: | ||
status[key] = 0; | ||
break; | ||
// Some endpoints are supported => partially supported | ||
default: | ||
status[key] = 1; | ||
} | ||
}); | ||
return { | ||
count: supportedFeatureCount, | ||
list: status | ||
}; | ||
} | ||
}; | ||
module.exports = FeatureList; | ||
/***/ }) | ||
/******/ ]); | ||
}); |
{ | ||
"name": "@openeo/js-commons", | ||
"version": "0.4.0-beta.2", | ||
"version": "0.4.0", | ||
"author": "openEO Consortium", | ||
@@ -12,2 +12,3 @@ "contributors": [ | ||
"license": "Apache-2.0", | ||
"homepage": "http://openeo.org", | ||
"bugs": { | ||
@@ -25,16 +26,11 @@ "url": "https://github.com/open-eo/openeo-js-commons/issues" | ||
], | ||
"scripts": { | ||
"build": "npx webpack", | ||
"test": "jest --env=jsdom", | ||
"test_node": "jest --env=node" | ||
}, | ||
"peerDependencies": { | ||
"ajv": "^6.10.0" | ||
}, | ||
"dependencies": { | ||
"compare-versions": "^3.4.0" | ||
}, | ||
"devDependencies": { | ||
"jest": "^24.5.0", | ||
"jest": "^24.7.1", | ||
"jest-html-reporter": "^2.5.0", | ||
"jsdoc": "^3.5.5", | ||
"jshint": "^2.10.2", | ||
"unminified-webpack-plugin": "^2.0.0", | ||
"webpack": "^4.30.0", | ||
@@ -44,7 +40,12 @@ "webpack-bundle-analyzer": "^3.3.2", | ||
}, | ||
"browserslist": [ | ||
"> 3%", | ||
"last 2 versions", | ||
"not ie < 11" | ||
] | ||
"dependencies": { | ||
"compare-versions": "^3.4.0" | ||
}, | ||
"scripts": { | ||
"docs": "jsdoc src -r -d docs/ -P package.json -R README.md", | ||
"build": "npx webpack", | ||
"compat": "jshint src", | ||
"test": "jest --env=jsdom", | ||
"test_node": "jest --env=node" | ||
} | ||
} |
# openeo-js-commons | ||
A set of common JavaScript functionalities for [openEO](http://openeo.org). | ||
**Version: 0.4.0-beta.1**, supports openEO API v0.4.0. | ||
[![Build Status](https://travis-ci.org/Open-EO/openeo-js-commons.svg?branch=master)](https://travis-ci.org/Open-EO/openeo-js-commons) | ||
This library's version is **0.4.0** and supports **openEO API version 0.4.x**. Legacy versions are available as releases. | ||
## Features | ||
- Converting responses to the latest API version is supported for: | ||
- Capabilities | ||
- Collections | ||
- Processes | ||
- Output Formats | ||
- Service Types | ||
- Capabilities | ||
- Collections | ||
- Processes | ||
- Output Formats | ||
- Service Types | ||
- Feature detection | ||
- Process graph handling: | ||
- Parsing a process graph | ||
- Validation based on the JSON Schemas | ||
- Framework to implement process graph execution | ||
- Parsing a process graph | ||
- Validation based on the JSON Schemas | ||
- Framework to implement process graph execution | ||
- JSON Schema validation for Process parameters and return values | ||
@@ -28,10 +30,12 @@ | ||
```html | ||
<script src="https://cdn.jsdelivr.net/npm/@openeo/js-commons@0.4/dist/main.min.js"></script> | ||
``` | ||
<script src="https://cdn.jsdelivr.net/npm/@openeo/js-commons@0.4.0/dist/main.min.js"></script> | ||
``` | ||
This library has a peer dependency to `ajv`, so if you'd like to use process graph validation or execution you need to include `ajv` (v6.10) in your package.json or include it in your web page: | ||
```html | ||
<script src="https://cdn.jsdelivr.net/npm/ajv@6.10/lib/ajv.min.js"></script> | ||
``` | ||
<script src="https://cdn.jsdelivr.net/npm/ajv@6.10.0/lib/ajv.min.js"></script> | ||
``` | ||
More information can be found in the [**JS commons documentation**](https://open-eo.github.io/openeo-js-commons/0.4.0/). |
@@ -8,7 +8,11 @@ module.exports = class ErrorList { | ||
first() { | ||
return this.errors[0]; | ||
return this.errors[0] || null; | ||
} | ||
last() { | ||
return this.errors[this.errors.length-1] || null; | ||
} | ||
merge(errorList) { | ||
this.errors.concat(errorList.getAll()); | ||
this.errors = this.errors.concat(errorList.getAll()); | ||
} | ||
@@ -41,3 +45,3 @@ | ||
for (var i in this.errors) { | ||
msg += (parseInt(i)+1) + ". " + this.errors[i].message + "\r\n"; | ||
msg += (parseInt(i, 10)+1) + ". " + this.errors[i].message + "\r\n"; | ||
} | ||
@@ -51,2 +55,2 @@ return msg.trim(); | ||
} | ||
}; |
@@ -15,7 +15,7 @@ const Utils = require('./utils.js'); | ||
'get /credentials/basic', | ||
// 'get /me' // not necessarily needed (just outputs metadata) | ||
// 'get /me' // not necessarily needed (just outputs metadata) | ||
], | ||
'Authenticate with OpenID Connect': [ // TODO: Remove later because the user doesn't care HOW the auth works | ||
'get /credentials/oidc', | ||
// 'get /me' // not necessarily needed (just outputs metadata) | ||
// 'get /me' // not necessarily needed (just outputs metadata) | ||
], | ||
@@ -26,7 +26,7 @@ 'Batch processing': [ | ||
'get /jobs/{}', | ||
// 'patch /jobs/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
// 'patch /jobs/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
'delete /jobs/{}', | ||
'get /jobs/{}/results', | ||
'post /jobs/{}/results', | ||
// 'delete /jobs/{}/results' // not necessarily needed (can be deleted by deleting the entire job) | ||
// 'delete /jobs/{}/results' // not necessarily needed (can be deleted by deleting the entire job) | ||
], | ||
@@ -44,3 +44,3 @@ 'Estimate processing costs': [ | ||
'get /services/{}', | ||
// 'patch /services/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
// 'patch /services/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
'delete /services/{}', | ||
@@ -58,3 +58,3 @@ ], | ||
'get /process_graphs/{}', | ||
// 'patch /process_graphs/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
// 'patch /process_graphs/{}', // not necessarily needed (can be achieved by deleting and re-creating) | ||
'delete /process_graphs/{}' | ||
@@ -79,3 +79,3 @@ ], | ||
getListForVersion(version) { | ||
getListForVersion(version) { | ||
var list = {}; | ||
@@ -82,0 +82,0 @@ for(var feature in this.features) { |
@@ -22,3 +22,3 @@ const Utils = require('../utils.js'); | ||
// Always returns a copy of the input object | ||
convertCapabilitiesToLatestSpec: function(originalCapabilities, version = null, title = "Unknown") { | ||
convertCapabilitiesToLatestSpec(originalCapabilities, version = null, title = "Unknown") { | ||
var capabilities = Object.assign({}, originalCapabilities); | ||
@@ -61,3 +61,3 @@ if (version === null) { | ||
// Always returns a copy of the input object | ||
convertBillingToLatestSpec: function(originalBilling, version) { | ||
convertBillingToLatestSpec(originalBilling, version) { | ||
var billing = Object.assign({}, originalBilling); | ||
@@ -84,3 +84,3 @@ // convert v0.3 billing info to v0.4 format | ||
// Always returns a copy of the input object | ||
convertEndpointsToLatestSpec: function(originalEndpoints, version) { | ||
convertEndpointsToLatestSpec(originalEndpoints, version) { | ||
var endpoints = []; | ||
@@ -98,3 +98,3 @@ if (Array.isArray(originalEndpoints)) { | ||
// Always returns a copy of the input object | ||
convertOutputFormatsToLatestSpec: function(originalFormats, version) { | ||
convertOutputFormatsToLatestSpec(originalFormats, version) { | ||
var formats = Object.assign({}, originalFormats); | ||
@@ -111,3 +111,3 @@ // convert v0.3 output formats to v0.4 format | ||
// Always returns a copy of the input object | ||
convertServiceTypesToLatestSpec: function(originalTypes, version) { | ||
convertServiceTypesToLatestSpec(originalTypes, version) { | ||
var types = Object.assign({}, originalTypes); | ||
@@ -114,0 +114,0 @@ // convert v0.3 service types to v0.4 format |
@@ -15,3 +15,3 @@ const Utils = require('../utils.js'); | ||
// Always returns a copy of the input collection object | ||
convertCollectionToLatestSpec: function(originalCollection, version = null) { | ||
convertCollectionToLatestSpec(originalCollection, version = null) { | ||
var collection = Object.assign({}, originalCollection); | ||
@@ -43,3 +43,3 @@ if (!Object.keys(collection).length) { | ||
var bands = []; | ||
for(var key in collection['eo:bands']) { | ||
for(let key in collection['eo:bands']) { | ||
var band = Object.assign({}, collection['eo:bands'][key]); | ||
@@ -60,3 +60,3 @@ band.name = key; | ||
// Move all other properties into properties. | ||
for (var key in collection) { | ||
for (let key in collection) { | ||
if (key.includes(':')) { | ||
@@ -63,0 +63,0 @@ collection.properties[key] = collection[key]; |
@@ -15,3 +15,3 @@ const Utils = require('../utils.js'); | ||
// Always returns a copy of the input process object | ||
convertProcessToLatestSpec: function(originalProcess, version = null) { | ||
convertProcessToLatestSpec(originalProcess, version = null) { | ||
var process = Object.assign({}, originalProcess); | ||
@@ -44,3 +44,3 @@ if (version === null) { | ||
if (typeof process.exceptions === 'object') { | ||
for(var key in process.exceptions) { | ||
for(let key in process.exceptions) { | ||
var e = process.exceptions[key]; | ||
@@ -57,3 +57,3 @@ if (typeof e.message === 'undefined') { | ||
var examples = []; | ||
for(var key in process.examples) { | ||
for(let key in process.examples) { | ||
var old = process.examples[key]; | ||
@@ -60,0 +60,0 @@ var example = { |
@@ -28,9 +28,13 @@ const Utils = require('../utils'); | ||
constructor(code, variables = {}) { | ||
constructor(codeOrMsg, variables = {}) { | ||
super(); | ||
this.code = code; | ||
this.variables = variables; | ||
if (typeof MESSAGES[code] === 'string') { | ||
this.message = Utils.replacePlaceholders(MESSAGES[code], variables); | ||
if (typeof MESSAGES[codeOrMsg] === 'string') { | ||
this.code = codeOrMsg; | ||
this.message = Utils.replacePlaceholders(MESSAGES[codeOrMsg], variables); | ||
} | ||
else { | ||
this.code = codeOrMsg.replace(/[^\w\d]+/g, ''); | ||
this.message = codeOrMsg; | ||
} | ||
} | ||
@@ -42,5 +46,5 @@ | ||
message: this.message | ||
} | ||
}; | ||
} | ||
} | ||
}; |
@@ -6,3 +6,3 @@ const ajv = require('ajv'); | ||
constructor(options) { | ||
constructor() { | ||
var ajvOptions = { | ||
@@ -12,19 +12,20 @@ schemaId: 'auto', | ||
formats: { | ||
'band-name': {type: 'string', validate: this.validateBandName.bind(this)}, | ||
'bounding-box': {type: 'object', validate: this.validateBoundingBox.bind(this)}, | ||
'callback': {type: 'object', validate: this.validateCallback.bind(this)}, | ||
'collection-id': {type: 'string', validate: this.validateCollectionId.bind(this)}, | ||
'epsg-code': {type: 'integer', validate: this.validateEpsgCode.bind(this)}, | ||
'geojson': {type: 'object', validate: this.validateGeoJson.bind(this)}, | ||
// See issue https://github.com/Open-EO/openeo-js-commons/issues/4 for information on why ajv doesn't support non-string validation | ||
'band-name': {type: 'string', async: true, validate: this.validateBandName.bind(this)}, | ||
'bounding-box': {type: 'object', async: true, validate: this.validateBoundingBox.bind(this)}, // Currently not supported by ajv 6.10 | ||
'callback': {type: 'object', async: true, validate: this.validateCallback.bind(this)}, // Currently not supported by ajv 6.10 | ||
'collection-id': {type: 'string', async: true, validate: this.validateCollectionId.bind(this)}, | ||
'epsg-code': {type: 'integer', async: true, validate: this.validateEpsgCode.bind(this)}, // Currently not supported by ajv 6.10 | ||
'geojson': {type: 'object', async: true, validate: this.validateGeoJson.bind(this)}, // Currently not supported by ajv 6.10 | ||
'job-id': {type: 'string', async: true, validate: this.validateJobId.bind(this)}, | ||
'kernel': {type: 'array', validate: this.validateKernel.bind(this)}, | ||
'output-format': {type: 'string', validate: this.validateOutputFormat.bind(this)}, | ||
'output-format-options': {type: 'array', validate: this.validateOutputFormatOptions.bind(this)}, | ||
'kernel': {type: 'array', async: true, validate: this.validateKernel.bind(this)}, // Currently not supported by ajv 6.10 | ||
'output-format': {type: 'string', async: true, validate: this.validateOutputFormat.bind(this)}, | ||
'output-format-options': {type: 'array', async: true, validate: this.validateOutputFormatOptions.bind(this)}, // Currently not supported by ajv 6.10 | ||
'process-graph-id': {type: 'string', async: true, validate: this.validateProcessGraphId.bind(this)}, | ||
'process-graph-variables': {type: 'array', validate: this.validateProcessGraphVariables.bind(this)}, | ||
'proj-definition': {type: 'string', validate: this.validateProjDefinition.bind(this)}, | ||
'raster-cube': {type: 'object', validate: this.validateRasterCube.bind(this)}, | ||
'temporal-interval': {type: 'array', validate: this.validateTemporalInterval.bind(this)}, | ||
'temporal-intervals': {type: 'array', validate: this.validateTemporalIntervals.bind(this)}, | ||
'vector-cube': {type: 'object', validate: this.validateVectorCube.bind(this)} | ||
'process-graph-variables': {type: 'array', async: true, validate: this.validateProcessGraphVariables.bind(this)}, // Currently not supported by ajv 6.10 | ||
'proj-definition': {type: 'string', async: true, validate: this.validateProjDefinition.bind(this)}, | ||
'raster-cube': {type: 'object', async: true, validate: this.validateRasterCube.bind(this)}, // Currently not supported by ajv 6.10 | ||
'temporal-interval': {type: 'array', async: true, validate: this.validateTemporalInterval.bind(this)}, // Currently not supported by ajv 6.10 | ||
'temporal-intervals': {type: 'array', async: true, validate: this.validateTemporalIntervals.bind(this)}, // Currently not supported by ajv 6.10 | ||
'vector-cube': {type: 'object', async: true, validate: this.validateVectorCube.bind(this)} // Currently not supported by ajv 6.10 | ||
} | ||
@@ -48,8 +49,4 @@ }; | ||
if (Utils.isObject(options)) { | ||
this.collectionResolver = options.collectionResolver || null, | ||
this.jobResolver = options.jobResolver || null; | ||
this.pgResolver = options.pgResolver || null; | ||
this.outputFormats = options.outputFormats || null; | ||
} | ||
this.outputFormats = null; | ||
this.geoJsonValidator = null; | ||
} | ||
@@ -60,6 +57,6 @@ | ||
var clonedSchema = Object.assign({}, schema); | ||
clonedSchema["$async"] = true; | ||
if (typeof schema["$schema"] === 'undefined') { | ||
// Set applicable JSON SChema draft version if not already set | ||
clonedSchema["$schema"] = "http://json-schema.org/draft-07/schema#"; | ||
clonedSchema.$async = true; | ||
if (typeof clonedSchema.$schema === 'undefined') { | ||
// Set applicable JSON Schema draft version if not already set | ||
clonedSchema.$schema = "http://json-schema.org/draft-07/schema#"; | ||
} | ||
@@ -82,5 +79,5 @@ | ||
// Set applicable JSON SChema draft version if not already set | ||
if (typeof schema["$schema"] === 'undefined') { | ||
var schema = Object.assign({}, schema); // Make sure we don't alter the process registry | ||
schema["$schema"] = "http://json-schema.org/draft-07/schema#"; | ||
if (typeof schema.$schema === 'undefined') { | ||
schema = Object.assign({}, schema); // Make sure we don't alter the process registry | ||
schema.$schema = "http://json-schema.org/draft-07/schema#"; | ||
} | ||
@@ -92,17 +89,8 @@ | ||
// callback is an async function accepting a single parameter, which is the requested collection id. Must return a boolean (true = found, false = not found). | ||
setCollectionResolver(callback) { | ||
this.collectionResolver = callback; | ||
// Pass the content of https://geojson.org/schema/GeoJSON.json | ||
setGeoJsonSchema(schema) { | ||
var gjv = new ajv(); | ||
this.geoJsonValidator = gjv.compile(schema); | ||
} | ||
// callback is an async function accepting a single parameter, which is the requested job id. Must return a boolean (true = found, false = not found). | ||
setJobResolver(callback) { | ||
this.jobResolver = callback; | ||
} | ||
// callback is an async function accepting a single parameter, which is the requested process graph id. Must return a boolean (true = found, false = not found). | ||
setStoredProcessGraphResolver(callback) { | ||
this.pgResolver = callback; | ||
} | ||
// Expects API compatible output formats (see GET /output_formats). | ||
@@ -116,84 +104,172 @@ setOutputFormats(outputFormats) { | ||
validateBandName(data) { | ||
return true; // ToDo | ||
/* istanbul ignore next */ | ||
async validateBandName(/*data*/) { | ||
// Can't validate band name without knowing/loading the data. | ||
// => To be overridden by end-user application. | ||
return true; | ||
} | ||
validateBoundingBox(data) { | ||
return true; // ToDo: Fully check against bounding box schema | ||
/* istanbul ignore next */ | ||
async validateBoundingBox(/*data*/) { | ||
// Nothing to validate, schema is (usually) delivered by processes. | ||
return true; | ||
} | ||
validateCallback(data) { | ||
return true; // ToDo | ||
/* istanbul ignore next */ | ||
async validateCallback(/*data*/) { | ||
// This should be checked by process graph parsing automatically. | ||
// Otherwise to be overridden by end-user application. | ||
return true; | ||
} | ||
async validateCollectionId(data) { | ||
if (typeof this.collectionResolver === 'function') { | ||
return this.collectionResolver(data); | ||
} | ||
/* istanbul ignore next */ | ||
async validateCollectionId(/*data*/) { | ||
// To be overridden by end-user application. | ||
return true; | ||
} | ||
validateEpsgCode(data) { | ||
return true; // ToDo | ||
async validateEpsgCode(data) { | ||
// Rough check for valid numbers as we don't want to maintain a full epsg code list in this repo. | ||
// Fully validation to be implemented by end-user application by overriding this method. | ||
if (data >= 2000) { | ||
return true; | ||
} | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid EPSG code specified." | ||
}]); | ||
} | ||
validateGeoJson(data) { | ||
if (typeof data.type !== 'string') { // ToDo: Fully check against GeoJSON schema | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (no type property)." | ||
}]); | ||
async validateGeoJson(data) { | ||
if (this.geoJsonValidator !== null) { | ||
if (!this.geoJsonValidator(data)) { | ||
throw new ajv.ValidationError(ajv.errors); | ||
} | ||
return true; | ||
} | ||
else { | ||
// A very rough GeoJSON validation if no GeoJSON schema is available. | ||
if (typeof data.type !== 'string') { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (no type property)." | ||
}]); | ||
} | ||
switch(data.type) { | ||
case "Point": | ||
case "MultiPoint": | ||
case "LineString": | ||
case "MultiLineString": | ||
case "Polygon": | ||
case "MultiPolygon": | ||
if (!Array.isArray(data.coordinates)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (Geometry has no valid coordinates member)." | ||
}]); | ||
} | ||
return true; | ||
case "GeometryCollection": | ||
if (!Array.isArray(data.geometries)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (GeometryCollection has no valid geometries member)." | ||
}]); | ||
} | ||
return true; | ||
case "Feature": | ||
if (data.geometry !== null && !Utils.isObject(data.geometry)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (Feature has no valid geometry member)." | ||
}]); | ||
} | ||
if (data.properties !== null && !Utils.isObject(data.properties)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (Feature has no valid properties member)." | ||
}]); | ||
} | ||
return true; | ||
case "FeatureCollection": | ||
if (!Array.isArray(data.features)) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON specified (FeatureCollection has no valid features member)." | ||
}]); | ||
} | ||
return true; | ||
default: | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid GeoJSON type specified." | ||
}]); | ||
} | ||
} | ||
} | ||
/* istanbul ignore next */ | ||
async validateJobId(/*data*/) { | ||
// To be overridden by end-user application | ||
return true; | ||
} | ||
async validateJobId(data) { | ||
if (typeof this.jobResolver === 'function') { | ||
return this.jobResolver(data); | ||
} | ||
/* istanbul ignore next */ | ||
async validateKernel(/*data*/) { | ||
// ToDo? / To be overridden by end-user application | ||
return true; | ||
} | ||
validateKernel(data) { | ||
return true; // ToDo | ||
} | ||
validateOutputFormat(data) { | ||
async validateOutputFormat(data) { | ||
if (Utils.isObject(this.outputFormats) && !(data.toUpperCase() in this.outputFormats)) { | ||
return false; | ||
throw new ajv.ValidationError([{ | ||
message: "Output format not supported." | ||
}]); | ||
} | ||
return true; | ||
} | ||
validateOutputFormatOptions(data) { | ||
return true; // ToDO: This depends on the output format specified and can't be fully validated without knowning the chosen output format. | ||
/* istanbul ignore next */ | ||
async validateOutputFormatOptions(/*data*/) { | ||
// This depends on the output format specified and can't be fully validated without knowning the chosen output format. | ||
return true; | ||
} | ||
async validateProcessGraphId(data) { | ||
if (typeof this.pgResolver === 'function') { | ||
return this.pgResolver(data); | ||
} | ||
/* istanbul ignore next */ | ||
async validateProcessGraphId(/*data*/) { | ||
// To be overridden by end-user application | ||
return true; | ||
} | ||
validateProcessGraphVariables(data) { | ||
return true; // ToDo | ||
/* istanbul ignore next */ | ||
async validateProcessGraphVariables(/*data*/) { | ||
// Nothing to validate against... | ||
return true; | ||
} | ||
validateProjDefinition(data) { | ||
return true; // ToDo | ||
async validateProjDefinition(data) { | ||
// To be overridden by end-user application, just doing a very basic check here. | ||
if (!data.toLowerCase().includes("+proj")) { | ||
throw new ajv.ValidationError([{ | ||
message: "Invalid PROJ string specified (doesn't contain '+proj')." | ||
}]); | ||
} | ||
return true; | ||
} | ||
validateRasterCube(data) { | ||
return true; // ToDo | ||
/* istanbul ignore next */ | ||
async validateRasterCube(/*data*/) { | ||
// This is usually a reference to a process result as we haven't specified any JSON encoding for raster cubes. | ||
return true; | ||
} | ||
validateTemporalInterval(data) { | ||
return true; // ToDo: Fully check against schema (Array, two elements, both being null or date-time or date or time). Can't be both null... | ||
async validateTemporalInterval(/*data*/) { | ||
// ToDo: Fully check against schema, most is already checked by JSON Schemas itself, but check for example that | ||
// both can't be null at the same time or the first element is > the second element. | ||
return true; | ||
} | ||
validateTemporalIntervals(data) { | ||
return true; // ToDo: Fully chack against schema (Array of the schema above) | ||
async validateTemporalIntervals(data) { | ||
var invalid = data.filter(x => !this.validateTemporalInterval(x)); | ||
return invalid.length === 0; | ||
} | ||
validateVectorCube(data) { | ||
return true; // ToDo | ||
/* istanbul ignore next */ | ||
async validateVectorCube(/*data*/) { | ||
// This is usually a reference to a process result as we haven't specified any JSON encoding for raster cubes. | ||
return true; | ||
} | ||
@@ -203,6 +279,65 @@ | ||
// So would a value compatible with valueSchema be accepted by paramSchema? | ||
static isSchemaCompatible(paramSchema, valueSchema) { | ||
return true; // ToDo: Implement | ||
static isSchemaCompatible(paramSchema, valueSchema, strict = false) { | ||
var paramSchemas = this._convertSchemaToArray(paramSchema); | ||
var valueSchemas = this._convertSchemaToArray(valueSchema); | ||
var compatible = paramSchemas.filter(ps => { | ||
for(var i in valueSchemas) { | ||
var vs = valueSchemas[i]; | ||
if (typeof ps.type !== 'string' || (!strict && typeof vs.type !== 'string')) { // "any" type is always compatible | ||
return true; | ||
} | ||
else if (ps.type === vs.type || (ps.type === 'number' && vs.type === 'integer') || (!strict && ps.type === 'integer' && vs.type === 'number')) { | ||
if (ps.type === 'array' && Utils.isObject(ps.items) && Utils.isObject(vs.items)) { | ||
if (JsonSchemaValidator.isSchemaCompatible(ps.items, vs.items, strict)) { | ||
return true; | ||
} | ||
} | ||
else if (ps.type === 'object' && Utils.isObject(ps.properties) && Utils.isObject(vs.properties)) { | ||
// ToDo: Check properties, required properties etc. | ||
return true; | ||
} | ||
else if (!strict && (typeof ps.format !== 'string' || typeof vs.format !== 'string')) { | ||
return true; | ||
} | ||
else if (typeof ps.format !== 'string') { // types without format always accepts the same type with a format | ||
return true; | ||
} | ||
else if (ps.format === vs.format) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}); | ||
return compatible.length > 0; | ||
} | ||
static _convertSchemaToArray(schema) { | ||
var schemas = []; | ||
// ToDo: schema.not and schema.allOf is not supported - see also class constructor of ProcessSchema in processSchema.js of openeo-web-editor. | ||
if (schema.oneOf || schema.anyOf) { | ||
schemas = (schema.oneOf || schema.anyOf); | ||
} | ||
else if (Array.isArray(schema.type)) { | ||
schemas = schema.type.map(t => Object.assign({}, schema, {type: t})); | ||
} | ||
else { | ||
schemas = [schema]; | ||
} | ||
return schemas; | ||
} | ||
/** | ||
* Returns the indices of provided JSON Schemas that the provided values matches against. | ||
* | ||
* Returns a single index if a single type is mathcing. | ||
* Returns undefined if no valid type is found. | ||
* Returns an array of indices if multiple types are found. | ||
* | ||
* @param {Array} types - Array of JSON schemas | ||
* @param {*} value - A value | ||
* @return {(string[]|string|undefined)} - Returns matching indices, see description. | ||
*/ | ||
static async getTypeForValue(types, value) { | ||
@@ -214,3 +349,3 @@ var validator = new JsonSchemaValidator(); | ||
if (errors.length === 0) { | ||
potentialTypes.push(i); | ||
potentialTypes.push(String(i)); | ||
} | ||
@@ -221,2 +356,2 @@ } | ||
} | ||
}; |
@@ -20,3 +20,3 @@ const ProcessGraphError = require('./error'); | ||
this.process_id = json.process_id; | ||
this.arguments = json.arguments || {}; | ||
this.arguments = Utils.isObject(json.arguments) ? JSON.parse(JSON.stringify(json.arguments)) : {}; | ||
this.isResultNode = json.result || false; | ||
@@ -159,2 +159,2 @@ this.expectsFrom = []; | ||
} | ||
}; |
@@ -5,3 +5,2 @@ const JsonSchemaValidator = require('./jsonschema'); | ||
const ProcessGraph = require('./processgraph'); | ||
const Utils = require('../utils'); | ||
@@ -69,12 +68,4 @@ module.exports = class BaseProcess { | ||
var cbParams = node.getProcessGraph().getCallbackParameters(); | ||
if (Utils.isObject(cbParams) && cbParams.hasOwnProperty(arg.from_argument)) { | ||
return JsonSchemaValidator.isSchemaCompatible(param.schema, cbParams[arg.from_argument]); | ||
} | ||
else { | ||
throw new ProcessGraphError('CallbackArgumentInvalid', { | ||
argument: arg.from_argument, | ||
node_id: node.id, | ||
process_id: this.schema.id | ||
}); | ||
} | ||
// No need for further checks, callback argument is validated in processgraph.js: see parseCallbackArgument() | ||
return JsonSchemaValidator.isSchemaCompatible(param.schema, cbParams[arg.from_argument]); | ||
case 'variable': | ||
@@ -95,7 +86,8 @@ var variableSchema = { | ||
case 'object': | ||
for(var i in arg) { | ||
await this.validateArgument(arg[i], node, parameterName); | ||
} | ||
return true; // ToDo: Remove this and check how we can validate arrays and objects that have references to callback arguments, variables and node results in them... | ||
break; | ||
// ToDo: Check how we can validate arrays and objects that have references to callback arguments, variables and node results in them... | ||
// See issue https://github.com/Open-EO/openeo-js-commons/issues/5 | ||
// for(var i in arg) { | ||
// await this.validateArgument(arg[i], node, parameterName, param); | ||
// } | ||
return true; | ||
} | ||
@@ -106,6 +98,8 @@ | ||
async execute(node) { | ||
/* istanbul ignore next */ | ||
async execute(/*node*/) { | ||
throw "execute not implemented yet"; | ||
} | ||
/* istanbul ignore next */ | ||
test() { | ||
@@ -112,0 +106,0 @@ // Run the tests from the examples |
@@ -11,3 +11,3 @@ const ErrorList = require('../errorlist'); | ||
constructor(jsonProcessGraph, processRegistry) { | ||
this.json = Utils.mergeDeep({}, jsonProcessGraph); | ||
this.json = jsonProcessGraph; | ||
this.processRegistry = processRegistry; | ||
@@ -27,3 +27,2 @@ this.nodes = []; | ||
// Important: This avoids circular reference errors | ||
toJSON() { | ||
@@ -59,7 +58,7 @@ return this.json; | ||
for(var id in this.json) { | ||
for(let id in this.json) { | ||
this.nodes[id] = this.createNodeInstance(this.json[id], id, this); | ||
} | ||
for(var id in this.nodes) { | ||
for(let id in this.nodes) { | ||
var node = this.nodes[id]; | ||
@@ -209,3 +208,10 @@ | ||
parseCallbackArgument(node, name) { | ||
// ToDo: Parse callback argument | ||
var cbParams = this.getCallbackParameters(); | ||
if (!Utils.isObject(cbParams) || !cbParams.hasOwnProperty(name)) { | ||
throw new ProcessGraphError('CallbackArgumentInvalid', { | ||
argument: name, | ||
node_id: node.id, | ||
process_id: node.process_id | ||
}); | ||
} | ||
} | ||
@@ -330,6 +336,2 @@ | ||
getJson() { | ||
return this.json; | ||
} | ||
getErrors() { | ||
@@ -361,2 +363,3 @@ return this.errors; | ||
// but they used the wrong callback parameters. | ||
// See issue https://github.com/Open-EO/openeo-js-commons/issues/6 | ||
@@ -363,0 +366,0 @@ var cbParams = {}; |
@@ -13,7 +13,10 @@ const BaseProcess = require('./process'); | ||
for(var i in response.processes) { | ||
var p = response.processes[i]; | ||
this.processes[p.id] = new BaseProcess(p); | ||
this.add(response.processes[i]); | ||
} | ||
} | ||
add(process) { | ||
this.processes[process.id] = new BaseProcess(process); | ||
} | ||
count() { | ||
@@ -31,2 +34,7 @@ return Utils.size(this.processes); | ||
getSchema(id) { | ||
var p = this.get(id); | ||
return p !== null ? p.schema : null; | ||
} | ||
getProcessSchemas() { | ||
@@ -33,0 +41,0 @@ return Object.values(this.processes).map(impl => impl.schema); |
@@ -36,25 +36,2 @@ const compareVersions = require('compare-versions'); | ||
return message; | ||
}, | ||
mergeDeep(target, ...sources) { | ||
if (!sources.length) { | ||
return target; | ||
} | ||
const source = sources.shift(); | ||
if (this.isObject(target) && this.isObject(source)) { | ||
for (const key in source) { | ||
if (this.isObject(source[key])) { | ||
if (!target[key]) { | ||
target[key] = {}; | ||
} | ||
this.mergeDeep(target[key], source[key]); | ||
} | ||
else { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
return this.mergeDeep(target, ...sources); | ||
} | ||
@@ -61,0 +38,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
147830
18
3054
2
40
8
1