diff --git a/packages/babel-core/package.json b/packages/babel-core/package.json index 02a94c552f..785dd3a65b 100644 --- a/packages/babel-core/package.json +++ b/packages/babel-core/package.json @@ -32,7 +32,7 @@ "babel-template": "7.0.0-alpha.12", "babel-traverse": "7.0.0-alpha.12", "babel-types": "7.0.0-alpha.12", - "babylon": "7.0.0-beta.12", + "babylon": "7.0.0-beta.13", "convert-source-map": "^1.1.0", "debug": "^2.1.1", "json5": "^0.5.0", diff --git a/packages/babel-generator/package.json b/packages/babel-generator/package.json index 5b8d2f622e..ec5bf9846a 100644 --- a/packages/babel-generator/package.json +++ b/packages/babel-generator/package.json @@ -20,6 +20,6 @@ }, "devDependencies": { "babel-helper-fixtures": "7.0.0-alpha.12", - "babylon": "^7.0.0-beta.12" + "babylon": "^7.0.0-beta.13" } } diff --git a/packages/babel-generator/src/generators/expressions.js b/packages/babel-generator/src/generators/expressions.js index a3600f83b5..0f1a9d1651 100644 --- a/packages/babel-generator/src/generators/expressions.js +++ b/packages/babel-generator/src/generators/expressions.js @@ -51,11 +51,16 @@ export function NewExpression(node: Object, parent: Object) { this.word("new"); this.space(); this.print(node.callee, node); - if (node.arguments.length === 0 && this.format.minified && + if (this.format.minified && + node.arguments.length === 0 && + !node.optional && !t.isCallExpression(parent, { callee: node }) && !t.isMemberExpression(parent) && !t.isNewExpression(parent)) return; + if (node.optional) { + this.token("?."); + } this.token("("); this.printList(node.arguments, node); this.token(")"); @@ -89,6 +94,9 @@ function commaSeparatorNewline() { export function CallExpression(node: Object) { this.print(node.callee, node); + if (node.optional) { + this.token("?."); + } this.token("("); const isPrettyCall = node._prettyCall; @@ -203,12 +211,17 @@ export function MemberExpression(node: Object) { computed = true; } + if (node.optional) { + this.token("?."); + } if (computed) { this.token("["); this.print(node.property, node); this.token("]"); } else { - this.token("."); + if (!node.optional) { + this.token("."); + } this.print(node.property, node); } } diff --git a/packages/babel-generator/test/fixtures/types/Optional-CallExpression/actual.js b/packages/babel-generator/test/fixtures/types/Optional-CallExpression/actual.js new file mode 100644 index 0000000000..7bf538b249 --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/Optional-CallExpression/actual.js @@ -0,0 +1,39 @@ +foo?.(); +foo?.("foo"); +foo?.("foo", "bar"); +foo?.(bar()); +foo?.(bar("test")); +foo(bar?.()); +foo(bar?.("test")); + +a.foo?.(); +a.foo?.("foo"); +a.foo?.("foo", "bar"); +a.foo?.(bar()); +a.foo?.(bar("test")); +a.foo(bar?.()); +a.foo(bar?.("test")); + +a?.foo?.(); +a?.foo?.("foo"); +a?.foo?.("foo", "bar"); +a?.foo?.(bar()); +a?.foo?.(bar("test")); +a?.foo(bar?.()); +a?.foo(bar?.("test")); + +a.foo?.().baz; +a.foo?.("foo").baz; +a.foo?.("foo", "bar").baz; +a.foo?.(bar()).baz; +a.foo?.(bar("test")).baz; +a.foo(bar?.()).baz; +a.foo(bar?.("test")).baz; + +a.foo?.()?.baz; +a.foo?.("foo")?.baz; +a.foo?.("foo", "bar")?.baz; +a.foo?.(bar())?.baz; +a.foo?.(bar("test"))?.baz; +a.foo(bar?.())?.baz; +a.foo(bar?.("test"))?.baz; diff --git a/packages/babel-generator/test/fixtures/types/Optional-CallExpression/expected.js b/packages/babel-generator/test/fixtures/types/Optional-CallExpression/expected.js new file mode 100644 index 0000000000..7bf538b249 --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/Optional-CallExpression/expected.js @@ -0,0 +1,39 @@ +foo?.(); +foo?.("foo"); +foo?.("foo", "bar"); +foo?.(bar()); +foo?.(bar("test")); +foo(bar?.()); +foo(bar?.("test")); + +a.foo?.(); +a.foo?.("foo"); +a.foo?.("foo", "bar"); +a.foo?.(bar()); +a.foo?.(bar("test")); +a.foo(bar?.()); +a.foo(bar?.("test")); + +a?.foo?.(); +a?.foo?.("foo"); +a?.foo?.("foo", "bar"); +a?.foo?.(bar()); +a?.foo?.(bar("test")); +a?.foo(bar?.()); +a?.foo(bar?.("test")); + +a.foo?.().baz; +a.foo?.("foo").baz; +a.foo?.("foo", "bar").baz; +a.foo?.(bar()).baz; +a.foo?.(bar("test")).baz; +a.foo(bar?.()).baz; +a.foo(bar?.("test")).baz; + +a.foo?.()?.baz; +a.foo?.("foo")?.baz; +a.foo?.("foo", "bar")?.baz; +a.foo?.(bar())?.baz; +a.foo?.(bar("test"))?.baz; +a.foo(bar?.())?.baz; +a.foo(bar?.("test"))?.baz; diff --git a/packages/babel-generator/test/fixtures/types/Optional-MemberExpression/actual.js b/packages/babel-generator/test/fixtures/types/Optional-MemberExpression/actual.js new file mode 100644 index 0000000000..1c60f76870 --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/Optional-MemberExpression/actual.js @@ -0,0 +1,16 @@ +foo?.["bar"]; +foo?.bar; + +foo.bar?.foo; +foo?.bar.foo; +foo?.bar?.foo; +foo.bar?.["foo"]; +foo?.bar["foo"]; +foo?.bar?.["foo"]; +foo["bar"]?.foo; +foo?.["bar"].foo; +foo?.["bar"]?.foo; + +0.?.toString(); +0.5?.toString(); +1.000?.toString(); diff --git a/packages/babel-generator/test/fixtures/types/Optional-MemberExpression/expected.js b/packages/babel-generator/test/fixtures/types/Optional-MemberExpression/expected.js new file mode 100644 index 0000000000..1c60f76870 --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/Optional-MemberExpression/expected.js @@ -0,0 +1,16 @@ +foo?.["bar"]; +foo?.bar; + +foo.bar?.foo; +foo?.bar.foo; +foo?.bar?.foo; +foo.bar?.["foo"]; +foo?.bar["foo"]; +foo?.bar?.["foo"]; +foo["bar"]?.foo; +foo?.["bar"].foo; +foo?.["bar"]?.foo; + +0.?.toString(); +0.5?.toString(); +1.000?.toString(); diff --git a/packages/babel-generator/test/fixtures/types/Optional-NewExpression/actual.js b/packages/babel-generator/test/fixtures/types/Optional-NewExpression/actual.js new file mode 100644 index 0000000000..fe994af68f --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/Optional-NewExpression/actual.js @@ -0,0 +1,39 @@ +new foo?.(); +new foo?.("foo"); +new foo?.("foo", "bar"); +new foo?.(bar()); +new foo?.(bar("test")); +foo(new bar?.()); +foo(new bar?.("test")); + +new a.foo?.(); +new a.foo?.("foo"); +new a.foo?.("foo", "bar"); +new a.foo?.(bar()); +new a.foo?.(bar("test")); +a.foo(new bar?.()); +a.foo(new bar?.("test")); + +new a?.foo?.(); +new a?.foo?.("foo"); +new a?.foo?.("foo", "bar"); +new a?.foo?.(bar()); +new a?.foo?.(bar("test")); +a?.foo(new bar?.()); +a?.foo(new bar?.("test")); + +new a.foo?.().baz; +new a.foo?.("foo").baz; +new a.foo?.("foo", "bar").baz; +new a.foo?.(bar()).baz; +new a.foo?.(bar("test")).baz; +a.foo(new bar?.()).baz; +a.foo(new bar?.("test")).baz; + +new a.foo?.()?.baz; +new a.foo?.("foo")?.baz; +new a.foo?.("foo", "bar")?.baz; +new a.foo?.(bar())?.baz; +new a.foo?.(bar("test"))?.baz; +a.foo(new bar?.())?.baz; +a.foo(new bar?.("test"))?.baz; diff --git a/packages/babel-generator/test/fixtures/types/Optional-NewExpression/expected.js b/packages/babel-generator/test/fixtures/types/Optional-NewExpression/expected.js new file mode 100644 index 0000000000..fe994af68f --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/Optional-NewExpression/expected.js @@ -0,0 +1,39 @@ +new foo?.(); +new foo?.("foo"); +new foo?.("foo", "bar"); +new foo?.(bar()); +new foo?.(bar("test")); +foo(new bar?.()); +foo(new bar?.("test")); + +new a.foo?.(); +new a.foo?.("foo"); +new a.foo?.("foo", "bar"); +new a.foo?.(bar()); +new a.foo?.(bar("test")); +a.foo(new bar?.()); +a.foo(new bar?.("test")); + +new a?.foo?.(); +new a?.foo?.("foo"); +new a?.foo?.("foo", "bar"); +new a?.foo?.(bar()); +new a?.foo?.(bar("test")); +a?.foo(new bar?.()); +a?.foo(new bar?.("test")); + +new a.foo?.().baz; +new a.foo?.("foo").baz; +new a.foo?.("foo", "bar").baz; +new a.foo?.(bar()).baz; +new a.foo?.(bar("test")).baz; +a.foo(new bar?.()).baz; +a.foo(new bar?.("test")).baz; + +new a.foo?.()?.baz; +new a.foo?.("foo")?.baz; +new a.foo?.("foo", "bar")?.baz; +new a.foo?.(bar())?.baz; +new a.foo?.(bar("test"))?.baz; +a.foo(new bar?.())?.baz; +a.foo(new bar?.("test"))?.baz; diff --git a/packages/babel-generator/test/index.js b/packages/babel-generator/test/index.js index c0e0ec4584..54c107bcd5 100644 --- a/packages/babel-generator/test/index.js +++ b/packages/babel-generator/test/index.js @@ -318,6 +318,7 @@ suites.forEach(function (testSuite) { "functionSent", "jsx", "objectRestSpread", + "optionalChaining", ], strictMode: false, sourceType: "module", diff --git a/packages/babel-plugin-syntax-optional-chaining/.gitignore b/packages/babel-plugin-syntax-optional-chaining/.gitignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-syntax-optional-chaining/.gitignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-syntax-optional-chaining/.npmignore b/packages/babel-plugin-syntax-optional-chaining/.npmignore new file mode 100644 index 0000000000..f980694583 --- /dev/null +++ b/packages/babel-plugin-syntax-optional-chaining/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-syntax-optional-chaining/README.md b/packages/babel-plugin-syntax-optional-chaining/README.md new file mode 100644 index 0000000000..b18c1c25b3 --- /dev/null +++ b/packages/babel-plugin-syntax-optional-chaining/README.md @@ -0,0 +1,35 @@ +# babel-plugin-syntax-optional-chaining + +Allow parsing of optional properties. + +## Installation + +```sh +npm install --save-dev babel-plugin-syntax-optional-chaining +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["syntax-optional-chaining"] +} +``` + +### Via CLI + +```sh +babel --plugins syntax-optional-chaining script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["syntax-optional-chaining"] +}); +``` diff --git a/packages/babel-plugin-syntax-optional-chaining/index.js b/packages/babel-plugin-syntax-optional-chaining/index.js new file mode 100644 index 0000000000..37e4c8f53d --- /dev/null +++ b/packages/babel-plugin-syntax-optional-chaining/index.js @@ -0,0 +1,7 @@ +export default function () { + return { + manipulateOptions(opts, parserOpts) { + parserOpts.plugins.push("optionalChaining"); + }, + }; +} diff --git a/packages/babel-plugin-syntax-optional-chaining/package.json b/packages/babel-plugin-syntax-optional-chaining/package.json new file mode 100644 index 0000000000..39ea71318d --- /dev/null +++ b/packages/babel-plugin-syntax-optional-chaining/package.json @@ -0,0 +1,13 @@ +{ + "name": "babel-plugin-syntax-optional-chaining", + "version": "7.0.0-alpha.13", + "description": "Allow parsing of optional properties", + "repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-chaining", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": {}, + "devDependencies": {} +} diff --git a/packages/babel-plugin-transform-optional-chaining/.npmignore b/packages/babel-plugin-transform-optional-chaining/.npmignore new file mode 100644 index 0000000000..f980694583 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-transform-optional-chaining/README.md b/packages/babel-plugin-transform-optional-chaining/README.md new file mode 100644 index 0000000000..849b6d98a4 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/README.md @@ -0,0 +1,118 @@ +# babel-plugin-transform-optional-chaining + +The Optional Chaining Operator allows you to handle properties of deeply nested +objects without worrying about undefined intermediate objects. + +## Example + +### Accessing deeply nested properties + +```js +const obj = { + foo: { + bar: { + baz: 42, + }, + }, +}; + +const baz = obj?.foo?.bar?.baz; // 42 + +const safe = obj?.qux?.baz; // undefined + +// Optional chaining and normal chaining can be intermixed +obj?.foo.bar?.baz; // Only access `foo` if `obj` exists, and `baz` if + // `bar` exists +``` + +### Calling deeply nested functions + +```js +const obj = { + foo: { + bar: { + baz() { + return 42; + }, + }, + }, +}; + +const baz = obj?.foo?.bar?.baz(); // 42 + +const safe = obj?.qux?.baz(); // undefined +const safe2 = obj?.foo.bar.qux?.(); // undefined + +const willThrow = obj?.foo.bar.qux(); // Error: not a function + +// Top function can be called directly, too. +function test() { + return 42; +} +test?.(); // 42 + +exists?.(); // undefined +``` + +### Constructing deeply nested classes + +```js +const obj = { + foo: { + bar: { + baz: class { + }, + }, + }, +}; + +const baz = new obj?.foo?.bar?.baz(); // baz instance + +const safe = new obj?.qux?.baz(); // undefined +const safe2 = new obj?.foo.bar.qux?.(); // undefined + +const willThrow = new obj?.foo.bar.qux(); // Error: not a constructor + +// Top classes can be called directly, too. +class Test { +} +new Test?.(); // test instance + +new exists?.(); // undefined +``` + +## Installation + +```sh +npm install --save-dev babel-plugin-syntax-optional-chaining +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["syntax-optional-chaining"] +} +``` + +### Via CLI + +```sh +babel --plugins syntax-optional-chaining script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["syntax-optional-chaining"] +}); +``` + +## References + +* [Proposal: Optional Chaining](https://github.com/tc39/proposal-optional-chaining) diff --git a/packages/babel-plugin-transform-optional-chaining/package.json b/packages/babel-plugin-transform-optional-chaining/package.json new file mode 100644 index 0000000000..f77af6f2c6 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/package.json @@ -0,0 +1,17 @@ +{ + "name": "babel-plugin-transform-optional-chaining", + "version": "7.0.0-alpha.13", + "description": "Transform optional chaining operators into a series of nil checks", + "repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-optional-chaining", + "license": "MIT", + "main": "lib/index.js", + "dependencies": { + "babel-plugin-syntax-optional-chaining": "7.0.0-alpha.13" + }, + "keywords": [ + "babel-plugin" + ], + "devDependencies": { + "babel-helper-plugin-test-runner": "7.0.0-alpha.12" + } +} diff --git a/packages/babel-plugin-transform-optional-chaining/src/index.js b/packages/babel-plugin-transform-optional-chaining/src/index.js new file mode 100644 index 0000000000..a3db104e61 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/src/index.js @@ -0,0 +1,117 @@ +import syntaxOptionalChaining from "babel-plugin-syntax-optional-chaining"; + +export default function ({ types: t }) { + function optional(path, replacementPath, loose = false) { + const { scope } = path; + const optionals = []; + const nil = scope.buildUndefinedNode(); + + let objectPath = path; + while (objectPath.isMemberExpression() || objectPath.isCallExpression() || objectPath.isNewExpression()) { + const { node } = objectPath; + if (node.optional) { + optionals.push(node); + } + + if (objectPath.isMemberExpression()) { + objectPath = objectPath.get("object"); + } else { + objectPath = objectPath.get("callee"); + } + } + + for (let i = optionals.length - 1; i >= 0; i--) { + const node = optionals[i]; + node.optional = false; + + const isCall = t.isCallExpression(node); + const replaceKey = isCall || t.isNewExpression(node) ? "callee" : "object"; + const chain = node[replaceKey]; + + let ref; + let check; + if (loose && isCall) { + // If we are using a loose transform (avoiding a Function#call) and we are at the call, + // we can avoid a needless memoize. + check = ref = chain; + } else { + ref = scope.maybeGenerateMemoised(chain); + if (ref) { + check = t.assignmentExpression("=", ref, chain); + node[replaceKey] = ref; + } else { + check = ref = chain; + } + } + + // Ensure call expressions have the proper `this` + // `foo.bar()` has context `foo`. + if (isCall && t.isMemberExpression(chain)) { + if (loose) { + // To avoid a Function#call, we can instead re-grab the property from the context object. + // `a.?b.?()` translates roughly to `_a.b != null && _a.b()` + node.callee = chain; + } else { + // Otherwise, we need to memoize the context object, and change the call into a Function#call. + // `a.?b.?()` translates roughly to `(_b = _a.b) != null && _b.call(_a)` + const { object } = chain; + let context = scope.maybeGenerateMemoised(object); + if (context) { + chain.object = t.assignmentExpression("=", context, object); + } else { + context = object; + } + + node.arguments.unshift(context); + node.callee = t.memberExpression(node.callee, t.identifier("call")); + } + } + + replacementPath.replaceWith(t.conditionalExpression( + t.binaryExpression("==", check, t.nullLiteral()), + nil, + replacementPath.node + )); + + replacementPath = replacementPath.get("alternate"); + } + } + + function findReplacementPath(path) { + return path.find((path) => { + const { parentPath } = path; + + if (path.key == "left" && parentPath.isAssignmentExpression()) { + return false; + } + if (path.key == "object" && parentPath.isMemberExpression()) { + return false; + } + if (path.key == "callee" && (parentPath.isCallExpression() || parentPath.isNewExpression())) { + return false; + } + if (path.key == "argument" && parentPath.isUpdateExpression()) { + return false; + } + if (path.key == "argument" && parentPath.isUnaryExpression({ operator: "delete" })) { + return false; + } + + return true; + }); + } + + return { + inherits: syntaxOptionalChaining, + + visitor: { + "MemberExpression|NewExpression|CallExpression"(path) { + if (!path.node.optional) { + return; + } + + optional(path, findReplacementPath(path), this.opts.loose); + }, + }, + }; +} diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/assignment-left.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/assignment-left.js new file mode 100644 index 0000000000..e9ae376fef --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/assignment-left.js @@ -0,0 +1,16 @@ +"use strict"; + +const obj = { + a: { + b: 0, + }, +}; + +obj?.a.b = 1; +assert.equal(obj.a.b, 1); + +obj?.a?.b = 2; +assert.equal(obj.a.b, 2); + +obj?.b?.b = 3; +assert.equal(obj.b, undefined); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/assignment-right.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/assignment-right.js new file mode 100644 index 0000000000..58d99d7927 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/assignment-right.js @@ -0,0 +1,28 @@ +"use strict"; + +const obj = { + a: { + b: { + c: { + d: 2, + }, + }, + }, +}; + +const a = obj?.a; +assert.equal(a, obj.a); + +const b = obj?.a?.b; +assert.equal(b, obj.a.b); + +const bad = obj?.b?.b; +assert.equal(bad, undefined); + +let val; +val = obj?.a?.b; +assert.equal(val, obj.a.b); + +assert.throws(() => { + const bad = obj?.b.b; +}); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/call.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/call.js new file mode 100644 index 0000000000..b3c044c519 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/call.js @@ -0,0 +1,63 @@ +"use strict"; + +let calls = 0; +const obj = { + a: { + b(val) { + assert.equal(val, 1); + assert.equal(this, obj.a); + return calls++; + }, + }, + c(val) { + assert.equal(val, 1); + assert.equal(this, obj); + return calls++; + }, +}; + +let ab = obj?.a?.b(1); +assert.equal(ab, 0); + +ab = obj?.a.b(1); +assert.equal(ab, 1); + +ab = obj?.a?.b?.(1); +assert.equal(ab, 2); + +ab = obj?.a.b?.(1); +assert.equal(ab, 3); + +ab = obj?.b?.b(1); +assert.equal(ab, undefined); + +ab = obj?.b?.b?.(1); +assert.equal(ab, undefined); + +let c = obj?.c(1); +assert.equal(c, 4); + +c = obj?.c?.(1); +assert.equal(c, 5); + +c = obj?.d?.(1); +assert.equal(c, undefined); + +obj?.a.b(1); +assert.equal(calls, 7); + +obj?.a?.b(1); +assert.equal(calls, 8); + +obj?.a?.b?.(1); +assert.equal(calls, 9); + +obj?.a.b?.(1); +assert.equal(calls, 10); + +obj?.c?.(1); +assert.equal(calls, 11); + +obj?.b?.b(1); +obj?.b?.b?.(1); +obj?.d?.(1); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/delete.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/delete.js new file mode 100644 index 0000000000..a397021233 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/delete.js @@ -0,0 +1,22 @@ +"use strict"; + +const obj = { + a: { + b: 0, + }, +}; + +let test = delete obj?.a?.b; +assert.equal(obj.a.b, undefined); +assert.equal(test, true); + +test = delete obj?.a.b; +assert.equal(obj.a.b, undefined); +assert.equal(test, true); + +test = delete obj?.b?.b; +assert.equal(obj.b, undefined); +assert.equal(test, undefined); + +delete obj?.a; +assert.equal(obj.a, undefined); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/new.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/new.js new file mode 100644 index 0000000000..184524f49e --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/new.js @@ -0,0 +1,67 @@ +"use strict"; + +let calls = 0; +const obj = { + a: { + b: class { + constructor(val) { + assert.equal(val, 1); + assert(this instanceof obj.a.b); + calls++; + } + }, + }, + c: class { + constructor(val) { + assert.equal(val, 1); + assert(this instanceof obj.c); + calls++; + } + }, +}; + +let ab = new obj?.a?.b(1); +assert(ab instanceof obj.a.b); + +ab = new obj?.a.b(1); +assert(ab instanceof obj.a.b); + +ab = new obj?.a?.b?.(1); +assert(ab instanceof obj.a.b); + +ab = new obj?.a.b?.(1); +assert(ab instanceof obj.a.b); + +ab = new obj?.b?.b(1); +assert.equal(ab, undefined); + +ab = new obj?.b?.b?.(1); +assert.equal(ab, undefined); + +let c = new obj?.c(1); +assert(c instanceof obj.c); + +c = new obj?.c?.(1); +assert(c instanceof obj.c); + +c = new obj?.d?.(1); +assert.equal(c, undefined); + +new obj?.a.b(1); +assert.equal(calls, 7); + +new obj?.a?.b(1); +assert.equal(calls, 8); + +new obj?.a?.b?.(1); +assert.equal(calls, 9); + +new obj?.a.b?.(1); +assert.equal(calls, 10); + +new obj?.c?.(1); +assert.equal(calls, 11); + +new obj?.b?.b(1); +new obj?.b?.b?.(1); +new obj?.d?.(1); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/unary.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/unary.js new file mode 100644 index 0000000000..f8a55d8646 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/unary.js @@ -0,0 +1,19 @@ +"use strict"; + +const obj = { + a: { + b: 0, + }, +}; + +let test = +obj?.a?.b; +assert.equal(test, 0); + +test = +obj?.a.b; +assert.equal(test, 0); + +test = +obj?.b?.b; +assert.isNaN(test); + +test = +obj?.b?.b; +assert.isNaN(test); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/update.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/update.js new file mode 100644 index 0000000000..320a8c75e0 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/execute/update.js @@ -0,0 +1,16 @@ +"use strict"; + +const obj = { + a: { + b: 0, + }, +}; + +obj?.a.b++; +assert.equal(obj.a.b, 1); + +obj?.a?.b++; +assert.equal(obj.a.b, 2); + +obj?.b?.b++; +assert.equal(obj.b, undefined); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/assignement/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/assignement/actual.js new file mode 100644 index 0000000000..b7d9cee953 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/assignement/actual.js @@ -0,0 +1,7 @@ +a?.b = 42 + +a?.b?.c?.d = 42 + +a?.b?.c?.d++ + +a?.b?.c?.d += 1 diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/assignement/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/assignement/expected.js new file mode 100644 index 0000000000..5670c0f0e1 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/assignement/expected.js @@ -0,0 +1,9 @@ +var _a, _a2, _a2$b, _a2$b$c, _a3, _a3$b, _a3$b$c, _a4, _a4$b, _a4$b$c; + +(_a = a) == null ? void 0 : _a.b = 42; + +(_a2 = a) == null ? void 0 : (_a2$b = _a2.b) == null ? void 0 : (_a2$b$c = _a2$b.c) == null ? void 0 : _a2$b$c.d = 42; + +(_a3 = a) == null ? void 0 : (_a3$b = _a3.b) == null ? void 0 : (_a3$b$c = _a3$b.c) == null ? void 0 : _a3$b$c.d++; + +(_a4 = a) == null ? void 0 : (_a4$b = _a4.b) == null ? void 0 : (_a4$b$c = _a4$b.c) == null ? void 0 : _a4$b$c.d += 1; \ No newline at end of file diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/containers/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/containers/actual.js new file mode 100644 index 0000000000..d699b16fa1 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/containers/actual.js @@ -0,0 +1,6 @@ +var street = user.address?.street +street = user.address?.street + +test(a?.b, 1); + +(1, a?.b, 2); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/containers/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/containers/expected.js new file mode 100644 index 0000000000..b0dc489b21 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/containers/expected.js @@ -0,0 +1,8 @@ +var _user$address, _user$address2, _a, _a2; + +var street = (_user$address = user.address) == null ? void 0 : _user$address.street; +street = (_user$address2 = user.address) == null ? void 0 : _user$address2.street; + +test((_a = a) == null ? void 0 : _a.b, 1); + +1, (_a2 = a) == null ? void 0 : _a2.b, 2; \ No newline at end of file diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/delete/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/delete/actual.js new file mode 100644 index 0000000000..e75af35f7f --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/delete/actual.js @@ -0,0 +1,3 @@ +delete a?.b + +delete a?.b?.c?.d diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/delete/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/delete/expected.js new file mode 100644 index 0000000000..a005adc52f --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/delete/expected.js @@ -0,0 +1,5 @@ +var _a, _a2, _a2$b, _a2$b$c; + +(_a = a) == null ? void 0 : delete _a.b; + +(_a2 = a) == null ? void 0 : (_a2$b = _a2.b) == null ? void 0 : (_a2$b$c = _a2$b.c) == null ? void 0 : delete _a2$b$c.d; diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/actual.js new file mode 100644 index 0000000000..9499c5f20e --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/actual.js @@ -0,0 +1,7 @@ +foo?.(foo); + +foo?.bar() + +foo.bar?.(foo.bar, false) + +foo?.bar?.(foo.bar, true) diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/expected.js new file mode 100644 index 0000000000..7c40785d92 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/expected.js @@ -0,0 +1,9 @@ +var _foo, _foo2; + +foo == null ? void 0 : foo(foo); + +(_foo = foo) == null ? void 0 : _foo.bar(); + +foo.bar == null ? void 0 : foo.bar(foo.bar, false); + +(_foo2 = foo) == null ? void 0 : _foo2.bar == null ? void 0 : _foo2.bar(foo.bar, true); diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/options.json b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/options.json new file mode 100644 index 0000000000..acc83616f9 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call-loose/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["transform-optional-chaining", {"loose": true}]] +} diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call/actual.js new file mode 100644 index 0000000000..51882eacf6 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call/actual.js @@ -0,0 +1,19 @@ +foo?.(foo); + +foo?.bar() + +foo.bar?.(foo.bar, false) + +foo?.bar?.(foo.bar, true) + +foo?.().bar + +foo?.()?.bar + +foo.bar?.().baz + +foo.bar?.()?.baz + +foo?.bar?.().baz + +foo?.bar?.()?.baz diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call/expected.js new file mode 100644 index 0000000000..297241cb9f --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/function-call/expected.js @@ -0,0 +1,21 @@ +var _foo, _foo2, _foo$bar, _foo3, _foo4, _foo4$bar, _foo5, _foo6, _foo7, _foo$bar2, _foo8, _foo$bar3, _foo9, _foo$bar3$call, _foo10, _foo10$bar, _foo11, _foo11$bar, _foo11$bar$call; + +(_foo = foo) == null ? void 0 : _foo(foo); + +(_foo2 = foo) == null ? void 0 : _foo2.bar(); + +(_foo$bar = (_foo3 = foo).bar) == null ? void 0 : _foo$bar.call(_foo3, foo.bar, false); + +(_foo4 = foo) == null ? void 0 : (_foo4$bar = _foo4.bar) == null ? void 0 : _foo4$bar.call(_foo4, foo.bar, true); + +(_foo5 = foo) == null ? void 0 : _foo5().bar; + +(_foo6 = foo) == null ? void 0 : (_foo7 = _foo6()) == null ? void 0 : _foo7.bar; + +(_foo$bar2 = (_foo8 = foo).bar) == null ? void 0 : _foo$bar2.call(_foo8).baz; + +(_foo$bar3 = (_foo9 = foo).bar) == null ? void 0 : (_foo$bar3$call = _foo$bar3.call(_foo9)) == null ? void 0 : _foo$bar3$call.baz; + +(_foo10 = foo) == null ? void 0 : (_foo10$bar = _foo10.bar) == null ? void 0 : _foo10$bar.call(_foo10).baz; + +(_foo11 = foo) == null ? void 0 : (_foo11$bar = _foo11.bar) == null ? void 0 : (_foo11$bar$call = _foo11$bar.call(_foo11)) == null ? void 0 : _foo11$bar$call.baz; \ No newline at end of file diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/actual.js new file mode 100644 index 0000000000..23c228afe6 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/actual.js @@ -0,0 +1,19 @@ +foo?.bar; + +a?.b.c?.d.e; + +a.b?.c.d?.e; + +a.b.c?.d?.e; + +orders?.[0].price; + +orders?.[0]?.price; + +orders[client?.key].price; + +orders[client.key]?.price; + +(0, a?.b).c; + +(0, (0, a?.b).c?.d).e; diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/expected.js new file mode 100644 index 0000000000..1e82625c57 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/expected.js @@ -0,0 +1,21 @@ +var _foo, _a, _a$b$c, _a$b, _a$b$c$d, _a$b$c2, _a$b$c2$d, _orders, _orders2, _orders2$, _client, _orders$client$key, _a2, _c, _a3; + +(_foo = foo) == null ? void 0 : _foo.bar; + +(_a = a) == null ? void 0 : (_a$b$c = _a.b.c) == null ? void 0 : _a$b$c.d.e; + +(_a$b = a.b) == null ? void 0 : (_a$b$c$d = _a$b.c.d) == null ? void 0 : _a$b$c$d.e; + +(_a$b$c2 = a.b.c) == null ? void 0 : (_a$b$c2$d = _a$b$c2.d) == null ? void 0 : _a$b$c2$d.e; + +(_orders = orders) == null ? void 0 : _orders[0].price; + +(_orders2 = orders) == null ? void 0 : (_orders2$ = _orders2[0]) == null ? void 0 : _orders2$.price; + +orders[(_client = client) == null ? void 0 : _client.key].price; + +(_orders$client$key = orders[client.key]) == null ? void 0 : _orders$client$key.price; + +(0, (_a2 = a) == null ? void 0 : _a2.b).c; + +(0, (_c = (0, (_a3 = a) == null ? void 0 : _a3.b).c) == null ? void 0 : _c.d).e; diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/actual.js new file mode 100644 index 0000000000..ffe543adde --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/actual.js @@ -0,0 +1,21 @@ +function test(foo) { + foo?.bar; + + foo?.bar?.baz; + + foo?.(foo); + + foo?.bar() + + foo.bar?.(foo.bar, false) + + foo?.bar?.(foo.bar, true) + + foo.bar?.baz(foo.bar, false) + + foo?.bar?.baz(foo.bar, true) + + foo.bar?.baz?.(foo.bar, false) + + foo?.bar?.baz?.(foo.bar, true) +} diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/expected.js new file mode 100644 index 0000000000..66f4809d09 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/expected.js @@ -0,0 +1,23 @@ +function test(foo) { + var _foo$bar, _foo$bar2, _foo$bar3, _foo$bar4, _foo$bar5; + + foo == null ? void 0 : foo.bar; + + foo == null ? void 0 : (_foo$bar = foo.bar) == null ? void 0 : _foo$bar.baz; + + foo == null ? void 0 : foo(foo); + + foo == null ? void 0 : foo.bar(); + + foo.bar == null ? void 0 : foo.bar(foo.bar, false); + + foo == null ? void 0 : foo.bar == null ? void 0 : foo.bar(foo.bar, true); + + (_foo$bar2 = foo.bar) == null ? void 0 : _foo$bar2.baz(foo.bar, false); + + foo == null ? void 0 : (_foo$bar3 = foo.bar) == null ? void 0 : _foo$bar3.baz(foo.bar, true); + + (_foo$bar4 = foo.bar) == null ? void 0 : _foo$bar4.baz == null ? void 0 : _foo$bar4.baz(foo.bar, false); + + foo == null ? void 0 : (_foo$bar5 = foo.bar) == null ? void 0 : _foo$bar5.baz == null ? void 0 : _foo$bar5.baz(foo.bar, true); +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/options.json b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/options.json new file mode 100644 index 0000000000..acc83616f9 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize-loose/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["transform-optional-chaining", {"loose": true}]] +} diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize/actual.js new file mode 100644 index 0000000000..ffe543adde --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize/actual.js @@ -0,0 +1,21 @@ +function test(foo) { + foo?.bar; + + foo?.bar?.baz; + + foo?.(foo); + + foo?.bar() + + foo.bar?.(foo.bar, false) + + foo?.bar?.(foo.bar, true) + + foo.bar?.baz(foo.bar, false) + + foo?.bar?.baz(foo.bar, true) + + foo.bar?.baz?.(foo.bar, false) + + foo?.bar?.baz?.(foo.bar, true) +} diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize/expected.js new file mode 100644 index 0000000000..2e24fb6f41 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/memoize/expected.js @@ -0,0 +1,23 @@ +function test(foo) { + var _foo$bar, _foo$bar2, _foo$bar3, _foo$bar4, _foo$bar5, _foo$bar6, _foo$bar6$baz, _foo$bar7, _foo$bar7$baz; + + foo == null ? void 0 : foo.bar; + + foo == null ? void 0 : (_foo$bar = foo.bar) == null ? void 0 : _foo$bar.baz; + + foo == null ? void 0 : foo(foo); + + foo == null ? void 0 : foo.bar(); + + (_foo$bar2 = foo.bar) == null ? void 0 : _foo$bar2.call(foo, foo.bar, false); + + foo == null ? void 0 : (_foo$bar3 = foo.bar) == null ? void 0 : _foo$bar3.call(foo, foo.bar, true); + + (_foo$bar4 = foo.bar) == null ? void 0 : _foo$bar4.baz(foo.bar, false); + + foo == null ? void 0 : (_foo$bar5 = foo.bar) == null ? void 0 : _foo$bar5.baz(foo.bar, true); + + (_foo$bar6 = foo.bar) == null ? void 0 : (_foo$bar6$baz = _foo$bar6.baz) == null ? void 0 : _foo$bar6$baz.call(_foo$bar6, foo.bar, false); + + foo == null ? void 0 : (_foo$bar7 = foo.bar) == null ? void 0 : (_foo$bar7$baz = _foo$bar7.baz) == null ? void 0 : _foo$bar7$baz.call(_foo$bar7, foo.bar, true); +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/new/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/new/actual.js new file mode 100644 index 0000000000..a42e650ea4 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/new/actual.js @@ -0,0 +1,16 @@ +new a?.b +new a?.b?.c?.d + +new a?.b() +new a?.b?.c?.d() + +new b?.(b) +new a?.b?.(a.b, true) + +new b?.().c +new b?.()?.c + +new a.b?.().c +new a.b?.()?.c +new a?.b?.().c +new a?.b?.()?.c diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/new/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/new/expected.js new file mode 100644 index 0000000000..7c22a8bc0d --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/new/expected.js @@ -0,0 +1,18 @@ +var _a, _a2, _a2$b, _a2$b$c, _a3, _a4, _a4$b, _a4$b$c, _b, _a5, _a5$b, _b2, _b3, _ref, _a$b, _a$b2, _ref2, _a6, _a6$b, _a7, _a7$b, _ref3; + +(_a = a) == null ? void 0 : new _a.b(); +(_a2 = a) == null ? void 0 : (_a2$b = _a2.b) == null ? void 0 : (_a2$b$c = _a2$b.c) == null ? void 0 : new _a2$b$c.d(); + +(_a3 = a) == null ? void 0 : new _a3.b(); +(_a4 = a) == null ? void 0 : (_a4$b = _a4.b) == null ? void 0 : (_a4$b$c = _a4$b.c) == null ? void 0 : new _a4$b$c.d(); + +(_b = b) == null ? void 0 : new _b(b); +(_a5 = a) == null ? void 0 : (_a5$b = _a5.b) == null ? void 0 : new _a5$b(a.b, true); + +(_b2 = b) == null ? void 0 : new _b2().c; +(_b3 = b) == null ? void 0 : (_ref = new _b3()) == null ? void 0 : _ref.c; + +(_a$b = a.b) == null ? void 0 : new _a$b().c; +(_a$b2 = a.b) == null ? void 0 : (_ref2 = new _a$b2()) == null ? void 0 : _ref2.c; +(_a6 = a) == null ? void 0 : (_a6$b = _a6.b) == null ? void 0 : new _a6$b().c; +(_a7 = a) == null ? void 0 : (_a7$b = _a7.b) == null ? void 0 : (_ref3 = new _a7$b()) == null ? void 0 : _ref3.c; \ No newline at end of file diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/options.json b/packages/babel-plugin-transform-optional-chaining/test/fixtures/options.json new file mode 100644 index 0000000000..846cf98412 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["transform-optional-chaining"] +} diff --git a/packages/babel-plugin-transform-optional-chaining/test/index.js b/packages/babel-plugin-transform-optional-chaining/test/index.js new file mode 100644 index 0000000000..09cfbc31f5 --- /dev/null +++ b/packages/babel-plugin-transform-optional-chaining/test/index.js @@ -0,0 +1,3 @@ +import runner from "babel-helper-plugin-test-runner"; + +runner(__dirname); diff --git a/packages/babel-preset-stage-1/package.json b/packages/babel-preset-stage-1/package.json index fcbe9d4838..e173b22fcc 100644 --- a/packages/babel-preset-stage-1/package.json +++ b/packages/babel-preset-stage-1/package.json @@ -11,6 +11,7 @@ "babel-plugin-transform-decorators": "7.0.0-alpha.12", "babel-plugin-transform-export-extensions": "7.0.0-alpha.12", "babel-plugin-transform-numeric-separator": "7.0.0-alpha.12", + "babel-plugin-transform-optional-chaining": "7.0.0-alpha.13", "babel-preset-stage-2": "7.0.0-alpha.12" } } diff --git a/packages/babel-preset-stage-1/src/index.js b/packages/babel-preset-stage-1/src/index.js index fd1be2d539..5a6e69a320 100644 --- a/packages/babel-preset-stage-1/src/index.js +++ b/packages/babel-preset-stage-1/src/index.js @@ -3,6 +3,7 @@ import presetStage2 from "babel-preset-stage-2"; import transformDecorators from "babel-plugin-transform-decorators"; import transformExportExtensions from "babel-plugin-transform-export-extensions"; import transformNumericSeparator from "babel-plugin-transform-numeric-separator"; +import transformOptionalChaining from "babel-plugin-transform-optional-chaining"; export default function () { return { @@ -13,6 +14,7 @@ export default function () { transformDecorators, transformExportExtensions, transformNumericSeparator, + transformOptionalChaining, ], }; } diff --git a/packages/babel-template/package.json b/packages/babel-template/package.json index 329b478c40..8825eb9b5d 100644 --- a/packages/babel-template/package.json +++ b/packages/babel-template/package.json @@ -10,7 +10,7 @@ "dependencies": { "babel-traverse": "7.0.0-alpha.12", "babel-types": "7.0.0-alpha.12", - "babylon": "7.0.0-beta.12", + "babylon": "7.0.0-beta.13", "lodash": "^4.2.0" } } diff --git a/packages/babel-traverse/package.json b/packages/babel-traverse/package.json index 12352ea083..a536ed3f90 100644 --- a/packages/babel-traverse/package.json +++ b/packages/babel-traverse/package.json @@ -12,7 +12,7 @@ "babel-helper-function-name": "7.0.0-alpha.12", "babel-messages": "7.0.0-alpha.12", "babel-types": "7.0.0-alpha.12", - "babylon": "7.0.0-beta.12", + "babylon": "7.0.0-beta.13", "debug": "^2.2.0", "globals": "^9.0.0", "invariant": "^2.2.0", diff --git a/packages/babel-types/package.json b/packages/babel-types/package.json index 0a70a3b843..a3208469fd 100644 --- a/packages/babel-types/package.json +++ b/packages/babel-types/package.json @@ -14,6 +14,6 @@ }, "devDependencies": { "babel-generator": "7.0.0-alpha.12", - "babylon": "^7.0.0-beta.12" + "babylon": "^7.0.0-beta.13" } } diff --git a/packages/babel-types/src/definitions/core.js b/packages/babel-types/src/definitions/core.js index 02572c87b5..d72feba5e3 100644 --- a/packages/babel-types/src/definitions/core.js +++ b/packages/babel-types/src/definitions/core.js @@ -119,6 +119,10 @@ defineType("CallExpression", { arguments: { validate: chain(assertValueType("array"), assertEach(assertNodeType("Expression", "SpreadElement"))), }, + optional: { + validate: assertOneOf(true, false), + optional: true, + }, }, aliases: ["Expression"], }); @@ -416,7 +420,7 @@ defineType("LogicalExpression", { }); defineType("MemberExpression", { - builder: ["object", "property", "computed"], + builder: ["object", "property", "computed", "optional"], visitor: ["object", "property"], aliases: ["Expression", "LVal"], fields: { @@ -437,6 +441,10 @@ defineType("MemberExpression", { computed: { default: false, }, + optional: { + validate: assertOneOf(true, false), + optional: true, + }, }, }); @@ -450,6 +458,10 @@ defineType("NewExpression", { arguments: { validate: chain(assertValueType("array"), assertEach(assertNodeType("Expression", "SpreadElement"))), }, + optional: { + validate: assertOneOf(true, false), + optional: true, + }, }, });