11/**
22 * @typedef {import('property-information').Schema } Schema
3- * @typedef {import('hast').Content } Content
3+ * @typedef {import('hast').Nodes } Nodes
4+ * @typedef {import('hast').Parents } Parents
45 * @typedef {import('hast').Element } Element
5- * @typedef {import('hast').Root } Root
66 * @typedef {import('./components.js').Components } Components
77 */
88
9- /**
10- * @typedef {Content | Root } Node
11- * @typedef {Extract<Node, import('unist').Parent> } Parent
12- */
13-
149/**
1510 * @typedef {unknown } Fragment
1611 * Represent the children, typically a symbol.
9186 *
9287 * @callback Create
9388 * Create something in development or production.
94- * @param {Node } node
89+ * @param {Nodes } node
9590 * hast node.
9691 * @param {unknown } type
9792 * Fragment symbol or tag name.
106101 * Info passed around.
107102 * @property {string | undefined } filePath
108103 * File path.
104+ * @property {Array<Parents> } ancestors
105+ * Stack of parents.
109106 * @property {Partial<Components> } components
110107 * Components to swap.
111108 * @property {boolean } passKeys
@@ -232,7 +229,7 @@ const tableElements = new Set(['table', 'thead', 'tbody', 'tfoot', 'tr'])
232229 * Transform a hast tree to preact, react, solid, svelte, vue, etc.,
233230 * with an automatic JSX runtime.
234231 *
235- * @param {Node } tree
232+ * @param {Nodes } tree
236233 * Tree to transform.
237234 * @param {Options } options
238235 * Configuration (required).
@@ -272,6 +269,7 @@ export function toJsxRuntime(tree, options) {
272269 /** @type {State } */
273270 const state = {
274271 Fragment : options . Fragment ,
272+ ancestors : [ ] ,
275273 schema : options . space === 'svg' ? svg : html ,
276274 passKeys : options . passKeys !== false ,
277275 passNode : options . passNode || false ,
@@ -303,7 +301,7 @@ export function toJsxRuntime(tree, options) {
303301 *
304302 * @param {State } state
305303 * Info passed around.
306- * @param {Node } node
304+ * @param {Nodes } node
307305 * Current node.
308306 * @param {string | undefined } key
309307 * Key.
@@ -324,13 +322,19 @@ function one(state, node, key) {
324322 state . schema = schema
325323 }
326324
325+ state . ancestors . push ( node )
326+
327327 let children = createChildren ( state , node )
328- const props = createProperties ( state , node )
328+ const props = createProperties ( state , state . ancestors )
329329 let type = state . Fragment
330330
331+ state . ancestors . pop ( )
332+
331333 if ( node . type === 'element' ) {
332334 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+ )
334338 }
335339
336340 if ( own . call ( state . components , node . tagName ) ) {
@@ -408,8 +412,8 @@ function developmentCreate(filePath, jsxDEV) {
408412 isStaticChildren ,
409413 {
410414 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
413417 } ,
414418 undefined
415419 )
@@ -421,7 +425,7 @@ function developmentCreate(filePath, jsxDEV) {
421425 *
422426 * @param {State } state
423427 * Info passed around.
424- * @param {Parent } node
428+ * @param {Parents } node
425429 * Current element.
426430 * @returns {Array<Child> }
427431 * Children.
@@ -458,12 +462,13 @@ function createChildren(state, node) {
458462 *
459463 * @param {State } state
460464 * Info passed around.
461- * @param {Parent } node
462- * Current element .
465+ * @param {Array<Parents> } ancestors
466+ * Stack of parents .
463467 * @returns {Props }
464468 * Props for runtime.
465469 */
466- function createProperties ( state , node ) {
470+ function createProperties ( state , ancestors ) {
471+ const node = ancestors [ ancestors . length - 1 ]
467472 /** @type {Props } */
468473 const props = { }
469474 /** @type {string } */
@@ -472,7 +477,12 @@ function createProperties(state, node) {
472477 if ( 'properties' in node && node . properties ) {
473478 for ( prop in node . properties ) {
474479 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+ )
476486
477487 if ( result ) {
478488 props [ result [ 0 ] ] = result [ 1 ]
@@ -489,16 +499,16 @@ function createProperties(state, node) {
489499 *
490500 * @param {State } state
491501 * Info passed around.
492- * @param {Element } node
493- * Current element .
502+ * @param {Array<Parents> } ancestors
503+ * Stack of parents .
494504 * @param {string } prop
495505 * Key.
496506 * @param {Array<string | number> | string | number | boolean | null | undefined } value
497507 * hast property value.
498508 * @returns {Field | void }
499509 * Field for runtime, optional.
500510 */
501- function createProperty ( state , node , prop , value ) {
511+ function createProperty ( state , ancestors , prop , value ) {
502512 const info = find ( state . schema , prop )
503513
504514 // Ignore nullish and `NaN` values.
@@ -519,7 +529,9 @@ function createProperty(state, node, prop, value) {
519529 // React only accepts `style` as object.
520530 if ( info . property === 'style' ) {
521531 let styleObject =
522- typeof value === 'object' ? value : parseStyle ( state , node , String ( value ) )
532+ typeof value === 'object'
533+ ? value
534+ : parseStyle ( state , ancestors , String ( value ) )
523535
524536 if ( state . stylePropertyNameCase === 'css' ) {
525537 styleObject = transformStyleToCssCasing ( styleObject )
@@ -541,31 +553,33 @@ function createProperty(state, node, prop, value) {
541553 *
542554 * @param {State } state
543555 * Info passed around.
544- * @param {Element } node
545- * Current element .
556+ * @param {Array<Nodes> } ancestors
557+ * Stack of nodes .
546558 * @param {string } value
547559 * CSS declarations.
548560 * @returns {Style }
549561 * Properties.
550562 * @throws
551563 * Throws `VFileMessage` when CSS cannot be parsed.
552564 */
553- function parseStyle ( state , node , value ) {
565+ function parseStyle ( state , ancestors , value ) {
554566 /** @type {Style } */
555567 const result = { }
556568
557569 try {
558570 styleToObject ( value , replacer )
559571 } 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'
569583
570584 throw message
571585 }
0 commit comments