From 80eadfe8c8a9791073e34161056063a8efbf63b0 Mon Sep 17 00:00:00 2001 From: "S. Elliott Johnson" Date: Mon, 8 May 2023 22:05:01 -0600 Subject: [PATCH] Convert src/runtime/internal/ssr.ts to JavaScript --- src/runtime/internal/ssr.ts | 341 +++++++++++++++++------------------- 1 file changed, 158 insertions(+), 183 deletions(-) diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index f5fa4613d9..6abe2de18b 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -2,222 +2,197 @@ import { set_current_component, current_component } from './lifecycle'; import { run_all, blank_object } from './utils'; import { boolean_attributes } from '../../shared/boolean_attributes'; export { is_void } from '../../shared/utils/names'; - -export const invalid_attribute_name_character = - /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; +export const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 // https://infra.spec.whatwg.org/#noncharacter - +/** @returns {string} */ export function spread(args, attrs_to_add) { - const attributes = Object.assign({}, ...args); - if (attrs_to_add) { - const classes_to_add = attrs_to_add.classes; - const styles_to_add = attrs_to_add.styles; - - if (classes_to_add) { - if (attributes.class == null) { - attributes.class = classes_to_add; - } else { - attributes.class += ' ' + classes_to_add; - } - } - - if (styles_to_add) { - if (attributes.style == null) { - attributes.style = style_object_to_string(styles_to_add); - } else { - attributes.style = style_object_to_string( - merge_ssr_styles(attributes.style, styles_to_add) - ); - } - } - } - - let str = ''; - - Object.keys(attributes).forEach((name) => { - if (invalid_attribute_name_character.test(name)) return; - - const value = attributes[name]; - if (value === true) str += ' ' + name; - else if (boolean_attributes.has(name.toLowerCase())) { - if (value) str += ' ' + name; - } else if (value != null) { - str += ` ${name}="${value}"`; - } - }); - - return str; + const attributes = Object.assign({}, ...args); + if (attrs_to_add) { + const classes_to_add = attrs_to_add.classes; + const styles_to_add = attrs_to_add.styles; + if (classes_to_add) { + if (attributes.class == null) { + attributes.class = classes_to_add; + } + else { + attributes.class += ' ' + classes_to_add; + } + } + if (styles_to_add) { + if (attributes.style == null) { + attributes.style = style_object_to_string(styles_to_add); + } + else { + attributes.style = style_object_to_string(merge_ssr_styles(attributes.style, styles_to_add)); + } + } + } + let str = ''; + Object.keys(attributes).forEach((name) => { + if (invalid_attribute_name_character.test(name)) + return; + const value = attributes[name]; + if (value === true) + str += ' ' + name; + else if (boolean_attributes.has(name.toLowerCase())) { + if (value) + str += ' ' + name; + } + else if (value != null) { + str += ` ${name}="${value}"`; + } + }); + return str; } - +/** @returns {{}} */ export function merge_ssr_styles(style_attribute, style_directive) { - const style_object = {}; - for (const individual_style of style_attribute.split(';')) { - const colon_index = individual_style.indexOf(':'); - const name = individual_style.slice(0, colon_index).trim(); - const value = individual_style.slice(colon_index + 1).trim(); - if (!name) continue; - style_object[name] = value; - } - - for (const name in style_directive) { - const value = style_directive[name]; - if (value) { - style_object[name] = value; - } else { - delete style_object[name]; - } - } - - return style_object; + const style_object = {}; + for (const individual_style of style_attribute.split(';')) { + const colon_index = individual_style.indexOf(':'); + const name = individual_style.slice(0, colon_index).trim(); + const value = individual_style.slice(colon_index + 1).trim(); + if (!name) + continue; + style_object[name] = value; + } + for (const name in style_directive) { + const value = style_directive[name]; + if (value) { + style_object[name] = value; + } + else { + delete style_object[name]; + } + } + return style_object; } - const ATTR_REGEX = /[&"]/g; const CONTENT_REGEX = /[&<]/g; - /** * Note: this method is performance sensitive and has been optimized * https://github.com/sveltejs/svelte/pull/5701 + * @param {unknown} value + * @returns {string} */ -export function escape(value: unknown, is_attr = false) { - const str = String(value); - - const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; - pattern.lastIndex = 0; - - let escaped = ''; - let last = 0; - - while (pattern.test(str)) { - const i = pattern.lastIndex - 1; - const ch = str[i]; - escaped += str.substring(last, i) + (ch === '&' ? '&' : ch === '"' ? '"' : '<'); - last = i + 1; - } - - return escaped + str.substring(last); +export function escape(value, is_attr = false) { + const str = String(value); + const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; + pattern.lastIndex = 0; + let escaped = ''; + let last = 0; + while (pattern.test(str)) { + const i = pattern.lastIndex - 1; + const ch = str[i]; + escaped += str.substring(last, i) + (ch === '&' ? '&' : ch === '"' ? '"' : '<'); + last = i + 1; + } + return escaped + str.substring(last); } - +/** @returns {any} */ export function escape_attribute_value(value) { - // keep booleans, null, and undefined for the sake of `spread` - const should_escape = typeof value === 'string' || (value && typeof value === 'object'); - return should_escape ? escape(value, true) : value; + // keep booleans, null, and undefined for the sake of `spread` + const should_escape = typeof value === 'string' || (value && typeof value === 'object'); + return should_escape ? escape(value, true) : value; } - +/** @returns {{}} */ export function escape_object(obj) { - const result = {}; - for (const key in obj) { - result[key] = escape_attribute_value(obj[key]); - } - return result; + const result = {}; + for (const key in obj) { + result[key] = escape_attribute_value(obj[key]); + } + return result; } - +/** @returns {string} */ export function each(items, fn) { - let str = ''; - for (let i = 0; i < items.length; i += 1) { - str += fn(items[i], i); - } - return str; + let str = ''; + for (let i = 0; i < items.length; i += 1) { + str += fn(items[i], i); + } + return str; } - export const missing_component = { - $$render: () => '' + $$render: () => '' }; - +/** @returns {any} */ export function validate_component(component, name) { - if (!component || !component.$$render) { - if (name === 'svelte:component') name += ' this={...}'; - throw new Error( - `<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a <${name}>.` - ); - } - - return component; + if (!component || !component.$$render) { + if (name === 'svelte:component') + name += ' this={...}'; + throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a <${name}>.`); + } + return component; } - +/** @returns {string} */ export function debug(file, line, column, values) { - console.log(`{@debug} ${file ? file + ' ' : ''}(${line}:${column})`); // eslint-disable-line no-console - console.log(values); // eslint-disable-line no-console - return ''; + console.log(`{@debug} ${file ? file + ' ' : ''}(${line}:${column})`); // eslint-disable-line no-console + console.log(values); // eslint-disable-line no-console + return ''; } - let on_destroy; - +/** @returns {{ render: (props?: {}, { $$slots, context }?: { $$slots?: {}; context?: Map; }) => { html: any; css: { code: string; map: any; }; head: string; }; $$render: (result: any, props: any, bindings: any, slots: any, context: any) => any; }} */ export function create_ssr_component(fn) { - function $$render(result, props, bindings, slots, context) { - const parent_component = current_component; - - const $$ = { - on_destroy, - context: new Map(context || (parent_component ? parent_component.$$.context : [])), - - // these will be immediately discarded - on_mount: [], - before_update: [], - after_update: [], - callbacks: blank_object() - }; - - set_current_component({ $$ }); - - const html = fn(result, props, bindings, slots); - - set_current_component(parent_component); - return html; - } - - return { - render: (props = {}, { $$slots = {}, context = new Map() } = {}) => { - on_destroy = []; - - const result: { - title: string; - head: string; - css: Set<{ - map: null; - code: string; - }>; - } = { title: '', head: '', css: new Set() }; - - const html = $$render(result, props, {}, $$slots, context); - - run_all(on_destroy); - - return { - html, - css: { - code: Array.from(result.css) - .map((css) => css.code) - .join('\n'), - map: null // TODO - }, - head: result.title + result.head - }; - }, - - $$render - }; + /** @returns {any} */ + function $$render(result, props, bindings, slots, context) { + const parent_component = current_component; + const $$ = { + on_destroy, + context: new Map(context || (parent_component ? parent_component.$$.context : [])), + // these will be immediately discarded + on_mount: [], + before_update: [], + after_update: [], + callbacks: blank_object() + }; + set_current_component({ $$ }); + const html = fn(result, props, bindings, slots); + set_current_component(parent_component); + return html; + } + return { + render: (props = {}, { $$slots = {}, context = new Map() } = {}) => { + on_destroy = []; + const result = { title: '', head: '', css: new Set() }; + const html = $$render(result, props, {}, $$slots, context); + run_all(on_destroy); + return { + html, + css: { + code: Array.from(result.css) + .map((css) => css.code) + .join('\n'), + map: null // TODO + }, + head: result.title + result.head + }; + }, + $$render + }; } - +/** @returns {string} */ export function add_attribute(name, value, boolean) { - if (value == null || (boolean && !value)) return ''; - const assignment = boolean && value === true ? '' : `="${escape(value, true)}"`; - return ` ${name}${assignment}`; + if (value == null || (boolean && !value)) + return ''; + const assignment = boolean && value === true ? '' : `="${escape(value, true)}"`; + return ` ${name}${assignment}`; } - +/** @returns {string} */ export function add_classes(classes) { - return classes ? ` class="${classes}"` : ''; + return classes ? ` class="${classes}"` : ''; } - +/** @returns {string} */ function style_object_to_string(style_object) { - return Object.keys(style_object) - .filter((key) => style_object[key]) - .map((key) => `${key}: ${escape_attribute_value(style_object[key])};`) - .join(' '); + return Object.keys(style_object) + .filter((key) => style_object[key]) + .map((key) => `${key}: ${escape_attribute_value(style_object[key])};`) + .join(' '); } - +/** @returns {string} */ export function add_styles(style_object) { - const styles = style_object_to_string(style_object); - - return styles ? ` style="${styles}"` : ''; + const styles = style_object_to_string(style_object); + return styles ? ` style="${styles}"` : ''; } + + + +