70 lines
1.8 KiB
JavaScript
70 lines
1.8 KiB
JavaScript
import { h } from 'preact';
|
|
import { directivePrefix as p } from './constants';
|
|
|
|
const ignoreAttr = `${ p }ignore`;
|
|
const islandAttr = `${ p }island`;
|
|
const directiveParser = new RegExp( `${ p }([^:]+):?(.*)$` );
|
|
|
|
export const hydratedIslands = new WeakSet();
|
|
|
|
// Recursive function that transfoms a DOM tree into vDOM.
|
|
export function toVdom( node ) {
|
|
const props = {};
|
|
const { attributes, childNodes } = node;
|
|
const directives = {};
|
|
let hasDirectives = false;
|
|
let ignore = false;
|
|
let island = false;
|
|
|
|
if ( node.nodeType === 3 ) return node.data;
|
|
if ( node.nodeType === 4 ) {
|
|
node.replaceWith( new Text( node.nodeValue ) );
|
|
return node.nodeValue;
|
|
}
|
|
|
|
for ( let i = 0; i < attributes.length; i++ ) {
|
|
const n = attributes[ i ].name;
|
|
if ( n[ p.length ] && n.slice( 0, p.length ) === p ) {
|
|
if ( n === ignoreAttr ) {
|
|
ignore = true;
|
|
} else if ( n === islandAttr ) {
|
|
island = true;
|
|
} else {
|
|
hasDirectives = true;
|
|
let val = attributes[ i ].value;
|
|
try {
|
|
val = JSON.parse( val );
|
|
} catch ( e ) {}
|
|
const [ , prefix, suffix ] = directiveParser.exec( n );
|
|
directives[ prefix ] = directives[ prefix ] || {};
|
|
directives[ prefix ][ suffix || 'default' ] = val;
|
|
}
|
|
} else if ( n === 'ref' ) {
|
|
continue;
|
|
} else {
|
|
props[ n ] = attributes[ i ].value;
|
|
}
|
|
}
|
|
|
|
if ( ignore && ! island )
|
|
return h( node.localName, {
|
|
dangerouslySetInnerHTML: { __html: node.innerHTML },
|
|
} );
|
|
if ( island ) hydratedIslands.add( node );
|
|
|
|
if ( hasDirectives ) props.directives = directives;
|
|
|
|
const children = [];
|
|
for ( let i = 0; i < childNodes.length; i++ ) {
|
|
const child = childNodes[ i ];
|
|
if ( child.nodeType === 8 || child.nodeType === 7 ) {
|
|
child.remove();
|
|
i--;
|
|
} else {
|
|
children.push( toVdom( child ) );
|
|
}
|
|
}
|
|
|
|
return h( node.localName, props, children );
|
|
}
|