mirror of https://github.com/sveltejs/svelte
parent
0af6f20c77
commit
de8a38ba0e
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': minor
|
||||
---
|
||||
|
||||
feat: templateless template generation
|
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @import { TemplateOperations } from "../types.js"
|
||||
*/
|
||||
import { template_to_string } from './to-string';
|
||||
|
||||
/**
|
||||
* @param {TemplateOperations} items
|
||||
*/
|
||||
export function transform_template(items) {
|
||||
// here we will check if we need to use `$.template` or create a series of `document.createElement` calls
|
||||
return template_to_string(items);
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @import { TemplateOperations } from "../types.js"
|
||||
*/
|
||||
import { is_void } from '../../../../../utils.js';
|
||||
|
||||
/**
|
||||
* @param {TemplateOperations} items
|
||||
*/
|
||||
export function template_to_string(items) {
|
||||
let elements = [];
|
||||
|
||||
/**
|
||||
* @type {Array<Element>}
|
||||
*/
|
||||
let elements_stack = [];
|
||||
|
||||
/**
|
||||
* @type {Element | undefined}
|
||||
*/
|
||||
let last_current_element;
|
||||
|
||||
for (let instruction of items) {
|
||||
if (instruction.kind === 'push_element' && last_current_element) {
|
||||
elements_stack.push(last_current_element);
|
||||
continue;
|
||||
}
|
||||
if (instruction.kind === 'pop_element') {
|
||||
elements_stack.pop();
|
||||
continue;
|
||||
}
|
||||
/**
|
||||
* @type {Node | void}
|
||||
*/
|
||||
// @ts-expect-error we can't be here if `swap_current_element` but TS doesn't know that
|
||||
const value = map[instruction.kind](
|
||||
...[
|
||||
...(instruction.kind === 'set_prop' ? [last_current_element] : []),
|
||||
...(instruction.args ?? [])
|
||||
]
|
||||
);
|
||||
if (instruction.kind !== 'set_prop') {
|
||||
if (elements_stack.length >= 1 && value) {
|
||||
map.insert(/** @type {Element} */ (elements_stack.at(-1)), value);
|
||||
} else if (value) {
|
||||
elements.push(value);
|
||||
}
|
||||
if (instruction.kind === 'create_element') {
|
||||
last_current_element = /** @type {Element} */ (value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return elements.map((el) => stringify(el)).join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {{ kind: "element", element: string, props?: Record<string, string>, children?: Array<Node> }} Element
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{ kind: "anchor", data?: string }} Anchor
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{ kind: "text", value?: string }} Text
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef { Element | Anchor| Text } Node
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} element
|
||||
* @returns {Element}
|
||||
*/
|
||||
function create_element(element) {
|
||||
return {
|
||||
kind: 'element',
|
||||
element
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} data
|
||||
* @returns {Anchor}
|
||||
*/
|
||||
function create_anchor(data) {
|
||||
return {
|
||||
kind: 'anchor',
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @returns {Text}
|
||||
*/
|
||||
function create_text(value) {
|
||||
return {
|
||||
kind: 'text',
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Element} el
|
||||
* @param {string} prop
|
||||
* @param {string} value
|
||||
*/
|
||||
function set_prop(el, prop, value) {
|
||||
el.props ??= {};
|
||||
el.props[prop] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Element} el
|
||||
* @param {Node} child
|
||||
* @param {Node} [anchor]
|
||||
*/
|
||||
function insert(el, child, anchor) {
|
||||
el.children ??= [];
|
||||
el.children.push(child);
|
||||
}
|
||||
|
||||
let map = {
|
||||
create_element,
|
||||
create_text,
|
||||
create_anchor,
|
||||
set_prop,
|
||||
insert
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Node} el
|
||||
* @returns
|
||||
*/
|
||||
function stringify(el) {
|
||||
let str = ``;
|
||||
if (el.kind === 'element') {
|
||||
str += `<${el.element}`;
|
||||
for (let [prop, value] of Object.entries(el.props ?? {})) {
|
||||
if (value == null) {
|
||||
str += ` ${prop}`;
|
||||
} else {
|
||||
str += ` ${prop}="${value}"`;
|
||||
}
|
||||
}
|
||||
str += `>`;
|
||||
for (let child of el.children ?? []) {
|
||||
str += stringify(child);
|
||||
}
|
||||
if (!is_void(el.element)) {
|
||||
str += `</${el.element}>`;
|
||||
}
|
||||
} else if (el.kind === 'text') {
|
||||
str += el.value;
|
||||
} else if (el.kind === 'anchor') {
|
||||
if (el.data) {
|
||||
str += `<!--${el.data}-->`;
|
||||
} else {
|
||||
str += `<!>`;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
Loading…
Reference in new issue