Skip to content

Commit 144609a

Browse files
Fix/issue 1124 (#1279)
* 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 <[email protected]>
1 parent 76fdb92 commit 144609a

3 files changed

Lines changed: 104 additions & 12 deletions

File tree

lib/parse.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,7 @@ var PRECEDENCE = (function(a, ret) {
10411041
{}
10421042
);
10431043

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

10461046
/* -----[ Parser ]----- */
10471047

@@ -1213,6 +1213,9 @@ function parse($TEXT, options) {
12131213
return simple_statement();
12141214

12151215
case "name":
1216+
case "privatename":
1217+
if(is("privatename") && !S.in_class)
1218+
croak("Private field must be used in an enclosing class");
12161219
if (S.token.value == "async" && is_token(peek(), "keyword", "function")) {
12171220
next();
12181221
next();
@@ -2176,6 +2179,11 @@ function parse($TEXT, options) {
21762179
case "name":
21772180
ret = _make_symbol(AST_SymbolRef);
21782181
break;
2182+
case "privatename":
2183+
if(!S.in_class)
2184+
croak("Private field must be used in an enclosing class");
2185+
ret = _make_symbol(AST_SymbolRef);
2186+
break;
21792187
case "num":
21802188
ret = new AST_Number({
21812189
start: tok,
@@ -2518,7 +2526,8 @@ function parse($TEXT, options) {
25182526
}
25192527

25202528
expect("{");
2521-
2529+
// mark in class feild,
2530+
S.in_class = true;
25222531
while (is("punc", ";")) { next(); } // Leading semicolons are okay in class bodies.
25232532
while (!is("punc", "}")) {
25242533
start = S.token;
@@ -2527,6 +2536,8 @@ function parse($TEXT, options) {
25272536
a.push(method);
25282537
while (is("punc", ";")) { next(); }
25292538
}
2539+
// mark in class feild,
2540+
S.in_class = false;
25302541

25312542
S.input.pop_directives_stack();
25322543

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

30873100
chain_contents = subscripts(call, true, true);
30883101
} else if (is("name") || is("privatename")) {
3102+
if(is("privatename") && !S.in_class)
3103+
croak("Private field must be used in an enclosing class");
30893104
const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
30903105
chain_contents = subscripts(new AST_DotVariant({
30913106
start,
@@ -3131,7 +3146,6 @@ function parse($TEXT, options) {
31313146
end: prev()
31323147
}), allow_calls);
31333148
}
3134-
31353149
return expr;
31363150
};
31373151

@@ -3206,6 +3220,9 @@ function parse($TEXT, options) {
32063220
&& left.operator !== "--" && left.operator !== "++")
32073221
unexpected(left.start);
32083222
var prec = op != null ? PRECEDENCE[op] : null;
3223+
// #<privatename> without subscription is only legal in `#<privatename> in <expression>` when inside a class.
3224+
if(left instanceof AST_SymbolRef && left.start.type === "privatename" && S.in_class && op !== "in")
3225+
croak("Unexpected privatename token");
32093226
if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) {
32103227
next();
32113228
var right = expr_op(maybe_unary(true), prec, no_in);

test/compress/class-properties.js

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,15 +344,6 @@ optional_chaining_private_fields: {
344344
// expect_stdout: "PASS" // < tested in chrome, fails with nodejs 14 (current LTS)
345345
}
346346

347-
tolerate_out_of_class_private_fields: {
348-
no_mozilla_ast = true;
349-
node_version = ">=12"
350-
input: {
351-
Bar.#foo = "bad"
352-
}
353-
expect_exact: 'Bar.#foo="bad";'
354-
}
355-
356347
private_properties_can_be_mangled: {
357348
no_mozilla_ast = true;
358349
node_version = ">=12"
@@ -455,3 +446,40 @@ nested_private_properties_can_be_mangled: {
455446
new X().log();
456447
}
457448
}
449+
450+
allow_private_field_with_in_operator : {
451+
no_mozilla_ast = true;
452+
node_version = ">=12"
453+
mangle = {
454+
properties: true
455+
}
456+
input: {
457+
class A {
458+
#p;
459+
isA (input) {
460+
#p in input;
461+
#p in this;
462+
return #p in this;
463+
}
464+
}
465+
}
466+
expect:{class A{#i;i(i){p in i;p in this;return p in this}}}
467+
}
468+
469+
allow_subscript_private_field: {
470+
no_mozilla_ast = true;
471+
node_version = ">=12"
472+
mangle = {
473+
properties: true
474+
}
475+
input: {
476+
class A {
477+
#p;
478+
isA (input) {
479+
console.log(input.#p);
480+
return this.#p;
481+
}
482+
}
483+
}
484+
expect: {class A{#s;i(s){console.log(s.#s);return this.#s}}}
485+
}

test/compress/syntax-errors.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,50 @@ invalid_privatename_in_object: {
347347
col: 12
348348
})
349349
}
350+
351+
private_field_out_of_class_field: {
352+
input: `
353+
function test() {
354+
return this.#p;
355+
}
356+
`
357+
expect_error: ({
358+
name: "SyntaxError",
359+
message: "Private field must be declared in an enclosing class",
360+
line: 3,
361+
col: 24
362+
})
363+
}
364+
365+
private_field_out_of_class_field_in_operator: {
366+
input: `
367+
function test(input) {
368+
#p in input;
369+
return 10;
370+
}
371+
`
372+
expect_error:({
373+
name: "SyntaxError",
374+
message: "Private field must be declared in an enclosing class",
375+
line: 3,
376+
col: 12
377+
})
378+
}
379+
380+
invaild__in_operator_expression_in_class_field: {
381+
input: `
382+
class A {
383+
#p;
384+
isA () {
385+
#p + 10;
386+
return this.#p;
387+
}
388+
}
389+
`
390+
expect_error: ({
391+
name: "SyntaxError",
392+
message: "Unexpected privatename token",
393+
line: 5,
394+
col: 19
395+
})
396+
}

0 commit comments

Comments
 (0)