async function expandStringHelper()

in src/expand.ts [123:237]


async function expandStringHelper(tmpl: string, opts: ExpansionOptions) {
    const envPreNormalize = opts.envOverride ? opts.envOverride : process.env;
    const env = EnvironmentUtils.create(envPreNormalize);
    const repls = opts.vars;

    // We accumulate a list of substitutions that we need to make, preventing
    // recursively expanding or looping forever on bad replacements
    const subs = new Map<string, string>();

    const var_re = /\$\{(\w+)\}/g;
    let mat: RegExpMatchArray | null = null;
    while ((mat = var_re.exec(tmpl))) {
        const full = mat[0];
        const key = mat[1];
        if (key !== 'dollar') {
            // Replace dollar sign at the very end of the expanding process
            const repl = repls[key];
            if (!repl) {
                log.warning(localize('invalid.variable.reference', 'Invalid variable reference {0} in string: {1}', full, tmpl));
            } else {
                subs.set(full, repl);
            }
        }
    }

    // Regular expression for variable value (between the variable suffix and the next ending curly bracket):
    // .+? matches any character (except line terminators) between one and unlimited times,
    // as few times as possible, expanding as needed (lazy)
    const varValueRegexp = ".+?";
    const env_re = RegExp(`\\$\\{env:(${varValueRegexp})\\}`, "g");
    while ((mat = env_re.exec(tmpl))) {
        const full = mat[0];
        const varname = mat[1];
        const repl = fixPaths(env[varname]) || '';
        subs.set(full, repl);
    }

    const env_re2 = RegExp(`\\$\\{env\\.(${varValueRegexp})\\}`, "g");
    while ((mat = env_re2.exec(tmpl))) {
        const full = mat[0];
        const varname = mat[1];
        const repl = fixPaths(env[varname]) || '';
        subs.set(full, repl);
    }

    const env_re3 = RegExp(`\\$env\\{(${varValueRegexp})\\}`, "g");
    while ((mat = env_re3.exec(tmpl))) {
        const full = mat[0];
        const varname = mat[1];
        const repl = fixPaths(env[varname]) || '';
        subs.set(full, repl);
    }

    const penv_re = RegExp(`\\$penv\\{(${varValueRegexp})\\}`, "g");
    while ((mat = penv_re.exec(tmpl))) {
        const full = mat[0];
        const varname = mat[1];
        const repl = fixPaths(process.env[varname]) || '';
        subs.set(full, repl);
    }

    if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
        const folder_re = RegExp(`\\$\\{workspaceFolder:(${varValueRegexp})\\}`, "g");
        mat = folder_re.exec(tmpl);
        while (mat) {
            const full = mat[0];
            const folderName = mat[1];
            const f = vscode.workspace.workspaceFolders.find(folder => folder.name.toLocaleLowerCase() === folderName.toLocaleLowerCase());
            if (f) {
                subs.set(full, f.uri.fsPath);
            }
            mat = folder_re.exec(tmpl);
        }
    }

    if (opts.variantVars) {
        const variants = opts.variantVars;
        const variant_regex = RegExp(`\\$\\{variant:(${varValueRegexp})\\}`, "g");
        while ((mat = variant_regex.exec(tmpl))) {
            const full = mat[0];
            const varname = mat[1];
            const repl = variants[varname] || '';
            subs.set(full, repl);
        }
    }

    const command_re = RegExp(`\\$\\{command:(${varValueRegexp})\\}`, "g");
    while ((mat = command_re.exec(tmpl))) {
        if (opts.doNotSupportCommands) {
            log.warning(localize('command.not.supported', 'Commands are not supported for string: {0}', tmpl));
            break;
        }
        const full = mat[0];
        const command = mat[1];
        if (subs.has(full)) {
            continue;  // Don't execute commands more than once per string
        }
        try {
            const command_ret = await vscode.commands.executeCommand(command, opts.vars.workspaceFolder);
            subs.set(full, `${command_ret}`);
        } catch (e) {
            log.warning(localize('exception.executing.command', 'Exception while executing command {0} for string: {1} {2}', command, tmpl, errorToString(e)));
        }
    }

    let final_str = tmpl;
    let didReplacement = false;
    subs.forEach((value, key) => {
        if (value !== key) {
            final_str = replaceAll(final_str, key, value);
            didReplacement = true;
        }
    });
    return { result: final_str, didReplacement };
}