@openeo/js-client 2.0.1 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ const Parameter = require('./parameter');
3
3
  const axios = require('axios').default;
4
4
  const Utils = require('@openeo/js-commons/src/utils');
5
5
  const ProcessUtils = require("@openeo/js-commons/src/processUtils");
6
+ const ProcessRegistry = require('@openeo/js-commons/src/processRegistry');
6
7
 
7
8
  const PROCESS_META = [
8
9
  "id", "summary", "description", "categories", "parameters", "returns",
@@ -83,7 +84,7 @@ class Builder {
83
84
  *
84
85
  * @async
85
86
  * @static
86
- * @param {?string} version
87
+ * @param {?string} [version=null]
87
88
  * @returns {Promise<Builder>}
88
89
  * @throws {Error}
89
90
  */
@@ -103,7 +104,7 @@ class Builder {
103
104
  *
104
105
  * @async
105
106
  * @static
106
- * @param {?string} url
107
+ * @param {string | null} url
107
108
  * @returns {Promise<Builder>}
108
109
  * @throws {Error}
109
110
  */
@@ -117,16 +118,17 @@ class Builder {
117
118
  *
118
119
  * Each process passed to the constructor is made available as object method.
119
120
  *
120
- * @param {Array.<Process>|Processes} processes - Either an array containing processes or an object compatible with `GET /processes` of the API.
121
+ * @param {Array.<Process>|Processes|ProcessRegistry} processes - Either an array containing processes or an object compatible with `GET /processes` of the API.
121
122
  * @param {?Builder} parent - The parent builder, usually only used by the Builder itself.
122
123
  * @param {string} id - A unique identifier for the process.
123
124
  */
124
125
  constructor(processes, parent = null, id = undefined) {
125
126
  /**
126
- * List of all process specifications.
127
- * @type {Array.<Process>}
127
+ * A unique identifier for the process.
128
+ * @public
129
+ * @type {string}
128
130
  */
129
- this.processes = [];
131
+ this.id = id;
130
132
  /**
131
133
  * The parent builder.
132
134
  * @type {?Builder}
@@ -149,57 +151,75 @@ class Builder {
149
151
  this.parameters = undefined;
150
152
 
151
153
  /**
152
- * A unique identifier for the process.
153
- * @public
154
- * @type {string}
154
+ * List of all non-namespaced process specifications.
155
+ * @type {ProcessRegistry}
155
156
  */
156
- this.id = id;
157
+ this.processes = null;
157
158
 
158
- if (Utils.isObject(processes) && Array.isArray(processes.processes)) {
159
- processes = processes.processes;
159
+ // Create process registry if not available yet
160
+ if (processes instanceof ProcessRegistry) {
161
+ this.processes = processes;
160
162
  }
161
- if (Array.isArray(processes)) {
162
- for(let process of processes) {
163
- try {
164
- this.addProcessSpec(process);
165
- } catch (error) {
166
- console.warn(error);
167
- }
168
- }
163
+ else if (Utils.isObject(processes) && Array.isArray(processes.processes)) {
164
+ this.processes = new ProcessRegistry(processes.processes);
165
+ }
166
+ else if (Array.isArray(processes)) {
167
+ this.processes = new ProcessRegistry(processes);
169
168
  }
170
169
  else {
171
170
  throw new Error("Processes are invalid; must be array or object according to the API.");
172
171
  }
172
+
173
+ // Create processes
174
+ this.processes.all().forEach(process => this.createFunction(process));
175
+ }
176
+
177
+ /**
178
+ * Creates a callable function on the builder object for a process.
179
+ *
180
+ * @param {Process} process
181
+ * @throws {Error}
182
+ */
183
+ createFunction(process) {
184
+ if (typeof this[process.id] !== 'undefined') {
185
+ throw new Error("Can't create function for process '" + process.id + "'. Already exists in Builder class.");
186
+ }
187
+
188
+ /**
189
+ * Implicitly calls the process with the given name on the back-end by adding it to the process.
190
+ *
191
+ * This is a shortcut for {@link Builder#process}.
192
+ *
193
+ * @param {...*} args - The arguments for the process.
194
+ * @returns {BuilderNode}
195
+ * @see Builder#process
196
+ */
197
+ this[process.id] = function(...args) {
198
+ // Don't use arrow functions, they don't support the arguments keyword.
199
+ return this.process(process.id, args);
200
+ };
173
201
  }
174
202
 
175
203
  /**
176
204
  * Adds a process specification to the builder so that it can be used to create a process graph.
177
205
  *
178
206
  * @param {Process} process - Process specification compliant to openEO API
207
+ * @param {?string} [namespace=null] - Namespace of the process (default to `null`, i.e. pre-defined processes). EXPERIMENTAL!
179
208
  * @throws {Error}
180
209
  */
181
- addProcessSpec(process) {
210
+ addProcessSpec(process, namespace = null) {
182
211
  if (!Utils.isObject(process)) {
183
212
  throw new Error("Process '" + process.id + "' must be an object.");
184
213
  }
185
- if (typeof this[process.id] === 'undefined') {
186
- this.processes.push(process);
187
- /**
188
- * Implicitly calls the process with the given name on the back-end by adding it to the process.
189
- *
190
- * This is a shortcut for {@link Builder#process}.
191
- *
192
- * @param {...*} args - The arguments for the process.
193
- * @returns {BuilderNode}
194
- * @see Builder#process
195
- */
196
- this[process.id] = function(...args) {
197
- // Don't use arrow functions, they don't support the arguments keyword.
198
- return this.process(process.id, args);
199
- };
214
+
215
+ if (!namespace) {
216
+ namespace = 'backend';
200
217
  }
201
- else {
202
- throw new Error("Can't create function for process '" + process.id + "'. Already exists in Builder class.");
218
+ this.processes.add(process, namespace);
219
+
220
+ // Create callable function for pre-defined processes
221
+ if (namespace === 'backend') {
222
+ this.createFunction(process);
203
223
  }
204
224
  }
205
225
 
@@ -281,13 +301,14 @@ class Builder {
281
301
  }
282
302
 
283
303
  /**
284
- * Returns the process specification for the given process identifier.
304
+ * Returns the process specification for the given process identifier and namespace (or `null`).
285
305
  *
286
- * @param {string} id
287
- * @returns {Process}
306
+ * @param {string} id - Process identifier
307
+ * @param {?string} [namespace=null] - Namespace of the process (default to `null`, i.e. user or backend namespace). EXPERIMENTAL!
308
+ * @returns {Process | null}
288
309
  */
289
- spec(id) {
290
- return this.processes.find(process => process.id === id);
310
+ spec(id, namespace = null) {
311
+ return this.processes.get(id, namespace);
291
312
  }
292
313
 
293
314
  /**
@@ -308,25 +329,32 @@ class Builder {
308
329
  }
309
330
 
310
331
  /**
311
- * Checks whether a process with the given id is supported by the back-end.
332
+ * Checks whether a process with the given id and namespace is supported by the back-end.
312
333
  *
313
- * @param {string} processId - The id of the process to call.
334
+ * @param {string} processId - The id of the process.
335
+ * @param {?string} [namespace=null] - Namespace of the process (default to `null`, i.e. pre-defined processes). EXPERIMENTAL!
314
336
  * @returns {boolean}
315
337
  */
316
- supports(processId) {
317
- return Utils.isObject(this.spec(processId));
338
+ supports(processId, namespace = null) {
339
+ return Boolean(this.spec(processId, namespace));
318
340
  }
319
341
 
320
342
  /**
321
343
  * Adds another process call to the process chain.
322
344
  *
323
- * @param {string} processId - The id of the process to call.
324
- * @param {object.<string, *>|Array} args - The arguments as key-value pairs or as array. For objects, they keys must be the parameter names and the values must be the arguments. For arrays, arguments must be specified in the same order as in the corresponding process.
325
- * @param {?string} description - An optional description for the process call.
345
+ * @param {string} processId - The id of the process to call. To access a namespaced process, use the `process@namespace` notation.
346
+ * @param {object.<string, *>|Array} [args={}] - The arguments as key-value pairs or as array. For objects, they keys must be the parameter names and the values must be the arguments. For arrays, arguments must be specified in the same order as in the corresponding process.
347
+ * @param {?string} [description=null] - An optional description for the process call.
326
348
  * @returns {BuilderNode}
327
349
  */
328
350
  process(processId, args = {}, description = null) {
329
- let node = new BuilderNode(this, processId, args, description);
351
+ let namespace = null;
352
+ if (processId.includes('@')) {
353
+ let rest;
354
+ [processId, ...rest] = processId.split('@');
355
+ namespace = rest.join('@');
356
+ }
357
+ let node = new BuilderNode(this, processId, args, description, namespace);
330
358
  this.nodes[node.id] = node;
331
359
  return node;
332
360
  }
@@ -8,6 +8,7 @@ const BuilderNode = require('./node');
8
8
  * Operators: - (subtract), + (add), / (divide), * (multiply), ^ (power)
9
9
  *
10
10
  * It supports all mathematical functions (i.e. expects a number and returns a number) the back-end implements, e.g. `sqrt(x)`.
11
+ * For namespaced processes, use for example `process@namespace(x)` - EXPERIMENTAL!
11
12
  *
12
13
  * Only available if a builder is specified in the constructor:
13
14
  * You can refer to output from processes with a leading `#`, e.g. `#loadco1` if the node to refer to has the key `loadco1`.
@@ -13,8 +13,9 @@ class BuilderNode {
13
13
  * @param {string} processId
14
14
  * @param {object.<string, *>} [processArgs={}]
15
15
  * @param {?string} [processDescription=null]
16
+ * @param {?string} [processNamespace=null]
16
17
  */
17
- constructor(parent, processId, processArgs = {}, processDescription = null) {
18
+ constructor(parent, processId, processArgs = {}, processDescription = null, processNamespace = null) {
18
19
  /**
19
20
  * The parent builder.
20
21
  * @type {Builder}
@@ -26,8 +27,8 @@ class BuilderNode {
26
27
  * @type {Process}
27
28
  * @readonly
28
29
  */
29
- this.spec = this.parent.spec(processId);
30
- if (!Utils.isObject(this.spec)) {
30
+ this.spec = this.parent.spec(processId, processNamespace);
31
+ if (!this.spec) {
31
32
  throw new Error("Process doesn't exist: " + processId);
32
33
  }
33
34
 
@@ -36,6 +37,11 @@ class BuilderNode {
36
37
  * @type {string}
37
38
  */
38
39
  this.id = parent.generateId(processId);
40
+ /**
41
+ * The namespace of the process - EXPERIMENTAL!
42
+ * @type {string}
43
+ */
44
+ this.namespace = processNamespace;
39
45
  /**
40
46
  * The arguments for the process.
41
47
  * @type {object.<string, *>}
@@ -176,7 +182,7 @@ class BuilderNode {
176
182
  *
177
183
  * @protected
178
184
  * @param {?BuilderNode} [parentNode=null]
179
- * @param {?string} parentParameter
185
+ * @param {?string} [parentParameter=null]
180
186
  * @returns {BuilderNode}
181
187
  */
182
188
  createBuilder(parentNode = null, parentParameter = null) {
@@ -228,6 +234,9 @@ class BuilderNode {
228
234
  process_id: this.spec.id,
229
235
  arguments: {}
230
236
  };
237
+ if (this.namespace) {
238
+ obj.namespace = this.namespace;
239
+ }
231
240
  for(let name in this.arguments) {
232
241
  if (typeof this.arguments[name] !== 'undefined') {
233
242
  obj.arguments[name] = this.exportArgument(this.arguments[name], name);
@@ -88,15 +88,14 @@ class Parameter {
88
88
  */
89
89
  set(target, name, value, receiver) {
90
90
  if (!Reflect.has(target, name)) {
91
- console.warn('Simplified array access is read-only');
91
+ throw new Error('Simplified array access is read-only');
92
92
  }
93
93
  return Reflect.set(target, name, value, receiver);
94
94
  }
95
95
  });
96
96
  }
97
97
  else {
98
- console.warn('Simplified array access not supported, use array_element directly');
99
- return parameter;
98
+ throw new Error('Simplified array access not supported, use array_element directly');
100
99
  }
101
100
  }
102
101
 
@@ -119,8 +119,12 @@ TapDigit.Lexer = function () {
119
119
  return (ch === '_') || (ch === '#') || (ch === '$') || isLetter(ch);
120
120
  }
121
121
 
122
- function isIdentifierPart(ch) {
123
- return (ch === '_') || isLetter(ch) || isDecimalDigit(ch);
122
+ function isAdditionalNamespaceChar(ch) {
123
+ return (ch === '-') || (ch === '.') || (ch === '~') || (ch === '@');
124
+ }
125
+
126
+ function isIdentifierPart(ch, ns = false) {
127
+ return (ch === '_') || isLetter(ch) || isDecimalDigit(ch) || (ns && isAdditionalNamespaceChar(ch));
124
128
  }
125
129
 
126
130
  function scanIdentifier() {
@@ -130,6 +134,7 @@ TapDigit.Lexer = function () {
130
134
  }
131
135
 
132
136
  let id = getNextChar();
137
+ let ns = false;
133
138
  while (true) {
134
139
  let ch = peekNextChar();
135
140
  // If the first character is a $, it is allowed that more $ follow directly after
@@ -138,7 +143,10 @@ TapDigit.Lexer = function () {
138
143
  startCh = ''; // Stop allowing $ once the first non-$ has been found
139
144
  } // else: allowed
140
145
  }
141
- else if (!isIdentifierPart(ch)) {
146
+ else if (ch === '@') {
147
+ ns = true;
148
+ }
149
+ else if (!isIdentifierPart(ch, ns)) {
142
150
  break;
143
151
  }
144
152
  id += getNextChar();
@@ -190,7 +190,7 @@ class Capabilities {
190
190
  /**
191
191
  * Get the billing currency.
192
192
  *
193
- * @returns {?string} The billing currency or `null` if not available.
193
+ * @returns {string | null} The billing currency or `null` if not available.
194
194
  */
195
195
  currency() {
196
196
  return (Utils.isObject(this.data.billing) && typeof this.data.billing.currency === 'string' ? this.data.billing.currency : null);