lightview
Version:
A reactive UI library with features of Bau, Juris, and HTMX plus safe LLM UI generation
70 lines (61 loc) • 2.72 kB
JavaScript
/**
* DOM-related JPRX helpers for navigating and querying the DOM structure.
*/
/**
* Registers DOM-related helpers including the xpath() helper.
* @param {Function} registerHelper - The helper registration function
*/
export const registerDOMHelpers = (registerHelper) => {
/**
* Evaluates an XPath expression against the current DOM element.
* Returns a computed signal that re-evaluates when observed nodes change.
* Only supports backward-looking axes (parent, ancestor, preceding-sibling, etc.)
*
* @param {string} expression - The XPath expression to evaluate
* @param {object} context - The evaluation context (contains __node__)
* @returns {any} The result of the XPath evaluation
*/
registerHelper('xpath', function (expression) {
const domNode = this; // 'this' is bound to the DOM element
if (!domNode || !(domNode instanceof Element)) {
console.warn('[Lightview-CDOM] xpath() called without valid DOM context');
return '';
}
// Validate the expression (no forward-looking axes)
const forbiddenAxes = /\b(child|descendant|following|following-sibling)::/;
if (forbiddenAxes.test(expression)) {
console.error(`[Lightview-CDOM] xpath(): Forward-looking axes not allowed: ${expression}`);
return '';
}
const hasShorthandChild = /\/[a-zA-Z]/.test(expression) && !expression.startsWith('/html');
if (hasShorthandChild) {
console.error(`[Lightview-CDOM] xpath(): Shorthand child axis (/) not allowed: ${expression}`);
return '';
}
// Get Lightview's computed function
const LV = globalThis.Lightview;
if (!LV || !LV.computed) {
console.warn('[Lightview-CDOM] xpath(): Lightview not available');
return '';
}
// Return a computed signal that evaluates the XPath
return LV.computed(() => {
try {
const result = document.evaluate(
expression,
domNode,
null,
XPathResult.STRING_TYPE,
null
);
// TODO: Set up MutationObserver for reactivity
// For now, this just evaluates once
// Future: Observe parent/ancestor/sibling changes
return result.stringValue;
} catch (e) {
console.error(`[Lightview-CDOM] xpath() evaluation failed:`, e.message);
return '';
}
});
}, { pathAware: false });
};