mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 09:35:41 -05:00
SQL Operations Studio Public Preview 1 (0.23) release source code
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const IConfigurationResolverService = createDecorator<IConfigurationResolverService>('configurationResolverService');
|
||||
|
||||
export interface IConfigurationResolverService {
|
||||
_serviceBrand: any;
|
||||
|
||||
// TODO@Isidor improve this API
|
||||
resolve(root: uri, value: string): string;
|
||||
resolve(root: uri, value: string[]): string[];
|
||||
resolve(root: uri, value: IStringDictionary<string>): IStringDictionary<string>;
|
||||
resolveAny<T>(root: uri, value: T): T;
|
||||
resolveInteractiveVariables(configuration: any, interactiveVariablesMap: { [key: string]: string }): TPromise<any>;
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import uri from 'vs/base/common/uri';
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
|
||||
export class ConfigurationResolverService implements IConfigurationResolverService {
|
||||
_serviceBrand: any;
|
||||
private _execPath: string;
|
||||
private _workspaceRoot: string;
|
||||
|
||||
constructor(
|
||||
envVariables: { [key: string]: string },
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
) {
|
||||
this._execPath = environmentService.execPath;
|
||||
Object.keys(envVariables).forEach(key => {
|
||||
this[`env:${key}`] = envVariables[key];
|
||||
});
|
||||
}
|
||||
|
||||
private get execPath(): string {
|
||||
return this._execPath;
|
||||
}
|
||||
|
||||
private get cwd(): string {
|
||||
return this.workspaceRoot;
|
||||
}
|
||||
|
||||
private get workspaceRoot(): string {
|
||||
return this._workspaceRoot;
|
||||
}
|
||||
|
||||
private get workspaceRootFolderName(): string {
|
||||
return this.workspaceRoot ? paths.basename(this.workspaceRoot) : '';
|
||||
}
|
||||
|
||||
private get file(): string {
|
||||
return this.getFilePath();
|
||||
}
|
||||
|
||||
private get relativeFile(): string {
|
||||
return (this.workspaceRoot) ? paths.relative(this.workspaceRoot, this.file) : this.file;
|
||||
}
|
||||
|
||||
private get fileBasename(): string {
|
||||
return paths.basename(this.getFilePath());
|
||||
}
|
||||
|
||||
private get fileBasenameNoExtension(): string {
|
||||
const basename = this.fileBasename;
|
||||
return basename.slice(0, basename.length - paths.extname(basename).length);
|
||||
}
|
||||
|
||||
private get fileDirname(): string {
|
||||
return paths.dirname(this.getFilePath());
|
||||
}
|
||||
|
||||
private get fileExtname(): string {
|
||||
return paths.extname(this.getFilePath());
|
||||
}
|
||||
|
||||
private get lineNumber(): string {
|
||||
const activeEditor = this.editorService.getActiveEditor();
|
||||
if (activeEditor) {
|
||||
const editorControl = (<ICommonCodeEditor>activeEditor.getControl());
|
||||
if (editorControl) {
|
||||
const lineNumber = editorControl.getSelection().positionLineNumber;
|
||||
return String(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private getFilePath(): string {
|
||||
let input = this.editorService.getActiveEditorInput();
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
let fileResource = toResource(input, { filter: 'file' });
|
||||
if (!fileResource) {
|
||||
return '';
|
||||
}
|
||||
return paths.normalize(fileResource.fsPath, true);
|
||||
}
|
||||
|
||||
public resolve(root: uri, value: string): string;
|
||||
public resolve(root: uri, value: string[]): string[];
|
||||
public resolve(root: uri, value: IStringDictionary<string>): IStringDictionary<string>;
|
||||
public resolve(root: uri, value: any): any {
|
||||
this._workspaceRoot = root.fsPath.toString();
|
||||
if (types.isString(value)) {
|
||||
return this.resolveString(root, value);
|
||||
} else if (types.isArray(value)) {
|
||||
return this.resolveArray(root, value);
|
||||
} else if (types.isObject(value)) {
|
||||
return this.resolveLiteral(root, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public resolveAny<T>(root: uri, value: T): T;
|
||||
public resolveAny<T>(root: uri, value: any): any {
|
||||
this._workspaceRoot = root.fsPath.toString();
|
||||
if (types.isString(value)) {
|
||||
return this.resolveString(root, value);
|
||||
} else if (types.isArray(value)) {
|
||||
return this.resolveAnyArray(root, value);
|
||||
} else if (types.isObject(value)) {
|
||||
return this.resolveAnyLiteral(root, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private resolveString(root: uri, value: string): string {
|
||||
let regexp = /\$\{(.*?)\}/g;
|
||||
const originalValue = value;
|
||||
const resolvedString = value.replace(regexp, (match: string, name: string) => {
|
||||
let newValue = (<any>this)[name];
|
||||
if (types.isString(newValue)) {
|
||||
return newValue;
|
||||
} else {
|
||||
return match && match.indexOf('env:') > 0 ? '' : match;
|
||||
}
|
||||
});
|
||||
|
||||
return this.resolveConfigVariable(root, resolvedString, originalValue);
|
||||
}
|
||||
|
||||
private resolveConfigVariable(root: uri, value: string, originalValue: string): string {
|
||||
const replacer = (match: string, name: string) => {
|
||||
let config = this.configurationService.getConfiguration<any>();
|
||||
let newValue: any;
|
||||
try {
|
||||
const keys: string[] = name.split('.');
|
||||
if (!keys || keys.length <= 0) {
|
||||
return '';
|
||||
}
|
||||
while (keys.length > 1) {
|
||||
const key = keys.shift();
|
||||
if (!config || !config.hasOwnProperty(key)) {
|
||||
return '';
|
||||
}
|
||||
config = config[key];
|
||||
}
|
||||
newValue = config && config.hasOwnProperty(keys[0]) ? config[keys[0]] : '';
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
if (types.isString(newValue)) {
|
||||
// Prevent infinite recursion and also support nested references (or tokens)
|
||||
return newValue === originalValue ? '' : this.resolveString(root, newValue);
|
||||
} else {
|
||||
return this.resolve(root, newValue) + '';
|
||||
}
|
||||
};
|
||||
|
||||
return value.replace(/\$\{config:(.+?)\}/g, replacer);
|
||||
}
|
||||
|
||||
private resolveLiteral(root: uri, values: IStringDictionary<string | IStringDictionary<string> | string[]>): IStringDictionary<string | IStringDictionary<string> | string[]> {
|
||||
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
|
||||
Object.keys(values).forEach(key => {
|
||||
let value = values[key];
|
||||
result[key] = <any>this.resolve(root, <any>value);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private resolveAnyLiteral<T>(root: uri, values: T): T;
|
||||
private resolveAnyLiteral<T>(root: uri, values: any): any {
|
||||
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
|
||||
Object.keys(values).forEach(key => {
|
||||
let value = values[key];
|
||||
result[key] = <any>this.resolveAny(root, <any>value);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private resolveArray(root: uri, value: string[]): string[] {
|
||||
return value.map(s => this.resolveString(root, s));
|
||||
}
|
||||
|
||||
private resolveAnyArray<T>(root: uri, value: T[]): T[];
|
||||
private resolveAnyArray(root: uri, value: any[]): any[] {
|
||||
return value.map(s => this.resolveAny(root, s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve all interactive variables in configuration #6569
|
||||
*/
|
||||
public resolveInteractiveVariables(configuration: any, interactiveVariablesMap: { [key: string]: string }): TPromise<any> {
|
||||
if (!configuration) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
// We need a map from interactive variables to keys because we only want to trigger an command once per key -
|
||||
// even though it might occur multiple times in configuration #7026.
|
||||
const interactiveVariablesToSubstitutes: { [interactiveVariable: string]: { object: any, key: string }[] } = {};
|
||||
const findInteractiveVariables = (object: any) => {
|
||||
Object.keys(object).forEach(key => {
|
||||
if (object[key] && typeof object[key] === 'object') {
|
||||
findInteractiveVariables(object[key]);
|
||||
} else if (typeof object[key] === 'string') {
|
||||
const matches = /\${command:(.+)}/.exec(object[key]);
|
||||
if (matches && matches.length === 2) {
|
||||
const interactiveVariable = matches[1];
|
||||
if (!interactiveVariablesToSubstitutes[interactiveVariable]) {
|
||||
interactiveVariablesToSubstitutes[interactiveVariable] = [];
|
||||
}
|
||||
interactiveVariablesToSubstitutes[interactiveVariable].push({ object, key });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
findInteractiveVariables(configuration);
|
||||
let substitionCanceled = false;
|
||||
|
||||
const factory: { (): TPromise<any> }[] = Object.keys(interactiveVariablesToSubstitutes).map(interactiveVariable => {
|
||||
return () => {
|
||||
let commandId: string = null;
|
||||
commandId = interactiveVariablesMap ? interactiveVariablesMap[interactiveVariable] : null;
|
||||
if (!commandId) {
|
||||
// Just launch any command if the interactive variable is not contributed by the adapter #12735
|
||||
commandId = interactiveVariable;
|
||||
}
|
||||
|
||||
return this.commandService.executeCommand<string>(commandId, configuration).then(result => {
|
||||
if (result) {
|
||||
interactiveVariablesToSubstitutes[interactiveVariable].forEach(substitute => {
|
||||
if (substitute.object[substitute.key].indexOf(`\${command:${interactiveVariable}}`) >= 0) {
|
||||
substitute.object[substitute.key] = substitute.object[substitute.key].replace(`\${command:${interactiveVariable}}`, result);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
substitionCanceled = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return sequence(factory).then(() => substitionCanceled ? null : configuration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import assert = require('assert');
|
||||
import uri from 'vs/base/common/uri';
|
||||
import platform = require('vs/base/common/platform');
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IConfigurationService, getConfigurationValue, IConfigurationOverrides, IConfigurationValue } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/node/configurationResolverService';
|
||||
import { TestEnvironmentService, TestEditorService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
|
||||
suite('Configuration Resolver Service', () => {
|
||||
let configurationResolverService: IConfigurationResolverService;
|
||||
let envVariables: { [key: string]: string } = { key1: 'Value for Key1', key2: 'Value for Key2' };
|
||||
let mockCommandService: MockCommandService;
|
||||
let editorService: TestEditorService;
|
||||
let workspaceUri: uri;
|
||||
|
||||
|
||||
setup(() => {
|
||||
mockCommandService = new MockCommandService();
|
||||
editorService = new TestEditorService();
|
||||
workspaceUri = uri.parse('file:///VSCode/workspaceLocation');
|
||||
configurationResolverService = new ConfigurationResolverService(envVariables, editorService, TestEnvironmentService, new TestConfigurationService(), mockCommandService);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
configurationResolverService = null;
|
||||
});
|
||||
|
||||
|
||||
test('substitute one', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} xyz'), 'abc \\VSCode\\workspaceLocation xyz');
|
||||
} else {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} xyz'), 'abc /VSCode/workspaceLocation xyz');
|
||||
}
|
||||
});
|
||||
|
||||
test('workspace root folder name', () => {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz');
|
||||
});
|
||||
|
||||
test('current selected line number', () => {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`);
|
||||
});
|
||||
|
||||
test('substitute many', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation');
|
||||
} else {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation');
|
||||
}
|
||||
});
|
||||
|
||||
test('substitute one env variable', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} ${env:key1} xyz'), 'abc \\VSCode\\workspaceLocation Value for Key1 xyz');
|
||||
} else {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} ${env:key1} xyz'), 'abc /VSCode/workspaceLocation Value for Key1 xyz');
|
||||
}
|
||||
});
|
||||
|
||||
test('substitute many env variable', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for Key1 - Value for Key2');
|
||||
} else {
|
||||
assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation Value for Key1 - Value for Key2');
|
||||
}
|
||||
});
|
||||
|
||||
test('substitute one configuration variable', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo'
|
||||
},
|
||||
terminal: {
|
||||
integrated: {
|
||||
fontFamily: 'bar'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz');
|
||||
});
|
||||
|
||||
test('substitute many configuration variables', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo'
|
||||
},
|
||||
terminal: {
|
||||
integrated: {
|
||||
fontFamily: 'bar'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo bar xyz');
|
||||
});
|
||||
|
||||
test('substitute nested configuration variables', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo ${workspaceRoot} ${config:terminal.integrated.fontFamily}'
|
||||
},
|
||||
terminal: {
|
||||
integrated: {
|
||||
fontFamily: 'bar'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz');
|
||||
} else {
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz');
|
||||
}
|
||||
});
|
||||
|
||||
test('substitute accidental self referenced configuration variables', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo ${workspaceRoot} ${config:terminal.integrated.fontFamily} ${config:editor.fontFamily}'
|
||||
},
|
||||
terminal: {
|
||||
integrated: {
|
||||
fontFamily: 'bar'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz');
|
||||
} else {
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz');
|
||||
}
|
||||
});
|
||||
|
||||
test('substitute one env variable and a configuration variable', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo'
|
||||
},
|
||||
terminal: {
|
||||
integrated: {
|
||||
fontFamily: 'bar'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${workspaceRoot} ${env:key1} xyz'), 'abc foo \\VSCode\\workspaceLocation Value for Key1 xyz');
|
||||
} else {
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${workspaceRoot} ${env:key1} xyz'), 'abc foo /VSCode/workspaceLocation Value for Key1 xyz');
|
||||
}
|
||||
});
|
||||
|
||||
test('substitute many env variable and a configuration variable', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo'
|
||||
},
|
||||
terminal: {
|
||||
integrated: {
|
||||
fontFamily: 'bar'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
if (platform.isWindows) {
|
||||
assert.strictEqual(service.resolve(workspaceUri, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), 'foo bar \\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for Key1 - Value for Key2');
|
||||
} else {
|
||||
assert.strictEqual(service.resolve(workspaceUri, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), 'foo bar /VSCode/workspaceLocation - /VSCode/workspaceLocation Value for Key1 - Value for Key2');
|
||||
}
|
||||
});
|
||||
|
||||
test('mixed types of configuration variables', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo',
|
||||
lineNumbers: 123,
|
||||
insertSpaces: false
|
||||
},
|
||||
terminal: {
|
||||
integrated: {
|
||||
fontFamily: 'bar'
|
||||
}
|
||||
},
|
||||
json: {
|
||||
schemas: [
|
||||
{
|
||||
fileMatch: [
|
||||
'/myfile',
|
||||
'/myOtherfile'
|
||||
],
|
||||
url: 'schemaURL'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz');
|
||||
});
|
||||
|
||||
test('configuration should not evaluate Javascript', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
abc: 'foo'
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor[\'abc\'.substr(0)]} xyz'), 'abc xyz');
|
||||
});
|
||||
|
||||
test('uses empty string as fallback', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.abc} xyz'), 'abc xyz');
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.abc.def} xyz'), 'abc xyz');
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:panel} xyz'), 'abc xyz');
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:panel.abc} xyz'), 'abc xyz');
|
||||
});
|
||||
|
||||
test('is restricted to own properties', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.__proto__} xyz'), 'abc xyz');
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.toString} xyz'), 'abc xyz');
|
||||
});
|
||||
|
||||
test('configuration variables with invalid accessor', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
fontFamily: 'foo'
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService);
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:} xyz'), 'abc ${config:} xyz');
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor..fontFamily} xyz'), 'abc xyz');
|
||||
assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.none.none2} xyz'), 'abc xyz');
|
||||
});
|
||||
|
||||
test('interactive variable simple', () => {
|
||||
const configuration = {
|
||||
'name': 'Attach to Process',
|
||||
'type': 'node',
|
||||
'request': 'attach',
|
||||
'processId': '${command:interactiveVariable1}',
|
||||
'port': 5858,
|
||||
'sourceMaps': false,
|
||||
'outDir': null
|
||||
};
|
||||
const interactiveVariables = Object.create(null);
|
||||
interactiveVariables['interactiveVariable1'] = 'command1';
|
||||
interactiveVariables['interactiveVariable2'] = 'command2';
|
||||
|
||||
configurationResolverService.resolveInteractiveVariables(configuration, interactiveVariables).then(resolved => {
|
||||
assert.deepEqual(resolved, {
|
||||
'name': 'Attach to Process',
|
||||
'type': 'node',
|
||||
'request': 'attach',
|
||||
'processId': 'command1',
|
||||
'port': 5858,
|
||||
'sourceMaps': false,
|
||||
'outDir': null
|
||||
});
|
||||
|
||||
assert.equal(1, mockCommandService.callCount);
|
||||
});
|
||||
});
|
||||
|
||||
test('interactive variable complex', () => {
|
||||
const configuration = {
|
||||
'name': 'Attach to Process',
|
||||
'type': 'node',
|
||||
'request': 'attach',
|
||||
'processId': '${command:interactiveVariable1}',
|
||||
'port': '${command:interactiveVariable2}',
|
||||
'sourceMaps': false,
|
||||
'outDir': 'src/${command:interactiveVariable2}',
|
||||
'env': {
|
||||
'processId': '__${command:interactiveVariable2}__',
|
||||
}
|
||||
};
|
||||
const interactiveVariables = Object.create(null);
|
||||
interactiveVariables['interactiveVariable1'] = 'command1';
|
||||
interactiveVariables['interactiveVariable2'] = 'command2';
|
||||
|
||||
configurationResolverService.resolveInteractiveVariables(configuration, interactiveVariables).then(resolved => {
|
||||
assert.deepEqual(resolved, {
|
||||
'name': 'Attach to Process',
|
||||
'type': 'node',
|
||||
'request': 'attach',
|
||||
'processId': 'command1',
|
||||
'port': 'command2',
|
||||
'sourceMaps': false,
|
||||
'outDir': 'src/command2',
|
||||
'env': {
|
||||
'processId': '__command2__',
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(2, mockCommandService.callCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
class MockConfigurationService implements IConfigurationService {
|
||||
public _serviceBrand: any;
|
||||
public serviceId = IConfigurationService;
|
||||
public constructor(private configuration: any = {}) { }
|
||||
public reloadConfiguration<T>(section?: string): TPromise<T> { return TPromise.as(this.getConfiguration()); }
|
||||
public lookup<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<T> { return { value: getConfigurationValue<T>(this.getConfiguration(), key), default: getConfigurationValue<T>(this.getConfiguration(), key), user: getConfigurationValue<T>(this.getConfiguration(), key), workspace: void 0, folder: void 0 }; }
|
||||
public keys() { return { default: [], user: [], workspace: [], folder: [] }; }
|
||||
public values() { return {}; }
|
||||
public getConfiguration(): any { return this.configuration; }
|
||||
public getConfigurationData(): any { return null; }
|
||||
public onDidUpdateConfiguration() { return { dispose() { } }; }
|
||||
}
|
||||
|
||||
class MockCommandService implements ICommandService {
|
||||
|
||||
public _serviceBrand: any;
|
||||
public callCount = 0;
|
||||
|
||||
onWillExecuteCommand = () => ({ dispose: () => { } });
|
||||
|
||||
public executeCommand<T>(commandId: string, ...args: any[]): TPromise<any> {
|
||||
this.callCount++;
|
||||
return TPromise.as(commandId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user