UNPKG

ember-source

Version:

A JavaScript framework for creating ambitious web applications

943 lines (897 loc) 32.2 kB
import './debug-to-string-BsFOvUtQ.js'; import { isDevelopingApp } from '@embroider/macros'; import { e as $v0, f as $t1, g as $t0, h as $s1, $ as $s0, d as $sp, c as $fp, b as $ra, a as $pc } from './registers-ylirb0dq.js'; import { b as assertNever } from './assert-CUCJBR2C.js'; import '../@glimmer/global-context/index.js'; import '../@glimmer/validator/index.js'; import './reference-B6HMX4y0.js'; import { I as InternalComponentCapabilities } from './flags-BsZlvEeR.js'; const CURRIED_COMPONENT = 0; const CURRIED_HELPER = 1; const CURRIED_MODIFIER = 2; const SIGN_BIT = -536870913; const MAX_INT = ~SIGN_BIT - 1; const MIN_INT = ~MAX_INT; function isHandle(value) { return value >= 0; } function constants(...values) { return [false, true, null, undefined, ...values]; } function isSmallInt(value) { return value % 1 === 0 && value <= MAX_INT && value >= MIN_INT; } function encodeNegative(num) { return num & SIGN_BIT; } function decodeNegative(num) { return num | ~SIGN_BIT; } function encodePositive(num) { return ~num; } function decodePositive(num) { return ~num; } function encodeHandle(num) { return num; } function decodeHandle(num) { return num; } function encodeImmediate(num) { num |= 0; return num < 0 ? encodeNegative(num) : encodePositive(num); } function decodeImmediate(num) { num |= 0; return num > SIGN_BIT ? decodePositive(num) : decodeNegative(num); } [1, -1].forEach(x => decodeImmediate(encodeImmediate(x))); const VM_HELPER_OP = 16; const VM_SET_NAMED_VARIABLES_OP = 17; const VM_SET_BLOCKS_OP = 18; const VM_SET_VARIABLE_OP = 19; const VM_SET_BLOCK_OP = 20; const VM_GET_VARIABLE_OP = 21; const VM_GET_PROPERTY_OP = 22; const VM_GET_BLOCK_OP = 23; const VM_SPREAD_BLOCK_OP = 24; const VM_HAS_BLOCK_OP = 25; const VM_HAS_BLOCK_PARAMS_OP = 26; const VM_CONCAT_OP = 27; const VM_CONSTANT_OP = 28; const VM_CONSTANT_REFERENCE_OP = 29; const VM_PRIMITIVE_OP = 30; const VM_PRIMITIVE_REFERENCE_OP = 31; const VM_DUP_OP = 33; const VM_POP_OP = 34; const VM_LOAD_OP = 35; const VM_FETCH_OP = 36; const VM_ROOT_SCOPE_OP = 37; const VM_VIRTUAL_ROOT_SCOPE_OP = 38; const VM_CHILD_SCOPE_OP = 39; const VM_POP_SCOPE_OP = 40; const VM_TEXT_OP = 41; const VM_COMMENT_OP = 42; const VM_APPEND_HTML_OP = 43; const VM_APPEND_SAFE_HTML_OP = 44; const VM_APPEND_DOCUMENT_FRAGMENT_OP = 45; const VM_APPEND_NODE_OP = 46; const VM_APPEND_TEXT_OP = 47; const VM_OPEN_ELEMENT_OP = 48; const VM_OPEN_DYNAMIC_ELEMENT_OP = 49; const VM_PUSH_REMOTE_ELEMENT_OP = 50; const VM_STATIC_ATTR_OP = 51; const VM_DYNAMIC_ATTR_OP = 52; const VM_COMPONENT_ATTR_OP = 53; const VM_FLUSH_ELEMENT_OP = 54; const VM_CLOSE_ELEMENT_OP = 55; const VM_POP_REMOTE_ELEMENT_OP = 56; const VM_MODIFIER_OP = 57; const VM_BIND_DYNAMIC_SCOPE_OP = 58; const VM_PUSH_DYNAMIC_SCOPE_OP = 59; const VM_POP_DYNAMIC_SCOPE_OP = 60; const VM_COMPILE_BLOCK_OP = 61; const VM_PUSH_BLOCK_SCOPE_OP = 62; const VM_PUSH_SYMBOL_TABLE_OP = 63; const VM_INVOKE_YIELD_OP = 64; const VM_JUMP_IF_OP = 65; const VM_JUMP_UNLESS_OP = 66; const VM_JUMP_EQ_OP = 67; const VM_ASSERT_SAME_OP = 68; const VM_ENTER_OP = 69; const VM_EXIT_OP = 70; const VM_TO_BOOLEAN_OP = 71; const VM_ENTER_LIST_OP = 72; const VM_EXIT_LIST_OP = 73; const VM_ITERATE_OP = 74; const VM_MAIN_OP = 75; const VM_CONTENT_TYPE_OP = 76; const VM_CURRY_OP = 77; const VM_PUSH_COMPONENT_DEFINITION_OP = 78; const VM_PUSH_DYNAMIC_COMPONENT_INSTANCE_OP = 79; const VM_RESOLVE_DYNAMIC_COMPONENT_OP = 80; const VM_RESOLVE_CURRIED_COMPONENT_OP = 81; const VM_PUSH_ARGS_OP = 82; const VM_PUSH_EMPTY_ARGS_OP = 83; const VM_PREPARE_ARGS_OP = 85; const VM_CAPTURE_ARGS_OP = 86; const VM_CREATE_COMPONENT_OP = 87; const VM_REGISTER_COMPONENT_DESTRUCTOR_OP = 88; const VM_PUT_COMPONENT_OPERATIONS_OP = 89; const VM_GET_COMPONENT_SELF_OP = 90; const VM_GET_COMPONENT_TAG_NAME_OP = 91; const VM_GET_COMPONENT_LAYOUT_OP = 92; const VM_POPULATE_LAYOUT_OP = 95; const VM_INVOKE_COMPONENT_LAYOUT_OP = 96; const VM_BEGIN_COMPONENT_TRANSACTION_OP = 97; const VM_COMMIT_COMPONENT_TRANSACTION_OP = 98; const VM_DID_CREATE_ELEMENT_OP = 99; const VM_DID_RENDER_LAYOUT_OP = 100; const VM_DEBUGGER_OP = 103; const VM_STATIC_COMPONENT_ATTR_OP = 105; const VM_DYNAMIC_CONTENT_TYPE_OP = 106; const VM_DYNAMIC_HELPER_OP = 107; const VM_DYNAMIC_MODIFIER_OP = 108; const VM_IF_INLINE_OP = 109; const VM_NOT_OP = 110; const VM_GET_DYNAMIC_VAR_OP = 111; const VM_LOG_OP = 112; const VM_SYSCALL_SIZE = 113; const VM_PUSH_FRAME_OP = 0; const VM_POP_FRAME_OP = 1; const VM_INVOKE_VIRTUAL_OP = 2; const VM_INVOKE_STATIC_OP = 3; const VM_JUMP_OP = 4; const VM_RETURN_OP = 5; const VM_RETURN_TO_OP = 6; const VM_MACHINE_SIZE = 7; function isMachineOp(value) { return value >= 0 && value <= 15; } function decodeCurry(curry) { switch (curry) { case CURRIED_COMPONENT: return 'component'; case CURRIED_HELPER: return 'helper'; case CURRIED_MODIFIER: return 'modifier'; default: throw Error(`Unexpected curry value: ${curry}`); } } function decodeRegister(register) { switch (register) { case $pc: return '$pc'; case $ra: return '$ra'; case $fp: return '$fp'; case $sp: return '$sp'; case $s0: return '$s0'; case $s1: return '$s1'; case $t0: return '$t0'; case $t1: return '$t1'; case $v0: return '$v0'; default: return `$bug${register}`; } } function decodePrimitive(primitive, constants) { if (primitive >= 0) { return constants.getValue(decodeHandle(primitive)); } return decodeImmediate(primitive); } const todo = ({ label, value }) => ['error:operand', value, { label }]; // eslint-disable-next-line @typescript-eslint/no-explicit-any class Disassembler { static build(builder) { return builder(new Disassembler()).#disms; } #disms; constructor() { this.#disms = {}; } addNullable(names, dism) { for (const name of names) { this.#disms[name] = dism; this.#disms[`${name}?`] = dism; } return this; } add(names, dism) { const add = (name, dism) => this.#disms[name] = dism; for (const name of names) { add(name, dism); } return this; } } Disassembler.build(d => { return d.add(['imm/u32', 'imm/i32', 'imm/u32{todo}', 'imm/i32{todo}'], ({ value }) => ['number', value]).add(['const/i32[]'], ({ value, constants }) => ['array', constants.getArray(value), { kind: Number }]).add(['const/bool'], ({ value }) => ['boolean', !!value]).add(['imm/bool'], ({ value, constants }) => ['boolean', constants.getValue(decodeHandle(value))]).add(['handle'], ({ constants, value }) => ['constant', constants.getValue(value)]).add(['handle/block'], ({ value, heap }) => ['instruction', heap.getaddr(value)]).add(['imm/pc'], ({ value }) => ['instruction', value]).add(['const/any[]'], ({ value, constants }) => ['array', constants.getArray(value)]).add(['const/primitive'], ({ value, constants }) => ['primitive', decodePrimitive(value, constants)]).add(['register'], ({ value }) => ['register', decodeRegister(value)]).add(['const/any'], ({ value, constants }) => ['dynamic', constants.getValue(value)]).add(['variable'], ({ value, meta }) => { return ['variable', value, { name: meta?.symbols.lexical?.at(value) ?? null }]; }).add(['register/instruction'], ({ value }) => ['instruction', value]).add(['imm/enum<curry>'], ({ value }) => ['enum<curry>', decodeCurry(value)]).addNullable(['const/str'], ({ value, constants }) => ['string', constants.getValue(value)]).addNullable(['const/str[]'], ({ value, constants }) => ['array', constants.getArray(value), { kind: String }]).add(['imm/block:handle'], todo).add(['const/definition'], todo).add(['const/fn'], todo).add(['instruction/relative'], ({ value, offset }) => ['instruction', offset + value]).add(['register/sN'], todo).add(['register/stack'], todo).add(['register/tN'], todo).add(['register/v0'], todo); }); /* This file is generated by build/debug.js */ new Array(VM_SYSCALL_SIZE).fill(null); new Array(VM_MACHINE_SIZE).fill(null); const ANNOTATION_STYLES = ['background-color: oklch(93% 0.03 300); color: oklch(34% 0.18 300)', 'background-color: oklch(93% 0.03 250); color: oklch(34% 0.18 250)', 'background-color: oklch(93% 0.03 200); color: oklch(34% 0.18 200)', 'background-color: oklch(93% 0.03 150); color: oklch(34% 0.18 150)', 'background-color: oklch(93% 0.03 100); color: oklch(34% 0.18 100)', 'background-color: oklch(93% 0.03 50); color: oklch(34% 0.18 50)', 'background-color: oklch(93% 0.03 0); color: oklch(34% 0.18 0)']; /** * The `LogFragmentBuffer` is responsible for collecting the fragments that are logged to the * `DebugLogger` so that they can be accumulated during a group and flushed together. * * This queuing serves two purposes: * * 1. To allow the individual fragments that make up a single line to append their values to * the current line. To accomplish this, each fragment can append static content and its * formatting specifier (e.g. `%o`) to the accumulated {@link #template} *and* append the * value to format to the {@link #substitutions} array. * 2. To allow logs that refer to objects to be represented as footnotes in the current line, * with the footnote to be printed in a later line. * * This allows a list of fragments, each of which represent formattable values, to be flattened * into a single template string and an array of values to format. * * ## Footnotes * * An opcode slice containing constant references will be logged like this: * * ``` * ... * 362. (PushArgs names=[] block-names=[] flags=16) * 366. (Helper helper=[0]) * [0] glimmerHelper() * 368. (PopFrame) * 369. (Fetch register=$v0) * 371. (Primitive constant="/index.html") * ... * ``` * * The fragment for line `366` includes an `ObjectFragment` for the helper value. When logged, * the object will be represented as a footnote and the value will be printed in a later * line. */ class LogFragmentBuffer { /** * The first parameter to the `console.log` family of APIs is a *template* that can use * format specifiers (e.g. `%c`, `%o`, and `%O`) to refer to subsequent parameters. * * When a fragment is appended to a line, */ #template = ''; /** * Each format specified in the {@link #template} corresponds to a value in the * `#substitutions` array. */ #substitutions = []; /** * The logging options for the buffer, which currently only contains `showSubtle`. * * When fragments call the buffer's {@linkcode append} method, they specify whether the * content to append is subtle or not. If the buffer is not configured to show subtle * content, the content is not appended. * * This allows fragments to append content to the buffer without having to know how the * buffer is configured. */ #options; /** * A single line can produce multiple queued log entries. This happens when fragments * append *footnotes* to the buffer. A *reference* to the footnote is appended to the * primary line, and a line containing the *value* of the footnote is appended to the * `#queued` array. * * Both the primary line and any queued footnotes are flushed together when the buffer * is flushed. */ #footnotes = []; #nextFootnote = 1; #style = 0; constructor(options) { this.#options = options; } /** * Add a footnoted value to the current buffer. * * If the `subtle` option is set, the fragment will only be printed if the buffer is configured * to show subtle content. * * This method takes two callbacks: `add` and `append`. * * The `append` callback behaves like {@linkcode append}, but without the `subtle` argument. If * `addFootnoted` is called with `subtle: false`, then the callback will never be called, so * there is no need to pass the `subtle` argument again. * * The `add` callback is responsible for appending the footnote itself to the buffer. The first * parameter to `add` (`useNumber`) specifies whether the caller has used the footnote number * to refer to the footnote. * * This is typically true, but fragments can specify an alternative annotation that should be used * instead of the default footnote number. In that case, the footnote number is not used, and the * next footnote is free to use it. * * The `add` callback also takes a template string and an optional list of substitutions, which * describe the way the footnote itself should be formatted. */ addFootnoted(subtle, add) { if (subtle && !this.#options.showSubtle) return; const child = new LogFragmentBuffer(this.#options); const style = ANNOTATION_STYLES[this.#style++ % ANNOTATION_STYLES.length]; const usedNumber = add({ n: this.#nextFootnote, style }, child); if (usedNumber) { this.#nextFootnote += 1; } this.#footnotes.push({ type: 'line', subtle: false, template: child.#template, substitutions: child.#substitutions }); this.#footnotes.push(...child.#footnotes); } /** * Append a fragment to the current buffer. * * If the `subtle` option is set, the fragment will only be printed if the buffer is configured * to show subtle content. */ append(subtle, template, ...substitutions) { if (subtle && !this.#options.showSubtle) return; this.#template += template; this.#substitutions.push(...substitutions); } #mapLine(line) { if (line.subtle && !this.#options.showSubtle) return []; return [{ type: 'line', line: [line.template, ...line.substitutions] }]; } flush() { return [{ type: 'line', line: [this.#template, ...this.#substitutions] }, ...this.#footnotes.flatMap(queued => this.#mapLine(queued))]; } } // inspired by https://github.com/ChromeDevTools/devtools-frontend/blob/c2c17396c9e0da3f1ce6514c3a946f88a06b17f2/front_end/ui/legacy/themeColors.css#L65 const STYLES = { var: 'color: grey', varReference: 'color: blue; text-decoration: underline', varBinding: 'color: blue;', specialVar: 'color: blue', prop: 'color: grey', specialProp: 'color: red', token: 'color: green', def: 'color: blue', builtin: 'color: blue', punct: 'color: GrayText', kw: 'color: rgb(185 0 99 / 100%);', type: 'color: teal', number: 'color: blue', string: 'color: red', null: 'color: grey', specialString: 'color: darkred', atom: 'color: blue', attrName: 'color: orange', attrValue: 'color: blue', boolean: 'color: blue', comment: 'color: green', meta: 'color: grey', register: 'color: purple', constant: 'color: purple', dim: 'color: grey', internals: 'color: lightgrey; font-style: italic', diffAdd: 'color: Highlight', diffDelete: 'color: SelectedItemText; background-color: SelectedItem', diffChange: 'color: MarkText; background-color: Mark', sublabel: 'font-style: italic; color: grey', error: 'color: red', label: 'text-decoration: underline', errorLabel: 'color: darkred; font-style: italic', errorMessage: 'color: darkred; text-decoration: underline', stack: 'color: grey; font-style: italic', unbold: 'font-weight: normal', pointer: 'background-color: lavender; color: indigo', pointee: 'background-color: lavender; color: indigo', focus: 'font-weight: bold', focusColor: 'background-color: lightred; color: darkred' }; function mergeStyle(a, b) { if (a && b) { return `${a}; ${b}`; } else { return a || b; } } function intoFormat(format) { if (typeof format === 'string') { return { style: STYLES[format] }; } else { return format; } } function formats(...formats) { return formats.map(c => intoFormat(c).style).join('; '); } const FORMATTERS = { value: '%O', string: '%s', integer: '%d', float: '%f', special: '%o' }; /** * A leaf fragment that represents an arbitrary value. * * When the value is a primitive, the fragment is appended to the buffer as if it was an instance of * the appropriate leaf fragment type (e.g. strings are appended as if they were `StringFragment`). * * Otherwise, `ValueFragment` is appended to the current line as a footnote reference and the value * itself is appended to a later line that *defines* the footnote using the `%O` format specifier. */ /** * A leaf fragment that represents a string value. * * Corresponds to the `%s` format specifier. */ /** * A leaf fragment that represents an integer value. * * Corresponds to the `%d` format specifier. */ /** * A leaf fragment that represents a float value. * * Corresponds to the `%f` format specifier. */ /** * A leaf fragment that represents a DOM node. * * Corresponds to the `%o` format specifier. */ /** * The list of leaf fragment types correspond exactly to the list of console.log * format specifiers. */ /** * @import { StyleName } from './styles'; */ /** * Fragment is the most fundamental building block of the debug logger. * */ class Fragment { static integer(value, options) { return new Fragment({ kind: 'integer', value, ...options }); } static float(value, options) { return new Fragment({ kind: 'float', value, ...options }); } static string(value, options) { return new Fragment({ kind: 'string', value, ...options }); } static special(value, options) { return new Fragment({ kind: 'special', value, ...options }); } #type; constructor(type) { this.#type = type; } /** * A subtle fragment is only printed if the `showSubtle` option is set. * * Returns true if this fragment is a subtle leaf or is a multi fragment * with all subtle leaves. */ isSubtle() { return this.leaves().every(leaf => leaf.#type.subtle); } /** * If the current fragment is not empty, apply `ifPresent` to the current * fragment. Otherwise, do nothing. * * If the current fragment is subtle, the result is also subtle. */ map(ifPresent) { if (this.isEmpty()) return this; const fragment = ifPresent(this); return this.isSubtle() ? fragment.subtle() : fragment; } /** * A fragment is empty if it should not be printed with the provided display options. * * This means that if a fragment is subtle and `showSubtle` is false, the fragment is empty. */ isEmpty(options = { showSubtle: true }) { return this.leaves().every(leaf => !leaf.#shouldShow(options)); } /** * Returns an array of {@linkcode LeafFragment}s that make up the current * fragment. * * This effectively flattens any number of nested multi-fragments into a flat array of leaf * fragments. */ leaves() { if (this.#type.kind === 'multi') { return this.#type.value.flatMap(f => f.leaves()); } else if (this.#type.kind === 'string' && this.#type.value === '') { return []; } else { return [this]; } } /** * Returns a fragment with the specified subtle status without mutating the current fragment. * * If `isSubtle` is true, the fragment will also be styled with the `subtle` style. */ subtle(isSubtle = true) { if (!this.isSubtle() && !isSubtle) { return this; } const fragment = this.#subtle(isSubtle); return isSubtle ? fragment.styleAll('dim') : fragment; } #subtle(isSubtle) { if (this.#type.kind === 'multi') { return new Fragment({ ...this.#type, value: this.leaves().flatMap(f => f.subtle(isSubtle).leaves()) }); } else { return new Fragment({ ...this.#type, subtle: isSubtle }); } } /** * Apply the specified styles to the current fragment (if it's a leaf) or all * of its children (if it's a multi-fragment). * * Keep in mind that merging styles might be very difficult to undo, so treat * this as a low-level operation, and prefer to use higher-level concepts like * `subtle` if you can instead. */ styleAll(...allFormats) { if (allFormats.length === 0) return this; if (this.#type.kind === 'multi') { return new Fragment({ ...this.#type, value: this.#type.value.flatMap(f => f.styleAll(...allFormats).leaves()) }); } else { return new Fragment({ ...this.#type, style: mergeStyle(this.#type.style, formats(...allFormats)) }); } } /** * Convert the current fragment into a string with no additional formatting. * The primary purpose for this method is to support converting a fragment * into a string for inclusion in thrown Errors. If you're going to *log* * a fragment, log it using `DebugLogger` and don't convert it to * a string first. */ stringify(options) { return this.leaves().filter(leaf => leaf.#shouldShow(options)).map(leaf => { const fragment = leaf.#type; if (fragment.kind === 'value') { return `<object>`; } else { // eslint-disable-next-line @typescript-eslint/no-base-to-string -- @fixme return String(fragment.value); } }).join(''); } /** * Should the current fragment be printed with the provided display options? * * Importantly, if the current fragment contains subtle content but the `showSubtle` option is * false, `#shouldShow` will return false. * * @see isEmpty */ #shouldShow(options) { return this.leaves().some(leaf => { const fragment = leaf.#type; if (fragment.subtle && !options.showSubtle) { return false; } else if (fragment.kind === 'string' && fragment.value === '') { return false; } return true; }); } /** * Convert this fragment into a Loggable for logging through the `DebugLogger`. */ toLoggable(options) { const buffer = new LogFragmentBuffer(options); for (const leaf of this.leaves()) { leaf.appendTo(buffer); } return buffer.flush(); } /** * Append this fragment to the low-level `LogFragmentBuffer`. */ appendTo(buffer) { const fragment = this.#type; const subtle = this.isSubtle(); // If the fragment is a multi fragment, append each of its leaves to the buffer // and return. if (fragment.kind === 'multi') { for (const f of fragment.value) { f.appendTo(buffer); } return; } // If the fragment is a value fragment and the value is a primitive, give it special // treatment since we can trivially serialize it. if (fragment.kind === 'value') { // If the value is a string or number, convert it into a string, float or integer // fragment and append that instead. This means that strings and numbers are // represented the same way in logs whether they are explicitly created as string, // float or integer fragments *or* whether they are the value of a value fragment. if (typeof fragment.value === 'string') { return Fragment.string(JSON.stringify(fragment.value), { style: STYLES.string, subtle }).appendTo(buffer); } else if (typeof fragment.value === 'number') { const f = fragment.value % 1 === 0 ? Fragment.integer : Fragment.float; return f(fragment.value, { style: STYLES.number, subtle }).appendTo(buffer); // Alternatively, if the value of a `value` fragment is `null` or `undefined`, // append the string `null` or `undefined`, respectively with the `null` style. } else if (fragment.value === null || fragment.value === undefined) { return Fragment.string('null', { style: STYLES.null, subtle: this.isSubtle() }).appendTo(buffer); // Finally, if the value of a `value` fragment is boolean, append the string // `true` or `false` with the `boolean` style. } else if (typeof fragment.value === 'boolean') { return Fragment.string(String(fragment.value), { style: STYLES.boolean, subtle }).appendTo(buffer); } // All other values (i.e. objects and functions) are represented as footnotes and // are handled below. } switch (fragment.kind) { // strings are appended using %s case 'string': // integers are appended using %d case 'integer': // floats are appended using %f case 'float': buffer.append(fragment.subtle ?? false, `%c${FORMATTERS[fragment.kind]}`, fragment.style, fragment.value); break; // the remaining value types are represented as footnotes // dom nodes are appended to the footnote line using %o case 'special': // values are appended to the footnote line using %O case 'value': { // If a fragment has an associated annotation, we'll use the annotation as the // footnote rather than the footnote number. const override = fragment.kind === 'value' ? fragment.display : undefined; buffer.addFootnoted(fragment.subtle ?? false, ({ n, style }, footnote) => { const appendValueAsFootnote = ref => void footnote.append(subtle, `%c| %c[${ref}]%c ${FORMATTERS[fragment.kind]}`, STYLES.dim, style, '', fragment.value); if (override) { if ('inline' in override) { override.inline.subtle(subtle).appendTo(footnote); return false; } buffer.append(subtle, `%c[${override.ref}]%c`, style, ''); if (override.footnote) { frag`${as.dim('| ')}${override.footnote}`.subtle(subtle).appendTo(footnote); } else { appendValueAsFootnote(override.ref); } return false; } buffer.append(subtle, `%c[${n}]%c`, style, ''); appendValueAsFootnote(String(n)); return true; }); break; } default: assertNever(fragment); } } } function intoFragment(value) { const fragments = intoFragments(value); const [first, ...rest] = fragments; if (first !== undefined && rest.length === 0) { return first; } return new Fragment({ kind: 'multi', value: fragments }); } function intoFragments(value) { if (Array.isArray(value)) { return value.flatMap(intoFragments); } else if (typeof value === 'object' && value !== null) { return value.leaves(); } else { return [intoLeafFragment(value)]; } } function intoLeafFragment(value) { if (value === null) { return new Fragment({ kind: 'value', value: null }); } else if (typeof value === 'number') { return new Fragment({ kind: 'integer', value }); } else if (typeof value === 'string') { // If the string contains only whitespace and punctuation, we can treat it as a // punctuation fragment. if (/^[\s\p{P}\p{Sm}]*$/u.test(value)) { return new Fragment({ kind: 'string', value, style: STYLES.punct }); } else { return new Fragment({ kind: 'string', value }); } } else { return value; } } function frag(strings, ...values) { const buffer = []; strings.forEach((string, i) => { buffer.push(...intoFragment(string).leaves()); const dynamic = values[i]; if (dynamic) { buffer.push(...intoFragment(dynamic).leaves()); } }); return new Fragment({ kind: 'multi', value: buffer }); } const as = Object.fromEntries(Object.entries(STYLES).map(([k, v]) => [k, value => intoFragment(value).styleAll({ style: v })])); const FROM_CAPABILITIES = isDevelopingApp() ? new WeakSet() : undefined; function buildCapabilities(capabilities) { if (isDevelopingApp()) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme FROM_CAPABILITIES.add(capabilities); Object.freeze(capabilities); } return capabilities; } const EMPTY = InternalComponentCapabilities.Empty; /** * Converts a ComponentCapabilities object into a 32-bit integer representation. */ function capabilityFlagsFrom(capabilities) { return EMPTY | capability(capabilities, 'dynamicLayout') | capability(capabilities, 'dynamicTag') | capability(capabilities, 'prepareArgs') | capability(capabilities, 'createArgs') | capability(capabilities, 'attributeHook') | capability(capabilities, 'elementHook') | capability(capabilities, 'dynamicScope') | capability(capabilities, 'createCaller') | capability(capabilities, 'updateHook') | capability(capabilities, 'createInstance') | capability(capabilities, 'wrapped') | capability(capabilities, 'willDestroy') | capability(capabilities, 'hasSubOwner'); } function capability(capabilities, capability) { return capabilities[capability] ? InternalComponentCapabilities[capability] : EMPTY; } function managerHasCapability(_manager, capabilities, capability) { return !!(capabilities & capability); } function hasCapability(capabilities, capability) { return !!(capabilities & capability); } export { VM_OPEN_ELEMENT_OP as $, VM_CONSTANT_OP as A, decodeHandle as B, CURRIED_COMPONENT as C, VM_CONSTANT_REFERENCE_OP as D, VM_PRIMITIVE_OP as E, FROM_CAPABILITIES as F, isHandle as G, decodeImmediate as H, VM_PRIMITIVE_REFERENCE_OP as I, VM_DUP_OP as J, VM_POP_OP as K, VM_LOAD_OP as L, VM_FETCH_OP as M, VM_BIND_DYNAMIC_SCOPE_OP as N, VM_ENTER_OP as O, VM_EXIT_OP as P, VM_PUSH_SYMBOL_TABLE_OP as Q, VM_PUSH_BLOCK_SCOPE_OP as R, VM_COMPILE_BLOCK_OP as S, VM_INVOKE_YIELD_OP as T, VM_JUMP_IF_OP as U, VM_MAIN_OP as V, VM_JUMP_UNLESS_OP as W, VM_JUMP_EQ_OP as X, VM_TO_BOOLEAN_OP as Y, VM_TEXT_OP as Z, VM_COMMENT_OP as _, constants as a, VM_OPEN_DYNAMIC_ELEMENT_OP as a0, VM_PUSH_REMOTE_ELEMENT_OP as a1, VM_POP_REMOTE_ELEMENT_OP as a2, VM_FLUSH_ELEMENT_OP as a3, VM_CLOSE_ELEMENT_OP as a4, VM_MODIFIER_OP as a5, VM_DYNAMIC_MODIFIER_OP as a6, VM_STATIC_ATTR_OP as a7, VM_DYNAMIC_ATTR_OP as a8, CURRIED_MODIFIER as a9, VM_HELPER_OP as aA, VM_GET_VARIABLE_OP as aB, VM_SET_VARIABLE_OP as aC, VM_SET_BLOCK_OP as aD, VM_ROOT_SCOPE_OP as aE, VM_GET_PROPERTY_OP as aF, VM_GET_BLOCK_OP as aG, VM_SPREAD_BLOCK_OP as aH, VM_HAS_BLOCK_OP as aI, VM_HAS_BLOCK_PARAMS_OP as aJ, VM_CONCAT_OP as aK, VM_IF_INLINE_OP as aL, VM_NOT_OP as aM, VM_GET_DYNAMIC_VAR_OP as aN, VM_LOG_OP as aO, VM_DYNAMIC_CONTENT_TYPE_OP as aP, VM_DEBUGGER_OP as aQ, VM_ENTER_LIST_OP as aR, VM_EXIT_LIST_OP as aS, VM_ITERATE_OP as aT, encodeHandle as aU, isMachineOp as aV, isSmallInt as aW, encodeImmediate as aX, VM_PUSH_COMPONENT_DEFINITION_OP as aa, VM_RESOLVE_DYNAMIC_COMPONENT_OP as ab, VM_PUSH_ARGS_OP as ac, VM_PUSH_EMPTY_ARGS_OP as ad, VM_CAPTURE_ARGS_OP as ae, VM_PREPARE_ARGS_OP as af, VM_CREATE_COMPONENT_OP as ag, VM_REGISTER_COMPONENT_DESTRUCTOR_OP as ah, VM_BEGIN_COMPONENT_TRANSACTION_OP as ai, VM_PUT_COMPONENT_OPERATIONS_OP as aj, VM_COMPONENT_ATTR_OP as ak, VM_STATIC_COMPONENT_ATTR_OP as al, VM_DID_CREATE_ELEMENT_OP as am, VM_GET_COMPONENT_SELF_OP as an, VM_GET_COMPONENT_TAG_NAME_OP as ao, VM_GET_COMPONENT_LAYOUT_OP as ap, VM_POPULATE_LAYOUT_OP as aq, VM_VIRTUAL_ROOT_SCOPE_OP as ar, VM_SET_NAMED_VARIABLES_OP as as, VM_SET_BLOCKS_OP as at, VM_INVOKE_COMPONENT_LAYOUT_OP as au, VM_DID_RENDER_LAYOUT_OP as av, VM_COMMIT_COMPONENT_TRANSACTION_OP as aw, VM_CURRY_OP as ax, VM_DYNAMIC_HELPER_OP as ay, CURRIED_HELPER as az, buildCapabilities as b, capabilityFlagsFrom as c, VM_CONTENT_TYPE_OP as d, VM_ASSERT_SAME_OP as e, VM_APPEND_HTML_OP as f, VM_APPEND_TEXT_OP as g, hasCapability as h, VM_RESOLVE_CURRIED_COMPONENT_OP as i, VM_PUSH_DYNAMIC_COMPONENT_INSTANCE_OP as j, VM_APPEND_SAFE_HTML_OP as k, VM_APPEND_DOCUMENT_FRAGMENT_OP as l, managerHasCapability as m, VM_APPEND_NODE_OP as n, VM_INVOKE_STATIC_OP as o, VM_RETURN_TO_OP as p, VM_RETURN_OP as q, VM_JUMP_OP as r, VM_INVOKE_VIRTUAL_OP as s, VM_POP_FRAME_OP as t, VM_PUSH_FRAME_OP as u, VM_SYSCALL_SIZE as v, VM_CHILD_SCOPE_OP as w, VM_POP_SCOPE_OP as x, VM_PUSH_DYNAMIC_SCOPE_OP as y, VM_POP_DYNAMIC_SCOPE_OP as z };