6
6
* @typedef {import('estree-jsx').JSXMemberExpression } JSXMemberExpression
7
7
*/
8
8
9
- import { name as isIdentifierName } from 'estree-util-is-identifier-name'
9
+ import {
10
+ start as esStart ,
11
+ cont as esCont ,
12
+ name as isIdentifierName
13
+ } from 'estree-util-is-identifier-name'
10
14
11
15
export const toIdOrMemberExpression = toIdOrMemberExpressionFactory (
12
16
'Identifier' ,
13
- 'MemberExpression'
17
+ 'MemberExpression' ,
18
+ isIdentifierName
14
19
)
15
20
16
21
export const toJsxIdOrMemberExpression =
17
22
// @ts -expect-error: fine
18
23
/** @type {(ids: Array<string|number>) => JSXIdentifier|JSXMemberExpression) } */
19
- ( toIdOrMemberExpressionFactory ( 'JSXIdentifier' , 'JSXMemberExpression' ) )
24
+ (
25
+ toIdOrMemberExpressionFactory (
26
+ 'JSXIdentifier' ,
27
+ 'JSXMemberExpression' ,
28
+ isJsxIdentifierName
29
+ )
30
+ )
20
31
21
32
/**
22
- * @param {string } [idType]
23
- * @param {string } [memberType]
33
+ * @param {string } idType
34
+ * @param {string } memberType
35
+ * @param {(value: string) => boolean } isIdentifier
24
36
*/
25
- function toIdOrMemberExpressionFactory ( idType , memberType ) {
37
+ function toIdOrMemberExpressionFactory ( idType , memberType , isIdentifier ) {
26
38
return toIdOrMemberExpression
27
39
/**
28
40
* @param {Array<string|number> } ids
@@ -35,12 +47,18 @@ function toIdOrMemberExpressionFactory(idType, memberType) {
35
47
36
48
while ( ++ index < ids . length ) {
37
49
const name = ids [ index ]
50
+ const valid = typeof name === 'string' && isIdentifier ( name )
51
+
52
+ // A value of `asd.123` could be turned into `asd['123']` in the JS form,
53
+ // but JSX does not have a form for it, so throw.
54
+ /* c8 ignore next 3 */
55
+ if ( idType === 'JSXIdentifier' && ! valid ) {
56
+ throw new Error ( 'Cannot turn `' + name + '` into a JSX identifier' )
57
+ }
58
+
38
59
/** @type {Identifier|Literal } */
39
60
// @ts -expect-error: JSX is fine.
40
- const id =
41
- typeof name === 'string' && isIdentifierName ( name )
42
- ? { type : idType , name}
43
- : { type : 'Literal' , value : name }
61
+ const id = valid ? { type : idType , name} : { type : 'Literal' , value : name }
44
62
// @ts -expect-error: JSX is fine.
45
63
object = object
46
64
? {
@@ -62,3 +80,29 @@ function toIdOrMemberExpressionFactory(idType, memberType) {
62
80
return object
63
81
}
64
82
}
83
+
84
+ /**
85
+ * Checks if the given string is a valid JSX identifier name.
86
+ * @param {string } name
87
+ */
88
+ function isJsxIdentifierName ( name ) {
89
+ let index = - 1
90
+
91
+ while ( ++ index < name . length ) {
92
+ // We currently receive valid input, but this catches bugs and is needed
93
+ // when externalized.
94
+ /* c8 ignore next */
95
+ if ( ! ( index ? jsxCont : esStart ) ( name . charCodeAt ( index ) ) ) return false
96
+ }
97
+
98
+ // `false` if `name` is empty.
99
+ return index > 0
100
+ }
101
+
102
+ /**
103
+ * Checks if the given character code can continue a JSX identifier.
104
+ * @param {number } code
105
+ */
106
+ function jsxCont ( code ) {
107
+ return code === 45 /* `-` */ || esCont ( code )
108
+ }
1 commit comments
vercel[bot] commentedon Jan 25, 2022
Successfully deployed to the following URLs: