diff --git a/packages/babel-plugin-transform-nullish-coalescing-operator/README.md b/packages/babel-plugin-transform-nullish-coalescing-operator/README.md index 8a399920b5..da80cf6e64 100644 --- a/packages/babel-plugin-transform-nullish-coalescing-operator/README.md +++ b/packages/babel-plugin-transform-nullish-coalescing-operator/README.md @@ -15,7 +15,7 @@ var foo = object.foo ?? "default"; ```javascript var _object$foo; -var foo = (_object$foo = object.foo, _object$foo !== null && _object$foo !== void 0 ? _object$foo : "default"); +var foo = (_object$foo = object.foo) !== null && _object$foo !== void 0 ? _object$foo : "default"; ``` > **NOTE:** We cannot use `!= null` here because `document.all == null` and @@ -52,3 +52,33 @@ require("@babel/core").transform("code", { plugins: ["transform-nullish-coalescing-operator"] }); ``` + +## Options + +### `loose` + +`boolean`, defaults to `false`. + +When `true`, this transform will pretend `document.all` does not exist, +and perform loose equality checks with `null` instead of string equality checks +against both `null` and `undefined`. + +#### Example + +**In** + +```javascript +var foo = object.foo ?? "default"; +``` + +**Out** + +```javascript +var _object$foo; + +var foo = (_object$foo = object.foo) != null ? _object$foo : "default"; +``` + +## References + +* [Proposal: Nullish Coalescing](https://github.com/tc39-transfer/proposal-nullish-coalescing) diff --git a/packages/babel-plugin-transform-nullish-coalescing-operator/src/index.js b/packages/babel-plugin-transform-nullish-coalescing-operator/src/index.js index d61fe1af49..dd567f3dad 100644 --- a/packages/babel-plugin-transform-nullish-coalescing-operator/src/index.js +++ b/packages/babel-plugin-transform-nullish-coalescing-operator/src/index.js @@ -1,6 +1,6 @@ import syntaxNullishCoalescingOperator from "@babel/plugin-syntax-nullish-coalescing-operator"; -export default function({ types: t }) { +export default function({ types: t }, { loose = false }) { return { inherits: syntaxNullishCoalescingOperator, @@ -14,25 +14,26 @@ export default function({ types: t }) { const ref = scope.generateUidIdentifierBasedOnNode(node.left); scope.push({ id: ref }); + const assignment = t.assignmentExpression("=", t.clone(ref), node.left); + path.replaceWith( - t.sequenceExpression([ - t.assignmentExpression("=", ref, node.left), - t.conditionalExpression( - // We cannot use `!= null` here because `document.all == null` - // and `document.all` has been deemed not "nullish". - t.logicalExpression( - "&&", - t.binaryExpression("!==", t.clone(ref), t.nullLiteral()), - t.binaryExpression( - "!==", - t.clone(ref), - scope.buildUndefinedNode(), + t.conditionalExpression( + // We cannot use `!= null` in spec mode because + // `document.all == null` and `document.all` is not "nullish". + loose + ? t.binaryExpression("!=", assignment, t.nullLiteral()) + : t.logicalExpression( + "&&", + t.binaryExpression("!==", assignment, t.nullLiteral()), + t.binaryExpression( + "!==", + t.clone(ref), + scope.buildUndefinedNode(), + ), ), - ), - t.clone(ref), - node.right, - ), - ]), + t.clone(ref), + node.right, + ), ); }, }, diff --git a/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-default/expected.js b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-default/expected.js index 236ab9c27b..303ed21599 100644 --- a/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-default/expected.js +++ b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-default/expected.js @@ -1,3 +1,3 @@ -function foo(foo, bar = (_foo = foo, _foo !== null && _foo !== void 0 ? _foo : "bar")) { +function foo(foo, bar = (_foo = foo) !== null && _foo !== void 0 ? _foo : "bar") { var _foo; } diff --git a/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-function/expected.js b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-function/expected.js index aa5ec8a47d..c90f8794b0 100644 --- a/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-function/expected.js +++ b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-in-function/expected.js @@ -1,5 +1,5 @@ function foo(opts) { var _opts$foo; - var foo = (_opts$foo = opts.foo, _opts$foo !== null && _opts$foo !== void 0 ? _opts$foo : "default"); + var foo = (_opts$foo = opts.foo) !== null && _opts$foo !== void 0 ? _opts$foo : "default"; } diff --git a/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/actual.js b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/actual.js new file mode 100644 index 0000000000..63b28b6c23 --- /dev/null +++ b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/actual.js @@ -0,0 +1,3 @@ +function foo(opts) { + var foo = opts.foo ?? "default"; +} diff --git a/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/expected.js b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/expected.js new file mode 100644 index 0000000000..ee76d1c950 --- /dev/null +++ b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/expected.js @@ -0,0 +1,5 @@ +function foo(opts) { + var _opts$foo; + + var foo = (_opts$foo = opts.foo) != null ? _opts$foo : "default"; +} diff --git a/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/options.json b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/options.json new file mode 100644 index 0000000000..4ca3c9d5c1 --- /dev/null +++ b/packages/babel-plugin-transform-nullish-coalescing-operator/test/fixtures/nullish-coalescing/transform-loose/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["transform-nullish-coalescing-operator", {"loose":true}]] +} diff --git a/packages/babel-plugin-transform-optional-chaining/README.md b/packages/babel-plugin-transform-optional-chaining/README.md index a0b10c19e0..2e12106c3c 100644 --- a/packages/babel-plugin-transform-optional-chaining/README.md +++ b/packages/babel-plugin-transform-optional-chaining/README.md @@ -113,6 +113,36 @@ require("@babel/core").transform("code", { }); ``` +## Options + +### `loose` + +`boolean`, defaults to `false`. + +When `true`, this transform will pretend `document.all` does not exist, +and perform loose equality checks with `null` instead of string equality checks +against both `null` and `undefined`. + +#### Example + +In + +```javascript +foo?.bar; +``` + +Out (`loose === true`) + +```javascript +foo == null ? void 0 : foo.bar; +``` + +Out (`loose === false`) + +```javascript +foo === null || foo === void 0 ? void 0 : foo.bar; +``` + ## References * [Proposal: Optional Chaining](https://github.com/tc39/proposal-optional-chaining)