import { ELEMENT_NODE, parse, render, walkSync } from 'ultrahtml' import { getFiles } from './get-files.mjs' /** * @typedef {import('../config/index.js').McFlyConfig} Config */ /** * Returns transformed HTML with custom elements registry in the head * @param {string} html * @param {Config['components']} type * @param {Storage} storage * @returns {Promise} */ export async function injectCustomElements(html, type, storage) { const ast = parse(html) const componentFiles = await getFiles(type, storage) const availableComponents = componentFiles.map((key) => key.replace(`.${type}`, '') ) const usedCustomElements = [] walkSync(ast, (node) => { const usedElement = availableComponents.find((name) => name === node.name) if (node.type === ELEMENT_NODE && !!usedElement) { usedCustomElements.push(usedElement) } }) // insert registry script to head if (usedCustomElements.length > 0) { const registryScript = await buildRegistry( usedCustomElements, type, storage ) walkSync(ast, (node) => { if (node.type === ELEMENT_NODE && node.name === 'head') { node.children.push(parse(registryScript)) } }) } return render(ast) } /** * Builds the string containing all custom elements definition * @param {Array} usedCustomElements * @param {Config['components']} type * @param {Storage} storage * @returns {Promise} */ async function buildRegistry(usedCustomElements, type, storage) { let registryScript = `' return registryScript } /** * Check if function is a constructor * @param {function} f * @returns boolean */ function isConstructor(f) { try { new f() // eslint-disable-next-line no-unused-vars } catch (err) { // TODO: verify err is the expected error and then return false } return true }