diff --git a/src/parser/expression.js b/src/parser/expression.js index 3aaa2faf08..588c1b106d 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -252,8 +252,16 @@ export default class ExpressionParser extends LValParser { if (update) { this.checkLVal(node.argument, undefined, undefined, "prefix operation"); - } else if (this.state.strict && node.operator === "delete" && node.argument.type === "Identifier") { - this.raise(node.start, "Deleting local variable in strict mode"); + } else if (this.state.strict && node.operator === "delete") { + const arg = node.argument; + + if (arg.type === "Identifier") { + this.raise(node.start, "Deleting local variable in strict mode"); + } else if (this.hasPlugin("classPrivateProperties")) { + if (arg.type === "PrivateName" || (arg.type === "MemberExpression" && arg.property.type === "PrivateName")) { + this.raise(node.start, "Deleting a private field is not allowed"); + } + } } return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); diff --git a/test/fixtures/experimental/class-private-properties/delete-non-private/actual.js b/test/fixtures/experimental/class-private-properties/delete-non-private/actual.js new file mode 100644 index 0000000000..eedc4456bc --- /dev/null +++ b/test/fixtures/experimental/class-private-properties/delete-non-private/actual.js @@ -0,0 +1,6 @@ +class Foo { + #x; + constructor() { + delete #x.d; + } +} diff --git a/test/fixtures/experimental/class-private-properties/delete-non-private/expected.json b/test/fixtures/experimental/class-private-properties/delete-non-private/expected.json new file mode 100644 index 0000000000..bc00bb10ad --- /dev/null +++ b/test/fixtures/experimental/class-private-properties/delete-non-private/expected.json @@ -0,0 +1,275 @@ +{ + "type": "File", + "start": 0, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 58, + "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": 58, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "body": [ + { + "type": "ClassPrivateProperty", + "start": 14, + "end": 17, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 5 + } + }, + "key": { + "type": "Identifier", + "start": 15, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 4 + }, + "identifierName": "x" + }, + "name": "x" + }, + "value": null + }, + { + "type": "ClassMethod", + "start": 20, + "end": 56, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "static": false, + "computed": false, + "key": { + "type": "Identifier", + "start": 20, + "end": 31, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 13 + }, + "identifierName": "constructor" + }, + "name": "constructor" + }, + "kind": "constructor", + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 34, + "end": 56, + "loc": { + "start": { + "line": 3, + "column": 16 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 40, + "end": 52, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 16 + } + }, + "expression": { + "type": "UnaryExpression", + "start": 40, + "end": 51, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 15 + } + }, + "operator": "delete", + "prefix": true, + "argument": { + "type": "MemberExpression", + "start": 47, + "end": 51, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 15 + } + }, + "object": { + "type": "PrivateName", + "start": 48, + "end": 49, + "loc": { + "start": { + "line": 4, + "column": 12 + }, + "end": { + "line": 4, + "column": 13 + } + }, + "name": { + "type": "Identifier", + "start": 48, + "end": 49, + "loc": { + "start": { + "line": 4, + "column": 12 + }, + "end": { + "line": 4, + "column": 13 + }, + "identifierName": "x" + }, + "name": "x" + } + }, + "property": { + "type": "Identifier", + "start": 50, + "end": 51, + "loc": { + "start": { + "line": 4, + "column": 14 + }, + "end": { + "line": 4, + "column": 15 + }, + "identifierName": "d" + }, + "name": "d" + }, + "computed": false + }, + "extra": { + "parenthesizedArgument": false + } + } + } + ], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/class-private-properties/delete-non-private/options.json b/test/fixtures/experimental/class-private-properties/delete-non-private/options.json new file mode 100644 index 0000000000..19c38d2996 --- /dev/null +++ b/test/fixtures/experimental/class-private-properties/delete-non-private/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["classProperties", "classPrivateProperties"] +} diff --git a/test/fixtures/experimental/class-private-properties/failure-delete-private-property/actual.js b/test/fixtures/experimental/class-private-properties/failure-delete-private-property/actual.js new file mode 100644 index 0000000000..d0ab9bc388 --- /dev/null +++ b/test/fixtures/experimental/class-private-properties/failure-delete-private-property/actual.js @@ -0,0 +1,6 @@ +class Foo { + #x; + constructor() { + delete this.#x; + } +} diff --git a/test/fixtures/experimental/class-private-properties/failure-delete-private-property/options.json b/test/fixtures/experimental/class-private-properties/failure-delete-private-property/options.json new file mode 100644 index 0000000000..32979c4d9e --- /dev/null +++ b/test/fixtures/experimental/class-private-properties/failure-delete-private-property/options.json @@ -0,0 +1,7 @@ +{ + "throws": "Deleting a private field is not allowed (4:4)", + "plugins": [ + "classProperties", + "classPrivateProperties" + ] +} diff --git a/test/fixtures/experimental/class-private-properties/failure-delete-shorthand/actual.js b/test/fixtures/experimental/class-private-properties/failure-delete-shorthand/actual.js new file mode 100644 index 0000000000..ccf46bb766 --- /dev/null +++ b/test/fixtures/experimental/class-private-properties/failure-delete-shorthand/actual.js @@ -0,0 +1,6 @@ +class Foo { + #x; + constructor() { + delete #x; + } +} diff --git a/test/fixtures/experimental/class-private-properties/failure-delete-shorthand/options.json b/test/fixtures/experimental/class-private-properties/failure-delete-shorthand/options.json new file mode 100644 index 0000000000..32979c4d9e --- /dev/null +++ b/test/fixtures/experimental/class-private-properties/failure-delete-shorthand/options.json @@ -0,0 +1,7 @@ +{ + "throws": "Deleting a private field is not allowed (4:4)", + "plugins": [ + "classProperties", + "classPrivateProperties" + ] +}