src/vs/workbench/services/configurationResolver/common/variableResolver.ts/AbstractVariableResolverService/recursiveResolve
class AbstractVariableResolverService:	private async recursiveResolve(environment: Environment, folderUri: uri | undefined, value: any, commandValueMapping?: IStringDictionary<string>, resolvedVariables?: Map<string, string>): Promise<any> {
		if (types.isString(value)) {
			return this.resolveString(environment, folderUri, value, commandValueMapping, resolvedVariables);
		} else if (types.isArray(value)) {
			return Promise.all(value.map(s => this.recursiveResolve(environment, folderUri, s, commandValueMapping, resolvedVariables)));
		} else if (types.isObject(value)) {
			const result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
			const replaced = await Promise.all(Object.keys(value).map(async key => {
				const replaced = await this.resolveString(environment, folderUri, key, commandValueMapping, resolvedVariables);
				return [replaced, await this.recursiveResolve(environment, folderUri, value[key], commandValueMapping, resolvedVariables)] as const;
			}));
			// two step process to preserve object key order
			for (const [key, value] of replaced) {
				result[key] = value;
			}
			return result;
		}
		return value;
	}