fix(Code Node): Fix $items in Code node when using task runner (#13368)

This commit is contained in:
Tomi Turtiainen 2025-02-19 17:33:26 +02:00 committed by GitHub
parent daa1fe9386
commit 87b3c508b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 58 additions and 3 deletions

View file

@ -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({

View file

@ -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"];');

View file

@ -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;
@ -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