ember-source
Version:
A JavaScript framework for creating ambitious web applications
943 lines (897 loc) • 32.2 kB
JavaScript
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 };