Skip to content

Commit

Permalink
fix(Code Node): Fix $items in Code node when using task runner (#13368
Browse files Browse the repository at this point in the history
)
  • Loading branch information
tomi authored Feb 19, 2025
1 parent daa1fe9 commit 87b3c50
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ describe('JsTaskRunner', () => {
});
});

test.each([['items'], ['$input.all()'], ["$('Trigger').all()"]])(
test.each([['items'], ['$input.all()'], ["$('Trigger').all()"], ['$items()']])(
'should have all input items in the context as %s',
async (expression) => {
const outcome = await executeForAllItems({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,23 @@ describe('BuiltInsParser', () => {
);
});

describe('$items(...)', () => {
it('should mark input as needed when $items() is used without arguments', () => {
const state = parseAndExpectOk('$items()');
expect(state).toEqual(new BuiltInsParserState({ needs$input: true }));
});

it('should require the given node when $items() is used with a static value', () => {
const state = parseAndExpectOk('$items("nodeName")');
expect(state).toEqual(new BuiltInsParserState({ neededNodeNames: new Set(['nodeName']) }));
});

it('should require all nodes when $items() is used with a variable', () => {
const state = parseAndExpectOk('var n = "name"; $items(n)');
expect(state).toEqual(new BuiltInsParserState({ needsAllNodes: true, needs$input: true }));
});
});

describe('$node', () => {
it('should require all nodes when $node is used', () => {
const state = parseAndExpectOk('return $node["name"];');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,22 @@ export class BuiltInsParser {
) => {
// $(...)
const isDollar = node.callee.type === 'Identifier' && node.callee.name === '$';
if (!isDollar) return;
const isItems = node.callee.type === 'Identifier' && node.callee.name === '$items';
if (isDollar) {
this.visitDollarCallExpression(node, state, ancestors);
} else if (isItems) {
// $items(...) is a legacy syntax that is not documented but we still
// need to support it for backwards compatibility
this.visitDollarItemsCallExpression(node, state);
}
};

/** $(...) */
private visitDollarCallExpression(
node: CallExpression,
state: BuiltInsParserState,
ancestors: Node[],
) {
// $(): This is not valid, ignore
if (node.arguments.length === 0) {
return;
Expand All @@ -78,7 +92,31 @@ export class BuiltInsParser {

// Determine how $("node") is used
this.handlePrevNodeCall(node, state, ancestors);
};
}

/** $items(...) */
private visitDollarItemsCallExpression(node: CallExpression, state: BuiltInsParserState) {
// $items(): This gets items from the previous node
if (node.arguments.length === 0) {
state.markInputAsNeeded();
return;
}

const firstArg = node.arguments[0];
if (!isLiteral(firstArg)) {
// $items(variable): Can't easily determine statically, mark all nodes as needed
state.markNeedsAllNodes();
return;
}

if (typeof firstArg.value !== 'string') {
// $items(123): Static value, but not a string --> unsupported code --> ignore
return;
}

// $items(nodeName): Static value, mark 'nodeName' as needed
state.markNodeAsNeeded(firstArg.value);
}

private handlePrevNodeCall(_node: CallExpression, state: BuiltInsParserState, ancestors: Node[]) {
// $("node").item, .pairedItem or .itemMatching: In a case like this, the execution
Expand Down

0 comments on commit 87b3c50

Please sign in to comment.