From 2952d94e60a942aad198a1596d883a1008fc0498 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Tue, 28 Apr 2015 14:27:30 +0100 Subject: [PATCH] wrap instanceof to support @@hasInstance - fixes #1364 --- src/babel/transformation/file/index.js | 1 + .../templates/helper-instanceof.js | 7 +++++++ .../transformers/es6/spec.symbols.js | 12 +++++++++-- .../es6.spec.symbols/basic/expected.js | 6 ------ .../es6.spec.symbols/instanceof/actual.js | 1 + .../es6.spec.symbols/instanceof/exec.js | 21 +++++++++++++++++++ .../es6.spec.symbols/instanceof/expected.js | 3 +++ .../es6.spec.symbols/options.json | 1 + .../{basic => typeof}/actual.js | 1 + .../{basic => typeof}/exec.js | 0 .../es6.spec.symbols/typeof/expected.js | 5 +++++ 11 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/babel/transformation/templates/helper-instanceof.js delete mode 100644 test/core/fixtures/transformation/es6.spec.symbols/basic/expected.js create mode 100644 test/core/fixtures/transformation/es6.spec.symbols/instanceof/actual.js create mode 100644 test/core/fixtures/transformation/es6.spec.symbols/instanceof/exec.js create mode 100644 test/core/fixtures/transformation/es6.spec.symbols/instanceof/expected.js rename test/core/fixtures/transformation/es6.spec.symbols/{basic => typeof}/actual.js (55%) rename test/core/fixtures/transformation/es6.spec.symbols/{basic => typeof}/exec.js (100%) create mode 100644 test/core/fixtures/transformation/es6.spec.symbols/typeof/expected.js diff --git a/src/babel/transformation/file/index.js b/src/babel/transformation/file/index.js index 84dd7d66d5..d9df3fdb92 100644 --- a/src/babel/transformation/file/index.js +++ b/src/babel/transformation/file/index.js @@ -85,6 +85,7 @@ export default class File { "temporal-assert-defined", "self-global", "default-props", + "instanceof", // legacy "interop-require", diff --git a/src/babel/transformation/templates/helper-instanceof.js b/src/babel/transformation/templates/helper-instanceof.js new file mode 100644 index 0000000000..8ce6479f4a --- /dev/null +++ b/src/babel/transformation/templates/helper-instanceof.js @@ -0,0 +1,7 @@ +(function (left, right) { + if (right != null && right[Symbol.hasInstance]) { + return right[Symbol.hasInstance](left); + } else { + return left instanceof right; + } +}); diff --git a/src/babel/transformation/transformers/es6/spec.symbols.js b/src/babel/transformation/transformers/es6/spec.symbols.js index 61dc672266..29dcae36cf 100644 --- a/src/babel/transformation/transformers/es6/spec.symbols.js +++ b/src/babel/transformation/transformers/es6/spec.symbols.js @@ -5,14 +5,16 @@ export var metadata = { }; export function UnaryExpression(node, parent, scope, file) { - this.skip(); + if (node._ignoreSpecSymbols) return; if (node.operator === "typeof") { var call = t.callExpression(file.addHelper("typeof"), [node.argument]); if (this.get("argument").isIdentifier()) { var undefLiteral = t.literal("undefined"); + var unary = t.unaryExpression("typeof", node.argument); + unary._ignoreSpecSymbols = true; return t.conditionalExpression( - t.binaryExpression("===", t.unaryExpression("typeof", node.argument), undefLiteral), + t.binaryExpression("===", unary, undefLiteral), undefLiteral, call ); @@ -22,6 +24,12 @@ export function UnaryExpression(node, parent, scope, file) { } } +export function BinaryExpression(node, parent, scope, file) { + if (node.operator === "instanceof") { + return t.callExpression(file.addHelper("instanceof"), [node.left, node.right]); + } +} + export function VariableDeclaration(node) { if (node._generated) this.skip(); } diff --git a/test/core/fixtures/transformation/es6.spec.symbols/basic/expected.js b/test/core/fixtures/transformation/es6.spec.symbols/basic/expected.js deleted file mode 100644 index 1fda755031..0000000000 --- a/test/core/fixtures/transformation/es6.spec.symbols/basic/expected.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; - -var _typeof = function (obj) { return obj && obj.constructor === Symbol ? "symbol" : typeof obj; }; - -var s = Symbol("s"); -assert.equal(typeof s === "undefined" ? "undefined" : _typeof(s), "symbol"); \ No newline at end of file diff --git a/test/core/fixtures/transformation/es6.spec.symbols/instanceof/actual.js b/test/core/fixtures/transformation/es6.spec.symbols/instanceof/actual.js new file mode 100644 index 0000000000..ca9651d5fa --- /dev/null +++ b/test/core/fixtures/transformation/es6.spec.symbols/instanceof/actual.js @@ -0,0 +1 @@ +a instanceof b; diff --git a/test/core/fixtures/transformation/es6.spec.symbols/instanceof/exec.js b/test/core/fixtures/transformation/es6.spec.symbols/instanceof/exec.js new file mode 100644 index 0000000000..983cfd7503 --- /dev/null +++ b/test/core/fixtures/transformation/es6.spec.symbols/instanceof/exec.js @@ -0,0 +1,21 @@ +var foo = { [Symbol.hasInstance]: function () { return true; } }; +var bar = {}; + +assert.ok(bar instanceof foo); +assert.ok(new String instanceof String); + +// + +function Greeting(greeting) { + this.greeting = greeting; +} + +Greeting[Symbol.hasInstance] = function(inst) { + return inst.greeting == "hello"; +}; + +var a = new Greeting("hello"); +var b = new Greeting("world"); + +assert.ok(a instanceof Greeting); +assert.ok(!(b instanceof Greeting)); diff --git a/test/core/fixtures/transformation/es6.spec.symbols/instanceof/expected.js b/test/core/fixtures/transformation/es6.spec.symbols/instanceof/expected.js new file mode 100644 index 0000000000..4ddd47c253 --- /dev/null +++ b/test/core/fixtures/transformation/es6.spec.symbols/instanceof/expected.js @@ -0,0 +1,3 @@ +"use strict"; + +babelHelpers._instanceof(a, b); diff --git a/test/core/fixtures/transformation/es6.spec.symbols/options.json b/test/core/fixtures/transformation/es6.spec.symbols/options.json index 2d94fb1fb3..e007f6a10a 100644 --- a/test/core/fixtures/transformation/es6.spec.symbols/options.json +++ b/test/core/fixtures/transformation/es6.spec.symbols/options.json @@ -1,3 +1,4 @@ { + "externalHelpers": true, "optional": ["es6.spec.symbols"] } diff --git a/test/core/fixtures/transformation/es6.spec.symbols/basic/actual.js b/test/core/fixtures/transformation/es6.spec.symbols/typeof/actual.js similarity index 55% rename from test/core/fixtures/transformation/es6.spec.symbols/basic/actual.js rename to test/core/fixtures/transformation/es6.spec.symbols/typeof/actual.js index 20422ebc64..d31f30ca86 100644 --- a/test/core/fixtures/transformation/es6.spec.symbols/basic/actual.js +++ b/test/core/fixtures/transformation/es6.spec.symbols/typeof/actual.js @@ -1,2 +1,3 @@ var s = Symbol("s"); assert.equal(typeof s, "symbol"); +assert.equal(typeof typeof s.foo, "symbol"); diff --git a/test/core/fixtures/transformation/es6.spec.symbols/basic/exec.js b/test/core/fixtures/transformation/es6.spec.symbols/typeof/exec.js similarity index 100% rename from test/core/fixtures/transformation/es6.spec.symbols/basic/exec.js rename to test/core/fixtures/transformation/es6.spec.symbols/typeof/exec.js diff --git a/test/core/fixtures/transformation/es6.spec.symbols/typeof/expected.js b/test/core/fixtures/transformation/es6.spec.symbols/typeof/expected.js new file mode 100644 index 0000000000..80d011bc00 --- /dev/null +++ b/test/core/fixtures/transformation/es6.spec.symbols/typeof/expected.js @@ -0,0 +1,5 @@ +"use strict"; + +var s = Symbol("s"); +assert.equal(typeof s === "undefined" ? "undefined" : babelHelpers._typeof(s), "symbol"); +assert.equal(babelHelpers._typeof(babelHelpers._typeof(s.foo)), "symbol");