66 * @typedef {import('estree-jsx').JSXMemberExpression } JSXMemberExpression
77 */
88
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'
1014
1115export const toIdOrMemberExpression = toIdOrMemberExpressionFactory (
1216 'Identifier' ,
13- 'MemberExpression'
17+ 'MemberExpression' ,
18+ isIdentifierName
1419)
1520
1621export const toJsxIdOrMemberExpression =
1722 // @ts -expect-error: fine
1823 /** @type {(ids: Array<string|number>) => JSXIdentifier|JSXMemberExpression) } */
19- ( toIdOrMemberExpressionFactory ( 'JSXIdentifier' , 'JSXMemberExpression' ) )
24+ (
25+ toIdOrMemberExpressionFactory (
26+ 'JSXIdentifier' ,
27+ 'JSXMemberExpression' ,
28+ isJsxIdentifierName
29+ )
30+ )
2031
2132/**
22- * @param {string } [idType]
23- * @param {string } [memberType]
33+ * @param {string } idType
34+ * @param {string } memberType
35+ * @param {(value: string) => boolean } isIdentifier
2436 */
25- function toIdOrMemberExpressionFactory ( idType , memberType ) {
37+ function toIdOrMemberExpressionFactory ( idType , memberType , isIdentifier ) {
2638 return toIdOrMemberExpression
2739 /**
2840 * @param {Array<string|number> } ids
@@ -35,12 +47,19 @@ function toIdOrMemberExpressionFactory(idType, memberType) {
3547
3648 while ( ++ index < ids . length ) {
3749 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+
3859 /** @type {Identifier|Literal } */
3960 // @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 }
62+
4463 // @ts -expect-error: JSX is fine.
4564 object = object
4665 ? {
@@ -62,3 +81,29 @@ function toIdOrMemberExpressionFactory(idType, memberType) {
6281 return object
6382 }
6483}
84+
85+ /**
86+ * Checks if the given string is a valid JSX identifier name.
87+ * @param {string } name
88+ */
89+ function isJsxIdentifierName ( name ) {
90+ let index = - 1
91+
92+ while ( ++ index < name . length ) {
93+ // We currently receive valid input, but this catches bugs and is needed
94+ // when externalized.
95+ /* c8 ignore next */
96+ if ( ! ( index ? jsxCont : esStart ) ( name . charCodeAt ( index ) ) ) return false
97+ }
98+
99+ // `false` if `name` is empty.
100+ return index > 0
101+ }
102+
103+ /**
104+ * Checks if the given character code can continue a JSX identifier.
105+ * @param {number } code
106+ */
107+ function jsxCont ( code ) {
108+ return code === 45 /* `-` */ || esCont ( code )
109+ }
0 commit comments