Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
This commit is contained in:
Karl Burtram
2018-01-28 23:37:17 -08:00
committed by GitHub
parent 9a1ac20710
commit 251ae01c3e
8009 changed files with 93378 additions and 35634 deletions

View File

@@ -11,7 +11,7 @@ import Event from 'vs/base/common/event';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
import { StrictResourceMap } from 'vs/base/common/map';
export const IConfigurationService = createDecorator<IConfigurationService>('configurationService');
@@ -57,12 +57,18 @@ export interface IConfigurationService {
getConfigurationData(): IConfigurationData;
getConfiguration<T>(): T;
getConfiguration<T>(section: string): T;
getConfiguration<T>(overrides: IConfigurationOverrides): T;
getConfiguration<T>(section: string, overrides: IConfigurationOverrides): T;
getValue<T>(key: string, overrides?: IConfigurationOverrides): T;
/**
* Fetches the value of the section for the given overrides.
* Value can be of native type or an object keyed off the section name.
*
* @param section - Section of the configuraion. Can be `null` or `undefined`.
* @param overrides - Overrides that has to be applied while fetching
*
*/
getValue<T>(): T;
getValue<T>(section: string): T;
getValue<T>(overrides: IConfigurationOverrides): T;
getValue<T>(section: string, overrides: IConfigurationOverrides): T;
updateValue(key: string, value: any): TPromise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise<void>;
@@ -72,7 +78,7 @@ export interface IConfigurationService {
reloadConfiguration(): TPromise<void>;
reloadConfiguration(folder: IWorkspaceFolder): TPromise<void>;
inspect<T>(key: string): {
inspect<T>(key: string, overrides?: IConfigurationOverrides): {
default: T,
user: T,
workspace: T,
@@ -124,6 +130,26 @@ export function compare(from: IConfigurationModel, to: IConfigurationModel): { a
return { added, removed, updated };
}
export function toOverrides(raw: any, conflictReporter: (message: string) => void): IOverrides[] {
const overrides: IOverrides[] = [];
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
for (const key of Object.keys(raw)) {
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
const overrideRaw = {};
for (const keyInOverrideRaw in raw[key]) {
if (configurationProperties[keyInOverrideRaw] && configurationProperties[keyInOverrideRaw].overridable) {
overrideRaw[keyInOverrideRaw] = raw[key][keyInOverrideRaw];
}
}
overrides.push({
identifiers: [overrideIdentifierFromKey(key).trim()],
contents: toValuesTree(overrideRaw, conflictReporter)
});
}
}
return overrides;
}
export function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any {
const root = Object.create(null);
@@ -153,7 +179,7 @@ export function addToValueTree(settingsTreeRoot: any, key: string, value: any, c
return;
}
curr = obj;
};
}
if (typeof curr === 'object') {
curr[last] = value; // workaround https://github.com/Microsoft/vscode/issues/13606

View File

@@ -7,74 +7,60 @@
import * as json from 'vs/base/common/json';
import { StrictResourceMap } from 'vs/base/common/map';
import * as arrays from 'vs/base/common/arrays';
import * as types from 'vs/base/common/types';
import * as objects from 'vs/base/common/objects';
import URI from 'vs/base/common/uri';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree } from 'vs/platform/configuration/common/configuration';
import { OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree, toOverrides } from 'vs/platform/configuration/common/configuration';
import { Workspace } from 'vs/platform/workspace/common/workspace';
export class ConfigurationModel implements IConfigurationModel {
constructor(protected _contents: any = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) {
private isFrozen: boolean = false;
constructor(
private _contents: any = {},
private _keys: string[] = [],
private _overrides: IOverrides[] = []
) {
}
public get contents(): any {
return this._contents;
get contents(): any {
return this.checkAndFreeze(this._contents);
}
public get overrides(): IOverrides[] {
return this._overrides;
get overrides(): IOverrides[] {
return this.checkAndFreeze(this._overrides);
}
public get keys(): string[] {
return this._keys;
get keys(): string[] {
return this.checkAndFreeze(this._keys);
}
public getSectionContents<V>(section: string): V {
return this.contents[section];
getValue<V>(section: string): V {
return section ? getConfigurationValue<any>(this.contents, section) : this.contents;
}
public setValue(key: string, value: any) {
this.addKey(key);
addToValueTree(this._contents, key, value, e => { throw new Error(e); });
}
public removeValue(key: string): void {
if (this.removeKey(key)) {
removeFromValueTree(this._contents, key);
}
}
public setValueInOverrides(overrideIdentifier: string, key: string, value: any): void {
let override = this._overrides.filter(override => override.identifiers.indexOf(overrideIdentifier) !== -1)[0];
if (!override) {
override = { identifiers: [overrideIdentifier], contents: {} };
this._overrides.push(override);
}
addToValueTree(override.contents, key, value, e => { throw new Error(e); });
}
public override<V>(identifier: string): ConfigurationModel {
override(identifier: string): ConfigurationModel {
const overrideContents = this.getContentsForOverrideIdentifer(identifier);
if (!overrideContents || typeof overrideContents !== 'object' || !Object.keys(overrideContents).length) {
// If there are no valid overrides, use base contents
return new ConfigurationModel(this._contents);
// If there are no valid overrides, return self
return this;
}
let contents = {};
for (const key of arrays.distinct([...Object.keys(this._contents), ...Object.keys(overrideContents)])) {
for (const key of arrays.distinct([...Object.keys(this.contents), ...Object.keys(overrideContents)])) {
let contentsForKey = this._contents[key];
let contentsForKey = this.contents[key];
let overrideContentsForKey = overrideContents[key];
// If there are override contents for the key, clone and merge otherwise use base contents
if (overrideContentsForKey) {
// Clone and merge only if base contents and override contents are of type object otherwise just override
if (typeof contentsForKey === 'object' && typeof overrideContentsForKey === 'object') {
contentsForKey = objects.clone(contentsForKey);
merge(contentsForKey, overrideContentsForKey, true);
contentsForKey = objects.deepClone(contentsForKey);
this.mergeContents(contentsForKey, overrideContentsForKey);
} else {
contentsForKey = overrideContentsForKey;
}
@@ -82,33 +68,62 @@ export class ConfigurationModel implements IConfigurationModel {
contents[key] = contentsForKey;
}
return new ConfigurationModel(contents);
}
public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel {
const mergedModel = new ConfigurationModel();
this.doMerge(mergedModel, this, overwrite);
this.doMerge(mergedModel, other, overwrite);
return mergedModel;
}
merge(...others: ConfigurationModel[]): ConfigurationModel {
const contents = objects.deepClone(this.contents);
const overrides = objects.deepClone(this.overrides);
const keys = [...this.keys];
protected doMerge(source: ConfigurationModel, target: ConfigurationModel, overwrite: boolean = true) {
merge(source.contents, objects.clone(target.contents), overwrite);
const overrides = objects.clone(source._overrides);
for (const override of target._overrides) {
const [sourceOverride] = overrides.filter(o => arrays.equals(o.identifiers, override.identifiers));
if (sourceOverride) {
merge(sourceOverride.contents, override.contents, overwrite);
} else {
overrides.push(override);
for (const other of others) {
this.mergeContents(contents, other.contents);
for (const otherOverride of other.overrides) {
const [override] = overrides.filter(o => arrays.equals(o.identifiers, otherOverride.identifiers));
if (override) {
this.mergeContents(override.contents, otherOverride.contents);
} else {
overrides.push(otherOverride);
}
}
for (const key of other.keys) {
if (keys.indexOf(key) === -1) {
keys.push(key);
}
}
}
source._overrides = overrides;
source._keys = arrays.distinct([...source._keys, ...target.keys]);
return new ConfigurationModel(contents, keys, overrides);
}
freeze(): ConfigurationModel {
// {{SQL CARBON EDIT}}
// this.isFrozen = true;
return this;
}
private mergeContents(source: any, target: any): void {
for (const key of Object.keys(target)) {
if (key in source) {
if (types.isObject(source[key]) && types.isObject(target[key])) {
this.mergeContents(source[key], target[key]);
continue;
}
}
source[key] = objects.deepClone(target[key]);
}
}
private checkAndFreeze<T>(data: T): T {
if (this.isFrozen && !Object.isFrozen(data)) {
return objects.deepFreeze(data);
}
return data;
}
private getContentsForOverrideIdentifer(identifier: string): any {
for (const override of this._overrides) {
for (const override of this.overrides) {
if (override.identifiers.indexOf(identifier) !== -1) {
return override.contents;
}
@@ -116,25 +131,6 @@ export class ConfigurationModel implements IConfigurationModel {
return null;
}
private addKey(key: string): void {
let index = this._keys.length;
for (let i = 0; i < index; i++) {
if (key.indexOf(this._keys[i]) === 0) {
index = i;
}
}
this._keys.splice(index, 1, key);
}
private removeKey(key: string): boolean {
let index = this._keys.indexOf(key);
if (index !== -1) {
this._keys.splice(index, 1);
return true;
}
return false;
}
toJSON(): IConfigurationModel {
return {
contents: this.contents,
@@ -142,50 +138,81 @@ export class ConfigurationModel implements IConfigurationModel {
keys: this.keys
};
}
// Update methods
public setValue(key: string, value: any) {
this.addKey(key);
addToValueTree(this.contents, key, value, e => { throw new Error(e); });
}
public removeValue(key: string): void {
if (this.removeKey(key)) {
removeFromValueTree(this.contents, key);
}
}
private addKey(key: string): void {
let index = this.keys.length;
for (let i = 0; i < index; i++) {
if (key.indexOf(this.keys[i]) === 0) {
index = i;
}
}
this.keys.splice(index, 1, key);
}
private removeKey(key: string): boolean {
let index = this.keys.indexOf(key);
if (index !== -1) {
this.keys.splice(index, 1);
return true;
}
return false;
}
}
export class DefaultConfigurationModel extends ConfigurationModel {
constructor() {
super(getDefaultValues());
this._keys = getConfigurationKeys();
this._overrides = Object.keys(this._contents)
.filter(key => OVERRIDE_PROPERTY_PATTERN.test(key))
.map(key => {
return <IOverrides>{
const contents = getDefaultValues();
const keys = getConfigurationKeys();
const overrides: IOverrides[] = [];
for (const key of Object.keys(contents)) {
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
overrides.push({
identifiers: [overrideIdentifierFromKey(key).trim()],
contents: toValuesTree(this._contents[key], message => console.error(`Conflict in default settings file: ${message}`))
};
});
}
public get keys(): string[] {
return this._keys;
}
}
interface Overrides extends IOverrides {
raw: any;
}
export class CustomConfigurationModel extends ConfigurationModel {
protected _parseErrors: any[] = [];
constructor(content: string = '', private name: string = '') {
super();
if (content) {
this.update(content);
contents: toValuesTree(contents[key], message => console.error(`Conflict in default settings file: ${message}`))
});
}
}
super(contents, keys, overrides);
}
}
export class ConfigurationModelParser {
private _configurationModel: ConfigurationModel = null;
private _parseErrors: any[] = [];
constructor(protected readonly _name: string) { }
get configurationModel(): ConfigurationModel {
return this._configurationModel || new ConfigurationModel();
}
public get errors(): any[] {
get errors(): any[] {
return this._parseErrors;
}
public update(content: string): void {
let parsed: any = {};
let overrides: Overrides[] = [];
public parse(content: string): void {
const raw = this.parseContent(content);
const configurationModel = this.parseRaw(raw);
this._configurationModel = new ConfigurationModel(configurationModel.contents, configurationModel.keys, configurationModel.overrides);
}
protected parseContent(content: string): any {
let raw: any = {};
let currentProperty: string = null;
let currentParent: any = [];
let previousParents: any[] = [];
@@ -197,17 +224,6 @@ export class CustomConfigurationModel extends ConfigurationModel {
} else if (currentProperty) {
currentParent[currentProperty] = value;
}
if (OVERRIDE_PROPERTY_PATTERN.test(currentProperty)) {
onOverrideSettingsValue(currentProperty, value);
}
}
function onOverrideSettingsValue(property: string, value: any): void {
overrides.push({
identifiers: [overrideIdentifierFromKey(property).trim()],
raw: value,
contents: null
});
}
let visitor: json.JSONVisitor = {
@@ -242,88 +258,41 @@ export class CustomConfigurationModel extends ConfigurationModel {
if (content) {
try {
json.visit(content, visitor);
parsed = currentParent[0] || {};
raw = currentParent[0] || {};
} catch (e) {
console.error(`Error while parsing settings file ${this.name}: ${e}`);
console.error(`Error while parsing settings file ${this._name}: ${e}`);
this._parseErrors = [e];
}
}
this.processRaw(parsed);
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
this._overrides = overrides.map<IOverrides>(override => {
// Filter unknown and non-overridable properties
const raw = {};
for (const key in override.raw) {
if (configurationProperties[key] && configurationProperties[key].overridable) {
raw[key] = override.raw[key];
}
}
return {
identifiers: override.identifiers,
contents: toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`))
};
});
return raw;
}
protected processRaw(raw: any): void {
this._contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`));
this._keys = Object.keys(raw);
protected parseRaw(raw: any): IConfigurationModel {
const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
const keys = Object.keys(raw);
const overrides: IOverrides[] = toOverrides(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
return { contents, keys, overrides };
}
}
export class Configuration {
private _globalConfiguration: ConfigurationModel;
private _workspaceConsolidatedConfiguration: ConfigurationModel;
protected _foldersConsolidatedConfigurations: StrictResourceMap<ConfigurationModel>;
private _workspaceConsolidatedConfiguration: ConfigurationModel = null;
private _foldersConsolidatedConfigurations: StrictResourceMap<ConfigurationModel> = new StrictResourceMap<ConfigurationModel>();
constructor(protected _defaults: ConfigurationModel,
protected _user: ConfigurationModel,
protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(),
protected folders: StrictResourceMap<ConfigurationModel> = new StrictResourceMap<ConfigurationModel>(),
protected _memoryConfiguration: ConfigurationModel = new ConfigurationModel(),
protected _memoryConfigurationByResource: StrictResourceMap<ConfigurationModel> = new StrictResourceMap<ConfigurationModel>()) {
this.merge();
constructor(
private _defaultConfiguration: ConfigurationModel,
private _userConfiguration: ConfigurationModel,
private _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(),
private _folderConfigurations: StrictResourceMap<ConfigurationModel> = new StrictResourceMap<ConfigurationModel>(),
private _memoryConfiguration: ConfigurationModel = new ConfigurationModel(),
private _memoryConfigurationByResource: StrictResourceMap<ConfigurationModel> = new StrictResourceMap<ConfigurationModel>()) {
}
get defaults(): ConfigurationModel {
return this._defaults;
}
get user(): ConfigurationModel {
return this._user;
}
get workspace(): ConfigurationModel {
return this._workspaceConfiguration;
}
protected merge(): void {
this._globalConfiguration = this._defaults.merge(this._user);
this.updateWorkspaceConsolidateConfiguration();
this._foldersConsolidatedConfigurations = new StrictResourceMap<ConfigurationModel>();
for (const folder of this.folders.keys()) {
this.mergeFolder(folder);
}
}
private updateWorkspaceConsolidateConfiguration() {
this._workspaceConsolidatedConfiguration = this._globalConfiguration.merge(this._workspaceConfiguration).merge(this._memoryConfiguration);
}
protected mergeFolder(folder: URI) {
this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder)));
}
getSection<C>(section: string = '', overrides: IConfigurationOverrides, workspace: Workspace): C {
const configModel = this.getConsolidateConfigurationModel(overrides, workspace);
return objects.clone(section ? configModel.getSectionContents<C>(section) : configModel.contents);
}
getValue(key: string, overrides: IConfigurationOverrides, workspace: Workspace): any {
getValue(section: string, overrides: IConfigurationOverrides, workspace: Workspace): any {
const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides, workspace);
return objects.clone(getConfigurationValue<any>(consolidateConfigurationModel.contents, key));
return consolidateConfigurationModel.getValue(section);
}
updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void {
@@ -345,11 +314,11 @@ export class Configuration {
}
if (!overrides.resource) {
this.updateWorkspaceConsolidateConfiguration();
this._workspaceConsolidatedConfiguration = null;
}
}
lookup<C>(key: string, overrides: IConfigurationOverrides, workspace: Workspace): {
inspect<C>(key: string, overrides: IConfigurationOverrides, workspace: Workspace): {
default: C,
user: C,
workspace: C,
@@ -360,14 +329,14 @@ export class Configuration {
const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides, workspace);
const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace);
const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration;
return objects.clone({
default: getConfigurationValue<C>(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key),
user: getConfigurationValue<C>(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key),
workspace: workspace ? getConfigurationValue<C>(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null
workspaceFolder: folderConfigurationModel ? getConfigurationValue<C>(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0,
memory: getConfigurationValue<C>(overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).contents : memoryConfigurationModel.contents, key),
value: getConfigurationValue<C>(consolidateConfigurationModel.contents, key)
});
return {
default: overrides.overrideIdentifier ? this._defaultConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._defaultConfiguration.freeze().getValue(key),
user: overrides.overrideIdentifier ? this._userConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._userConfiguration.freeze().getValue(key),
workspace: workspace ? overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._workspaceConfiguration.freeze().getValue(key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null
workspaceFolder: folderConfigurationModel ? overrides.overrideIdentifier ? folderConfigurationModel.freeze().override(overrides.overrideIdentifier).getValue(key) : folderConfigurationModel.freeze().getValue(key) : void 0,
memory: overrides.overrideIdentifier ? memoryConfigurationModel.freeze().override(overrides.overrideIdentifier).getValue(key) : memoryConfigurationModel.freeze().getValue(key),
value: consolidateConfigurationModel.getValue(key)
};
}
keys(workspace: Workspace): {
@@ -377,76 +346,163 @@ export class Configuration {
workspaceFolder: string[];
} {
const folderConfigurationModel = this.getFolderConfigurationModelForResource(null, workspace);
return objects.clone({
default: this._defaults.keys,
user: this._user.keys,
workspace: this._workspaceConfiguration.keys,
workspaceFolder: folderConfigurationModel ? folderConfigurationModel.keys : []
});
return {
default: this._defaultConfiguration.freeze().keys,
user: this._userConfiguration.freeze().keys,
workspace: this._workspaceConfiguration.freeze().keys,
workspaceFolder: folderConfigurationModel ? folderConfigurationModel.freeze().keys : []
};
}
private getConsolidateConfigurationModel<C>(overrides: IConfigurationOverrides, workspace: Workspace): ConfigurationModel {
updateDefaultConfiguration(defaultConfiguration: ConfigurationModel): void {
this._defaultConfiguration = defaultConfiguration;
this._workspaceConsolidatedConfiguration = null;
this._foldersConsolidatedConfigurations.clear();
}
updateUserConfiguration(userConfiguration: ConfigurationModel): void {
this._userConfiguration = userConfiguration;
this._workspaceConsolidatedConfiguration = null;
this._foldersConsolidatedConfigurations.clear();
}
updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): void {
this._workspaceConfiguration = workspaceConfiguration;
this._workspaceConsolidatedConfiguration = null;
this._foldersConsolidatedConfigurations.clear();
}
updateFolderConfiguration(resource: URI, configuration: ConfigurationModel): void {
this._folderConfigurations.set(resource, configuration);
this._foldersConsolidatedConfigurations.delete(resource);
}
deleteFolderConfiguration(resource: URI): void {
this.folders.delete(resource);
this._foldersConsolidatedConfigurations.delete(resource);
}
get defaults(): ConfigurationModel {
return this._defaultConfiguration;
}
get user(): ConfigurationModel {
return this._userConfiguration;
}
get workspace(): ConfigurationModel {
return this._workspaceConfiguration;
}
protected get folders(): StrictResourceMap<ConfigurationModel> {
return this._folderConfigurations;
}
private get memory(): ConfigurationModel {
return this._memoryConfiguration;
}
private get memoryByResource(): StrictResourceMap<ConfigurationModel> {
return this._memoryConfigurationByResource;
}
private getConsolidateConfigurationModel(overrides: IConfigurationOverrides, workspace: Workspace): ConfigurationModel {
let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace);
return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel;
}
private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides, workspace: Workspace): ConfigurationModel {
if (!workspace) {
return this._globalConfiguration;
}
let consolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
if (!resource) {
return this._workspaceConsolidatedConfiguration;
}
let consolidateConfiguration = this._workspaceConsolidatedConfiguration;
const root = workspace.getFolder(resource);
if (root) {
consolidateConfiguration = this._foldersConsolidatedConfigurations.get(root.uri) || this._workspaceConsolidatedConfiguration;
}
const memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource);
if (memoryConfigurationForResource) {
consolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource);
if (workspace && resource) {
const root = workspace.getFolder(resource);
if (root) {
consolidateConfiguration = this.getFolderConsolidatedConfiguration(root.uri) || consolidateConfiguration;
}
const memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource);
if (memoryConfigurationForResource) {
consolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource);
}
}
return consolidateConfiguration;
}
private getFolderConfigurationModelForResource(resource: URI, workspace: Workspace): ConfigurationModel {
if (!workspace || !resource) {
return null;
private getWorkspaceConsolidatedConfiguration(): ConfigurationModel {
if (!this._workspaceConsolidatedConfiguration) {
this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this._userConfiguration).merge(this._workspaceConfiguration).merge(this._memoryConfiguration).freeze();
}
const root = workspace.getFolder(resource);
return root ? this.folders.get(root.uri) : null;
return this._workspaceConsolidatedConfiguration;
}
public toData(): IConfigurationData {
private getFolderConsolidatedConfiguration(folder: URI): ConfigurationModel {
let folderConsolidatedConfiguration = this._foldersConsolidatedConfigurations.get(folder);
if (!folderConsolidatedConfiguration) {
const workspaceConsolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
const folderConfiguration = this._folderConfigurations.get(folder);
if (folderConfiguration) {
folderConsolidatedConfiguration = workspaceConsolidateConfiguration.merge(folderConfiguration).freeze();
this._foldersConsolidatedConfigurations.set(folder, folderConsolidatedConfiguration);
} else {
folderConsolidatedConfiguration = workspaceConsolidateConfiguration;
}
}
return folderConsolidatedConfiguration;
}
private getFolderConfigurationModelForResource(resource: URI, workspace: Workspace): ConfigurationModel {
if (workspace && resource) {
const root = workspace.getFolder(resource);
if (root) {
return this._folderConfigurations.get(root.uri);
}
}
return null;
}
toData(): IConfigurationData {
return {
defaults: {
contents: this._defaults.contents,
overrides: this._defaults.overrides,
keys: this._defaults.keys
contents: this._defaultConfiguration.contents,
overrides: this._defaultConfiguration.overrides,
keys: this._defaultConfiguration.keys
},
user: {
contents: this._user.contents,
overrides: this._user.overrides,
keys: this._user.keys
contents: this._userConfiguration.contents,
overrides: this._userConfiguration.overrides,
keys: this._userConfiguration.keys
},
workspace: {
contents: this._workspaceConfiguration.contents,
overrides: this._workspaceConfiguration.overrides,
keys: this._workspaceConfiguration.keys
},
folders: this.folders.keys().reduce((result, folder) => {
const { contents, overrides, keys } = this.folders.get(folder);
folders: this._folderConfigurations.keys().reduce((result, folder) => {
const { contents, overrides, keys } = this._folderConfigurations.get(folder);
result[folder.toString()] = { contents, overrides, keys };
return result;
}, Object.create({}))
};
}
allKeys(workspace: Workspace): string[] {
let keys = this.keys(workspace);
let all = [...keys.default];
const addKeys = (keys) => {
for (const key of keys) {
if (all.indexOf(key) === -1) {
all.push(key);
}
}
};
addKeys(keys.user);
addKeys(keys.workspace);
for (const resource of this.folders.keys()) {
addKeys(this.folders.get(resource).keys);
}
return all;
}
public static parse(data: IConfigurationData): Configuration {
const defaultConfiguration = Configuration.parseConfigurationModel(data.defaults);
const userConfiguration = Configuration.parseConfigurationModel(data.user);
@@ -455,11 +511,11 @@ export class Configuration {
result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key]));
return result;
}, new StrictResourceMap<ConfigurationModel>());
return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap<ConfigurationModel>());
return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders);
}
private static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel {
return new ConfigurationModel(model.contents, model.keys, model.overrides);
return new ConfigurationModel(model.contents, model.keys, model.overrides).freeze();
}
}
@@ -487,29 +543,6 @@ export class AbstractConfigurationChangeEvent {
}
}
export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent {
private _changedConfiguration: ConfigurationModel = null;
constructor(readonly affectedKeys: string[], readonly source: ConfigurationTarget, readonly sourceConfig: any) { super(); }
get changedConfiguration(): ConfigurationModel {
if (!this._changedConfiguration) {
this._changedConfiguration = new ConfigurationModel();
this.updateKeys(this._changedConfiguration, this.affectedKeys);
}
return this._changedConfiguration;
}
get changedConfigurationByResource(): StrictResourceMap<IConfigurationModel> {
return new StrictResourceMap();
}
affectsConfiguration(config: string, resource?: URI): boolean {
return this.doesConfigurationContains(this.changedConfiguration, config);
}
}
export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent {
private _source: ConfigurationTarget;
@@ -529,8 +562,8 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i
return this._changedConfigurationByResource;
}
change(event: ConfigurationChangeEvent): ConfigurationChangeEvent
change(keys: string[], resource?: URI): ConfigurationChangeEvent
change(event: ConfigurationChangeEvent): ConfigurationChangeEvent;
change(keys: string[], resource?: URI): ConfigurationChangeEvent;
change(arg1: any, arg2?: any): ConfigurationChangeEvent {
if (arg1 instanceof ConfigurationChangeEvent) {
this._changedConfiguration = this._changedConfiguration.merge(arg1._changedConfiguration);
@@ -554,7 +587,7 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i
get affectedKeys(): string[] {
const keys = [...this._changedConfiguration.keys];
this._changedConfigurationByResource.forEach(model => keys.push(...model.keys));
return keys;
return arrays.distinct(keys);
}
get source(): ConfigurationTarget {
@@ -599,4 +632,4 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i
}
return changedConfigurationByResource;
}
}
}

View File

@@ -11,7 +11,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import types = require('vs/base/common/types');
import * as strings from 'vs/base/common/strings';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { clone } from 'vs/base/common/objects';
import { deepClone } from 'vs/base/common/objects';
export const Extensions = {
Configuration: 'base.contributions.configuration'
@@ -27,7 +27,7 @@ export interface IConfigurationRegistry {
/**
* Register multiple configurations to the registry.
*/
registerConfigurations(configurations: IConfigurationNode[], validate?: boolean): void;
registerConfigurations(configurations: IConfigurationNode[], defaultConfigurations: IDefaultConfigurationExtension[], validate?: boolean): void;
/**
* Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values.
@@ -35,8 +35,6 @@ export interface IConfigurationRegistry {
*/
notifyConfigurationSchemaUpdated(configuration: IConfigurationNode): void;
registerDefaultConfigurations(defaultConfigurations: IDefaultConfigurationExtension[]): void;
/**
* Event that fires whenver a configuration has been
* registered.
@@ -53,6 +51,11 @@ export interface IConfigurationRegistry {
*/
getConfigurationProperties(): { [qualifiedKey: string]: IConfigurationPropertySchema };
/**
* Returns all excluded configurations settings of all configuration nodes contributed to this registry.
*/
getExcludedConfigurationProperties(): { [qualifiedKey: string]: IConfigurationPropertySchema };
/**
* Register the identifiers for editor configurations
*/
@@ -69,6 +72,7 @@ export interface IConfigurationPropertySchema extends IJSONSchema {
isExecutable?: boolean;
scope?: ConfigurationScope;
notMultiRootAdopted?: boolean;
included?: boolean;
}
export interface IConfigurationNode {
@@ -99,6 +103,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
private configurationContributors: IConfigurationNode[];
private configurationProperties: { [qualifiedKey: string]: IJSONSchema };
private excludedConfigurationProperties: { [qualifiedKey: string]: IJSONSchema };
private editorConfigurationSchema: IJSONSchema;
private overrideIdentifiers: string[] = [];
private overridePropertyPattern: string;
@@ -110,16 +115,22 @@ class ConfigurationRegistry implements IConfigurationRegistry {
this.configurationContributors = [];
this.editorConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting' };
this.configurationProperties = {};
this.excludedConfigurationProperties = {};
this.computeOverridePropertyPattern();
contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema);
}
public registerConfiguration(configuration: IConfigurationNode, validate: boolean = true): void {
this.registerConfigurations([configuration], validate);
this.registerConfigurations([configuration], [], validate);
}
public registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void {
public registerConfigurations(configurations: IConfigurationNode[], defaultConfigurations: IDefaultConfigurationExtension[], validate: boolean = true): void {
const configurationNode = this.toConfiguration(defaultConfigurations);
if (configurationNode) {
configurations.push(configurationNode);
}
const properties: string[] = [];
configurations.forEach(configuration => {
properties.push(...this.validateAndRegisterProperties(configuration, validate)); // fills in defaults
@@ -140,7 +151,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
this.updateOverridePropertyPatternKey();
}
public registerDefaultConfigurations(defaultConfigurations: IDefaultConfigurationExtension[]): void {
private toConfiguration(defaultConfigurations: IDefaultConfigurationExtension[]): IConfigurationNode {
const configurationNode: IConfigurationNode = {
id: 'defaultOverrides',
title: nls.localize('defaultConfigurations.title', "Default Configuration Overrides"),
@@ -159,9 +170,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
}
}
}
if (Object.keys(configurationNode.properties).length) {
this.registerConfiguration(configurationNode, false);
}
return Object.keys(configurationNode.properties).length ? configurationNode : null;
}
private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW, overridable: boolean = false): string[] {
@@ -190,8 +199,17 @@ class ConfigurationRegistry implements IConfigurationRegistry {
if (property.scope === void 0) {
property.scope = scope;
}
// add to properties map
this.configurationProperties[key] = properties[key];
// Add to properties maps
// Property is included by default if 'included' is unspecified
if (properties[key].hasOwnProperty('included') && !properties[key].included) {
this.excludedConfigurationProperties[key] = properties[key];
delete properties[key];
continue;
} else {
this.configurationProperties[key] = properties[key];
}
propertyKeys.push(key);
}
}
@@ -204,10 +222,6 @@ class ConfigurationRegistry implements IConfigurationRegistry {
return propertyKeys;
}
validateProperty(property: string): boolean {
return !OVERRIDE_PROPERTY_PATTERN.test(property) && this.getConfigurationProperties()[property] !== void 0;
}
getConfigurations(): IConfigurationNode[] {
return this.configurationContributors;
}
@@ -216,13 +230,17 @@ class ConfigurationRegistry implements IConfigurationRegistry {
return this.configurationProperties;
}
getExcludedConfigurationProperties(): { [qualifiedKey: string]: IConfigurationPropertySchema } {
return this.excludedConfigurationProperties;
}
private registerJSONConfiguration(configuration: IConfigurationNode) {
function register(configuration: IConfigurationNode) {
let properties = configuration.properties;
if (properties) {
for (let key in properties) {
settingsSchema.properties[key] = properties[key];
resourceSettingsSchema.properties[key] = clone(properties[key]);
resourceSettingsSchema.properties[key] = deepClone(properties[key]);
if (properties[key].scope !== ConfigurationScope.RESOURCE) {
resourceSettingsSchema.properties[key].doNotSuggest = true;
}
@@ -232,7 +250,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
if (subNodes) {
subNodes.forEach(register);
}
};
}
register(configuration);
}
@@ -321,4 +339,4 @@ export function validateProperty(property: string): string {
export function getScopes(keys: string[]): ConfigurationScope[] {
const configurationProperties = configurationRegistry.getConfigurationProperties();
return keys.map(key => configurationProperties[key].scope);
}
}

View File

@@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ConfigurationModelParser, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { ConfigWatcher } from 'vs/base/node/config';
import Event, { Emitter } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
export class UserConfiguration extends Disposable {
private userConfigModelWatcher: ConfigWatcher<ConfigurationModelParser>;
private _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
constructor(settingsPath: string) {
super();
this.userConfigModelWatcher = new ConfigWatcher(settingsPath, {
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(settingsPath), parse: (content: string, parseErrors: any[]) => {
const userConfigModelParser = new ConfigurationModelParser(settingsPath);
userConfigModelParser.parse(content);
parseErrors = [...userConfigModelParser.errors];
return userConfigModelParser;
}
});
this._register(this.userConfigModelWatcher);
// Listeners
this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this._onDidChangeConfiguration.fire(this.configurationModel)));
}
get configurationModel(): ConfigurationModel {
return this.userConfigModelWatcher.getConfig().configurationModel;
}
reload(): TPromise<void> {
return new TPromise(c => this.userConfigModelWatcher.reload(() => c(null)));
}
}

View File

@@ -4,25 +4,24 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { ConfigWatcher } from 'vs/base/node/config';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration';
import { CustomConfigurationModel, DefaultConfigurationModel, ConfigurationModel, Configuration, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { DefaultConfigurationModel, Configuration, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import Event, { Emitter } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { onUnexpectedError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { equals } from 'vs/base/common/objects';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { UserConfiguration } from 'vs/platform/configuration/node/configuration';
export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable {
_serviceBrand: any;
private _configuration: Configuration;
private userConfigModelWatcher: ConfigWatcher<ConfigurationModel>;
private userConfiguration: UserConfiguration;
private _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
@@ -32,19 +31,12 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
) {
super();
this.userConfigModelWatcher = new ConfigWatcher(environmentService.appSettingsPath, {
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new CustomConfigurationModel(null, environmentService.appSettingsPath), parse: (content: string, parseErrors: any[]) => {
const userConfigModel = new CustomConfigurationModel(content, environmentService.appSettingsPath);
parseErrors = [...userConfigModel.errors];
return userConfigModel;
}
});
this._register(this.userConfigModelWatcher);
this.userConfiguration = this._register(new UserConfiguration(environmentService.appSettingsPath));
this.reset();
// Listeners
this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this.onDidUpdateConfigModel()));
this._register(this.userConfiguration.onDidChangeConfiguration(() => this.onDidChangeUserConfiguration()));
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidRegisterConfiguration(configurationProperties => this.onDidRegisterConfiguration(configurationProperties)));
}
@@ -56,24 +48,20 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
return this.configuration.toData();
}
getConfiguration<T>(): T
getConfiguration<T>(section: string): T
getConfiguration<T>(overrides: IConfigurationOverrides): T
getConfiguration<T>(section: string, overrides: IConfigurationOverrides): T
getConfiguration(arg1?: any, arg2?: any): any {
getValue<T>(): T;
getValue<T>(section: string): T;
getValue<T>(overrides: IConfigurationOverrides): T;
getValue<T>(section: string, overrides: IConfigurationOverrides): T;
getValue(arg1?: any, arg2?: any): any {
const section = typeof arg1 === 'string' ? arg1 : void 0;
const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : {};
return this.configuration.getSection(section, overrides, null);
return this.configuration.getValue(section, overrides, null);
}
getValue(key: string, overrides: IConfigurationOverrides = {}): any {
return this.configuration.getValue(key, overrides, null);
}
updateValue(key: string, value: any): TPromise<void>
updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise<void>
updateValue(key: string, value: any, target: ConfigurationTarget): TPromise<void>
updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise<void>
updateValue(key: string, value: any): TPromise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise<void>;
updateValue(key: string, value: any, target: ConfigurationTarget): TPromise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise<void>;
updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise<void> {
return TPromise.wrapError(new Error('not supported'));
}
@@ -85,7 +73,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
workspaceFolder: T
value: T
} {
return this.configuration.lookup<T>(key, {}, null);
return this.configuration.inspect<T>(key, {}, null);
}
keys(): {
@@ -99,12 +87,12 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
reloadConfiguration(folder?: IWorkspaceFolder): TPromise<void> {
return folder ? TPromise.as(null) :
new TPromise((c, e) => this.userConfigModelWatcher.reload(() => c(this.onDidUpdateConfigModel())));
this.userConfiguration.reload().then(() => this.onDidChangeUserConfiguration());
}
private onDidUpdateConfigModel(): void {
private onDidChangeUserConfiguration(): void {
let changedKeys = [];
const { added, updated, removed } = compare(this._configuration.user, this.userConfigModelWatcher.getConfig());
const { added, updated, removed } = compare(this._configuration.user, this.userConfiguration.configurationModel);
changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
const oldConfiguartion = this._configuration;
@@ -123,7 +111,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
private reset(): void {
const defaults = new DefaultConfigurationModel();
const user = this.userConfigModelWatcher.getConfig();
const user = this.userConfiguration.configurationModel;
this._configuration = new Configuration(defaults, user);
}

View File

@@ -5,11 +5,10 @@
'use strict';
import * as assert from 'assert';
import { ConfigurationModel, CustomConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { ConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import URI from 'vs/base/common/uri';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
suite('ConfigurationModel', () => {
@@ -103,44 +102,6 @@ suite('ConfigurationModel', () => {
assert.deepEqual(testObject.keys, []);
});
test('setValueInOverrides adds to overrides if does not exist', () => {
let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a']);
testObject.setValueInOverrides('or', 'a', 2);
assert.deepEqual(testObject.overrides[0].contents, { 'a': 2 });
assert.deepEqual(testObject.override('or').contents, { 'a': 2, 'b': 1 });
});
test('setValueInOverrides adds to overrides if exist', () => {
let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or'], contents: { 'a': 2 } }]);
testObject.setValueInOverrides('or', 'a', 3);
assert.deepEqual(testObject.overrides[0].contents, { 'a': 3 });
assert.deepEqual(testObject.override('or').contents, { 'a': 3, 'b': 1 });
});
test('setValueInOverrides adds a nested key to overrides if exist', () => {
let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or'], contents: { 'a': { 'c': 1 } } }]);
testObject.setValueInOverrides('or', 'a.c', 2);
assert.deepEqual(testObject.overrides[0].contents, { 'a': { 'c': 2 } });
assert.deepEqual(testObject.override('or').contents, { 'a': { 'c': 2 }, 'b': 1 });
});
test('setValueInOverrides adds new overrides if exist', () => {
let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or1'], contents: { 'a': 2 } }]);
testObject.setValueInOverrides('or2', 'b', 2);
assert.deepEqual(testObject.overrides[0].contents, { 'a': 2 });
assert.deepEqual(testObject.overrides[1].contents, { 'b': 2 });
assert.deepEqual(testObject.override('or1').contents, { 'a': 2, 'b': 1 });
assert.deepEqual(testObject.override('or2').contents, { 'a': 1, 'b': 2 });
});
test('get overriding configuration model for an existing identifier', () => {
let testObject = new ConfigurationModel(
{ 'a': { 'b': 1 }, 'f': 1 }, [],
@@ -212,7 +173,7 @@ suite('ConfigurationModel', () => {
let result = base.merge(add);
assert.deepEqual(result.contents, { 'a': { 'b': 2 } });
assert.deepEqual(result.getSectionContents('a'), { 'b': 2 });
assert.deepEqual(result.getValue('a'), { 'b': 2 });
assert.deepEqual(result.keys, ['a.b']);
});
@@ -240,16 +201,16 @@ suite('ConfigurationModel', () => {
test('Test contents while getting an existing property', () => {
let testObject = new ConfigurationModel({ 'a': 1 });
assert.deepEqual(testObject.getSectionContents('a'), 1);
assert.deepEqual(testObject.getValue('a'), 1);
testObject = new ConfigurationModel({ 'a': { 'b': 1 } });
assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 });
assert.deepEqual(testObject.getValue('a'), { 'b': 1 });
});
test('Test contents are undefined for non existing properties', () => {
const testObject = new ConfigurationModel({ awesome: true });
assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined);
assert.deepEqual(testObject.getValue('unknownproperty'), undefined);
});
test('Test override gives all content merged with overrides', () => {
@@ -279,86 +240,97 @@ suite('CustomConfigurationModel', () => {
});
test('simple merge using models', () => {
let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 }));
let add = new CustomConfigurationModel(JSON.stringify({ 'a': 3, 'c': 4 }));
let result = base.merge(add);
let base = new ConfigurationModelParser('base');
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
let add = new ConfigurationModelParser('add');
add.parse(JSON.stringify({ 'a': 3, 'c': 4 }));
let result = base.configurationModel.merge(add.configurationModel);
assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 });
});
test('simple merge with an undefined contents', () => {
let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 }));
let add = new CustomConfigurationModel(null);
let result = base.merge(add);
let base = new ConfigurationModelParser('base');
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
let add = new ConfigurationModelParser('add');
let result = base.configurationModel.merge(add.configurationModel);
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
base = new CustomConfigurationModel(null);
add = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 }));
result = base.merge(add);
base = new ConfigurationModelParser('base');
add = new ConfigurationModelParser('add');
add.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
result = base.configurationModel.merge(add.configurationModel);
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
base = new CustomConfigurationModel(null);
add = new CustomConfigurationModel(null);
result = base.merge(add);
base = new ConfigurationModelParser('base');
add = new ConfigurationModelParser('add');
result = base.configurationModel.merge(add.configurationModel);
assert.deepEqual(result.contents, {});
});
test('Recursive merge using config models', () => {
let base = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } }));
let add = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 2 } }));
let result = base.merge(add);
let base = new ConfigurationModelParser('base');
base.parse(JSON.stringify({ 'a': { 'b': 1 } }));
let add = new ConfigurationModelParser('add');
add.parse(JSON.stringify({ 'a': { 'b': 2 } }));
let result = base.configurationModel.merge(add.configurationModel);
assert.deepEqual(result.contents, { 'a': { 'b': 2 } });
});
test('Test contents while getting an existing property', () => {
let testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1 }));
assert.deepEqual(testObject.getSectionContents('a'), 1);
let testObject = new ConfigurationModelParser('test');
testObject.parse(JSON.stringify({ 'a': 1 }));
assert.deepEqual(testObject.configurationModel.getValue('a'), 1);
testObject = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } }));
assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 });
testObject.parse(JSON.stringify({ 'a': { 'b': 1 } }));
assert.deepEqual(testObject.configurationModel.getValue('a'), { 'b': 1 });
});
test('Test contents are undefined for non existing properties', () => {
const testObject = new CustomConfigurationModel(JSON.stringify({
const testObject = new ConfigurationModelParser('test');
testObject.parse(JSON.stringify({
awesome: true
}));
assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined);
assert.deepEqual(testObject.configurationModel.getValue('unknownproperty'), undefined);
});
test('Test contents are undefined for undefined config', () => {
const testObject = new CustomConfigurationModel(null);
const testObject = new ConfigurationModelParser('test');
assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined);
assert.deepEqual(testObject.configurationModel.getValue('unknownproperty'), undefined);
});
test('Test configWithOverrides gives all content merged with overrides', () => {
const testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
const testObject = new ConfigurationModelParser('test');
testObject.parse(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } });
assert.deepEqual(testObject.configurationModel.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } });
});
test('Test configWithOverrides gives empty contents', () => {
const testObject = new CustomConfigurationModel(null);
const testObject = new ConfigurationModelParser('test');
assert.deepEqual(testObject.override('b').contents, {});
assert.deepEqual(testObject.configurationModel.override('b').contents, {});
});
test('Test update with empty data', () => {
const testObject = new CustomConfigurationModel();
testObject.update('');
const testObject = new ConfigurationModelParser('test');
testObject.parse('');
assert.deepEqual(testObject.contents, {});
assert.deepEqual(testObject.keys, []);
assert.deepEqual(testObject.configurationModel.contents, {});
assert.deepEqual(testObject.configurationModel.keys, []);
testObject.update(null);
testObject.parse(null);
assert.deepEqual(testObject.contents, {});
assert.deepEqual(testObject.keys, []);
assert.deepEqual(testObject.configurationModel.contents, {});
assert.deepEqual(testObject.configurationModel.keys, []);
testObject.update(undefined);
testObject.parse(undefined);
assert.deepEqual(testObject.contents, {});
assert.deepEqual(testObject.keys, []);
assert.deepEqual(testObject.configurationModel.contents, {});
assert.deepEqual(testObject.configurationModel.keys, []);
});
test('Test registering the same property again', () => {
@@ -375,7 +347,7 @@ suite('CustomConfigurationModel', () => {
}
}
});
assert.equal(true, new DefaultConfigurationModel().getSectionContents('a'));
assert.equal(true, new DefaultConfigurationModel().getValue('a'));
});
test('Test registering the language property', () => {
@@ -392,7 +364,7 @@ suite('CustomConfigurationModel', () => {
}
}
});
assert.equal(undefined, new DefaultConfigurationModel().getSectionContents('[a]'));
assert.equal(undefined, new DefaultConfigurationModel().getValue('[a]'));
});
});
@@ -503,48 +475,4 @@ suite('ConfigurationChangeEvent', () => {
assert.ok(actual.affectsConfiguration('[markdown]', URI.file('file2')));
});
});
suite('AllKeysConfigurationChangeEvent', () => {
test('changeEvent affects keys for any resource', () => {
let testObject = new AllKeysConfigurationChangeEvent(['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows'], ConfigurationTarget.USER, null);
assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']);
assert.ok(testObject.affectsConfiguration('window.zoomLevel'));
assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window.restoreFullscreen'));
assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window.restoreWindows'));
assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.title'));
assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window'));
assert.ok(testObject.affectsConfiguration('window', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview'));
assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('workbench.editor'));
assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('workbench'));
assert.ok(testObject.affectsConfiguration('workbench', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench', URI.file('file1')));
assert.ok(!testObject.affectsConfiguration('files'));
assert.ok(!testObject.affectsConfiguration('files', URI.file('file1')));
});
});

View File

@@ -8,10 +8,9 @@
import { TernarySearchTree } from 'vs/base/common/map';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
export class TestConfigurationService extends EventEmitter implements IConfigurationService {
export class TestConfigurationService implements IConfigurationService {
public _serviceBrand: any;
private configuration = Object.create(null);
@@ -19,23 +18,21 @@ export class TestConfigurationService extends EventEmitter implements IConfigura
private configurationByRoot: TernarySearchTree<any> = TernarySearchTree.forPaths<any>();
public reloadConfiguration<T>(): TPromise<T> {
return TPromise.as(this.getConfiguration());
return TPromise.as(this.getValue());
}
public getConfiguration<C>(arg1?: any, arg2?: any): C {
public getValue(arg1?: any, arg2?: any): any {
if (arg1 && typeof arg1 === 'string') {
return this.inspect(<string>arg1).value;
}
const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0;
if (overrides && overrides.resource) {
const configForResource = this.configurationByRoot.findSubstr(overrides.resource.fsPath);
return configForResource || this.configuration;
}
return this.configuration;
}
public getValue(key: string, overrides?: IConfigurationOverrides): any {
return this.inspect(key).value;
}
public updateValue(key: string, overrides?: IConfigurationOverrides): TPromise<void> {
return TPromise.as(null);
}
@@ -63,7 +60,7 @@ export class TestConfigurationService extends EventEmitter implements IConfigura
workspaceFolder: T
value: T,
} {
const config = this.getConfiguration(undefined, overrides);
const config = this.getValue(undefined, overrides);
return {
value: getConfigurationValue<T>(config, key),

View File

@@ -18,6 +18,7 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ
import extfs = require('vs/base/node/extfs');
import uuid = require('vs/base/common/uuid');
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { mkdirp } from 'vs/base/node/pfs';
class SettingsTestEnvironmentService extends EnvironmentService {
@@ -36,9 +37,9 @@ suite('ConfigurationService - Node', () => {
const newDir = path.join(parentDir, 'config', id);
const testFile = path.join(newDir, 'config.json');
extfs.mkdirp(newDir, 493, (error) => {
callback(testFile, (callback) => extfs.del(parentDir, os.tmpdir(), () => { }, callback));
});
const onMkdirp = error => callback(testFile, (callback) => extfs.del(parentDir, os.tmpdir(), () => { }, callback));
mkdirp(newDir, 493).done(() => onMkdirp(null), error => onMkdirp(error));
}
test('simple', (done: () => void) => {
@@ -47,7 +48,7 @@ suite('ConfigurationService - Node', () => {
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
const config = service.getConfiguration<{ foo: string }>();
const config = service.getValue<{ foo: string }>();
assert.ok(config);
assert.equal(config.foo, 'bar');
@@ -63,7 +64,7 @@ suite('ConfigurationService - Node', () => {
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
const config = service.getConfiguration<{ testworkbench: { editor: { tabs: boolean } } }>();
const config = service.getValue<{ testworkbench: { editor: { tabs: boolean } } }>();
assert.ok(config);
assert.ok(config.testworkbench);
assert.ok(config.testworkbench.editor);
@@ -81,7 +82,7 @@ suite('ConfigurationService - Node', () => {
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
const config = service.getConfiguration<{ foo: string }>();
const config = service.getValue<{ foo: string }>();
assert.ok(config);
service.dispose();
@@ -98,7 +99,7 @@ suite('ConfigurationService - Node', () => {
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
const config = service.getConfiguration<{ foo: string }>();
const config = service.getValue<{ foo: string }>();
assert.ok(config);
service.dispose();
@@ -110,20 +111,20 @@ suite('ConfigurationService - Node', () => {
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
let config = service.getConfiguration<{ foo: string }>();
let config = service.getValue<{ foo: string }>();
assert.ok(config);
assert.equal(config.foo, 'bar');
fs.writeFileSync(testFile, '{ "foo": "changed" }');
// still outdated
config = service.getConfiguration<{ foo: string }>();
config = service.getValue<{ foo: string }>();
assert.ok(config);
assert.equal(config.foo, 'bar');
// force a reload to get latest
service.reloadConfiguration().then(() => {
config = service.getConfiguration<{ foo: string }>();
config = service.getValue<{ foo: string }>();
assert.ok(config);
assert.equal(config.foo, 'changed');
@@ -156,7 +157,7 @@ suite('ConfigurationService - Node', () => {
});
let serviceWithoutFile = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, '__testFile'));
let setting = serviceWithoutFile.getConfiguration<ITestSetting>();
let setting = serviceWithoutFile.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isSet');
@@ -166,7 +167,7 @@ suite('ConfigurationService - Node', () => {
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
let setting = service.getConfiguration<ITestSetting>();
let setting = service.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isSet');
@@ -174,7 +175,7 @@ suite('ConfigurationService - Node', () => {
fs.writeFileSync(testFile, '{ "configuration.service.testSetting": "isChanged" }');
service.reloadConfiguration().then(() => {
let setting = service.getConfiguration<ITestSetting>();
let setting = service.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isChanged');