@lowdefy/operators 4.5.1 → 4.6.0

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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -12,11 +12,41 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ import { serializer, type } from '@lowdefy/helpers';
15
+ */ import { ConfigError, OperatorError } from '@lowdefy/errors';
16
+ import { serializer, type } from '@lowdefy/helpers';
16
17
  let BuildParser = class BuildParser {
17
- // TODO: Look at logging here
18
- // TODO: Remove console.error = () => {}; from tests
19
- parse({ args, input, location, operatorPrefix = '_' }) {
18
+ // Check if value or its immediate children have the dynamic marker
19
+ // Note: Only checks immediate children because bubble-up happens bottom-up in reviver
20
+ static hasDynamicMarker(value) {
21
+ if (type.isArray(value) && value['~dyn'] === true) return true;
22
+ if (type.isObject(value) && value['~dyn'] === true) return true;
23
+ if (type.isArray(value)) {
24
+ return value.some((item)=>{
25
+ if (type.isArray(item) && item['~dyn'] === true) return true;
26
+ if (type.isObject(item) && item['~dyn'] === true) return true;
27
+ return false;
28
+ });
29
+ }
30
+ if (type.isObject(value)) {
31
+ return Object.values(value).some((item)=>{
32
+ if (type.isArray(item) && item['~dyn'] === true) return true;
33
+ if (type.isObject(item) && item['~dyn'] === true) return true;
34
+ return false;
35
+ });
36
+ }
37
+ return false;
38
+ }
39
+ // Set dynamic marker as non-enumerable property
40
+ static setDynamicMarker(value) {
41
+ if (type.isObject(value) || type.isArray(value)) {
42
+ Object.defineProperty(value, '~dyn', {
43
+ value: true,
44
+ enumerable: false
45
+ });
46
+ }
47
+ return value;
48
+ }
49
+ parse({ args, input, operatorPrefix = '_' }) {
20
50
  if (type.isUndefined(input)) {
21
51
  return {
22
52
  output: input,
@@ -26,28 +56,76 @@ let BuildParser = class BuildParser {
26
56
  if (args && !type.isArray(args)) {
27
57
  throw new Error('Operator parser args must be an array.');
28
58
  }
29
- if (!type.isString(location)) {
30
- throw new Error('Operator parser location must be a string.');
31
- }
32
59
  const errors = [];
33
60
  const reviver = (_, value)=>{
61
+ // Handle arrays: bubble up dynamic marker if any element is dynamic
62
+ if (type.isArray(value)) {
63
+ if (BuildParser.hasDynamicMarker(value)) {
64
+ return BuildParser.setDynamicMarker(value);
65
+ }
66
+ return value;
67
+ }
34
68
  if (!type.isObject(value)) return value;
35
- // TODO: pass ~r in errors. Build does not have ~k.
36
- if (type.isString(value['~r'])) return value;
37
- if (Object.keys(value).length !== 1) return value;
38
- const key = Object.keys(value)[0];
39
- if (!key.startsWith(operatorPrefix)) return value;
69
+ // ~shallow placeholders are unresolved refs mark as dynamic so operators
70
+ // wrapping them are preserved for evaluation after resolution (JIT builds).
71
+ if (value['~shallow'] === true) {
72
+ return BuildParser.setDynamicMarker(value);
73
+ }
74
+ // Check if this is an operator object BEFORE checking ~r
75
+ // Operators in vars have ~r set by copyVarValue (as enumerable), but should still be evaluated
76
+ // Filter out ~ prefixed keys (like ~r, ~k, ~l) when determining if single-key operator
77
+ const keys = Object.keys(value);
78
+ const nonTildeKeys = keys.filter((k)=>!k.startsWith('~'));
79
+ const isSingleKeyObject = nonTildeKeys.length === 1;
80
+ const key = isSingleKeyObject ? nonTildeKeys[0] : null;
81
+ const isOperatorObject = key && key.startsWith(operatorPrefix);
82
+ // Type boundary reset: if object has a 'type' key matching a registered type,
83
+ // delete the ~dyn marker and skip bubble-up to prevent propagation past this boundary
84
+ const isTypeBoundary = type.isString(value.type) && this.typeNames.has(value.type);
85
+ if (isTypeBoundary) {
86
+ delete value['~dyn'];
87
+ }
88
+ // Check if params contain dynamic content (bubble up), but not at type boundaries
89
+ // This must happen BEFORE the ~r check to allow dynamic markers to propagate
90
+ if (!isTypeBoundary && BuildParser.hasDynamicMarker(value)) {
91
+ return BuildParser.setDynamicMarker(value);
92
+ }
93
+ // Skip non-operator objects that have already been processed (have ~r marker)
94
+ // But allow operator objects to be evaluated even if they have ~r
95
+ if (type.isString(value['~r']) && !isOperatorObject) return value;
96
+ if (!isSingleKeyObject) return value;
97
+ if (!isOperatorObject) return value;
40
98
  const [op, methodName] = `_${key.substring(operatorPrefix.length)}`.split('.');
41
- if (type.isUndefined(this.operators[op])) return value;
99
+ // Check if this operator/method is dynamic
100
+ // Skip this check for _build.* operators (operatorPrefix === '_build.') because
101
+ // build operators should ALWAYS be evaluated at build time
102
+ const fullIdentifier = methodName ? `${op}.${methodName}` : op;
103
+ if (operatorPrefix !== '_build.') {
104
+ if (this.dynamicIdentifiers.has(fullIdentifier) || this.dynamicIdentifiers.has(op)) {
105
+ return BuildParser.setDynamicMarker(value);
106
+ }
107
+ }
108
+ // If operator is not in our operators map, it's a runtime-only operator
109
+ // Mark it as dynamic to preserve it for runtime evaluation
110
+ if (type.isUndefined(this.operators[op])) {
111
+ return BuildParser.setDynamicMarker(value);
112
+ }
113
+ // Check if params contain dynamic content before evaluating
114
+ if (BuildParser.hasDynamicMarker(value[key])) {
115
+ return BuildParser.setDynamicMarker(value);
116
+ }
117
+ const configKey = value['~k'];
118
+ const lineNumber = value['~l'];
119
+ const refId = value['~r'];
120
+ const params = value[key];
42
121
  try {
43
122
  const res = this.operators[op]({
44
123
  args,
45
124
  arrayIndices: [],
46
125
  env: this.env,
47
- location,
48
126
  methodName,
49
127
  operators: this.operators,
50
- params: value[key],
128
+ params,
51
129
  operatorPrefix,
52
130
  parser: this,
53
131
  payload: this.payload,
@@ -57,10 +135,34 @@ let BuildParser = class BuildParser {
57
135
  });
58
136
  return res;
59
137
  } catch (e) {
60
- errors.push(e);
61
- if (this.verbose) {
62
- console.error(e);
138
+ if (e instanceof ConfigError) {
139
+ if (!e.configKey) {
140
+ e.configKey = configKey;
141
+ }
142
+ if (!e.lineNumber) {
143
+ e.lineNumber = lineNumber;
144
+ }
145
+ if (!e.refId) {
146
+ e.refId = refId;
147
+ }
148
+ errors.push(e);
149
+ return null;
63
150
  }
151
+ const operatorError = new OperatorError(e.message, {
152
+ cause: e,
153
+ typeName: op,
154
+ received: {
155
+ [key]: params
156
+ },
157
+ configKey: e.configKey ?? configKey
158
+ });
159
+ // lineNumber and refId needed by buildRefs consumers (evaluateBuildOperators,
160
+ // evaluateStaticOperators) which run before addKeys — no configKey
161
+ // exists yet, so they use filePath + lineNumber for resolution.
162
+ // refId (from ~r) identifies the source file in the refMap.
163
+ operatorError.lineNumber = lineNumber;
164
+ operatorError.refId = refId;
165
+ errors.push(operatorError);
64
166
  return null;
65
167
  }
66
168
  };
@@ -71,14 +173,15 @@ let BuildParser = class BuildParser {
71
173
  errors
72
174
  };
73
175
  }
74
- constructor({ env, payload, secrets, user, operators, verbose }){
176
+ constructor({ env, payload, secrets, user, operators, dynamicIdentifiers, typeNames }){
75
177
  this.env = env;
76
178
  this.operators = operators;
77
179
  this.parse = this.parse.bind(this);
78
180
  this.payload = payload;
79
181
  this.secrets = secrets;
80
182
  this.user = user;
81
- this.verbose = verbose;
183
+ this.dynamicIdentifiers = dynamicIdentifiers ?? new Set();
184
+ this.typeNames = typeNames ?? new Set();
82
185
  }
83
186
  };
84
187
  export default BuildParser;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -26,12 +26,12 @@ function getFromArray({ params, array, key, operator, location }) {
26
26
  if (type.isString(params.value)) return array.find((item)=>item[key] === params.value);
27
27
  if (type.isNumber(params.index)) return array[params.index];
28
28
  if (!type.isNone(params.value) && !type.isString(params.value)) {
29
- throw new Error(`Operator Error: ${operator}.value must be of type string. Received: ${JSON.stringify(params)} at ${location}.`);
29
+ throw new Error(`${operator}.value must be of type string.`);
30
30
  }
31
31
  if (!type.isNone(params.index) && !type.isNumber(params.index)) {
32
- throw new Error(`Operator Error: ${operator}.index must be of type number. Received: ${JSON.stringify(params)} at ${location}.`);
32
+ throw new Error(`${operator}.index must be of type number.`);
33
33
  }
34
34
  }
35
- throw new Error(`Operator Error: ${operator} must be of type string, number or object. Received: ${JSON.stringify(params)} at ${location}.`);
35
+ throw new Error(`${operator} must be of type string, number or object.`);
36
36
  }
37
37
  export default getFromArray;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@ function getFromObject({ params, object, arrayIndices, operator, location }) {
21
21
  key: params
22
22
  };
23
23
  if (!type.isObject(params)) {
24
- throw new Error(`Operator Error: ${operator} params must be of type string, integer, boolean or object. Received: ${JSON.stringify(params)} at ${location}.`);
24
+ throw new Error(`${operator} params must be of type string, integer, boolean or object.`);
25
25
  }
26
26
  if (params.key === null) return get(params, 'default', {
27
27
  default: null,
@@ -29,7 +29,7 @@ function getFromObject({ params, object, arrayIndices, operator, location }) {
29
29
  });
30
30
  if (params.all === true) return serializer.copy(object);
31
31
  if (!type.isString(params.key) && !type.isInt(params.key)) {
32
- throw new Error(`Operator Error: ${operator}.key must be of type string or integer. Received: ${JSON.stringify(params)} at ${location}.`);
32
+ throw new Error(`${operator}.key must be of type string or integer.`);
33
33
  }
34
34
  return get(object, applyArrayIndices(arrayIndices, params.key), {
35
35
  default: get(params, 'default', {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
package/dist/runClass.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -20,25 +20,18 @@ const runClass = ({ location, meta, methodName, operator, params, functions, def
20
20
  } else if (defaultFunction) {
21
21
  methodName = defaultFunction;
22
22
  } else {
23
- throw new Error(`Operator Error: ${operator} requires a valid method name, use one of the following: ${Object.keys(meta).join(', ')}.
24
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
23
+ throw new Error(`${operator} requires a valid method name, use one of the following: ${Object.keys(meta).join(', ')}.`);
25
24
  }
26
25
  }
27
26
  if (!meta[methodName] && !functions[methodName]) {
28
- throw new Error(`Operator Error: ${operator}.${methodName} is not supported, use one of the following: ${Object.keys(meta).join(', ')}.
29
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
27
+ throw new Error(`${operator}.${methodName} is not supported, use one of the following: ${Object.keys(meta).join(', ')}.`);
30
28
  }
31
29
  // validate params type
32
30
  if (meta[methodName].validTypes && !meta[methodName].validTypes.includes(type.typeOf(params))) {
33
- throw new Error(`Operator Error: ${operator}.${methodName} accepts one of the following types: ${meta[methodName].validTypes.join(', ')}.
34
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
31
+ throw new Error(`${operator}.${methodName} accepts one of the following types: ${meta[methodName].validTypes.join(', ')}.`);
35
32
  }
36
33
  if (meta[methodName].noArgs) {
37
- try {
38
- return functions[methodName]();
39
- } catch (e) {
40
- throw new Error(`Operator Error: ${operator}: - ${e.message} Received: {"${operator}":${JSON.stringify(params)}} at ${location}.`);
41
- }
34
+ return functions[methodName]();
42
35
  }
43
36
  let args = [];
44
37
  if (meta[methodName].singleArg || meta[methodName].property) {
@@ -52,8 +45,7 @@ const runClass = ({ location, meta, methodName, operator, params, functions, def
52
45
  if (type.isObject(params)) {
53
46
  args.push(...(meta[methodName].namedArgs || []).map((key)=>params[key]));
54
47
  if (!type.isNone(meta[methodName].spreadArgs) && !type.isArray(params[meta[methodName].spreadArgs])) {
55
- throw new Error(`Operator Error: ${operator}.${methodName} takes an array as input argument for ${meta[methodName].spreadArgs}.
56
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
48
+ throw new Error(`${operator}.${methodName} takes an array as input argument for ${meta[methodName].spreadArgs}.`);
57
49
  }
58
50
  args.push(...params[meta[methodName].spreadArgs] || []);
59
51
  }
@@ -67,10 +59,6 @@ const runClass = ({ location, meta, methodName, operator, params, functions, def
67
59
  if (meta[methodName].property) {
68
60
  return functions[methodName];
69
61
  }
70
- try {
71
- return functions[methodName](...args);
72
- } catch (e) {
73
- throw new Error(`Operator Error: ${operator}.${methodName} - ${e.message} Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
74
- }
62
+ return functions[methodName](...args);
75
63
  };
76
64
  export default runClass;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -14,14 +14,15 @@
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
16
  const runInstance = ({ location, meta, methodName, operator, params, instanceType })=>{
17
+ if (type.isUndefined(methodName)) {
18
+ throw new Error(`${operator} requires a method. Use one of the following: ${Object.keys(meta).join(', ')}.`);
19
+ }
17
20
  if (!meta[methodName]) {
18
- throw new Error(`Operator Error: ${operator}.${methodName} is not supported, use one of the following: ${Object.keys(meta).join(', ')}.
19
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
21
+ throw new Error(`${operator}.${methodName} is not supported, use one of the following: ${Object.keys(meta).join(', ')}.`);
20
22
  }
21
23
  // validate params type
22
24
  if (meta[methodName].validTypes && !meta[methodName].validTypes.includes(type.typeOf(params))) {
23
- throw new Error(`Operator Error: ${operator}.${methodName} accepts one of the following types: ${meta[methodName].validTypes.join(', ')}.
24
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
25
+ throw new Error(`${operator}.${methodName} accepts one of the following types: ${meta[methodName].validTypes.join(', ')}.`);
25
26
  }
26
27
  let instance;
27
28
  let args = [];
@@ -38,8 +39,7 @@ const runInstance = ({ location, meta, methodName, operator, params, instanceTyp
38
39
  instance = params[meta[methodName].namedArgs[0]];
39
40
  args.push(...meta[methodName].namedArgs.slice(1).map((key)=>params[key]));
40
41
  if (!type.isNone(meta[methodName].spreadArgs) && !type.isArray(params[meta[methodName].spreadArgs])) {
41
- throw new Error(`Operator Error: ${operator}.${methodName} takes an array as input argument for ${meta[methodName].spreadArgs}.
42
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
42
+ throw new Error(`${operator}.${methodName} takes an array as input argument for ${meta[methodName].spreadArgs}.`);
43
43
  }
44
44
  args.push(...params[meta[methodName].spreadArgs] || []);
45
45
  }
@@ -51,26 +51,20 @@ const runInstance = ({ location, meta, methodName, operator, params, instanceTyp
51
51
  ]);
52
52
  }
53
53
  if (type.typeOf(instance) !== instanceType) {
54
- throw new Error(`Operator Error: ${operator}.${methodName} must be evaluated on an ${instanceType} instance. For named args provide an ${instanceType} instance to the "on" property, for listed args provide and ${instanceType} instance as the first element in the operator argument array.
55
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
54
+ throw new Error(`${operator}.${methodName} must be evaluated on an ${instanceType} instance. For named args provide an ${instanceType} instance to the "on" property, for listed args provide an ${instanceType} instance as the first element in the operator argument array.`);
56
55
  }
57
56
  // Error for invalid method key.
58
57
  if (type.isNone(instance[methodName])) {
59
- throw new Error(`Operator Error: ${operator} must be evaluated using one of the following: ${Object.keys(meta).join(', ')}.
60
- Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
58
+ throw new Error(`${operator} must be evaluated using one of the following: ${Object.keys(meta).join(', ')}.`);
61
59
  }
62
60
  // for property
63
61
  if (meta[methodName].property) {
64
62
  return instance[methodName];
65
63
  }
66
- try {
67
- const result = instance[methodName](...args);
68
- if (meta[methodName].returnInstance) {
69
- return instance;
70
- }
71
- return result;
72
- } catch (e) {
73
- throw new Error(`Operator Error: ${operator}.${methodName} - ${e.message} Received: {"${operator}.${methodName}":${JSON.stringify(params)}} at ${location}.`);
64
+ const result = instance[methodName](...args);
65
+ if (meta[methodName].returnInstance) {
66
+ return instance;
74
67
  }
68
+ return result;
75
69
  };
76
70
  export default runInstance;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -12,10 +12,9 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ import { serializer, type } from '@lowdefy/helpers';
15
+ */ import { ConfigError, OperatorError } from '@lowdefy/errors';
16
+ import { serializer, type } from '@lowdefy/helpers';
16
17
  let ServerParser = class ServerParser {
17
- // TODO: Look at logging here
18
- // TODO: Remove console.error = () => {}; from tests
19
18
  parse({ args, input, items, location, operatorPrefix = '_' }) {
20
19
  if (type.isUndefined(input)) {
21
20
  return {
@@ -32,14 +31,13 @@ let ServerParser = class ServerParser {
32
31
  const errors = [];
33
32
  const reviver = (_, value)=>{
34
33
  if (!type.isObject(value)) return value;
35
- // TODO: pass ~k in errors.
36
- // const _k = value['~k'];
37
- delete value['~k'];
38
34
  if (Object.keys(value).length !== 1) return value;
39
35
  const key = Object.keys(value)[0];
40
36
  if (!key.startsWith(operatorPrefix)) return value;
41
37
  const [op, methodName] = `_${key.substring(operatorPrefix.length)}`.split('.');
42
38
  if (type.isUndefined(this.operators[op])) return value;
39
+ const configKey = value['~k'];
40
+ const params = value[key];
43
41
  try {
44
42
  const res = this.operators[op]({
45
43
  args,
@@ -51,7 +49,7 @@ let ServerParser = class ServerParser {
51
49
  methodName,
52
50
  operatorPrefix,
53
51
  operators: this.operators,
54
- params: value[key],
52
+ params,
55
53
  parser: this,
56
54
  payload: this.payload,
57
55
  runtime: 'node',
@@ -62,10 +60,24 @@ let ServerParser = class ServerParser {
62
60
  });
63
61
  return res;
64
62
  } catch (e) {
65
- errors.push(e);
66
- if (this.verbose) {
67
- console.error(e);
63
+ if (e instanceof ConfigError) {
64
+ if (!e.configKey) {
65
+ e.configKey = configKey;
66
+ }
67
+ errors.push(e);
68
+ return null;
68
69
  }
70
+ const operatorError = new OperatorError(e.message, {
71
+ cause: e,
72
+ typeName: op,
73
+ methodName,
74
+ received: {
75
+ [key]: params
76
+ },
77
+ location,
78
+ configKey: e.configKey ?? configKey
79
+ });
80
+ errors.push(operatorError);
69
81
  return null;
70
82
  }
71
83
  };
@@ -76,7 +88,7 @@ let ServerParser = class ServerParser {
76
88
  errors
77
89
  };
78
90
  }
79
- constructor({ env, jsMap, operators, payload, secrets, state, steps, user, verbose }){
91
+ constructor({ env, jsMap, operators, payload, secrets, state, steps, user }){
80
92
  this.env = env;
81
93
  this.jsMap = jsMap;
82
94
  this.operators = operators;
@@ -86,7 +98,6 @@ let ServerParser = class ServerParser {
86
98
  this.state = state;
87
99
  this.steps = steps;
88
100
  this.user = user;
89
- this.verbose = verbose;
90
101
  }
91
102
  };
92
103
  export default ServerParser;
package/dist/webParser.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
2
+ Copyright 2020-2026 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -12,7 +12,8 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ import { applyArrayIndices, serializer, type } from '@lowdefy/helpers';
15
+ */ import { ConfigError, OperatorError } from '@lowdefy/errors';
16
+ import { applyArrayIndices, serializer, type } from '@lowdefy/helpers';
16
17
  let WebParser = class WebParser {
17
18
  parse({ actions, args, arrayIndices, event, input, location, operatorPrefix = '_' }) {
18
19
  if (type.isUndefined(input)) {
@@ -34,14 +35,14 @@ let WebParser = class WebParser {
34
35
  const { apiResponses, basePath, home, inputs, lowdefyGlobal, menus, pageId, user, _internal } = this.context._internal.lowdefy;
35
36
  const reviver = (_, value)=>{
36
37
  if (!type.isObject(value)) return value;
37
- // TODO: pass ~k in errors.
38
- // const _k = value['~k'];
39
- delete value['~k'];
40
38
  if (Object.keys(value).length !== 1) return value;
41
39
  const key = Object.keys(value)[0];
42
40
  if (!key.startsWith(operatorPrefix)) return value;
43
41
  const [op, methodName] = `_${key.substring(operatorPrefix.length)}`.split('.');
44
42
  if (type.isUndefined(this.operators[op])) return value;
43
+ const configKey = value['~k'];
44
+ const params = value[key];
45
+ const operatorLocation = applyArrayIndices(arrayIndices, location);
45
46
  try {
46
47
  const res = this.operators[op]({
47
48
  actions,
@@ -55,14 +56,14 @@ let WebParser = class WebParser {
55
56
  home,
56
57
  input: inputs[this.context.id],
57
58
  jsMap: this.context.jsMap,
58
- location: applyArrayIndices(arrayIndices, location),
59
+ location: operatorLocation,
59
60
  lowdefyGlobal,
60
61
  menus,
61
62
  methodName,
62
63
  operatorPrefix,
63
64
  operators: this.operators,
64
65
  pageId,
65
- params: value[key],
66
+ params,
66
67
  parser: this,
67
68
  requests: this.context.requests,
68
69
  runtime: 'browser',
@@ -71,8 +72,25 @@ let WebParser = class WebParser {
71
72
  });
72
73
  return res;
73
74
  } catch (e) {
74
- errors.push(e);
75
- console.error(e);
75
+ // ConfigError from plugin - add configKey and re-throw structure
76
+ if (e instanceof ConfigError) {
77
+ if (!e.configKey) {
78
+ e.configKey = configKey;
79
+ }
80
+ errors.push(e);
81
+ return null;
82
+ }
83
+ // Plain error from plugin - wrap in OperatorError
84
+ errors.push(new OperatorError(e.message, {
85
+ cause: e,
86
+ typeName: op,
87
+ methodName,
88
+ received: {
89
+ [key]: params
90
+ },
91
+ location: operatorLocation,
92
+ configKey: e.configKey ?? configKey
93
+ }));
76
94
  return null;
77
95
  }
78
96
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/operators",
3
- "version": "4.5.1",
3
+ "version": "4.6.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -34,7 +34,8 @@
34
34
  "dist/*"
35
35
  ],
36
36
  "dependencies": {
37
- "@lowdefy/helpers": "4.5.1"
37
+ "@lowdefy/errors": "4.6.0",
38
+ "@lowdefy/helpers": "4.6.0"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@jest/globals": "28.1.3",