|
|
@@ -116,12 +116,19 @@ async function execute(config, input, context) {
|
|
|
// 1. An already-evaluated array (from {{expression}} that was resolved by the engine)
|
|
|
// 2. A string path like "data.items" (raw path without expression syntax)
|
|
|
let items;
|
|
|
+ let pathResolutionFailed = false;
|
|
|
if (Array.isArray(inputField)) {
|
|
|
// Expression was already evaluated to an array by the engine
|
|
|
items = inputField;
|
|
|
} else if (typeof inputField === 'string') {
|
|
|
// Raw path - resolve it from the data
|
|
|
items = getFieldValue(data, inputField);
|
|
|
+ // A named path that resolves to nothing is a misconfiguration, not an
|
|
|
+ // empty list. Wrapping the whole payload as a single item here is what
|
|
|
+ // made a wrong path look like a working loop: the body ran exactly once,
|
|
|
+ // the item variable held the entire input instead of an element, and every
|
|
|
+ // field read off it came back undefined.
|
|
|
+ pathResolutionFailed = items === undefined;
|
|
|
} else {
|
|
|
// Unexpected type - try to use as-is
|
|
|
items = inputField;
|
|
|
@@ -133,6 +140,21 @@ async function execute(config, input, context) {
|
|
|
}
|
|
|
|
|
|
// Validate input
|
|
|
+ if (pathResolutionFailed) {
|
|
|
+ // Note that getFieldValue drops a leading "data." segment, so "data.x"
|
|
|
+ // and "x" mean the same thing and reaching a field genuinely called
|
|
|
+ // "data" needs it written twice.
|
|
|
+ const available = (data && typeof data === 'object' && !Array.isArray(data))
|
|
|
+ ? Object.keys(data).join(', ')
|
|
|
+ : typeof data;
|
|
|
+ throw new Error(
|
|
|
+ 'Loop node: nothing found at "' + inputField + '". The loop needs the path of ' +
|
|
|
+ 'an array to iterate. Available at the top level here: ' + available + '. ' +
|
|
|
+ 'Note a leading "data." is ignored, so a field actually named "data" has to be ' +
|
|
|
+ 'written as "data.data".'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
if (!Array.isArray(items)) {
|
|
|
const fieldDesc = typeof inputField === 'string' ? inputField : 'evaluated expression';
|
|
|
smartbotic.log.warn(`Loop node: Input at "${fieldDesc}" is not an array, converting to single-item array`);
|