UNPKG

@tmorin/ceb-templating-literal

Version:

The package is part of the `<ceb/>` library. It provides the implementation of a templating solution which leverages on the vanilla string literals.

158 lines 5.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.html = void 0; const ceb_utilities_1 = require("@tmorin/ceb-utilities"); const ceb_templating_parser_1 = require("@tmorin/ceb-templating-parser"); const ceb_templating_engine_1 = require("@tmorin/ceb-templating-engine"); const PATTERN_CEB_VALUE_INDEX = /{{ceb_value_index:([0-9]+)}}/gm; const PREFIX_CEB_VALUE_INDEX = "{{ceb_value_index:"; const SUFFIX_CEB_VALUE_INDEX = "}}"; const PREFIX_CEB_PROPERTY = "p:"; const PREFIX_CEB_OPTION = "o:"; const PROTECTED_TAGS = ["slot", "ceb-slot"]; function fromStringToValues(string = "", args = []) { const values = []; const r = new RegExp(PATTERN_CEB_VALUE_INDEX); let cursorFrom = 0; let cursorTo = 0; let match; while ((match = r.exec(string))) { cursorTo = match.index; const textValue = string.substring(cursorFrom, cursorTo); if (textValue) { values.push(textValue); } const argIndex = match[1]; const argValue = args[parseInt(argIndex)]; values.push(argValue); cursorFrom = cursorTo + match[0].length; } const finalTextValue = string.substring(cursorFrom); if (finalTextValue) { values.push(finalTextValue); } return values; } function isOperations(candidate) { return candidate && typeof candidate.render === "function" && typeof candidate.push === "function"; } function fromValuesToOperations(values, accumulator) { const operations = new Operations(); values.forEach((value) => { if (Array.isArray(value)) { for (const item of value) { if (isOperations(item)) { operations.push(item); } else { accumulator(operations, item); } } } else if (isOperations(value)) { operations.push(value); } else { accumulator(operations, value); } }); return operations; } function generateParameters(tagAttrs = [], args) { const attributes = []; const properties = []; const options = {}; tagAttrs.forEach(({ name: attrName, value: attrValue }) => { const values = fromStringToValues(attrValue, args); const value = values.length === 1 ? values[0] : values.join(""); const isProperty = attrName.startsWith(PREFIX_CEB_PROPERTY); const isOption = attrName.startsWith(PREFIX_CEB_OPTION); if (isProperty) { const propName = (0, ceb_utilities_1.toCamelCase)(attrName.replace(PREFIX_CEB_PROPERTY, "")); if (propName) { properties.push([propName, value]); } } else if (isOption) { const optName = (0, ceb_utilities_1.toCamelCase)(attrName.replace(PREFIX_CEB_OPTION, "")); if (optName) { Object.assign(options, { [optName]: value === "" || value === attrName ? true : value, }); } } else { attributes.push([attrName, value]); } }); return { attributes, properties, options }; } class Operations { constructor(operations = []) { this.operations = operations; } push(value) { if (value instanceof Operations) { value.operations.forEach((o) => this.operations.push(o)); } else { this.operations.push(value); } } render(destination, parameters) { ceb_templating_engine_1.Engine.update(destination, (engine) => { this.operations.forEach((operation) => operation(engine)); }, Object.assign({ greyDom: parameters === null || parameters === void 0 ? void 0 : parameters.greyDom }, parameters)); } } /** * This function is a [tag function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) * which converts a [literal statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literal) to a {@link Template}. * The template can then be used to update the DOM. * * @example Render a simple greeting * ```typescript * import {Template} from "@tmorin/ceb-templating-builder" * import {html} from "@tmorin/ceb-templating-literal" * const name = "World" * const template : Template = html`<p>Hello, ${name}!</p>` * template.render(document.body) * ``` * * @param strings the strings * @param args the arguments */ function html(strings, ...args) { const template = strings .map((text, index) => `${text}${typeof args[index] !== "undefined" ? `${PREFIX_CEB_VALUE_INDEX}${index}${SUFFIX_CEB_VALUE_INDEX}` : ""}`) .join(""); const operations = new Operations(); (0, ceb_templating_parser_1.parse)(template, { openTag(name, attrs, selfClosing) { const parameters = generateParameters(attrs, args); if (PROTECTED_TAGS.indexOf(name) > -1) { Object.assign(parameters.options, { slot: true, }); } operations.push((engine) => engine.openElement(name, parameters)); if (selfClosing) { operations.push((engine) => engine.closeElement()); } }, closeTag() { operations.push((engine) => engine.closeElement()); }, text(data) { const values = fromStringToValues(data, args); operations.push(fromValuesToOperations(values, (childOperations, value) => childOperations.push((engine) => engine.text(value)))); }, comment(data) { const values = fromStringToValues(data, args); operations.push(fromValuesToOperations(values, (childOperations, value) => childOperations.push((engine) => engine.comment(value)))); }, }); return operations; } exports.html = html; //# sourceMappingURL=literal.js.map