Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/issue 1124 #1279

Merged
merged 3 commits into from Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 declared in an enclosing class");
fabiosantoscode marked this conversation as resolved.
Show resolved Hide resolved
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 declared in an enclosing class");
fabiosantoscode marked this conversation as resolved.
Show resolved Hide resolved
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 declared in an enclosing class");
fabiosantoscode marked this conversation as resolved.
Show resolved Hide resolved
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 declared in an enclosing class");
fabiosantoscode marked this conversation as resolved.
Show resolved Hide resolved
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 should only legel in `#<privatename> in <expression>` when exist in class feild.
fabiosantoscode marked this conversation as resolved.
Show resolved Hide resolved
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
})
}