From 6a15f7123710de8225bdf797a11a04b8f5f970ab Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:49:35 -0400 Subject: [PATCH] Commit from Devin --- .../integration-tests/index.ts | 1 + .../lib/modes/jit/delegate.ts | 2 ++ .../integration-tests/test/jit-suites-test.ts | 4 ++++ .../compiler/lib/passes/2-encoding/mir.ts | 1 + packages/@glimmer/constants/lib/dom.ts | 17 +++++++++++++- .../lib/compile/wire-format/opcodes.d.ts | 1 + .../@glimmer/interfaces/lib/vm-opcodes.d.ts | 14 +++++++++++ .../opcode-compiler/lib/syntax/statements.ts | 23 +++++++++++++++++++ packages/@glimmer/runtime/index.ts | 6 +++++ .../runtime/lib/compiled/opcodes/dom.ts | 13 +++++++++++ packages/@glimmer/wire-format/lib/opcodes.ts | 1 + 11 files changed, 82 insertions(+), 1 deletion(-) diff --git a/packages/@glimmer-workspace/integration-tests/index.ts b/packages/@glimmer-workspace/integration-tests/index.ts index 0ef9359634..5b12bfbc48 100644 --- a/packages/@glimmer-workspace/integration-tests/index.ts +++ b/packages/@glimmer-workspace/integration-tests/index.ts @@ -26,3 +26,4 @@ export * from './lib/test-helpers/test'; export * from './lib/test-helpers/tracked'; export * from './lib/test-helpers/tracked-object'; export { syntaxErrorFor } from '@glimmer-workspace/test-utils'; +export { ElementHelperTest, ElementHelperStrictModeTest } from './test/helpers/element-test'; diff --git a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts index a4fae43a8b..99500795c9 100644 --- a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts +++ b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts @@ -27,6 +27,7 @@ import { array, clientBuilder, concat, + element, fn, get, hash, @@ -101,6 +102,7 @@ export class JitRenderDelegate implements RenderDelegate { this.registry.register('helper', 'array', array); this.registry.register('helper', 'get', get); this.registry.register('helper', 'concat', concat); + this.registry.register('helper', 'element', element); } get context(): EvaluationContext { diff --git a/packages/@glimmer-workspace/integration-tests/test/jit-suites-test.ts b/packages/@glimmer-workspace/integration-tests/test/jit-suites-test.ts index 69afb5a202..411e633f6f 100644 --- a/packages/@glimmer-workspace/integration-tests/test/jit-suites-test.ts +++ b/packages/@glimmer-workspace/integration-tests/test/jit-suites-test.ts @@ -1,6 +1,8 @@ import { DebuggerSuite, EachSuite, + ElementHelperTest, + ElementHelperStrictModeTest, EmberishComponentTests, GlimmerishComponents, HasBlockParamsHelperSuite, @@ -18,6 +20,8 @@ import { jitComponentSuite(DebuggerSuite); jitSuite(EachSuite); jitSuite(InElementSuite); +jitSuite(ElementHelperTest); +jitSuite(ElementHelperStrictModeTest); jitComponentSuite(GlimmerishComponents); jitComponentSuite(TemplateOnlyComponents); diff --git a/packages/@glimmer/compiler/lib/passes/2-encoding/mir.ts b/packages/@glimmer/compiler/lib/passes/2-encoding/mir.ts index cb10e013e8..f1c5177329 100644 --- a/packages/@glimmer/compiler/lib/passes/2-encoding/mir.ts +++ b/packages/@glimmer/compiler/lib/passes/2-encoding/mir.ts @@ -214,6 +214,7 @@ export type Statement = | AppendTextNode | Component | SimpleElement + | DynamicElement | InvokeBlock | AppendComment | If diff --git a/packages/@glimmer/constants/lib/dom.ts b/packages/@glimmer/constants/lib/dom.ts index a507f87ef7..15779a0672 100644 --- a/packages/@glimmer/constants/lib/dom.ts +++ b/packages/@glimmer/constants/lib/dom.ts @@ -1,4 +1,4 @@ -import type { InsertPosition, Namespace, NodeType } from '@glimmer/interfaces'; +import type { InsertPosition, Namespace, NodeType, VmDomCloseElement, VmDomComment, VmDomDynamicAttr, VmDomDynamicModifier, VmDomFlushElement, VmDomModifier, VmDomOpenDynamicElement, VmDomOpenElement, VmDomPopRemoteElement, VmDomPushRemoteElement, VmDomStaticAttr, VmDomText } from '@glimmer/interfaces'; export const RAW_NODE = -1; export const ELEMENT_NODE: NodeType.ELEMENT_NODE = 1; @@ -19,3 +19,18 @@ export const INSERT_BEFORE_BEGIN = 'beforebegin' as InsertPosition.beforebegin; export const INSERT_AFTER_BEGIN = 'afterbegin' as InsertPosition.afterbegin; export const INSERT_BEFORE_END = 'beforeend' as InsertPosition.beforeend; export const INSERT_AFTER_END = 'afterend' as InsertPosition.afterend; + +// DOM Opcodes - using different names to avoid conflicts with syscall-ops.ts +export const VM_DOM_TEXT_OP = 28 satisfies VmDomText; +export const VM_DOM_COMMENT_OP = 29 satisfies VmDomComment; +export const VM_DOM_OPEN_ELEMENT_OP = 30 satisfies VmDomOpenElement; +// Using a different name to avoid conflicts with syscall-ops.ts +export const VM_DOM_OPEN_DYNAMIC_ELEMENT_OP = 31 satisfies VmDomOpenDynamicElement; +export const VM_DOM_FLUSH_ELEMENT_OP = 32 satisfies VmDomFlushElement; +export const VM_DOM_CLOSE_ELEMENT_OP = 33 satisfies VmDomCloseElement; +export const VM_DOM_STATIC_ATTR_OP = 34 satisfies VmDomStaticAttr; +export const VM_DOM_DYNAMIC_ATTR_OP = 35 satisfies VmDomDynamicAttr; +export const VM_DOM_MODIFIER_OP = 36 satisfies VmDomModifier; +export const VM_DOM_DYNAMIC_MODIFIER_OP = 37 satisfies VmDomDynamicModifier; +export const VM_DOM_PUSH_REMOTE_ELEMENT_OP = 38 satisfies VmDomPushRemoteElement; +export const VM_DOM_POP_REMOTE_ELEMENT_OP = 39 satisfies VmDomPopRemoteElement; diff --git a/packages/@glimmer/interfaces/lib/compile/wire-format/opcodes.d.ts b/packages/@glimmer/interfaces/lib/compile/wire-format/opcodes.d.ts index 56781bbfff..6e11871a27 100644 --- a/packages/@glimmer/interfaces/lib/compile/wire-format/opcodes.d.ts +++ b/packages/@glimmer/interfaces/lib/compile/wire-format/opcodes.d.ts @@ -7,6 +7,7 @@ export type StrictModifierOpcode = 5; export type BlockOpcode = 6; export type StrictBlockOpcode = 7; export type ComponentOpcode = 8; +export type DynamicElementOpcode = 9; export type OpenElementOpcode = 10; export type OpenElementWithSplatOpcode = 11; diff --git a/packages/@glimmer/interfaces/lib/vm-opcodes.d.ts b/packages/@glimmer/interfaces/lib/vm-opcodes.d.ts index 53058efcdd..9f7464d167 100644 --- a/packages/@glimmer/interfaces/lib/vm-opcodes.d.ts +++ b/packages/@glimmer/interfaces/lib/vm-opcodes.d.ts @@ -18,6 +18,20 @@ export type VmMachineOp = | VmMachineReturn | VmMachineReturnTo | VmMachineSize; + +// DOM Opcodes +export type VmDomText = 28; +export type VmDomComment = 29; +export type VmDomOpenElement = 30; +export type VmDomOpenDynamicElement = 31; +export type VmDomFlushElement = 32; +export type VmDomCloseElement = 33; +export type VmDomStaticAttr = 34; +export type VmDomDynamicAttr = 35; +export type VmDomModifier = 36; +export type VmDomDynamicModifier = 37; +export type VmDomPushRemoteElement = 38; +export type VmDomPopRemoteElement = 39; export type VmHelper = 16; export type VmSetNamedVariables = 17; diff --git a/packages/@glimmer/opcode-compiler/lib/syntax/statements.ts b/packages/@glimmer/opcode-compiler/lib/syntax/statements.ts index 300fd5bf36..5c09ed395c 100644 --- a/packages/@glimmer/opcode-compiler/lib/syntax/statements.ts +++ b/packages/@glimmer/opcode-compiler/lib/syntax/statements.ts @@ -142,6 +142,29 @@ STATEMENTS.add(SexpOpcodes.OpenElement, (op, [, tag]) => { op(VM_OPEN_ELEMENT_OP, inflateTagName(tag)); }); +STATEMENTS.add(SexpOpcodes.DynamicElement, (op, [, tag, params, body]) => { + expr(op, tag); + op(VM_DOM_OPEN_DYNAMIC_ELEMENT_OP); + + if (params && params.length > 0) { + op(VM_PUT_COMPONENT_OPERATIONS_OP); + + for (let param of params) { + STATEMENTS.compile(op, param); + } + } + + op(VM_FLUSH_ELEMENT_OP); + + if (body && body.length > 0) { + for (let statement of body) { + STATEMENTS.compile(op, statement); + } + } + + op(VM_CLOSE_ELEMENT_OP); +}); + STATEMENTS.add(SexpOpcodes.OpenElementWithSplat, (op, [, tag]) => { op(VM_PUT_COMPONENT_OPERATIONS_OP); op(VM_OPEN_ELEMENT_OP, inflateTagName(tag)); diff --git a/packages/@glimmer/runtime/index.ts b/packages/@glimmer/runtime/index.ts index 9ec4eb2b60..f4d5f09f8b 100644 --- a/packages/@glimmer/runtime/index.ts +++ b/packages/@glimmer/runtime/index.ts @@ -17,6 +17,11 @@ export { templateOnlyComponent, TemplateOnlyComponentManager, } from './lib/component/template-only'; +export { + DynamicTagComponent, + DynamicTagComponentManager, + DYNAMIC_TAG_COMPONENT_MANAGER, +} from './lib/component/dynamic-tag'; export { CurriedValue, curry } from './lib/curried-value'; export { DOMChanges, @@ -33,6 +38,7 @@ export { } from './lib/environment'; export { array } from './lib/helpers/array'; export { concat } from './lib/helpers/concat'; +export { element } from './lib/helpers/element'; export { fn } from './lib/helpers/fn'; export { get } from './lib/helpers/get'; export { hash } from './lib/helpers/hash'; diff --git a/packages/@glimmer/runtime/lib/compiled/opcodes/dom.ts b/packages/@glimmer/runtime/lib/compiled/opcodes/dom.ts index 2036ba47fc..991f11b460 100644 --- a/packages/@glimmer/runtime/lib/compiled/opcodes/dom.ts +++ b/packages/@glimmer/runtime/lib/compiled/opcodes/dom.ts @@ -68,6 +68,19 @@ APPEND_OPCODES.add(VM_OPEN_DYNAMIC_ELEMENT_OP, (vm) => { vm.tree().openElement(tagName); }); +APPEND_OPCODES.add(VM_OPEN_DYNAMIC_ELEMENT_OP, (vm) => { + let tagRef = check(vm.stack.pop(), CheckReference); + let tagName = valueForRef(tagRef); + + if (tagName === null || tagName === undefined || tagName === '') { + vm.tree().openElement(''); + } else if (typeof tagName !== 'string') { + throw new Error(`The argument passed to the element helper must be a string (you passed \`${tagName}\`)`); + } else { + vm.tree().openElement(tagName); + } +}); + APPEND_OPCODES.add(VM_PUSH_REMOTE_ELEMENT_OP, (vm) => { let elementRef = check(vm.stack.pop(), CheckReference); let insertBeforeRef = check(vm.stack.pop(), CheckReference); diff --git a/packages/@glimmer/wire-format/lib/opcodes.ts b/packages/@glimmer/wire-format/lib/opcodes.ts index 824348c763..615a393347 100644 --- a/packages/@glimmer/wire-format/lib/opcodes.ts +++ b/packages/@glimmer/wire-format/lib/opcodes.ts @@ -56,6 +56,7 @@ export const opcodes = { Block: 6 satisfies BlockOpcode, StrictBlock: 7 satisfies StrictBlockOpcode, Component: 8 satisfies ComponentOpcode, + DynamicElement: 9 satisfies number, OpenElement: 10 satisfies OpenElementOpcode, OpenElementWithSplat: 11 satisfies OpenElementWithSplatOpcode, FlushElement: 12 satisfies FlushElementOpcode,