Skip to content

Commit

Permalink
Fix: isTranslationFunctionCall doesn’t care about jr:itext Argume…
Browse files Browse the repository at this point in the history
…nt type
  • Loading branch information
eyelidlessness committed Jul 25, 2024
1 parent e7c7e80 commit e39b018
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
22 changes: 17 additions & 5 deletions packages/xforms-engine/src/parse/xpath/semantic-analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,14 @@ const isCallToLocalNamedFunction = <LocalName extends string>(
return localNameNode?.text === localName;
};

type ArgumentTypes = readonly [AnySyntaxType, ...AnySyntaxType[]];
const ANY_ARGUMENT_TYPE = Symbol('ANY_ARGUMENT_TYPE');
type AnyArgumentType = typeof ANY_ARGUMENT_TYPE;

type ArgumentFilter = AnyArgumentType | readonly [AnySyntaxType, ...AnySyntaxType[]];

const hasCallSignature = (
syntaxNode: FunctionCallNode,
expected: readonly ArgumentTypes[]
expected: readonly ArgumentFilter[]
): boolean => {
const [, ...argumentNodes] = syntaxNode.children;

Expand All @@ -64,14 +67,18 @@ const hasCallSignature = (
return false;
}

return expected.every((types, i) => {
return expected.every((filter, i) => {
const argumentNode = argumentNodes[i];

if (argumentNode == null) {
return false;
}

const [firstMatch] = collectTypedNodes(types, argumentNode);
if (filter === ANY_ARGUMENT_TYPE) {
return true;
}

const [firstMatch] = collectTypedNodes(filter, argumentNode);

return firstMatch != null && isCompleteSubExpression(argumentNode, firstMatch);
});
Expand All @@ -81,7 +88,12 @@ const isTranslationFunctionCall = (syntaxNode: FunctionCallNode): boolean => {
return (
isCallToLocalNamedFunction(syntaxNode, 'itext') &&
hasCallSignature(syntaxNode, [
['string_literal', 'absolute_location_path', 'relative_location_path'],
// We don't need to check the argument type here, just its presence. We'd
// originally checked for arguments we presume could produce a string.
// Giving it a little more thought, it was clear that applies to any
// conceivable argument, because anything can be cast to a string in XPath
// semantics.
ANY_ARGUMENT_TYPE,
])
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ describe('Semantic analysis', () => {
expected: true,
},
{
description: 'unexpected Number argument',
description: 'Number argument; this counts because it will be cast to string',
expression: 'jr:itext(1)',
expected: false,
expected: true,
},
{
description: 'FuntionName references another function',
Expand Down Expand Up @@ -63,6 +63,12 @@ describe('Semantic analysis', () => {
expression: '/foo[jr:itext("id") = 1]',
expected: false,
},

{
description: 'argument is a string',
expression: 'jr:itext(string(1))',
expected: true,
},
])(
'determines that an expression is a translation - $expression = $expected ($description)',
({ expression, expected }) => {
Expand Down

0 comments on commit e39b018

Please sign in to comment.