File tree Expand file tree Collapse file tree 4 files changed +148
-6
lines changed
compiler/packages/babel-plugin-react-compiler/src
__tests__/fixtures/compiler/ecma Expand file tree Collapse file tree 4 files changed +148
-6
lines changed Original file line number Diff line number Diff line change @@ -14,6 +14,7 @@ import type {HookKind} from './ObjectShape';
1414import { Type , makeType } from './Types' ;
1515import { z } from 'zod' ;
1616import type { AliasingEffect } from '../Inference/AliasingEffects' ;
17+ import { isReservedWord } from '../Utils/Keyword' ;
1718
1819/*
1920 * *******************************************************************************************
@@ -1320,12 +1321,21 @@ export function forkTemporaryIdentifier(
13201321 * original source code.
13211322 */
13221323export function makeIdentifierName ( name : string ) : ValidatedIdentifier {
1323- CompilerError . invariant ( t . isValidIdentifier ( name ) , {
1324- reason : `Expected a valid identifier name` ,
1325- loc : GeneratedSource ,
1326- description : `\`${ name } \` is not a valid JavaScript identifier` ,
1327- suggestions : null ,
1328- } ) ;
1324+ if ( isReservedWord ( name ) ) {
1325+ CompilerError . throwInvalidJS ( {
1326+ reason : 'Expected a non-reserved identifier name' ,
1327+ loc : GeneratedSource ,
1328+ description : `\`${ name } \` is a reserved word in JavaScript and cannot be used as an identifier name` ,
1329+ suggestions : null ,
1330+ } ) ;
1331+ } else {
1332+ CompilerError . invariant ( t . isValidIdentifier ( name ) , {
1333+ reason : `Expected a valid identifier name` ,
1334+ loc : GeneratedSource ,
1335+ description : `\`${ name } \` is not a valid JavaScript identifier` ,
1336+ suggestions : null ,
1337+ } ) ;
1338+ }
13291339 return {
13301340 kind : 'named' ,
13311341 value : name as ValidIdentifierName ,
Original file line number Diff line number Diff line change 1+ /**
2+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3+ *
4+ * This source code is licensed under the MIT license found in the
5+ * LICENSE file in the root directory of this source tree.
6+ */
7+
8+ /**
9+ * https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#sec-keywords-and-reserved-words
10+ */
11+
12+ /**
13+ * Note: `await` and `yield` are contextually allowed as identifiers.
14+ * await: reserved inside async functions and modules
15+ * yield: reserved inside generator functions
16+ *
17+ * Note: `async` is not reserved.
18+ */
19+ const RESERVED_WORDS = new Set ( [
20+ 'break' ,
21+ 'case' ,
22+ 'catch' ,
23+ 'class' ,
24+ 'const' ,
25+ 'continue' ,
26+ 'debugger' ,
27+ 'default' ,
28+ 'delete' ,
29+ 'do' ,
30+ 'else' ,
31+ 'enum' ,
32+ 'export' ,
33+ 'extends' ,
34+ 'false' ,
35+ 'finally' ,
36+ 'for' ,
37+ 'function' ,
38+ 'if' ,
39+ 'import' ,
40+ 'in' ,
41+ 'instanceof' ,
42+ 'new' ,
43+ 'null' ,
44+ 'return' ,
45+ 'super' ,
46+ 'switch' ,
47+ 'this' ,
48+ 'throw' ,
49+ 'true' ,
50+ 'try' ,
51+ 'typeof' ,
52+ 'var' ,
53+ 'void' ,
54+ 'while' ,
55+ 'with' ,
56+ ] ) ;
57+
58+ /**
59+ * Reserved when a module has a 'use strict' directive.
60+ */
61+ const STRICT_MODE_RESERVED_WORDS = new Set ( [
62+ 'let' ,
63+ 'static' ,
64+ 'implements' ,
65+ 'interface' ,
66+ 'package' ,
67+ 'private' ,
68+ 'protected' ,
69+ 'public' ,
70+ ] ) ;
71+ /**
72+ * The names arguments and eval are not keywords, but they are subject to some restrictions in
73+ * strict mode code.
74+ */
75+ const STRICT_MODE_RESTRICTED_WORDS = new Set ( [ 'eval' , 'arguments' ] ) ;
76+
77+ /**
78+ * Conservative check for whether an identifer name is reserved or not. We assume that code is
79+ * written with strict mode.
80+ */
81+ export function isReservedWord ( identifierName : string ) : boolean {
82+ return (
83+ RESERVED_WORDS . has ( identifierName ) ||
84+ STRICT_MODE_RESERVED_WORDS . has ( identifierName ) ||
85+ STRICT_MODE_RESTRICTED_WORDS . has ( identifierName )
86+ ) ;
87+ }
Original file line number Diff line number Diff line change 1+
2+ ## Input
3+
4+ ``` javascript
5+ import {useRef } from ' react' ;
6+
7+ function useThing (fn ) {
8+ const fnRef = useRef (fn);
9+ const ref = useRef (null );
10+
11+ if (ref .current === null ) {
12+ ref .current = function (this : unknown , ... args ) {
13+ return fnRef .current .call (this , ... args);
14+ };
15+ }
16+ return ref .current ;
17+ }
18+
19+ ```
20+
21+
22+ ## Error
23+
24+ ```
25+ Found 1 error:
26+
27+ Error: Expected a non-reserved identifier name
28+
29+ `this` is a reserved word in JavaScript and cannot be used as an identifier name.
30+ ```
31+
32+
Original file line number Diff line number Diff line change 1+ import { useRef } from 'react' ;
2+
3+ function useThing ( fn ) {
4+ const fnRef = useRef ( fn ) ;
5+ const ref = useRef ( null ) ;
6+
7+ if ( ref . current === null ) {
8+ ref . current = function ( this : unknown , ...args ) {
9+ return fnRef . current . call ( this , ...args ) ;
10+ } ;
11+ }
12+ return ref . current ;
13+ }
You can’t perform that action at this time.
0 commit comments