Skip to content

Commit

Permalink
Fix/issue 1124 (#1279)
Browse files Browse the repository at this point in the history
* fix: support "#private in" syntax. Ref #1124

* fix: Add Test case to issue 1124

* Change some comments, error messages

Co-authored-by: F谩bio Santos <fabiosantosart@gmail.com>
  • Loading branch information
Solo-steven and fabiosantoscode committed Nov 1, 2022
1 parent 76fdb92 commit 144609a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 12 deletions.
23 changes: 20 additions & 3 deletions lib/parse.js
Expand Up @@ -1041,7 +1041,7 @@ var PRECEDENCE = (function(a, ret) {
{}
);

var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "big_int", "string", "regexp", "name" ]);
var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "big_int", "string", "regexp", "name", "privatename"]);

/* -----[ Parser ]----- */

Expand Down Expand Up @@ -1213,6 +1213,9 @@ function parse($TEXT, options) {
return simple_statement();

case "name":
case "privatename":
if(is("privatename") && !S.in_class)
croak("Private field must be used in an enclosing class");
if (S.token.value == "async" && is_token(peek(), "keyword", "function")) {
next();
next();
Expand Down Expand Up @@ -2176,6 +2179,11 @@ function parse($TEXT, options) {
case "name":
ret = _make_symbol(AST_SymbolRef);
break;
case "privatename":
if(!S.in_class)
croak("Private field must be used in an enclosing class");
ret = _make_symbol(AST_SymbolRef);
break;
case "num":
ret = new AST_Number({
start: tok,
Expand Down Expand Up @@ -2518,7 +2526,8 @@ function parse($TEXT, options) {
}

expect("{");

// mark in class feild,
S.in_class = true;
while (is("punc", ";")) { next(); } // Leading semicolons are okay in class bodies.
while (!is("punc", "}")) {
start = S.token;
Expand All @@ -2527,6 +2536,8 @@ function parse($TEXT, options) {
a.push(method);
while (is("punc", ";")) { next(); }
}
// mark in class feild,
S.in_class = false;

S.input.pop_directives_stack();

Expand Down Expand Up @@ -3033,6 +3044,8 @@ function parse($TEXT, options) {
var start = expr.start;
if (is("punc", ".")) {
next();
if(is("privatename") && !S.in_class)
croak("Private field must be used in an enclosing class");
const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
return subscripts(new AST_DotVariant({
start : start,
Expand Down Expand Up @@ -3086,6 +3099,8 @@ function parse($TEXT, options) {

chain_contents = subscripts(call, true, true);
} else if (is("name") || is("privatename")) {
if(is("privatename") && !S.in_class)
croak("Private field must be used in an enclosing class");
const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
chain_contents = subscripts(new AST_DotVariant({
start,
Expand Down Expand Up @@ -3131,7 +3146,6 @@ function parse($TEXT, options) {
end: prev()
}), allow_calls);
}

return expr;
};

Expand Down Expand Up @@ -3206,6 +3220,9 @@ function parse($TEXT, options) {
&& left.operator !== "--" && left.operator !== "++")
unexpected(left.start);
var prec = op != null ? PRECEDENCE[op] : null;
// #<privatename> without subscription is only legal in `#<privatename> in <expression>` when inside a class.
if(left instanceof AST_SymbolRef && left.start.type === "privatename" && S.in_class && op !== "in")
croak("Unexpected privatename token");
if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) {
next();
var right = expr_op(maybe_unary(true), prec, no_in);
Expand Down
46 changes: 37 additions & 9 deletions test/compress/class-properties.js
Expand Up @@ -344,15 +344,6 @@ optional_chaining_private_fields: {
// expect_stdout: "PASS" // < tested in chrome, fails with nodejs 14 (current LTS)
}

tolerate_out_of_class_private_fields: {
no_mozilla_ast = true;
node_version = ">=12"
input: {
Bar.#foo = "bad"
}
expect_exact: 'Bar.#foo="bad";'
}

private_properties_can_be_mangled: {
no_mozilla_ast = true;
node_version = ">=12"
Expand Down Expand Up @@ -455,3 +446,40 @@ nested_private_properties_can_be_mangled: {
new X().log();
}
}

allow_private_field_with_in_operator : {
no_mozilla_ast = true;
node_version = ">=12"
mangle = {
properties: true
}
input: {
class A {
#p;
isA (input) {
#p in input;
#p in this;
return #p in this;
}
}
}
expect:{class A{#i;i(i){p in i;p in this;return p in this}}}
}

allow_subscript_private_field: {
no_mozilla_ast = true;
node_version = ">=12"
mangle = {
properties: true
}
input: {
class A {
#p;
isA (input) {
console.log(input.#p);
return this.#p;
}
}
}
expect: {class A{#s;i(s){console.log(s.#s);return this.#s}}}
}
47 changes: 47 additions & 0 deletions test/compress/syntax-errors.js
Expand Up @@ -347,3 +347,50 @@ invalid_privatename_in_object: {
col: 12
})
}

private_field_out_of_class_field: {
input: `
function test() {
return this.#p;
}
`
expect_error: ({
name: "SyntaxError",
message: "Private field must be declared in an enclosing class",
line: 3,
col: 24
})
}

private_field_out_of_class_field_in_operator: {
input: `
function test(input) {
#p in input;
return 10;
}
`
expect_error:({
name: "SyntaxError",
message: "Private field must be declared in an enclosing class",
line: 3,
col: 12
})
}

invaild__in_operator_expression_in_class_field: {
input: `
class A {
#p;
isA () {
#p + 10;
return this.#p;
}
}
`
expect_error: ({
name: "SyntaxError",
message: "Unexpected privatename token",
line: 5,
col: 19
})
}

0 comments on commit 144609a

Please sign in to comment.