diff --git a/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelignore/options.json b/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelignore/options.json index 39e3d0dc2606..c328b7ff8d23 100644 --- a/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelignore/options.json +++ b/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelignore/options.json @@ -1,9 +1,3 @@ { - "args": [ - "src", - "--out-dir", - "lib", - "--copy-files", - "--verbose" - ] + "args": ["src", "--out-dir", "lib", "--copy-files", "--verbose"] } diff --git a/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelrc/options.json b/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelrc/options.json index 39e3d0dc2606..c328b7ff8d23 100644 --- a/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelrc/options.json +++ b/packages/babel-cli/test/fixtures/babel/--copy-files with ignore in babelrc/options.json @@ -1,9 +1,3 @@ { - "args": [ - "src", - "--out-dir", - "lib", - "--copy-files", - "--verbose" - ] + "args": ["src", "--out-dir", "lib", "--copy-files", "--verbose"] } diff --git a/packages/babel-cli/test/fixtures/babel/--minified/options.json b/packages/babel-cli/test/fixtures/babel/--minified/options.json index 2df8c827b826..90d89bbbccdb 100644 --- a/packages/babel-cli/test/fixtures/babel/--minified/options.json +++ b/packages/babel-cli/test/fixtures/babel/--minified/options.json @@ -1,3 +1,9 @@ { - "args": ["--out-file", "script2.js", "--no-comments", "--minified", "script.js"] + "args": [ + "--out-file", + "script2.js", + "--no-comments", + "--minified", + "script.js" + ] } diff --git a/packages/babel-helper-create-class-features-plugin/src/features.js b/packages/babel-helper-create-class-features-plugin/src/features.js index 4fc528bff185..06f6570f81fe 100644 --- a/packages/babel-helper-create-class-features-plugin/src/features.js +++ b/packages/babel-helper-create-class-features-plugin/src/features.js @@ -5,6 +5,7 @@ export const FEATURES = Object.freeze({ fields: 1 << 1, privateMethods: 1 << 2, decorators: 1 << 3, + privateIn: 1 << 4, }); // We can't use a symbol because this needs to always be the same, even if @@ -28,6 +29,39 @@ export function enableFeature(file, feature, loose) { file.set(featuresKey, file.get(featuresKey) | feature); if (loose) file.set(looseKey, file.get(looseKey) | feature); } + + if ( + hasFeature(file, FEATURES.fields) && + hasFeature(file, FEATURES.privateMethods) && + isLoose(file, FEATURES.fields) !== isLoose(file, FEATURES.privateMethods) + ) { + throw new Error( + "'loose' mode configuration must be the same for both @babel/plugin-proposal-class-properties " + + "and @babel/plugin-proposal-private-methods", + ); + } + + if ( + hasFeature(file, FEATURES.fields) && + hasFeature(file, FEATURES.privateIn) && + isLoose(file, FEATURES.fields) !== isLoose(file, FEATURES.privateIn) + ) { + throw new Error( + "'loose' mode configuration must be the same for both @babel/plugin-proposal-class-properties " + + "and @babel/plugin-proposal-private-property-in-object", + ); + } + + if ( + hasFeature(file, FEATURES.privateMethods) && + hasFeature(file, FEATURES.privateIn) && + isLoose(file, FEATURES.privateMethods) !== isLoose(file, FEATURES.privateIn) + ) { + throw new Error( + "'loose' mode configuration must be the same for both @babel/plugin-proposal-private-methods " + + "and @babel/plugin-proposal-private-property-in-object", + ); + } } function hasFeature(file, feature) { @@ -69,14 +103,17 @@ export function verifyUsedFeatures(path, file) { } if ( - hasFeature(file, FEATURES.privateMethods) && - hasFeature(file, FEATURES.fields) && - isLoose(file, FEATURES.privateMethods) !== isLoose(file, FEATURES.fields) + path.isPrivateName() && + path.parentPath.isBinaryExpression({ + operator: "in", + left: path.node, + }) ) { - throw path.buildCodeFrameError( - "'loose' mode configuration must be the same for both @babel/plugin-proposal-class-properties " + - "and @babel/plugin-proposal-private-methods", - ); + if (!hasFeature(file, FEATURES.privateIn)) { + throw path.buildCodeFrameError( + "Private property in checks are not enabled.", + ); + } } if (path.isProperty()) { diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 504cf807e68f..566458b1c585 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -70,69 +70,104 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) { // Traverses the class scope, handling private name references. If an inner // class redeclares the same private name, it will hand off traversal to the // restricted visitor (which doesn't traverse the inner class's inner scope). -const privateNameVisitor = { +function privateNameVisitorFactory(visitor) { + const privateNameVisitor = { + ...visitor, + + Class(path) { + const { privateNamesMap } = this; + const body = path.get("body.body"); + + const visiblePrivateNames = new Map(privateNamesMap); + const redeclared = []; + for (const prop of body) { + if (!prop.isPrivate()) continue; + const { name } = prop.node.key.id; + visiblePrivateNames.delete(name); + redeclared.push(name); + } + + // If the class doesn't redeclare any private fields, we can continue with + // our overall traversal. + if (!redeclared.length) { + return; + } + + // This class redeclares some private field. We need to process the outer + // environment with access to all the outer privates, then we can process + // the inner environment with only the still-visible outer privates. + path.get("body").traverse(nestedVisitor, { + ...this, + redeclared, + }); + path.traverse(privateNameVisitor, { + ...this, + privateNamesMap: visiblePrivateNames, + }); + + // We'll eventually hit this class node again with the overall Class + // Features visitor, which'll process the redeclared privates. + path.skipKey("body"); + }, + }; + + // Traverses the outer portion of a class, without touching the class's inner + // scope, for private names. + const nestedVisitor = traverse.visitors.merge([ + { + ...visitor, + }, + environmentVisitor, + ]); + + return privateNameVisitor; +} + +const privateNameVisitor = privateNameVisitorFactory({ PrivateName(path) { - const { privateNamesMap } = this; + const { privateNamesMap, redeclared } = this; const { node, parentPath } = path; if (!parentPath.isMemberExpression({ property: node })) return; - if (!privateNamesMap.has(node.id.name)) return; + + const { name } = node.id; + if (!privateNamesMap.has(name)) return; + if (redeclared && redeclared.includes(name)) return; this.handle(parentPath); }, +}); - Class(path) { - const { privateNamesMap } = this; - const body = path.get("body.body"); +const privateInVisitor = privateNameVisitorFactory({ + BinaryExpression(path) { + const { operator, left, right } = path.node; + if (operator !== "in") return; + if (!path.get("left").isPrivateName()) return; - const visiblePrivateNames = new Map(privateNamesMap); - const redeclared = []; - for (const prop of body) { - if (!prop.isPrivate()) continue; - const { name } = prop.node.key.id; - visiblePrivateNames.delete(name); - redeclared.push(name); - } + const { loose, privateNamesMap, redeclared } = this; + const { name } = left.id; + + if (!privateNamesMap.has(name)) return; + if (redeclared && redeclared.includes(name)) return; - // If the class doesn't redeclare any private fields, we can continue with - // our overall traversal. - if (!redeclared.length) { + if (loose) { + const { id } = privateNamesMap.get(name); + path.replaceWith(template.expression.ast` + Object.prototype.hasOwnProperty.call(${right}, ${id}) + `); return; } - // This class redeclares some private field. We need to process the outer - // environment with access to all the outer privates, then we can process - // the inner environment with only the still-visible outer privates. - path.get("body").traverse(privateNameNestedVisitor, { - ...this, - redeclared, - }); - path.traverse(privateNameVisitor, { - ...this, - privateNamesMap: visiblePrivateNames, - }); + const { id, static: isStatic } = privateNamesMap.get(name); - // We'll eventually hit this class node again with the overall Class - // Features visitor, which'll process the redeclared privates. - path.skipKey("body"); - }, -}; + if (isStatic) { + path.replaceWith(template.expression.ast`${right} === ${this.classRef}`); + return; + } -// Traverses the outer portion of a class, without touching the class's inner -// scope, for private names. -const privateNameNestedVisitor = traverse.visitors.merge([ - { - PrivateName(path) { - const { redeclared } = this; - const { name } = path.node.id; - if (redeclared.includes(name)) path.skip(); - }, - }, - { - PrivateName: privateNameVisitor.PrivateName, + path.replaceWith(template.expression.ast`${id}.has(${right})`); }, - environmentVisitor, -]); +}); const privateNameHandlerSpec = { memoise(member, count) { @@ -306,6 +341,12 @@ export function transformPrivateNamesUsage( ...privateNameHandlerSpec, }); } + body.traverse(privateInVisitor, { + privateNamesMap, + classRef: ref, + file: state, + loose, + }); } function buildPrivateFieldInitLoose(ref, prop, privateNamesMap) { diff --git a/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-decorators/ignore-abstract-methods/options.json b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-decorators/ignore-abstract-methods/options.json index d36531b4df09..1783c7d93113 100644 --- a/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-decorators/ignore-abstract-methods/options.json +++ b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-decorators/ignore-abstract-methods/options.json @@ -1,9 +1,7 @@ { - "presets": [ - ["typescript"] - ], + "presets": [["typescript"]], "plugins": [ ["proposal-decorators", { "decoratorsBeforeExport": true }], ["proposal-class-properties"] ] -} \ No newline at end of file +} diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 13f6c947d29a..e4acf72cfdda 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -27,6 +27,7 @@ import { isReservedWord, isStrictReservedWord, isStrictBindReservedWord, + isIdentifierStart, } from "../util/identifier"; import type { Pos, Position } from "../util/location"; import * as charCodes from "charcodes"; @@ -1138,6 +1139,26 @@ export default class ExpressionParser extends LValParser { this.registerTopicReference(); return this.finishNode(node, "PipelinePrimaryTopicReference"); } + + const nextCh = this.input.codePointAt(this.state.end); + if (isIdentifierStart(nextCh) || nextCh === charCodes.backslash) { + const start = this.state.start; + // $FlowIgnore It'll either parse a PrivateName or throw. + node = (this.parseMaybePrivateName(true): N.PrivateName); + if (this.match(tt._in)) { + this.expectPlugin("privateIn"); + this.classScope.usePrivateName(node.id.name, node.start); + } else if (this.hasPlugin("privateIn")) { + this.raise( + this.state.start, + Errors.PrivateInExpectedIn, + node.id.name, + ); + } else { + throw this.unexpected(start); + } + return node; + } } // fall through default: diff --git a/packages/babel-parser/src/parser/location.js b/packages/babel-parser/src/parser/location.js index 035bbc7d0452..a03f41af63cc 100644 --- a/packages/babel-parser/src/parser/location.js +++ b/packages/babel-parser/src/parser/location.js @@ -125,6 +125,8 @@ export const Errors = Object.freeze({ "Topic reference was used in a lexical context without topic binding", PrimaryTopicRequiresSmartPipeline: "Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.", + PrivateInExpectedIn: + "Private names are only allowed in property accesses (`obj.#%0`) or in `in` expressions (`#%0 in obj`)", PrivateNameRedeclaration: "Duplicate private name #%0", RecordExpressionBarIncorrectEndSyntaxType: "Record expressions ending with '|}' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'", diff --git a/packages/babel-parser/test/fixtures/es2016/simple-parameter-list/async-arrow-function-after-binary-operator/options.json b/packages/babel-parser/test/fixtures/es2016/simple-parameter-list/async-arrow-function-after-binary-operator/options.json index f6781c9d58a8..663c13698524 100644 --- a/packages/babel-parser/test/fixtures/es2016/simple-parameter-list/async-arrow-function-after-binary-operator/options.json +++ b/packages/babel-parser/test/fixtures/es2016/simple-parameter-list/async-arrow-function-after-binary-operator/options.json @@ -1,3 +1,3 @@ { "throws": "Unexpected token, expected \";\" (1:12)" -} \ No newline at end of file +} diff --git a/packages/babel-parser/test/fixtures/es2020/nullish-coalescing-operator/with-pipeline/options.json b/packages/babel-parser/test/fixtures/es2020/nullish-coalescing-operator/with-pipeline/options.json index f96a57c74821..a474f3dd5093 100644 --- a/packages/babel-parser/test/fixtures/es2020/nullish-coalescing-operator/with-pipeline/options.json +++ b/packages/babel-parser/test/fixtures/es2020/nullish-coalescing-operator/with-pipeline/options.json @@ -1,5 +1,3 @@ { - "plugins": [ - ["pipelineOperator", { "proposal": "minimal" }] - ] + "plugins": [["pipelineOperator", { "proposal": "minimal" }]] } diff --git a/packages/babel-parser/test/fixtures/experimental/_no-plugin/private-in/input.js b/packages/babel-parser/test/fixtures/experimental/_no-plugin/private-in/input.js new file mode 100644 index 000000000000..3cc8ada625d1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/_no-plugin/private-in/input.js @@ -0,0 +1,7 @@ +class Point { + #x = 1; + #y = 2; + static isPoint(obj) { + return #x in obj && #y in obj; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/_no-plugin/private-in/options.json b/packages/babel-parser/test/fixtures/experimental/_no-plugin/private-in/options.json new file mode 100644 index 000000000000..582e8a659ab4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/_no-plugin/private-in/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "classPrivateProperties" + ], + "throws": "This experimental syntax requires enabling the parser plugin: 'privateIn' (5:14)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-private-methods/asi-failure-generator/options.json b/packages/babel-parser/test/fixtures/experimental/class-private-methods/asi-failure-generator/options.json index 6fa0f15832a1..ab97abb8eb41 100644 --- a/packages/babel-parser/test/fixtures/experimental/class-private-methods/asi-failure-generator/options.json +++ b/packages/babel-parser/test/fixtures/experimental/class-private-methods/asi-failure-generator/options.json @@ -1,4 +1,7 @@ { "throws": "Unexpected token (3:3)", - "plugins": ["classProperties", "classPrivateMethods"] -} + "plugins": [ + "classProperties", + "classPrivateMethods" + ] +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/class-private-properties/failure-shorthand/options.json b/packages/babel-parser/test/fixtures/experimental/class-private-properties/failure-shorthand/options.json index 1c13dabac28a..fc0e9a4e81a4 100644 --- a/packages/babel-parser/test/fixtures/experimental/class-private-properties/failure-shorthand/options.json +++ b/packages/babel-parser/test/fixtures/experimental/class-private-properties/failure-shorthand/options.json @@ -1,4 +1,6 @@ { "throws": "Unexpected token (4:11)", - "plugins": ["classPrivateProperties"] + "plugins": [ + "classPrivateProperties" + ] } diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-smart-error,-unbound-topic,-simple/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-smart-error,-unbound-topic,-simple/options.json index 736cde0e101d..602ec88c9337 100644 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-smart-error,-unbound-topic,-simple/options.json +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-smart-error,-unbound-topic,-simple/options.json @@ -1,4 +1,11 @@ { - "plugins": [["pipelineOperator", { "proposal": "smart" }]], + "plugins": [ + [ + "pipelineOperator", + { + "proposal": "smart" + } + ] + ], "throws": "Unexpected token (1:4)" -} +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/input.js new file mode 100644 index 000000000000..a03ee4299f40 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/input.js @@ -0,0 +1,6 @@ +class Foo { + #x = 1; + test() { + #x + 1; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/output.json new file mode 100644 index 000000000000..d641de74a78d --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-left/output.json @@ -0,0 +1,105 @@ +{ + "type": "File", + "start":0,"end":50,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "errors": [ + "SyntaxError: Private names are only allowed in property accesses (`obj.#x`) or in `in` expressions (`#x in obj`) (4:7)" + ], + "program": { + "type": "Program", + "start":0,"end":50,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":50,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":50,"loc":{"start":{"line":1,"column":10},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}}, + "static": false, + "key": { + "type": "PrivateName", + "start":14,"end":16,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}}, + "id": { + "type": "Identifier", + "start":15,"end":16,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4},"identifierName":"x"}, + "name": "x" + } + }, + "value": { + "type": "NumericLiteral", + "start":19,"end":20,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ClassMethod", + "start":24,"end":48,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":24,"end":28,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":48,"loc":{"start":{"line":3,"column":9},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":37,"end":44,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":11}}, + "expression": { + "type": "BinaryExpression", + "start":37,"end":43,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":10}}, + "left": { + "type": "PrivateName", + "start":37,"end":39,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":6}}, + "id": { + "type": "Identifier", + "start":38,"end":39,"loc":{"start":{"line":4,"column":5},"end":{"line":4,"column":6},"identifierName":"x"}, + "name": "x" + } + }, + "operator": "+", + "right": { + "type": "NumericLiteral", + "start":42,"end":43,"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":10}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/input.js new file mode 100644 index 000000000000..6282042729c0 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/input.js @@ -0,0 +1,6 @@ +class Foo { + #x = 1; + test() { + 1 + #x; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/output.json new file mode 100644 index 000000000000..b6dd5e0efde8 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-binary-expression-right/output.json @@ -0,0 +1,105 @@ +{ + "type": "File", + "start":0,"end":50,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "errors": [ + "SyntaxError: Private names are only allowed in property accesses (`obj.#x`) or in `in` expressions (`#x in obj`) (4:10)" + ], + "program": { + "type": "Program", + "start":0,"end":50,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":50,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":50,"loc":{"start":{"line":1,"column":10},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}}, + "static": false, + "key": { + "type": "PrivateName", + "start":14,"end":16,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}}, + "id": { + "type": "Identifier", + "start":15,"end":16,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4},"identifierName":"x"}, + "name": "x" + } + }, + "value": { + "type": "NumericLiteral", + "start":19,"end":20,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ClassMethod", + "start":24,"end":48,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":24,"end":28,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":48,"loc":{"start":{"line":3,"column":9},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":37,"end":44,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":11}}, + "expression": { + "type": "BinaryExpression", + "start":37,"end":43,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":10}}, + "left": { + "type": "NumericLiteral", + "start":37,"end":38,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":5}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + }, + "operator": "+", + "right": { + "type": "PrivateName", + "start":41,"end":43,"loc":{"start":{"line":4,"column":8},"end":{"line":4,"column":10}}, + "id": { + "type": "Identifier", + "start":42,"end":43,"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":10},"identifierName":"x"}, + "name": "x" + } + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/input.js new file mode 100644 index 000000000000..4f8b5a895691 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/input.js @@ -0,0 +1,6 @@ +class Foo { + #x = 1; + test() { + #x; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/output.json new file mode 100644 index 000000000000..f690ece03932 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-expression/output.json @@ -0,0 +1,91 @@ +{ + "type": "File", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "errors": [ + "SyntaxError: Private names are only allowed in property accesses (`obj.#x`) or in `in` expressions (`#x in obj`) (4:6)" + ], + "program": { + "type": "Program", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":46,"loc":{"start":{"line":1,"column":10},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}}, + "static": false, + "key": { + "type": "PrivateName", + "start":14,"end":16,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}}, + "id": { + "type": "Identifier", + "start":15,"end":16,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4},"identifierName":"x"}, + "name": "x" + } + }, + "value": { + "type": "NumericLiteral", + "start":19,"end":20,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ClassMethod", + "start":24,"end":44,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":24,"end":28,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":44,"loc":{"start":{"line":3,"column":9},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":37,"end":40,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":7}}, + "expression": { + "type": "PrivateName", + "start":37,"end":39,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":6}}, + "id": { + "type": "Identifier", + "start":38,"end":39,"loc":{"start":{"line":4,"column":5},"end":{"line":4,"column":6},"identifierName":"x"}, + "name": "x" + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/input.js new file mode 100644 index 000000000000..79a02d650ef7 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/input.js @@ -0,0 +1,6 @@ +class Foo { + #x = 1; + test() { + class X extends (#x in {}) {}; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/output.json new file mode 100644 index 000000000000..fb316b24404d --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-class-heritage/output.json @@ -0,0 +1,116 @@ +{ + "type": "File", + "start":0,"end":73,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":73,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":73,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":73,"loc":{"start":{"line":1,"column":10},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}}, + "static": false, + "key": { + "type": "PrivateName", + "start":14,"end":16,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}}, + "id": { + "type": "Identifier", + "start":15,"end":16,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4},"identifierName":"x"}, + "name": "x" + } + }, + "value": { + "type": "NumericLiteral", + "start":19,"end":20,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ClassMethod", + "start":24,"end":71,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":24,"end":28,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":71,"loc":{"start":{"line":3,"column":9},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ClassDeclaration", + "start":37,"end":66,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":33}}, + "id": { + "type": "Identifier", + "start":43,"end":44,"loc":{"start":{"line":4,"column":10},"end":{"line":4,"column":11},"identifierName":"X"}, + "name": "X" + }, + "superClass": { + "type": "BinaryExpression", + "start":54,"end":62,"loc":{"start":{"line":4,"column":21},"end":{"line":4,"column":29}}, + "left": { + "type": "PrivateName", + "start":54,"end":56,"loc":{"start":{"line":4,"column":21},"end":{"line":4,"column":23}}, + "id": { + "type": "Identifier", + "start":55,"end":56,"loc":{"start":{"line":4,"column":22},"end":{"line":4,"column":23},"identifierName":"x"}, + "name": "x" + } + }, + "operator": "in", + "right": { + "type": "ObjectExpression", + "start":60,"end":62,"loc":{"start":{"line":4,"column":27},"end":{"line":4,"column":29}}, + "properties": [] + }, + "extra": { + "parenthesized": true, + "parenStart": 53 + } + }, + "body": { + "type": "ClassBody", + "start":64,"end":66,"loc":{"start":{"line":4,"column":31},"end":{"line":4,"column":33}}, + "body": [] + } + }, + { + "type": "EmptyStatement", + "start":66,"end":67,"loc":{"start":{"line":4,"column":33},"end":{"line":4,"column":34}} + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/input.js new file mode 100644 index 000000000000..78069bae8a6d --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/input.js @@ -0,0 +1,6 @@ +class Foo { + #\u{61} = 1; + test() { + #\u{61} in {}; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/output.json new file mode 100644 index 000000000000..1e1d2919424f --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-escaped-sequence/output.json @@ -0,0 +1,98 @@ +{ + "type": "File", + "start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":62,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":62,"loc":{"start":{"line":1,"column":10},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":14,"end":26,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":14}}, + "static": false, + "key": { + "type": "PrivateName", + "start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}}, + "id": { + "type": "Identifier", + "start":15,"end":21,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":9},"identifierName":"a"}, + "name": "a" + } + }, + "value": { + "type": "NumericLiteral", + "start":24,"end":25,"loc":{"start":{"line":2,"column":12},"end":{"line":2,"column":13}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ClassMethod", + "start":29,"end":60,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":29,"end":33,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":36,"end":60,"loc":{"start":{"line":3,"column":9},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":42,"end":56,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":18}}, + "expression": { + "type": "BinaryExpression", + "start":42,"end":55,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":17}}, + "left": { + "type": "PrivateName", + "start":42,"end":49,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":11}}, + "id": { + "type": "Identifier", + "start":43,"end":49,"loc":{"start":{"line":4,"column":5},"end":{"line":4,"column":11},"identifierName":"a"}, + "name": "a" + } + }, + "operator": "in", + "right": { + "type": "ObjectExpression", + "start":53,"end":55,"loc":{"start":{"line":4,"column":15},"end":{"line":4,"column":17}}, + "properties": [] + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/input.js new file mode 100644 index 000000000000..cb45d3472e3c --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/input.js @@ -0,0 +1,6 @@ +class Foo { + #x = 1; + test() { + (#x) in {}; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/output.json new file mode 100644 index 000000000000..fa97d8cdcf31 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-parenthesized/output.json @@ -0,0 +1,105 @@ +{ + "type": "File", + "start":0,"end":54,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "errors": [ + "SyntaxError: Private names are only allowed in property accesses (`obj.#x`) or in `in` expressions (`#x in obj`) (4:7)" + ], + "program": { + "type": "Program", + "start":0,"end":54,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":54,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":54,"loc":{"start":{"line":1,"column":10},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}}, + "static": false, + "key": { + "type": "PrivateName", + "start":14,"end":16,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}}, + "id": { + "type": "Identifier", + "start":15,"end":16,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4},"identifierName":"x"}, + "name": "x" + } + }, + "value": { + "type": "NumericLiteral", + "start":19,"end":20,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ClassMethod", + "start":24,"end":52,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":24,"end":28,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":52,"loc":{"start":{"line":3,"column":9},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":37,"end":48,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":15}}, + "expression": { + "type": "BinaryExpression", + "start":37,"end":47,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":14}}, + "left": { + "type": "PrivateName", + "start":38,"end":40,"loc":{"start":{"line":4,"column":5},"end":{"line":4,"column":7}}, + "id": { + "type": "Identifier", + "start":39,"end":40,"loc":{"start":{"line":4,"column":6},"end":{"line":4,"column":7},"identifierName":"x"}, + "name": "x" + }, + "extra": { + "parenthesized": true, + "parenStart": 37 + } + }, + "operator": "in", + "right": { + "type": "ObjectExpression", + "start":45,"end":47,"loc":{"start":{"line":4,"column":12},"end":{"line":4,"column":14}}, + "properties": [] + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/input.js new file mode 100644 index 000000000000..cdc6d00c7091 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/input.js @@ -0,0 +1,5 @@ +class Foo { + test() { + #x in {}; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/output.json new file mode 100644 index 000000000000..faefdfa5404b --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in-without-field/output.json @@ -0,0 +1,78 @@ +{ + "type": "File", + "start":0,"end":42,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "errors": [ + "SyntaxError: Private name #x is not defined (3:4)" + ], + "program": { + "type": "Program", + "start":0,"end":42,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":42,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":42,"loc":{"start":{"line":1,"column":10},"end":{"line":5,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":14,"end":40,"loc":{"start":{"line":2,"column":2},"end":{"line":4,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":14,"end":18,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":21,"end":40,"loc":{"start":{"line":2,"column":9},"end":{"line":4,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":27,"end":36,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":13}}, + "expression": { + "type": "BinaryExpression", + "start":27,"end":35,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":12}}, + "left": { + "type": "PrivateName", + "start":27,"end":29,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":6}}, + "id": { + "type": "Identifier", + "start":28,"end":29,"loc":{"start":{"line":3,"column":5},"end":{"line":3,"column":6},"identifierName":"x"}, + "name": "x" + } + }, + "operator": "in", + "right": { + "type": "ObjectExpression", + "start":33,"end":35,"loc":{"start":{"line":3,"column":10},"end":{"line":3,"column":12}}, + "properties": [] + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in/input.js b/packages/babel-parser/test/fixtures/experimental/private-in/private-in/input.js new file mode 100644 index 000000000000..32c8b6edbdd1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in/input.js @@ -0,0 +1,6 @@ +class Foo { + #x = 1; + test() { + #x in {}; + } +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in/options.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in/options.json new file mode 100644 index 000000000000..4f1c66180f1e --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classPrivateProperties", "privateIn"] +} diff --git a/packages/babel-parser/test/fixtures/experimental/private-in/private-in/output.json b/packages/babel-parser/test/fixtures/experimental/private-in/private-in/output.json new file mode 100644 index 000000000000..20550bc95856 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/private-in/private-in/output.json @@ -0,0 +1,98 @@ +{ + "type": "File", + "start":0,"end":52,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":52,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":52,"loc":{"start":{"line":1,"column":0},"end":{"line":6,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":10,"end":52,"loc":{"start":{"line":1,"column":10},"end":{"line":6,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}}, + "static": false, + "key": { + "type": "PrivateName", + "start":14,"end":16,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}}, + "id": { + "type": "Identifier", + "start":15,"end":16,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4},"identifierName":"x"}, + "name": "x" + } + }, + "value": { + "type": "NumericLiteral", + "start":19,"end":20,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8}}, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + }, + { + "type": "ClassMethod", + "start":24,"end":50,"loc":{"start":{"line":3,"column":2},"end":{"line":5,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":24,"end":28,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":6},"identifierName":"test"}, + "name": "test" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":50,"loc":{"start":{"line":3,"column":9},"end":{"line":5,"column":3}}, + "body": [ + { + "type": "ExpressionStatement", + "start":37,"end":46,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":13}}, + "expression": { + "type": "BinaryExpression", + "start":37,"end":45,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":12}}, + "left": { + "type": "PrivateName", + "start":37,"end":39,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":6}}, + "id": { + "type": "Identifier", + "start":38,"end":39,"loc":{"start":{"line":4,"column":5},"end":{"line":4,"column":6},"identifierName":"x"}, + "name": "x" + } + }, + "operator": "in", + "right": { + "type": "ObjectExpression", + "start":43,"end":45,"loc":{"start":{"line":4,"column":10},"end":{"line":4,"column":12}}, + "properties": [] + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/typings/babel-parser.d.ts b/packages/babel-parser/typings/babel-parser.d.ts index 40161080996b..2e6412141f84 100644 --- a/packages/babel-parser/typings/babel-parser.d.ts +++ b/packages/babel-parser/typings/babel-parser.d.ts @@ -122,6 +122,7 @@ export type ParserPlugin = 'partialApplication' | 'pipelineOperator' | 'placeholders' | + 'privateIn' | 'throwExpressions' | 'topLevelAwait' | 'typescript' | diff --git a/packages/babel-plugin-proposal-private-property-in-object/.npmignore b/packages/babel-plugin-proposal-private-property-in-object/.npmignore new file mode 100644 index 000000000000..f9806945836e --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-proposal-private-property-in-object/README.md b/packages/babel-plugin-proposal-private-property-in-object/README.md new file mode 100644 index 000000000000..7e43d649ec34 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/README.md @@ -0,0 +1,20 @@ +# @babel/plugin-proposal-private-property-in-object + +> This plugin transforms checks for a private property in an object + +See our website [@babel/plugin-proposal-private-property-in-object](https://babeljs.io/docs/en/next/babel-plugin-proposal-private-property-in-object.html) for more information. + +## Install + +Using npm: + +```sh +npm install --save-dev +@babel/plugin-proposal-private-property-in-object +``` + +or using yarn: + +```sh +yarn add @babel/plugin-proposal-private-property-in-object --dev +``` diff --git a/packages/babel-plugin-proposal-private-property-in-object/package.json b/packages/babel-plugin-proposal-private-property-in-object/package.json new file mode 100644 index 000000000000..2f22ca46775e --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/package.json @@ -0,0 +1,25 @@ +{ + "name": "@babel/plugin-proposal-private-property-in-object", + "version": "7.8.3", + "description": "This plugin transforms checks for a private property in an object", + "repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-private-property-in-object", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "devDependencies": { + "@babel/core": "^7.8.3", + "@babel/helper-plugin-test-runner": "^7.8.3" + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/src/index.js b/packages/babel-plugin-proposal-private-property-in-object/src/index.js new file mode 100644 index 000000000000..70dbf3e4c737 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/src/index.js @@ -0,0 +1,22 @@ +/* eslint-disable @babel/development/plugin-name */ + +import { declare } from "@babel/helper-plugin-utils"; +import { + createClassFeaturePlugin, + FEATURES, +} from "@babel/helper-create-class-features-plugin"; + +export default declare((api, options) => { + api.assertVersion(7); + + return createClassFeaturePlugin({ + name: "proposal-class-properties", + + feature: FEATURES.privateIn, + loose: options.loose, + + manipulateOptions(opts, parserOpts) { + parserOpts.plugins.push("privateIn"); + }, + }); +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/accessor/input.js new file mode 100644 index 000000000000..c0e9000615fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/accessor/output.js new file mode 100644 index 000000000000..4d79bb7e1d7c --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/accessor/output.js @@ -0,0 +1,23 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + get: _get_foo, + set: void 0 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +var _get_foo = function () {}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/field/input.js new file mode 100644 index 000000000000..a682a1a15c5b --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/field/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/field/output.js new file mode 100644 index 000000000000..685d22492d76 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/field/output.js @@ -0,0 +1,21 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/method/input.js new file mode 100644 index 000000000000..365843c59708 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/method/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/method/output.js new file mode 100644 index 000000000000..ea73df0d60df --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/method/output.js @@ -0,0 +1,22 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + value: _foo2 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +var _foo2 = function _foo2() {}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/input.js new file mode 100644 index 000000000000..23c266018025 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/input.js @@ -0,0 +1,12 @@ +class Foo { + static #foo = "foo"; + #bar = "bar"; + + static test() { + return #foo in Foo; + } + + test() { + return #bar in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/options.json new file mode 100644 index 000000000000..b669b8ab51a4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "proposal-private-property-in-object", + "proposal-class-properties", + "proposal-private-methods" + ] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/output.js new file mode 100644 index 000000000000..6c628a018ea4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/native-classes/output.js @@ -0,0 +1,24 @@ +class Foo { + constructor() { + _bar.set(this, { + writable: true, + value: "bar" + }); + } + + static test() { + return Foo === Foo; + } + + test() { + return _bar.has(this); + } + +} + +var _bar = new WeakMap(); + +var _foo = { + writable: true, + value: "foo" +}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-other-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-other-redeclared/input.js new file mode 100644 index 000000000000..a084dd06afd6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-other-redeclared/input.js @@ -0,0 +1,18 @@ +class Foo { + #foo = 1; + #bar = 1; + + test() { + class Nested { + #bar = 2; + + test() { + #foo in this; + #bar in this; + } + } + + #foo in this; + #bar in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-other-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-other-redeclared/output.js new file mode 100644 index 000000000000..ee30d7732679 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-other-redeclared/output.js @@ -0,0 +1,49 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + Object.defineProperty(this, _bar, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + let Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + Object.defineProperty(this, _bar2, { + writable: true, + value: 2 + }); + } + + babelHelpers.createClass(Nested, [{ + key: "test", + value: function test() { + Object.prototype.hasOwnProperty.call(this, _foo); + Object.prototype.hasOwnProperty.call(this, _bar2); + } + }]); + return Nested; + }(); + + var _bar2 = babelHelpers.classPrivateFieldLooseKey("bar"); + + Object.prototype.hasOwnProperty.call(this, _foo); + Object.prototype.hasOwnProperty.call(this, _bar); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +var _bar = babelHelpers.classPrivateFieldLooseKey("bar"); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-redeclared/input.js new file mode 100644 index 000000000000..2258be35c5fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-redeclared/input.js @@ -0,0 +1,15 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + #foo = 2; + + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-redeclared/output.js new file mode 100644 index 000000000000..2c073c4703ea --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class-redeclared/output.js @@ -0,0 +1,41 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + let Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + Object.defineProperty(this, _foo2, { + writable: true, + value: 2 + }); + } + + babelHelpers.createClass(Nested, [{ + key: "test", + value: function test() { + Object.prototype.hasOwnProperty.call(this, _foo2); + } + }]); + return Nested; + }(); + + var _foo2 = babelHelpers.classPrivateFieldLooseKey("foo"); + + Object.prototype.hasOwnProperty.call(this, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class/input.js new file mode 100644 index 000000000000..e17e438b314d --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class/input.js @@ -0,0 +1,13 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class/output.js new file mode 100644 index 000000000000..f6d0eac71613 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/nested-class/output.js @@ -0,0 +1,35 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + let Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + } + + babelHelpers.createClass(Nested, [{ + key: "test", + value: function test() { + Object.prototype.hasOwnProperty.call(this, _foo); + } + }]); + return Nested; + }(); + + Object.prototype.hasOwnProperty.call(this, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/options.json new file mode 100644 index 000000000000..39f3b895b374 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + ["proposal-private-property-in-object", { "loose": true }], + ["proposal-class-properties", { "loose": true }], + ["proposal-private-methods", { "loose": true }], + "transform-classes" + ] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-accessor/input.js new file mode 100644 index 000000000000..e74333f2055f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + static get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-accessor/output.js new file mode 100644 index 000000000000..0b3ff5b6e694 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-accessor/output.js @@ -0,0 +1,24 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +var _get_foo = function () {}; + +Object.defineProperty(Foo, _foo, { + get: _get_foo, + set: void 0 +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-field/input.js new file mode 100644 index 000000000000..a4f771844fe9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-field/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-field/output.js new file mode 100644 index 000000000000..e775b5c2eabe --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-field/output.js @@ -0,0 +1,22 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +Object.defineProperty(Foo, _foo, { + writable: true, + value: 1 +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-method/input.js new file mode 100644 index 000000000000..9fffe7a01622 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-method/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-method/output.js new file mode 100644 index 000000000000..cb3de8d9c3a7 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private-loose/static-method/output.js @@ -0,0 +1,23 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +var _foo2 = function _foo2() {}; + +Object.defineProperty(Foo, _foo, { + value: _foo2 +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/accessor/input.js new file mode 100644 index 000000000000..c0e9000615fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/accessor/output.js new file mode 100644 index 000000000000..1bf0ad977094 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/accessor/output.js @@ -0,0 +1,24 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.set(this, { + get: _get_foo, + set: void 0 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return _foo.has(other); + } + }]); + return Foo; +}(); + +var _foo = new WeakMap(); + +var _get_foo = function () {}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/field/input.js new file mode 100644 index 000000000000..a682a1a15c5b --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/field/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/field/output.js new file mode 100644 index 000000000000..51925683ab1f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/field/output.js @@ -0,0 +1,22 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.set(this, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return _foo.has(other); + } + }]); + return Foo; +}(); + +var _foo = new WeakMap(); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/method/input.js new file mode 100644 index 000000000000..365843c59708 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/method/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/method/output.js new file mode 100644 index 000000000000..246f5ecdc2b0 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/method/output.js @@ -0,0 +1,21 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.add(this); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return _foo.has(other); + } + }]); + return Foo; +}(); + +var _foo = new WeakSet(); + +var _foo2 = function _foo2() {}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/input.js new file mode 100644 index 000000000000..23c266018025 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/input.js @@ -0,0 +1,12 @@ +class Foo { + static #foo = "foo"; + #bar = "bar"; + + static test() { + return #foo in Foo; + } + + test() { + return #bar in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/options.json new file mode 100644 index 000000000000..b669b8ab51a4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "proposal-private-property-in-object", + "proposal-class-properties", + "proposal-private-methods" + ] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/output.js new file mode 100644 index 000000000000..6c628a018ea4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/native-classes/output.js @@ -0,0 +1,24 @@ +class Foo { + constructor() { + _bar.set(this, { + writable: true, + value: "bar" + }); + } + + static test() { + return Foo === Foo; + } + + test() { + return _bar.has(this); + } + +} + +var _bar = new WeakMap(); + +var _foo = { + writable: true, + value: "foo" +}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-other-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-other-redeclared/input.js new file mode 100644 index 000000000000..a084dd06afd6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-other-redeclared/input.js @@ -0,0 +1,18 @@ +class Foo { + #foo = 1; + #bar = 1; + + test() { + class Nested { + #bar = 2; + + test() { + #foo in this; + #bar in this; + } + } + + #foo in this; + #bar in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-other-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-other-redeclared/output.js new file mode 100644 index 000000000000..f5505ae4e5cb --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-other-redeclared/output.js @@ -0,0 +1,54 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.set(this, { + writable: true, + value: 1 + }); + + _bar.set(this, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + let Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + + _bar2.set(this, { + writable: true, + value: 2 + }); + } + + babelHelpers.createClass(Nested, [{ + key: "test", + value: function test() { + _foo.has(this); + + _bar2.has(this); + } + }]); + return Nested; + }(); + + var _bar2 = new WeakMap(); + + _foo.has(this); + + _bar.has(this); + } + }]); + return Foo; +}(); + +var _foo = new WeakMap(); + +var _bar = new WeakMap(); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-redeclared/input.js new file mode 100644 index 000000000000..2258be35c5fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-redeclared/input.js @@ -0,0 +1,15 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + #foo = 2; + + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-redeclared/output.js new file mode 100644 index 000000000000..40a032ccb4e8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class-redeclared/output.js @@ -0,0 +1,43 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.set(this, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + let Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + + _foo2.set(this, { + writable: true, + value: 2 + }); + } + + babelHelpers.createClass(Nested, [{ + key: "test", + value: function test() { + _foo2.has(this); + } + }]); + return Nested; + }(); + + var _foo2 = new WeakMap(); + + _foo.has(this); + } + }]); + return Foo; +}(); + +var _foo = new WeakMap(); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class/input.js new file mode 100644 index 000000000000..e17e438b314d --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class/input.js @@ -0,0 +1,13 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class/output.js new file mode 100644 index 000000000000..33627fd1a1ce --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/nested-class/output.js @@ -0,0 +1,36 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.set(this, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + let Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + } + + babelHelpers.createClass(Nested, [{ + key: "test", + value: function test() { + _foo.has(this); + } + }]); + return Nested; + }(); + + _foo.has(this); + } + }]); + return Foo; +}(); + +var _foo = new WeakMap(); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/options.json new file mode 100644 index 000000000000..9d27af601e04 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "proposal-private-property-in-object", + "proposal-class-properties", + "proposal-private-methods", + "transform-classes" + ] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-accessor/input.js new file mode 100644 index 000000000000..e74333f2055f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + static get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-accessor/output.js new file mode 100644 index 000000000000..e29d7e1009a1 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-accessor/output.js @@ -0,0 +1,22 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return other === Foo; + } + }]); + return Foo; +}(); + +var _get_foo = function () {}; + +var _foo = { + get: _get_foo, + set: void 0 +}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-field/input.js new file mode 100644 index 000000000000..a4f771844fe9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-field/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-field/output.js new file mode 100644 index 000000000000..c631923cb5a9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-field/output.js @@ -0,0 +1,20 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return other === Foo; + } + }]); + return Foo; +}(); + +var _foo = { + writable: true, + value: 1 +}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-method/input.js new file mode 100644 index 000000000000..9fffe7a01622 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-method/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-method/output.js new file mode 100644 index 000000000000..f97846c679a6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/private/static-method/output.js @@ -0,0 +1,17 @@ +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test(other) { + return other === Foo; + } + }]); + return Foo; +}(); + +var _foo = function _foo() {}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/index.js b/packages/babel-plugin-proposal-private-property-in-object/test/index.js new file mode 100644 index 000000000000..1b534b8fc64a --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/index.js @@ -0,0 +1,3 @@ +import runner from "@babel/helper-plugin-test-runner"; + +runner(__dirname); diff --git a/packages/babel-types/src/definitions/core.js b/packages/babel-types/src/definitions/core.js index f27aa81c9172..a0f7865b9d05 100644 --- a/packages/babel-types/src/definitions/core.js +++ b/packages/babel-types/src/definitions/core.js @@ -80,7 +80,15 @@ defineType("BinaryExpression", { validate: assertOneOf(...BINARY_OPERATORS), }, left: { - validate: assertNodeType("Expression"), + validate: (function() { + const expression = assertNodeType("Expression"); + const inOp = assertNodeType("Expression", "PrivateName"); + + return function(node, key, val) { + const validator = node.operator === "in" ? inOp : expression; + validator(node, key, val); + }; + })(), }, right: { validate: assertNodeType("Expression"),