function splitExpressionIntoSegments()

in src/documents/templates/getResourcesInfo.ts [452:513]


function splitExpressionIntoSegments(jsonString: string): string[] {
    assert(jsonString[0] === '[');

    // No sense taking time for parsing the expression if '/' is nowhere in the expression
    if (jsonString.includes('/')) {
        const quotedValue = `"${jsonString}"`;
        const parseResult = TLE.Parser.parse(quotedValue);
        const expression = parseResult.expression;
        if (parseResult.errors.length === 0 && expression) {
            // Handle this pattern:
            // "[concat(expression1, '/' , expression2)]" => [expression1, expression2]
            if (expression instanceof TLE.FunctionCallValue && expression.isCallToBuiltinWithName('concat')) {
                const argumentExpressions = expression.argumentExpressions;
                if (argumentExpressions.every(v => !!v)) {
                    // First, rewrite any string literals that contain a forward slash
                    // into separate string literals, e.g.
                    //   concat('a/', parameters('p1')) -> [ 'a', parameters('p1') ]
                    let rewrittenArgs: (TLE.Value | string)[] = []; // string instances are string literals
                    for (let arg of argumentExpressions) {
                        if (arg instanceof TLE.StringValue && arg.unquotedValue.includes('/')) {
                            const refactoredArg: string[] = splitStringAndKeepSeparators(arg.unquotedValue, '/')
                                .map(s => `'${s}'`);
                            rewrittenArgs.push(...refactoredArg);
                        } else {
                            // tslint:disable-next-line: no-non-null-assertion // checked with .every() above
                            rewrittenArgs.push(arg!);
                        }
                    }

                    // Separate it into groups of arguments that are separated by '/'
                    // string literals, e.g.
                    //   [a, '/', b, c, '/', d] -> [ [a], [b, c], [d]]
                    let segmentGroups: string[][] = [];
                    let newGroup: string[] = [];

                    let separatorFound = false;
                    for (let arg of rewrittenArgs) {
                        const argAsString = typeof arg === 'string' ? arg : arg.getSpan().getText(quotedValue);
                        if (arg === `'/'`) {
                            separatorFound = true;
                            segmentGroups.push(newGroup);
                            newGroup = [];
                        } else {
                            newGroup.push(argAsString);
                        }
                    }
                    segmentGroups.push(newGroup);

                    if (separatorFound && !segmentGroups.some(g => g.length === 0)) {
                        // Create segments out of the groups - groups with more than one element must be recombined
                        // using 'concat'
                        return segmentGroups.map(g => g.length > 1 ? `concat(${g.join(', ')})` : g[0]);
                    }
                }
            }
        }
    }

    // We don't know how to split this expression into segments in a generic
    // way, so just return the entire expression
    return [jsonStringToTleExpression(jsonString)];
}