1
1
/**
2
2
* @typedef {import('property-information').Schema } Schema
3
- * @typedef {import('hast').Content } Content
3
+ * @typedef {import('hast').Nodes } Nodes
4
+ * @typedef {import('hast').Parents } Parents
4
5
* @typedef {import('hast').Element } Element
5
- * @typedef {import('hast').Root } Root
6
6
* @typedef {import('./components.js').Components } Components
7
7
*/
8
8
9
- /**
10
- * @typedef {Content | Root } Node
11
- * @typedef {Extract<Node, import('unist').Parent> } Parent
12
- */
13
-
14
9
/**
15
10
* @typedef {unknown } Fragment
16
11
* Represent the children, typically a symbol.
91
86
*
92
87
* @callback Create
93
88
* Create something in development or production.
94
- * @param {Node } node
89
+ * @param {Nodes } node
95
90
* hast node.
96
91
* @param {unknown } type
97
92
* Fragment symbol or tag name.
106
101
* Info passed around.
107
102
* @property {string | undefined } filePath
108
103
* File path.
104
+ * @property {Array<Parents> } ancestors
105
+ * Stack of parents.
109
106
* @property {Partial<Components> } components
110
107
* Components to swap.
111
108
* @property {boolean } passKeys
@@ -232,7 +229,7 @@ const tableElements = new Set(['table', 'thead', 'tbody', 'tfoot', 'tr'])
232
229
* Transform a hast tree to preact, react, solid, svelte, vue, etc.,
233
230
* with an automatic JSX runtime.
234
231
*
235
- * @param {Node } tree
232
+ * @param {Nodes } tree
236
233
* Tree to transform.
237
234
* @param {Options } options
238
235
* Configuration (required).
@@ -272,6 +269,7 @@ export function toJsxRuntime(tree, options) {
272
269
/** @type {State } */
273
270
const state = {
274
271
Fragment : options . Fragment ,
272
+ ancestors : [ ] ,
275
273
schema : options . space === 'svg' ? svg : html ,
276
274
passKeys : options . passKeys !== false ,
277
275
passNode : options . passNode || false ,
@@ -303,7 +301,7 @@ export function toJsxRuntime(tree, options) {
303
301
*
304
302
* @param {State } state
305
303
* Info passed around.
306
- * @param {Node } node
304
+ * @param {Nodes } node
307
305
* Current node.
308
306
* @param {string | undefined } key
309
307
* Key.
@@ -324,13 +322,19 @@ function one(state, node, key) {
324
322
state . schema = schema
325
323
}
326
324
325
+ state . ancestors . push ( node )
326
+
327
327
let children = createChildren ( state , node )
328
- const props = createProperties ( state , node )
328
+ const props = createProperties ( state , state . ancestors )
329
329
let type = state . Fragment
330
330
331
+ state . ancestors . pop ( )
332
+
331
333
if ( node . type === 'element' ) {
332
334
if ( children && tableElements . has ( node . tagName ) ) {
333
- children = children . filter ( ( child ) => ! whitespace ( child ) )
335
+ children = children . filter (
336
+ ( child ) => typeof child !== 'string' || ! whitespace ( child )
337
+ )
334
338
}
335
339
336
340
if ( own . call ( state . components , node . tagName ) ) {
@@ -408,8 +412,8 @@ function developmentCreate(filePath, jsxDEV) {
408
412
isStaticChildren ,
409
413
{
410
414
fileName : filePath ,
411
- lineNumber : point . line === null ? undefined : point . line ,
412
- columnNumber : point . column === null ? undefined : point . column - 1
415
+ lineNumber : point ? point . line : undefined ,
416
+ columnNumber : point ? point . column - 1 : undefined
413
417
} ,
414
418
undefined
415
419
)
@@ -421,7 +425,7 @@ function developmentCreate(filePath, jsxDEV) {
421
425
*
422
426
* @param {State } state
423
427
* Info passed around.
424
- * @param {Parent } node
428
+ * @param {Parents } node
425
429
* Current element.
426
430
* @returns {Array<Child> }
427
431
* Children.
@@ -458,12 +462,13 @@ function createChildren(state, node) {
458
462
*
459
463
* @param {State } state
460
464
* Info passed around.
461
- * @param {Parent } node
462
- * Current element .
465
+ * @param {Array<Parents> } ancestors
466
+ * Stack of parents .
463
467
* @returns {Props }
464
468
* Props for runtime.
465
469
*/
466
- function createProperties ( state , node ) {
470
+ function createProperties ( state , ancestors ) {
471
+ const node = ancestors [ ancestors . length - 1 ]
467
472
/** @type {Props } */
468
473
const props = { }
469
474
/** @type {string } */
@@ -472,7 +477,12 @@ function createProperties(state, node) {
472
477
if ( 'properties' in node && node . properties ) {
473
478
for ( prop in node . properties ) {
474
479
if ( prop !== 'children' && own . call ( node . properties , prop ) ) {
475
- const result = createProperty ( state , node , prop , node . properties [ prop ] )
480
+ const result = createProperty (
481
+ state ,
482
+ ancestors ,
483
+ prop ,
484
+ node . properties [ prop ]
485
+ )
476
486
477
487
if ( result ) {
478
488
props [ result [ 0 ] ] = result [ 1 ]
@@ -489,16 +499,16 @@ function createProperties(state, node) {
489
499
*
490
500
* @param {State } state
491
501
* Info passed around.
492
- * @param {Element } node
493
- * Current element .
502
+ * @param {Array<Parents> } ancestors
503
+ * Stack of parents .
494
504
* @param {string } prop
495
505
* Key.
496
506
* @param {Array<string | number> | string | number | boolean | null | undefined } value
497
507
* hast property value.
498
508
* @returns {Field | void }
499
509
* Field for runtime, optional.
500
510
*/
501
- function createProperty ( state , node , prop , value ) {
511
+ function createProperty ( state , ancestors , prop , value ) {
502
512
const info = find ( state . schema , prop )
503
513
504
514
// Ignore nullish and `NaN` values.
@@ -519,7 +529,9 @@ function createProperty(state, node, prop, value) {
519
529
// React only accepts `style` as object.
520
530
if ( info . property === 'style' ) {
521
531
let styleObject =
522
- typeof value === 'object' ? value : parseStyle ( state , node , String ( value ) )
532
+ typeof value === 'object'
533
+ ? value
534
+ : parseStyle ( state , ancestors , String ( value ) )
523
535
524
536
if ( state . stylePropertyNameCase === 'css' ) {
525
537
styleObject = transformStyleToCssCasing ( styleObject )
@@ -541,31 +553,33 @@ function createProperty(state, node, prop, value) {
541
553
*
542
554
* @param {State } state
543
555
* Info passed around.
544
- * @param {Element } node
545
- * Current element .
556
+ * @param {Array<Nodes> } ancestors
557
+ * Stack of nodes .
546
558
* @param {string } value
547
559
* CSS declarations.
548
560
* @returns {Style }
549
561
* Properties.
550
562
* @throws
551
563
* Throws `VFileMessage` when CSS cannot be parsed.
552
564
*/
553
- function parseStyle ( state , node , value ) {
565
+ function parseStyle ( state , ancestors , value ) {
554
566
/** @type {Style } */
555
567
const result = { }
556
568
557
569
try {
558
570
styleToObject ( value , replacer )
559
571
} catch ( error_ ) {
560
- const error = /** @type {Error } */ ( error_ )
561
- const cleanMessage = error . message . replace ( / ^ u n d e f i n e d : \d + : \d + : / , '' )
562
-
563
- const message = new VFileMessage (
564
- 'Cannot parse style attribute: ' + cleanMessage ,
565
- node ,
566
- 'hast-util-to-jsx-runtime:style'
567
- )
568
- message . file = state . filePath || null
572
+ const cause = /** @type {Error } */ ( error_ )
573
+
574
+ const message = new VFileMessage ( 'Cannot parse `style` attribute' , {
575
+ ancestors,
576
+ cause,
577
+ source : 'hast-util-to-jsx-runtime' ,
578
+ ruleId : 'style'
579
+ } )
580
+ message . file = state . filePath || undefined
581
+ message . url =
582
+ 'https://github.com/syntax-tree/hast-util-to-jsx-runtime#cannot-parse-style-attribute'
569
583
570
584
throw message
571
585
}
0 commit comments