@@ -5,40 +5,53 @@ const XHTMLEntities = require('./xhtml');
5
5
const hexNumber = / ^ [ \d a - f A - F ] + $ / ;
6
6
const decimalNumber = / ^ \d + $ / ;
7
7
8
- const acorn = require ( "acorn" ) ;
9
- const tt = acorn . tokTypes ;
10
- const TokContext = acorn . TokContext ;
11
- const tokContexts = acorn . tokContexts ;
12
- const TokenType = acorn . TokenType ;
13
- const isNewLine = acorn . isNewLine ;
14
- const isIdentifierStart = acorn . isIdentifierStart ;
15
- const isIdentifierChar = acorn . isIdentifierChar ;
16
-
17
- const tc_oTag = new TokContext ( '<tag' , false ) ;
18
- const tc_cTag = new TokContext ( '</tag' , false ) ;
19
- const tc_expr = new TokContext ( '<tag>...</tag>' , true , true ) ;
20
-
21
- const tok = {
22
- jsxName : new TokenType ( 'jsxName' ) ,
23
- jsxText : new TokenType ( 'jsxText' , { beforeExpr : true } ) ,
24
- jsxTagStart : new TokenType ( 'jsxTagStart' ) ,
25
- jsxTagEnd : new TokenType ( 'jsxTagEnd' )
26
- }
8
+ // The map to `acorn-jsx` tokens from `acorn` namespace objects.
9
+ const acornJsxMap = new WeakMap ( ) ;
10
+
11
+ // Get the original tokens for the given `acorn` namespace object.
12
+ function getJsxTokens ( acorn ) {
13
+ acorn = acorn . Parser . acorn || acorn ;
14
+ let acornJsx = acornJsxMap . get ( acorn ) ;
15
+ if ( ! acornJsx ) {
16
+ const tt = acorn . tokTypes ;
17
+ const TokContext = acorn . TokContext ;
18
+ const TokenType = acorn . TokenType ;
19
+ const tc_oTag = new TokContext ( '<tag' , false ) ;
20
+ const tc_cTag = new TokContext ( '</tag' , false ) ;
21
+ const tc_expr = new TokContext ( '<tag>...</tag>' , true , true ) ;
22
+ const tokContexts = {
23
+ tc_oTag : tc_oTag ,
24
+ tc_cTag : tc_cTag ,
25
+ tc_expr : tc_expr
26
+ } ;
27
+ const tokTypes = {
28
+ jsxName : new TokenType ( 'jsxName' ) ,
29
+ jsxText : new TokenType ( 'jsxText' , { beforeExpr : true } ) ,
30
+ jsxTagStart : new TokenType ( 'jsxTagStart' ) ,
31
+ jsxTagEnd : new TokenType ( 'jsxTagEnd' )
32
+ } ;
33
+
34
+ tokTypes . jsxTagStart . updateContext = function ( ) {
35
+ this . context . push ( tc_expr ) ; // treat as beginning of JSX expression
36
+ this . context . push ( tc_oTag ) ; // start opening tag context
37
+ this . exprAllowed = false ;
38
+ } ;
39
+ tokTypes . jsxTagEnd . updateContext = function ( prevType ) {
40
+ let out = this . context . pop ( ) ;
41
+ if ( out === tc_oTag && prevType === tt . slash || out === tc_cTag ) {
42
+ this . context . pop ( ) ;
43
+ this . exprAllowed = this . curContext ( ) === tc_expr ;
44
+ } else {
45
+ this . exprAllowed = true ;
46
+ }
47
+ } ;
27
48
28
- tok . jsxTagStart . updateContext = function ( ) {
29
- this . context . push ( tc_expr ) ; // treat as beginning of JSX expression
30
- this . context . push ( tc_oTag ) ; // start opening tag context
31
- this . exprAllowed = false ;
32
- } ;
33
- tok . jsxTagEnd . updateContext = function ( prevType ) {
34
- let out = this . context . pop ( ) ;
35
- if ( out === tc_oTag && prevType === tt . slash || out === tc_cTag ) {
36
- this . context . pop ( ) ;
37
- this . exprAllowed = this . curContext ( ) === tc_expr ;
38
- } else {
39
- this . exprAllowed = true ;
49
+ acornJsx = { tokContexts : tokContexts , tokTypes : tokTypes } ;
50
+ acornJsxMap . set ( acorn , acornJsx ) ;
40
51
}
41
- } ;
52
+
53
+ return acornJsx ;
54
+ }
42
55
43
56
// Transforms JSX element name to string.
44
57
@@ -64,12 +77,38 @@ module.exports = function(options) {
64
77
allowNamespaces : options . allowNamespaces !== false ,
65
78
allowNamespacedObjects : ! ! options . allowNamespacedObjects
66
79
} , Parser ) ;
67
- }
80
+ } ;
68
81
} ;
69
- module . exports . tokTypes = tok ;
82
+
83
+ // This is `tokTypes` of the peer dep.
84
+ // This can be different instances from the actual `tokTypes` this plugin uses.
85
+ Object . defineProperty ( module . exports , "tokTypes" , {
86
+ get : function get_tokTypes ( ) {
87
+ return getJsxTokens ( require ( "acorn" ) ) . tokTypes ;
88
+ } ,
89
+ configurable : true ,
90
+ enumerable : true
91
+ } ) ;
70
92
71
93
function plugin ( options , Parser ) {
94
+ const acorn = Parser . acorn || require ( "acorn" ) ;
95
+ const acornJsx = getJsxTokens ( acorn ) ;
96
+ const tt = acorn . tokTypes ;
97
+ const tok = acornJsx . tokTypes ;
98
+ const tokContexts = acorn . tokContexts ;
99
+ const tc_oTag = acornJsx . tokContexts . tc_oTag ;
100
+ const tc_cTag = acornJsx . tokContexts . tc_cTag ;
101
+ const tc_expr = acornJsx . tokContexts . tc_expr ;
102
+ const isNewLine = acorn . isNewLine ;
103
+ const isIdentifierStart = acorn . isIdentifierStart ;
104
+ const isIdentifierChar = acorn . isIdentifierChar ;
105
+
72
106
return class extends Parser {
107
+ // Expose actual `tokTypes` and `tokContexts` to other plugins.
108
+ static get acornJsx ( ) {
109
+ return acornJsx ;
110
+ }
111
+
73
112
// Reads inline JSX contents token.
74
113
jsx_readToken ( ) {
75
114
let out = '' , chunkStart = this . pos ;
@@ -419,15 +458,15 @@ function plugin(options, Parser) {
419
458
++ this . pos ;
420
459
return this . finishToken ( tok . jsxTagStart ) ;
421
460
}
422
- return super . readToken ( code )
461
+ return super . readToken ( code ) ;
423
462
}
424
463
425
464
updateContext ( prevType ) {
426
465
if ( this . type == tt . braceL ) {
427
466
var curContext = this . curContext ( ) ;
428
467
if ( curContext == tc_oTag ) this . context . push ( tokContexts . b_expr ) ;
429
468
else if ( curContext == tc_expr ) this . context . push ( tokContexts . b_tmpl ) ;
430
- else super . updateContext ( prevType )
469
+ else super . updateContext ( prevType ) ;
431
470
this . exprAllowed = true ;
432
471
} else if ( this . type === tt . slash && prevType === tok . jsxTagStart ) {
433
472
this . context . length -= 2 ; // do not consider JSX expr -> JSX open tag -> ... anymore
0 commit comments