in libs/designer-ui/src/lib/workflow/languageservice/workflowlanguageservice.ts [372:438]
function parseExpression(value: string, position: Position, templateFunctions: Record<string, FunctionDefinition>): ExpressionInfo | null {
// parsing multi-line values
if (position.lineNumber > 1) {
// eslint-disable-next-line no-param-reassign
value = value.split('\n')[position.lineNumber - 1];
}
const caretPosition = position.column - 1;
const scanner = new ExpressionScanner(value, /*prefetch*/ false);
let previousToken: ExpressionToken | undefined;
let currentToken: ExpressionToken | undefined;
const identifiersInfo: IdentifierTokenInfo[] = [];
try {
previousToken = currentToken = scanner.getNextToken();
while (currentToken !== null && currentToken.type !== ExpressionTokenType.EndOfData) {
const { type, startPosition, endPosition } = currentToken;
if (caretPosition >= startPosition && caretPosition < endPosition) {
break;
}
if (type === ExpressionTokenType.LeftParenthesis) {
if (previousToken.type === ExpressionTokenType.Identifier) {
identifiersInfo.push({
name: previousToken.value,
argumentsCovered: 0,
});
}
} else if (type === ExpressionTokenType.Comma) {
identifiersInfo[identifiersInfo.length - 1].argumentsCovered += 1;
} else if (type === ExpressionTokenType.RightParenthesis) {
identifiersInfo.pop();
}
previousToken = currentToken;
currentToken = scanner.getNextToken();
}
} catch {
// Note: Exceptions thrown by the scanner and proceed with recognized tokens.
}
if (!identifiersInfo.length) {
return null;
}
const hasEmptyArgument =
currentToken?.type === ExpressionTokenType.RightParenthesis && previousToken?.type === ExpressionTokenType.LeftParenthesis;
const token = identifiersInfo.pop();
if (!token) {
return null;
}
const identifierName = token?.name;
const argumentsCovered = token?.argumentsCovered;
const templateFunction = getPropertyValue(templateFunctions, identifierName);
if (!templateFunction) {
return null;
}
return {
templateFunction,
argumentsCovered,
hasEmptyArgument,
};
}