diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 2cae5106d8a3ca527ed304f3ab7aa9db2815ea19..6f0fb98af61bfdb7cef122c7b2a98b150ff02a14 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -17,6 +17,8 @@ STATIC_VALUES.set('isWindows', isWindows); STATIC_VALUES.set('isWeb', isWeb); STATIC_VALUES.set('isMacNative', isMacintosh && !isWeb); +const hasOwnProperty = Object.prototype.hasOwnProperty; + export const enum ContextKeyExprType { False = 0, True = 1, @@ -138,7 +140,7 @@ export abstract class ContextKeyExpr { if (serializedOne.indexOf(' in ') >= 0) { let pieces = serializedOne.split(' in '); - return ContextKeyInExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); + return ContextKeyInExpr.create(pieces[0].trim(), pieces[1].trim()); } if (/^\!\s*/.test(serializedOne)) { @@ -451,8 +453,8 @@ export class ContextKeyInExpr implements IContextKeyExpression { return (source.indexOf(item) >= 0); } - if (typeof item === 'string' && typeof source === 'object' && source !== undefined && source !== null) { - return item in source; + if (typeof item === 'string' && typeof source === 'object' && source !== null) { + return hasOwnProperty.call(source, item); } return false; } @@ -462,7 +464,7 @@ export class ContextKeyInExpr implements IContextKeyExpression { } public keys(): string[] { - return [this.key]; + return [this.key, this.valueKey]; } public map(mapFnc: IContextKeyExprMapper): ContextKeyInExpr { diff --git a/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts index c7784c888e18b282e092bc2ff14e4d7befc1bef3..042012f1d3355e5638ad09b5e931833e842b4d68 100644 --- a/src/vs/platform/contextkey/test/common/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/common/contextkey.test.ts @@ -150,4 +150,19 @@ suite('ContextKeyExpr', () => { t('a || b', 'c && d', 'a && c && d || b && c && d'); t('a || b', 'c && d || e', 'a && e || b && e || a && c && d || b && c && d'); }); + + test('ContextKeyInExpr', () => { + const ainb = ContextKeyExpr.deserialize('a in b')!; + assert.equal(ainb.evaluate(createContext({ 'a': 3, 'b': [3, 2, 1] })), true); + assert.equal(ainb.evaluate(createContext({ 'a': 3, 'b': [1, 2, 3] })), true); + assert.equal(ainb.evaluate(createContext({ 'a': 3, 'b': [1, 2] })), false); + assert.equal(ainb.evaluate(createContext({ 'a': 3 })), false); + assert.equal(ainb.evaluate(createContext({ 'a': 3, 'b': null })), false); + assert.equal(ainb.evaluate(createContext({ 'a': 'x', 'b': ['x'] })), true); + assert.equal(ainb.evaluate(createContext({ 'a': 'x', 'b': ['y'] })), false); + assert.equal(ainb.evaluate(createContext({ 'a': 'x', 'b': {} })), false); + assert.equal(ainb.evaluate(createContext({ 'a': 'x', 'b': { 'x': false } })), true); + assert.equal(ainb.evaluate(createContext({ 'a': 'x', 'b': { 'x': true } })), true); + assert.equal(ainb.evaluate(createContext({ 'a': 'prototype', 'b': {} })), false); + }); });