octane 0.2.12 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/README.md +5 -0
  2. package/dist/behavior-root.d.ts +13 -3
  3. package/dist/behavior-root.js +28 -5
  4. package/dist/cjs/behavior-root.cjs +32 -6
  5. package/dist/cjs/class-names.cjs +49 -0
  6. package/dist/cjs/constants.cjs +9 -0
  7. package/dist/cjs/css.cjs +6 -27
  8. package/dist/cjs/data-encoding.cjs +160 -0
  9. package/dist/cjs/dom-binding-handoff.cjs +93 -0
  10. package/dist/cjs/dom-binding-protocol.cjs +115 -0
  11. package/dist/cjs/dom-binding-styles.cjs +292 -0
  12. package/dist/cjs/dom-bindings.cjs +700 -0
  13. package/dist/cjs/dom-focused-move.cjs +66 -0
  14. package/dist/cjs/dom-tables.cjs +4 -94
  15. package/dist/cjs/error-codes.client.generated.cjs +33 -0
  16. package/dist/cjs/error-codes.server.generated.cjs +19 -0
  17. package/dist/cjs/hydration/control-capture.cjs +244 -0
  18. package/dist/cjs/hydration/event-capture.cjs +125 -43
  19. package/dist/cjs/hydration/interaction-config.cjs +50 -2
  20. package/dist/cjs/hydration-markers.cjs +37 -0
  21. package/dist/cjs/independent-hydration-protocol.cjs +106 -0
  22. package/dist/cjs/index.cjs +6 -0
  23. package/dist/cjs/runtime.cjs +2791 -215
  24. package/dist/cjs/runtime.server.cjs +716 -76
  25. package/dist/cjs/server/early-signals.cjs +45 -0
  26. package/dist/cjs/server/index.cjs +44 -0
  27. package/dist/cjs/server/rpc-batch.cjs +149 -0
  28. package/dist/cjs/server/rpc-stream.cjs +146 -0
  29. package/dist/cjs/server/rpc.cjs +34 -15
  30. package/dist/cjs/server/signal-query-observation.cjs +158 -0
  31. package/dist/cjs/server/streamed-region.cjs +52 -0
  32. package/dist/cjs/server/streamed-signals.cjs +512 -0
  33. package/dist/cjs/server-call.cjs +103 -0
  34. package/dist/cjs/server-rpc-batch-client.cjs +141 -0
  35. package/dist/cjs/server-rpc-client.cjs +94 -27
  36. package/dist/cjs/server-rpc-protocol.cjs +141 -0
  37. package/dist/cjs/server-rpc-stream-client.cjs +118 -0
  38. package/dist/cjs/signals/actions.cjs +474 -0
  39. package/dist/cjs/signals/client.cjs +4 -1
  40. package/dist/cjs/signals/computations.cjs +460 -0
  41. package/dist/cjs/signals/control-binding.cjs +368 -0
  42. package/dist/cjs/signals/derived-facade.cjs +50 -0
  43. package/dist/cjs/signals/document-owner.cjs +71 -0
  44. package/dist/cjs/signals/early-values.cjs +155 -0
  45. package/dist/cjs/signals/encoding.cjs +6 -95
  46. package/dist/cjs/signals/engine.cjs +276 -12
  47. package/dist/cjs/signals/errors.cjs +18 -0
  48. package/dist/cjs/signals/facade.cjs +477 -0
  49. package/dist/cjs/signals/graph.cjs +163 -20
  50. package/dist/cjs/signals/handle-protocol.cjs +36 -0
  51. package/dist/cjs/signals/index.cjs +81 -2
  52. package/dist/cjs/signals/native-read-client.cjs +10 -0
  53. package/dist/cjs/signals/owner-context.cjs +112 -0
  54. package/dist/cjs/signals/query-attempt-observer.cjs +68 -0
  55. package/dist/cjs/signals/query-facade.cjs +72 -0
  56. package/dist/cjs/signals/read-protocol.cjs +32 -0
  57. package/dist/cjs/signals/requests.cjs +287 -14
  58. package/dist/cjs/signals/scalar-computations.cjs +76 -0
  59. package/dist/cjs/signals/server.cjs +4 -1
  60. package/dist/cjs/signals/transition-candidate.cjs +567 -0
  61. package/dist/cjs/signals/transition-state.cjs +106 -0
  62. package/dist/cjs/signals/types.cjs +50 -0
  63. package/dist/cjs/stream-protocol.cjs +3 -0
  64. package/dist/cjs/streamed-signals-protocol.cjs +159 -0
  65. package/dist/cjs/style-values.cjs +122 -0
  66. package/dist/cjs/version.cjs +1 -1
  67. package/dist/class-names.d.ts +5 -0
  68. package/dist/class-names.js +25 -0
  69. package/dist/compiler/bundler.js +34 -6
  70. package/dist/compiler/compile.js +2234 -559
  71. package/dist/compiler/dom-binding-program.js +935 -0
  72. package/dist/compiler/dom-binding-request.js +57 -0
  73. package/dist/compiler/dom-bindings.js +2245 -0
  74. package/dist/compiler/hook-deps.js +26 -0
  75. package/dist/compiler/hydrate-boundaries.js +358 -15
  76. package/dist/compiler/index.d.ts +38 -1
  77. package/dist/compiler/index.js +1 -0
  78. package/dist/compiler/native-attribute-reads.js +127 -0
  79. package/dist/compiler/native-read-diagnostics.js +48 -9
  80. package/dist/compiler/native-read-types.js +55 -32
  81. package/dist/compiler/server-context.js +118 -0
  82. package/dist/compiler/signal-attempt-reads.js +479 -0
  83. package/dist/compiler/signal-declarations.js +557 -0
  84. package/dist/compiler/signal-start-reads.js +413 -0
  85. package/dist/compiler/slot-hooks.js +57 -10
  86. package/dist/compiler/template-ir.js +200 -0
  87. package/dist/compiler/typescript.d.ts +2 -0
  88. package/dist/compiler/typescript.js +2 -0
  89. package/dist/compiler/vite.d.ts +3 -1
  90. package/dist/compiler/vite.js +122 -4
  91. package/dist/compiler/volar.d.ts +6 -1
  92. package/dist/compiler/volar.js +674 -143
  93. package/dist/constants.d.ts +1 -0
  94. package/dist/constants.js +10 -0
  95. package/dist/css.d.ts +2 -5
  96. package/dist/css.js +2 -23
  97. package/dist/data-encoding.d.ts +9 -0
  98. package/dist/data-encoding.js +134 -0
  99. package/dist/dom-binding-classes.d.ts +15 -0
  100. package/dist/dom-binding-classes.js +129 -0
  101. package/dist/dom-binding-controls.d.ts +2 -0
  102. package/dist/dom-binding-controls.js +6 -0
  103. package/dist/dom-binding-handoff.d.ts +55 -0
  104. package/dist/dom-binding-handoff.js +62 -0
  105. package/dist/dom-binding-program.d.ts +300 -0
  106. package/dist/dom-binding-program.js +1625 -0
  107. package/dist/dom-binding-projections.d.ts +15 -0
  108. package/dist/dom-binding-projections.js +187 -0
  109. package/dist/dom-binding-protocol.d.ts +13 -0
  110. package/dist/dom-binding-protocol.js +88 -0
  111. package/dist/dom-binding-signals.d.ts +21 -0
  112. package/dist/dom-binding-signals.js +109 -0
  113. package/dist/dom-binding-styles.d.ts +17 -0
  114. package/dist/dom-binding-styles.js +272 -0
  115. package/dist/dom-bindings.d.ts +89 -0
  116. package/dist/dom-bindings.js +670 -0
  117. package/dist/dom-focused-move.d.ts +6 -0
  118. package/dist/dom-focused-move.js +42 -0
  119. package/dist/dom-tables.d.ts +1 -3
  120. package/dist/dom-tables.js +1 -91
  121. package/dist/error-codes.client.generated.d.ts +9 -0
  122. package/dist/error-codes.client.generated.js +33 -0
  123. package/dist/error-codes.server.generated.d.ts +5 -0
  124. package/dist/error-codes.server.generated.js +19 -0
  125. package/dist/hydration/control-capture.d.ts +62 -0
  126. package/dist/hydration/control-capture.js +223 -0
  127. package/dist/hydration/document-lifecycle.d.ts +23 -0
  128. package/dist/hydration/document-lifecycle.js +80 -0
  129. package/dist/hydration/event-capture.d.ts +20 -1
  130. package/dist/hydration/event-capture.js +128 -42
  131. package/dist/hydration/independent-island.d.ts +45 -0
  132. package/dist/hydration/independent-island.js +233 -0
  133. package/dist/hydration/index.d.ts +8 -1
  134. package/dist/hydration/index.js +55 -1
  135. package/dist/hydration/interaction-config.d.ts +5 -0
  136. package/dist/hydration/interaction-config.js +44 -1
  137. package/dist/hydration/stream-delivery.d.ts +32 -0
  138. package/dist/hydration/stream-delivery.js +333 -0
  139. package/dist/hydration/stream-receiver.d.ts +26 -0
  140. package/dist/hydration/stream-receiver.js +204 -0
  141. package/dist/hydration/stream-result-receiver.d.ts +70 -0
  142. package/dist/hydration/stream-result-receiver.js +246 -0
  143. package/dist/hydration/streamed-signals.d.ts +44 -0
  144. package/dist/hydration/streamed-signals.js +186 -0
  145. package/dist/hydration/types.d.ts +6 -0
  146. package/dist/hydration-markers.d.ts +7 -0
  147. package/dist/hydration-markers.js +10 -0
  148. package/dist/independent-hydration-protocol.d.ts +31 -0
  149. package/dist/independent-hydration-protocol.js +80 -0
  150. package/dist/index.d.ts +2 -0
  151. package/dist/index.js +4 -0
  152. package/dist/internal/signal-read.d.ts +1 -0
  153. package/dist/internal/signal-read.js +4 -0
  154. package/dist/jsx-runtime.d.ts +45 -6
  155. package/dist/public-types.d.ts +15 -1
  156. package/dist/runtime.d.ts +259 -21
  157. package/dist/runtime.js +2812 -220
  158. package/dist/runtime.server.d.ts +86 -6
  159. package/dist/runtime.server.js +712 -76
  160. package/dist/server/early-signals.d.ts +14 -0
  161. package/dist/server/early-signals.js +34 -0
  162. package/dist/server/index.d.ts +10 -2
  163. package/dist/server/index.js +48 -1
  164. package/dist/server/rpc-batch.d.ts +17 -0
  165. package/dist/server/rpc-batch.js +129 -0
  166. package/dist/server/rpc-stream.d.ts +9 -0
  167. package/dist/server/rpc-stream.js +125 -0
  168. package/dist/server/rpc.d.ts +5 -1
  169. package/dist/server/rpc.js +37 -13
  170. package/dist/server/signal-query-observation.d.ts +3 -0
  171. package/dist/server/signal-query-observation.js +134 -0
  172. package/dist/server/streamed-region.d.ts +15 -0
  173. package/dist/server/streamed-region.js +30 -0
  174. package/dist/server/streamed-signals.d.ts +45 -0
  175. package/dist/server/streamed-signals.js +488 -0
  176. package/dist/server-call.d.ts +41 -0
  177. package/dist/server-call.js +75 -0
  178. package/dist/server-rpc-batch-client.d.ts +7 -0
  179. package/dist/server-rpc-batch-client.js +119 -0
  180. package/dist/server-rpc-client.d.ts +3 -1
  181. package/dist/server-rpc-client.js +99 -27
  182. package/dist/server-rpc-protocol.d.ts +47 -0
  183. package/dist/server-rpc-protocol.js +109 -0
  184. package/dist/server-rpc-stream-client.d.ts +5 -0
  185. package/dist/server-rpc-stream-client.js +98 -0
  186. package/dist/signals/actions.d.ts +12 -0
  187. package/dist/signals/actions.js +466 -0
  188. package/dist/signals/client.d.ts +2 -0
  189. package/dist/signals/client.js +1 -0
  190. package/dist/signals/computations.d.ts +37 -0
  191. package/dist/signals/computations.js +455 -0
  192. package/dist/signals/control-binding.d.ts +31 -0
  193. package/dist/signals/control-binding.js +353 -0
  194. package/dist/signals/derived-facade.d.ts +3 -0
  195. package/dist/signals/derived-facade.js +25 -0
  196. package/dist/signals/document-owner.d.ts +10 -0
  197. package/dist/signals/document-owner.js +43 -0
  198. package/dist/signals/early-values.d.ts +24 -0
  199. package/dist/signals/early-values.js +124 -0
  200. package/dist/signals/encoding.d.ts +1 -3
  201. package/dist/signals/encoding.js +3 -93
  202. package/dist/signals/engine.d.ts +53 -4
  203. package/dist/signals/engine.js +275 -16
  204. package/dist/signals/errors.d.ts +7 -0
  205. package/dist/signals/errors.js +16 -0
  206. package/dist/signals/facade.d.ts +74 -0
  207. package/dist/signals/facade.js +452 -0
  208. package/dist/signals/graph.d.ts +50 -5
  209. package/dist/signals/graph.js +170 -19
  210. package/dist/signals/handle-protocol.d.ts +4 -0
  211. package/dist/signals/handle-protocol.js +11 -0
  212. package/dist/signals/index.d.ts +12 -3
  213. package/dist/signals/index.js +71 -2
  214. package/dist/signals/native-read-client.d.ts +3 -0
  215. package/dist/signals/native-read-client.js +10 -0
  216. package/dist/signals/owner-context.d.ts +22 -0
  217. package/dist/signals/owner-context.js +77 -0
  218. package/dist/signals/query-attempt-observer.d.ts +49 -0
  219. package/dist/signals/query-attempt-observer.js +41 -0
  220. package/dist/signals/query-facade.d.ts +3 -0
  221. package/dist/signals/query-facade.js +49 -0
  222. package/dist/signals/read-protocol.d.ts +32 -3
  223. package/dist/signals/read-protocol.js +26 -0
  224. package/dist/signals/requests.d.ts +38 -5
  225. package/dist/signals/requests.js +298 -15
  226. package/dist/signals/scalar-computations.d.ts +2 -0
  227. package/dist/signals/scalar-computations.js +60 -0
  228. package/dist/signals/server.d.ts +2 -0
  229. package/dist/signals/server.js +1 -0
  230. package/dist/signals/transition-candidate.d.ts +71 -0
  231. package/dist/signals/transition-candidate.js +557 -0
  232. package/dist/signals/transition-state.d.ts +51 -0
  233. package/dist/signals/transition-state.js +70 -0
  234. package/dist/signals/types.d.ts +95 -5
  235. package/dist/signals/types.js +20 -0
  236. package/dist/stream-protocol.d.ts +0 -5
  237. package/dist/stream-protocol.js +3 -0
  238. package/dist/streamed-signals-protocol.d.ts +60 -0
  239. package/dist/streamed-signals-protocol.js +130 -0
  240. package/dist/style-values.d.ts +3 -0
  241. package/dist/style-values.js +96 -0
  242. package/dist/version.js +1 -1
  243. package/package.json +37 -1
@@ -0,0 +1,935 @@
1
+ /** Compiler-owned presentation programs; authored views never execute in the browser. */
2
+ import { builders as b, strongHash } from '@tsrx/core';
3
+ import { inheritHookMemoOrigin as origin } from './inline-hook-memo.js';
4
+ import {
5
+ createTemplateIr,
6
+ appendTemplatePart,
7
+ appendTemplateIr,
8
+ templateElement,
9
+ serializeTemplateIr,
10
+ } from './template-ir.js';
11
+ import {
12
+ ATTRIBUTE_ALIASES,
13
+ BOOLEAN_ATTR_PROPS,
14
+ VOID_ELEMENTS,
15
+ hyphenateStyleName,
16
+ isEnumeratedBooleanAttr,
17
+ isUnitlessStyleProp,
18
+ } from '../dom-tables.js';
19
+ import { shouldSanitizeURLAttribute } from '../sanitize-url.js';
20
+ import { formatDomBindingRequest } from './dom-binding-request.js';
21
+
22
+ function unwrap(node) {
23
+ while (
24
+ [
25
+ 'TSAsExpression',
26
+ 'TSTypeAssertion',
27
+ 'TSNonNullExpression',
28
+ 'TSSatisfiesExpression',
29
+ 'ParenthesizedExpression',
30
+ ].includes(node?.type)
31
+ )
32
+ node = node.expression;
33
+ return node;
34
+ }
35
+
36
+ function tagOf(node) {
37
+ return node.openingElement?.name?.name ?? node.id?.name;
38
+ }
39
+
40
+ function significant(node) {
41
+ return (
42
+ node &&
43
+ !(
44
+ node.type === 'JSXText' &&
45
+ (node.value === '' || (/^\s*$/.test(node.value) && /[\r\n]/.test(node.value)))
46
+ ) &&
47
+ !(node.type === 'JSXExpressionContainer' && node.expression?.type === 'JSXEmptyExpression')
48
+ );
49
+ }
50
+
51
+ export function needsBindingProgram(node, isUnbound) {
52
+ if (!significant(node)) return false;
53
+ if (node.type === 'JSXExpressionContainer' && isUnbound(node.expression)) return false;
54
+ if (node.type !== 'JSXElement' && node.type !== 'Element') return true;
55
+ if (!/^[a-z]/.test(tagOf(node) ?? '')) return true;
56
+ if (
57
+ (node.openingElement?.attributes ?? node.attributes ?? []).some(
58
+ (attr) => rawName(attr) === 'ref' || /^on[A-Z]/.test(rawName(attr) ?? ''),
59
+ )
60
+ )
61
+ return true;
62
+ if (tagOf(node) === 'textarea') return false;
63
+ return (node.children ?? []).some((child) => needsBindingProgram(child, isUnbound));
64
+ }
65
+
66
+ function data(value) {
67
+ return Array.isArray(value) ? b.array(value.map(data)) : b.literal(value);
68
+ }
69
+
70
+ function object(properties) {
71
+ return b.object(
72
+ Object.entries(properties).map(([name, value]) => b.prop('init', b.id(name), value)),
73
+ );
74
+ }
75
+
76
+ function rawName(attr) {
77
+ return attr.name?.type === 'JSXNamespacedName'
78
+ ? `${attr.name.namespace.name}:${attr.name.name.name}`
79
+ : (attr.name?.name ?? attr.name);
80
+ }
81
+
82
+ function attrValue(attr) {
83
+ return attr.value === null
84
+ ? b.literal(true)
85
+ : attr.value?.type === 'JSXExpressionContainer'
86
+ ? attr.value.expression
87
+ : attr.value;
88
+ }
89
+
90
+ function blockNodes(node) {
91
+ return node == null ? [] : node.type === 'BlockStatement' ? node.body : [node];
92
+ }
93
+
94
+ /** Build AST only. The owning compiler prints the completed module once. */
95
+ export function planBindingProgram(fn, render, context) {
96
+ const {
97
+ source,
98
+ filename,
99
+ helpers,
100
+ isUnbound,
101
+ nativePlan,
102
+ assertProjection,
103
+ assertAdapter,
104
+ mapCow,
105
+ imports,
106
+ lexical,
107
+ localProgram,
108
+ allocateProgramName,
109
+ projectionBody,
110
+ parameterNames,
111
+ refDependencies,
112
+ canCarryValue,
113
+ isChildSlot,
114
+ } = context;
115
+ const id = `d:${strongHash(`octane:dom-bindings:2\0${filename}\0${fn.id.name}\0${source}`)}`;
116
+ const replacements = new Map();
117
+ const unbound = new Map();
118
+ const classAttributes = new Map();
119
+ const restAttributes = new Map();
120
+ const dependencies = [];
121
+ const hoists = [];
122
+ const expressions = [];
123
+ const importedPrograms = new Map();
124
+ const childPrograms = new Set();
125
+ let activationHelper = null;
126
+ let classFactory = null;
127
+ let methodDependency = null;
128
+ let slotFactory = null;
129
+ let signals = false;
130
+ let controls = false;
131
+ let hostOperations = false;
132
+ let lists = false;
133
+ let styles = false;
134
+ let projectionsEnabled = false;
135
+ let nextSite = 0;
136
+ const fail = (node, message) => {
137
+ const error = new Error(
138
+ `Octane DOM bindings (${filename}:${node?.loc?.start?.line ?? 1}): ${message}`,
139
+ );
140
+ error.code = 'OCTANE_DOM_BINDINGS';
141
+ throw error;
142
+ };
143
+ const metadata = () => ({ id, site: nextSite++ });
144
+ const stripUnbound = (expression) => {
145
+ const call = unwrap(expression);
146
+ if (call.arguments.length !== 1 || call.arguments[0].type === 'SpreadElement' || call.optional)
147
+ fail(call, 'unbound requires one externally owned value');
148
+ unbound.set(call, call.arguments[0]);
149
+ return call.arguments[0];
150
+ };
151
+ const annotate = (node, nativeChild = false) => {
152
+ if (!node || typeof node !== 'object') return node;
153
+ if (Array.isArray(node)) return node.map((child) => annotate(child, nativeChild));
154
+ let next = node;
155
+ if (node.type === 'JSXExpressionContainer') {
156
+ if (isUnbound(node.expression)) {
157
+ stripUnbound(node.expression);
158
+ next = { ...node, _octaneBindingOpaque: metadata() };
159
+ } else if (nativeChild && helpers.conditionalJsxStatement(node.expression)) {
160
+ next = {
161
+ ...node,
162
+ expression: {
163
+ ...node.expression,
164
+ _octaneBindingSite: metadata(),
165
+ consequent: annotate(node.expression.consequent),
166
+ alternate: annotate(node.expression.alternate),
167
+ },
168
+ };
169
+ } else if (isChildSlot(node.expression)) {
170
+ next = { ...node, _octaneBindingSlot: metadata() };
171
+ } else if (helpers.isText(node.expression)) {
172
+ next = { ...node, _octaneBindingText: metadata() };
173
+ } else if (canCarryValue(node.expression)) {
174
+ next = { ...node, _octaneBindingValue: metadata() };
175
+ }
176
+ } else if (node.type === 'JSXElement' || node.type === 'Element') {
177
+ const native = /^[a-z]/.test(tagOf(node) ?? '');
178
+ if (context.annotationsOnly) {
179
+ const attributes = node.openingElement?.attributes ?? node.attributes ?? [];
180
+ if (
181
+ attributes.some((attribute) => ['class', 'className'].includes(rawName(attribute))) &&
182
+ attributes.some((attribute) =>
183
+ attribute._octaneKnownAttributeSpread?.fields.some((name) =>
184
+ ['class', 'className'].includes(name),
185
+ ),
186
+ )
187
+ )
188
+ fail(
189
+ node,
190
+ 'generic binding rest annotations cannot combine class attributes and known spreads',
191
+ );
192
+ for (const attribute of attributes) {
193
+ if (isUnbound(attrValue(attribute))) stripUnbound(attrValue(attribute));
194
+ }
195
+ }
196
+ const children = annotate(node.children ?? [], native);
197
+ next = { ...node, children };
198
+ if (!native) next._octaneBindingSite = metadata();
199
+ } else if (node.type === 'JSXFragment' || node.type === 'Fragment') {
200
+ next = { ...node, children: annotate(node.children ?? []) };
201
+ } else if (node.type === 'JSXIfExpression' || node.type === 'IfStatement') {
202
+ next = {
203
+ ...node,
204
+ _octaneBindingSite: metadata(),
205
+ consequent: annotate(node.consequent),
206
+ alternate: annotate(node.alternate),
207
+ };
208
+ } else if (node.type === 'JSXForExpression' || node.type === 'ForOfStatement') {
209
+ next = {
210
+ ...node,
211
+ _octaneBindingSite: metadata(),
212
+ body: annotate(node.body),
213
+ empty: annotate(node.empty),
214
+ };
215
+ } else if (node.type === 'BlockStatement') {
216
+ next = { ...node, body: annotate(node.body) };
217
+ } else if (node.type === 'JSXCodeBlock' && node.body.length === 0) {
218
+ next = { ...node, render: annotate(node.render) };
219
+ }
220
+ if (next !== node) replacements.set(node, next);
221
+ return next;
222
+ };
223
+ const annotated = annotate(render);
224
+ const normalize = (nodes, namespace) =>
225
+ helpers.normalizeChildren(nodes, namespace === 1, null, false, false);
226
+ const environment = (names, exclude = []) =>
227
+ b.array_pattern(
228
+ names.map((name, index) =>
229
+ name !== null && !exclude.includes(name) && names.lastIndexOf(name) === index
230
+ ? b.id(name)
231
+ : null,
232
+ ),
233
+ );
234
+ const project = (names, value, node = fn, temporaries = []) => {
235
+ expressions.push(value);
236
+ return origin(
237
+ b.arrow([environment(names)], projectionBody(value, expressions, temporaries)),
238
+ node,
239
+ );
240
+ };
241
+ const validate = (expression) => {
242
+ if (!context.annotationsOnly) assertProjection(expression);
243
+ };
244
+ const regionMarker = (site, arm) => `<!--[b;${id};${site};${arm}--><!--]-->`;
245
+ const compileFragment = (rawNodes, names, namespace = 0, ancestors = []) => {
246
+ // Only this fragment's writers determine its entry capability. Conditional
247
+ // arms and caller slots are checked when their concrete ranges are entered.
248
+ let structural = true;
249
+ const nodes = [];
250
+ const appendNode = (node) => {
251
+ nodes.push(node);
252
+ if (node[0] >= 0) nodes[node[0]][4]++;
253
+ };
254
+ const bindings = [];
255
+ const values = [];
256
+ const signalIndices = [];
257
+ const styleIndices = [];
258
+ const projectionGroups = [];
259
+ const projections = [];
260
+ const initializers = [];
261
+ const initialValues = [];
262
+ const regions = [];
263
+ const adapters = [];
264
+ const restSites = [];
265
+ let constructionError = null;
266
+ const initialize = (index, kind, name, value, unitless) => {
267
+ validate(value);
268
+ initializers.push([index, kind, name, ...(unitless === undefined ? [] : [unitless])]);
269
+ initialValues.push(value);
270
+ };
271
+ const emit = (node, parent, ns, parents) => {
272
+ if (node.type === 'Text' || node.type === 'TSRXExpression') {
273
+ if (node.expression?._octaneBindingSite) {
274
+ const conditional = helpers.conditionalJsxStatement(node.expression);
275
+ if (conditional) return emit(conditional, parent, ns, parents);
276
+ }
277
+ const opaque = node._octaneBindingOpaque;
278
+ if (opaque) {
279
+ structural = false;
280
+ const index = nodes.length;
281
+ appendNode([parent, 'region', String(opaque.site)]);
282
+ regions.push(object({ node: b.literal(index), kind: b.literal('opaque') }));
283
+ constructionError ??=
284
+ 'This view contains externally owned children that cannot be constructed by a binding program.';
285
+ const html = createTemplateIr();
286
+ appendTemplatePart(html, regionMarker(opaque.site, 'o'), 'anchor');
287
+ return html;
288
+ }
289
+ if (node._octaneBindingSlot) {
290
+ validate(node.expression);
291
+ const site = node._octaneBindingSlot.site;
292
+ const index = nodes.length;
293
+ appendNode([parent, 'region', String(site)]);
294
+ regions.push(
295
+ object({
296
+ node: b.literal(index),
297
+ kind: b.literal('slot'),
298
+ read: project(names, node.expression, node),
299
+ }),
300
+ );
301
+ // A caller-owned fragment can acquire direct channels in a later publication.
302
+ signals = true;
303
+ const html = createTemplateIr();
304
+ appendTemplatePart(html, regionMarker(site, 's'), 'anchor');
305
+ return html;
306
+ }
307
+ const value = unwrap(node.expression);
308
+ if (value?.type === 'Literal' && !node._octaneBindingText) {
309
+ const text =
310
+ value.value == null || typeof value.value === 'boolean' ? '' : String(value.value);
311
+ const html = createTemplateIr();
312
+ if (text !== '') {
313
+ const previous = nodes.at(-1);
314
+ if (previous?.[0] === parent && previous[1] === 'text') previous[2] += text;
315
+ else appendNode([parent, 'text', text]);
316
+ appendTemplatePart(html, helpers.escapeHtml(text), 'text');
317
+ }
318
+ return html;
319
+ }
320
+ if (
321
+ !node._octaneBindingValue &&
322
+ (!node._octaneBindingText || !helpers.isText(node.expression))
323
+ )
324
+ fail(
325
+ node.expression ?? node,
326
+ 'binding child values must be proven text; use an explicit string cast or unbound external children',
327
+ );
328
+ validate(node.expression);
329
+ const site = (node._octaneBindingText ?? node._octaneBindingValue).site;
330
+ if (node._octaneBindingValue) structural = false;
331
+ const signal = helpers.canCarryDirectSignalHandle(node.expression);
332
+ signals ||= signal;
333
+ const index = nodes.length;
334
+ appendNode([parent, 'region', String(site)]);
335
+ regions.push(
336
+ object({
337
+ node: b.literal(index),
338
+ kind: b.literal('text'),
339
+ read: project(names, node.expression, node),
340
+ ...(signal ? { signal: b.literal(true) } : {}),
341
+ ...(node._octaneBindingValue ? { generic: b.literal(true) } : {}),
342
+ }),
343
+ );
344
+ const html = createTemplateIr();
345
+ appendTemplatePart(html, regionMarker(site, 't'), 'anchor');
346
+ return html;
347
+ }
348
+ if (node.type === 'IfStatement') {
349
+ validate(node.test);
350
+ const site = node._octaneBindingSite?.site;
351
+ if (site === undefined) fail(node, 'binding condition is missing its authored site');
352
+ const thenNodes = blockNodes(node.consequent);
353
+ const elseNodes = blockNodes(node.alternate);
354
+ const arms = [
355
+ compileFragment(thenNodes, names, ns, parents).fragment,
356
+ compileFragment(elseNodes, names, ns, parents).fragment,
357
+ ];
358
+ const index = nodes.length;
359
+ appendNode([parent, 'region', String(site)]);
360
+ regions.push(
361
+ object({
362
+ node: b.literal(index),
363
+ kind: b.literal('if'),
364
+ select: project(
365
+ names,
366
+ b.conditional(
367
+ node.test,
368
+ b.literal(node.consequent ? 0 : -1),
369
+ b.literal(node.alternate ? 1 : -1),
370
+ ),
371
+ node,
372
+ ),
373
+ arms: b.array(arms),
374
+ armRange: b.literal(
375
+ !(
376
+ helpers.canBorrowSsrHostBranchRange(thenNodes) &&
377
+ helpers.canBorrowSsrHostBranchRange(elseNodes)
378
+ ),
379
+ ),
380
+ }),
381
+ );
382
+ const html = createTemplateIr();
383
+ appendTemplatePart(html, regionMarker(site, '-1'), 'anchor');
384
+ return html;
385
+ }
386
+ if (node.type === 'ForOfStatement') {
387
+ lists = true;
388
+ structural = false;
389
+ const item = node.left?.declarations?.[0]?.id;
390
+ if (node.await || item?.type !== 'Identifier' || !node.key)
391
+ fail(
392
+ node,
393
+ 'binding lists require a synchronous @for with one item identifier and an explicit stable key',
394
+ );
395
+ validate(node.right);
396
+ validate(node.key);
397
+ const site = node._octaneBindingSite?.site;
398
+ if (site === undefined) fail(node, 'binding list is missing its authored site');
399
+ const indexName = node.index?.name ?? null;
400
+ const keyIndex = indexName ?? `_bindingIndex${site}`;
401
+ expressions.push(node.key);
402
+ const key = origin(
403
+ b.arrow(
404
+ [b.id(item.name), b.id(keyIndex), environment(names, [item.name, keyIndex])],
405
+ projectionBody(node.key, expressions),
406
+ ),
407
+ node,
408
+ );
409
+ const body = compileFragment(
410
+ blockNodes(node.body),
411
+ [...names, item.name, indexName],
412
+ ns,
413
+ parents,
414
+ ).fragment;
415
+ const empty = compileFragment(blockNodes(node.empty), names, ns, parents).fragment;
416
+ const index = nodes.length;
417
+ appendNode([parent, 'region', String(site)]);
418
+ regions.push(
419
+ object({
420
+ node: b.literal(index),
421
+ kind: b.literal('for'),
422
+ items: project(names, node.right, node),
423
+ key,
424
+ item: body,
425
+ empty,
426
+ }),
427
+ );
428
+ const html = createTemplateIr();
429
+ appendTemplatePart(html, `<!--[f0;b;${id};${site}--><!--]-->`, 'anchor');
430
+ return html;
431
+ }
432
+ if (node.type !== 'Element') fail(node, `unsupported binding program construct ${node.type}`);
433
+ const tag = tagOf(node);
434
+ if (!/^[a-z]/.test(tag ?? '')) {
435
+ const site = node._octaneBindingSite?.site;
436
+ if (site === undefined) fail(node, 'binding child component is missing its authored site');
437
+ const index = nodes.length;
438
+ appendNode([parent, 'region', String(site)]);
439
+ const html = createTemplateIr();
440
+ appendTemplatePart(html, regionMarker(site, 'v'), 'anchor');
441
+ if (context.annotationsOnly) {
442
+ localProgram(tag, null, true);
443
+ if ((node.children ?? []).some(significant))
444
+ compileFragment(node.children, names, ns, parents);
445
+ return html;
446
+ }
447
+ const props = [];
448
+ const propNames = [];
449
+ for (const attr of node.attributes ?? []) {
450
+ if (attr.type !== 'Attribute' && attr.type !== 'JSXAttribute')
451
+ fail(attr, 'binding child program props must be explicit');
452
+ const name = rawName(attr);
453
+ if (['key', 'children', '__proto__'].includes(name))
454
+ fail(attr, `binding child program ${name} is not supported`);
455
+ if (propNames.includes(name))
456
+ fail(attr, 'binding child program props cannot be repeated');
457
+ const value = attrValue(attr);
458
+ validate(value);
459
+ propNames.push(name);
460
+ props.push(b.prop('init', b.literal(name), value));
461
+ }
462
+ if ((node.children ?? []).some(significant)) propNames.push('children');
463
+ const imported = imports.get(tag);
464
+ const child = !imported ? localProgram(tag, propNames) : null;
465
+ if (
466
+ !child &&
467
+ (!imported?.imported ||
468
+ imported.specifier.type !== 'ImportSpecifier' ||
469
+ /[?#]/.test(imported.source))
470
+ )
471
+ fail(node, 'binding child components must be directly imported named pure binding views');
472
+ const request = child
473
+ ? null
474
+ : formatDomBindingRequest(imported.source, {
475
+ exportName: imported.imported,
476
+ mount: true,
477
+ props: propNames,
478
+ });
479
+ let local = importedPrograms.get(request);
480
+ if (local === undefined && !child) {
481
+ local = allocateProgramName('_bindingChild');
482
+ importedPrograms.set(request, local);
483
+ childPrograms.add(local);
484
+ dependencies.push(origin(b.imports([['default', local]], request), node));
485
+ }
486
+ if (child) {
487
+ // Child capability is checked for the entered view instance when the
488
+ // lease is acquired and published, including a changed active branch.
489
+ signals ||= child.signals;
490
+ controls ||= child.controls;
491
+ hostOperations ||= child.hostOperations;
492
+ styles ||= child.styles;
493
+ projectionsEnabled ||= child.projectionsEnabled;
494
+ for (const program of child.childPrograms) childPrograms.add(program);
495
+ lists ||= child.lists;
496
+ for (const dependency of child.dependencies)
497
+ if (!dependencies.includes(dependency)) dependencies.push(dependency);
498
+ for (const hoist of child.hoists) if (!hoists.includes(hoist)) hoists.push(hoist);
499
+ // A cached plan identifies one declaration and ordered prop specialization.
500
+ // Share only its immutable descriptor; each entered region owns its state.
501
+ const childHoists = (lexical.domBindingChildHoists ??= new WeakMap());
502
+ let hoist = childHoists.get(child);
503
+ if (hoist === undefined) {
504
+ hoist = origin(
505
+ b.const(
506
+ b.id(allocateProgramName('_bindingChild')),
507
+ object({
508
+ id: b.literal(child.id),
509
+ root: child.root,
510
+ ...(child.prepareProps ? { prepareProps: child.prepareProps } : {}),
511
+ }),
512
+ ),
513
+ child.fn,
514
+ );
515
+ childHoists.set(child, hoist);
516
+ }
517
+ if (!hoists.includes(hoist)) hoists.push(hoist);
518
+ local = hoist.declarations[0].id.name;
519
+ expressions.push(...child.expressions);
520
+ } else signals = true;
521
+ if ((node.children ?? []).some(significant)) {
522
+ const fragment = compileFragment(node.children, names, ns, parents).fragment;
523
+ const local = allocateProgramName('_bindingSlotFragment');
524
+ hoists.push(origin(b.const(b.id(local), fragment), node));
525
+ if (slotFactory === null) {
526
+ slotFactory = allocateProgramName('_bindingSlot');
527
+ dependencies.push(
528
+ origin(
529
+ b.imports([['__bindingSlot', slotFactory]], 'octane/dom-binding-program'),
530
+ node,
531
+ ),
532
+ );
533
+ }
534
+ props.push(
535
+ b.prop(
536
+ 'init',
537
+ b.id('children'),
538
+ b.call(
539
+ b.id(slotFactory),
540
+ b.literal(id),
541
+ b.id(local),
542
+ b.array(
543
+ names.map((name, index) =>
544
+ name !== null && names.lastIndexOf(name) === index
545
+ ? b.id(name)
546
+ : b.unary('void', b.literal(0)),
547
+ ),
548
+ ),
549
+ b.literal(site),
550
+ ),
551
+ ),
552
+ );
553
+ }
554
+ regions.push(
555
+ object({
556
+ node: b.literal(index),
557
+ kind: b.literal('view'),
558
+ view: b.id(local),
559
+ props: project(names, b.object(props), node),
560
+ }),
561
+ );
562
+ return html;
563
+ }
564
+ const selfNs = tag === 'svg' ? 1 : ns;
565
+ const index = nodes.length;
566
+ for (const rest of context.restSites?.get(node.attributes) ?? []) {
567
+ const { site, spread, keys } = rest;
568
+ // The same normalized fragment allocator supplies descriptor addresses
569
+ // and normal-renderer metadata, including sites inside branches/slots.
570
+ if (keys !== undefined)
571
+ restSites.push(
572
+ object({
573
+ site: b.literal(site),
574
+ node: b.literal(index),
575
+ spread: b.literal(spread),
576
+ keys: data(keys),
577
+ }),
578
+ );
579
+ if (context.annotationsOnly)
580
+ restAttributes.set(rest.attribute, {
581
+ ...rest.attribute,
582
+ _octaneBindingRest: { id, site, node: index, spread },
583
+ });
584
+ }
585
+ const nativeAttributes = (node.attributes ?? []).filter((attr) => {
586
+ const name = rawName(attr);
587
+ // Annotation-only compilation shares this fragment's exact normalized
588
+ // node allocation, but needs only partial-class ownership receipts.
589
+ // Other native props remain on the ordinary authored renderer path.
590
+ if (context.annotationsOnly) return name === 'class' || name === 'className';
591
+ if (name !== 'ref' && !/^on[A-Z]/.test(name ?? '')) return true;
592
+ const expression = attrValue(attr);
593
+ // Event/ref callbacks are native owner adapters, not eager projections.
594
+ assertAdapter(expression);
595
+ if (
596
+ name !== 'ref' &&
597
+ ![
598
+ 'ArrowFunctionExpression',
599
+ 'FunctionExpression',
600
+ 'MemberExpression',
601
+ 'Identifier',
602
+ 'Literal',
603
+ ].includes(unwrap(expression)?.type)
604
+ )
605
+ fail(attr, 'native event adapters need a callback or callback prop');
606
+ const capture =
607
+ name !== 'ref' &&
608
+ name.endsWith('Capture') &&
609
+ !['onGotPointerCapture', 'onLostPointerCapture'].includes(name);
610
+ const event = capture ? name.slice(2, -7) : name.slice(2);
611
+ const refRecords = name === 'ref' ? refDependencies(expression) : null;
612
+ const refValues = refRecords?.map((record) => {
613
+ if (!record.method) return record.node;
614
+ if (methodDependency === null) {
615
+ methodDependency = allocateProgramName('_bindingMethodDependency');
616
+ dependencies.push(
617
+ origin(
618
+ b.imports([['__methodDep', methodDependency]], 'octane/dom-binding-program'),
619
+ attr,
620
+ ),
621
+ );
622
+ }
623
+ return origin(
624
+ b.call(b.id(methodDependency), record.method.root, b.literal(record.method.name)),
625
+ record.node,
626
+ );
627
+ });
628
+ adapters.push(
629
+ object({
630
+ node: b.literal(index),
631
+ kind: b.literal(name === 'ref' ? 'ref' : 'event'),
632
+ ...(refValues !== null && refValues !== undefined
633
+ ? refValues.length === 0
634
+ ? { stable: b.literal(true) }
635
+ : { dependencies: project(names, b.array(refValues), attr) }
636
+ : {}),
637
+ ...(name === 'ref'
638
+ ? {}
639
+ : {
640
+ name: b.literal(
641
+ event === 'DoubleClick'
642
+ ? 'dblclick'
643
+ : event === 'Focus'
644
+ ? 'focusin'
645
+ : event === 'Blur'
646
+ ? 'focusout'
647
+ : event.toLowerCase(),
648
+ ),
649
+ ...(capture ? { capture: b.literal(true) } : {}),
650
+ }),
651
+ read: project(names, expression, attr),
652
+ }),
653
+ );
654
+ return false;
655
+ });
656
+ const native = nativePlan(
657
+ { ...node, openingElement: undefined, attributes: nativeAttributes },
658
+ selfNs,
659
+ parents,
660
+ );
661
+ for (const [attr, replacement] of native.classAttributes) {
662
+ const metadata = {
663
+ ...replacement._octaneBindingClassGroups,
664
+ receipt: `data-octane-class-${id}-${index}`,
665
+ };
666
+ native.classAttributes.set(attr, { ...replacement, _octaneBindingClassGroups: metadata });
667
+ const original =
668
+ node.openingElement?.attributes.find(
669
+ (candidate) => rawName(candidate) === rawName(attr),
670
+ ) ?? attr;
671
+ classAttributes.set(original, {
672
+ ...original,
673
+ _octaneBindingClassGroups: metadata,
674
+ });
675
+ }
676
+ for (const [call, value] of native.unbound) unbound.set(call, value);
677
+ projections.push(...native.projections);
678
+ for (const signalIndex of native.signalIndices)
679
+ signalIndices.push(bindings.length + signalIndex);
680
+ for (const styleIndex of native.styleIndices) styleIndices.push(bindings.length + styleIndex);
681
+ for (const group of native.projectionGroups)
682
+ projectionGroups.push(group.map(([binding, field]) => [bindings.length + binding, field]));
683
+ projectionsEnabled ||= native.projectionGroups.length > 0;
684
+ signals ||= native.signalIndices.length > 0;
685
+ controls ||= native.bindings.some((binding) => binding[1] === 'control');
686
+ styles ||= native.styleIndices.length > 0;
687
+ const normalizedChildren = normalize(node.children ?? [], selfNs);
688
+ const opaqueChildren =
689
+ normalizedChildren.length > 0 &&
690
+ normalizedChildren.every((child) => child._octaneBindingOpaque);
691
+ const nativeNode = [
692
+ parent,
693
+ 'element',
694
+ tag,
695
+ selfNs,
696
+ tag === 'textarea' || opaqueChildren ? null : 0,
697
+ ];
698
+ if (opaqueChildren)
699
+ constructionError ??=
700
+ 'This view contains externally owned children that cannot be constructed by a binding program.';
701
+ appendNode(nativeNode);
702
+ for (let i = 0; i < native.bindings.length; i++) {
703
+ const binding = native.bindings[i];
704
+ bindings.push(
705
+ binding[1] === 'classGroup'
706
+ ? [index, 'classGroup', `data-octane-class-${id}-${index}`, binding[3]]
707
+ : [index, ...binding.slice(1)],
708
+ );
709
+ values.push(native.values[i]);
710
+ }
711
+ const attributes = createTemplateIr();
712
+ for (const attr of node.attributes ?? []) {
713
+ if (attr._octaneKnownAttributeSpread) continue;
714
+ if (rawName(attr) === 'ref' || /^on[A-Z]/.test(rawName(attr) ?? '')) continue;
715
+ if (attr.type === 'SpreadAttribute' || attr.type === 'JSXSpreadAttribute') {
716
+ constructionError ??=
717
+ 'This view contains an external attribute spread without a native construction adapter.';
718
+ continue;
719
+ }
720
+ const raw = rawName(attr);
721
+ const name = raw === 'className' ? 'class' : (ATTRIBUTE_ALIASES.get(raw) ?? raw);
722
+ // The staged capability owns these values after native construction.
723
+ if (
724
+ native.bindings.some(
725
+ (binding) =>
726
+ (binding[1] === 'control' && binding[2] === name) ||
727
+ (binding[1] === 'styleObject' && name === 'style'),
728
+ )
729
+ )
730
+ continue;
731
+ const expression = attrValue(attr);
732
+ const bare = unwrap(expression);
733
+ const external = native.unbound.has(bare);
734
+ const value = external ? native.unbound.get(bare) : expression;
735
+ const literal = unwrap(value);
736
+ const property =
737
+ (tag !== 'button' || raw !== 'value') &&
738
+ ['value', 'checked', 'defaultValue', 'defaultChecked', 'selected'].includes(raw);
739
+ const classGroup = native.classAttributes.get(attr)?._octaneBindingClassGroups;
740
+ if (classGroup) {
741
+ initialize(index, 'classGroupInitial', classGroup.receipt, b.array(classGroup.baseline));
742
+ } else if (raw === 'dangerouslySetInnerHTML') {
743
+ if ((node.children ?? []).some(significant))
744
+ fail(attr, 'an opaque HTML host cannot also declare binding children');
745
+ nativeNode[4] = null;
746
+ constructionError ??=
747
+ 'This view contains externally owned HTML that cannot be constructed by a binding program.';
748
+ } else if (property) {
749
+ initialize(index, raw, raw, value);
750
+ } else if (name === 'style' && literal?.type === 'ObjectExpression') {
751
+ for (const field of literal.properties) {
752
+ if (
753
+ field.type !== 'Property' ||
754
+ field.computed ||
755
+ field.kind !== 'init' ||
756
+ field.method
757
+ ) {
758
+ constructionError ??=
759
+ 'This view contains an external style object without fixed properties.';
760
+ continue;
761
+ }
762
+ const key = field.key.name ?? field.key.value;
763
+ if (external || unwrap(field.value)?.type === 'Literal')
764
+ initialize(
765
+ index,
766
+ 'styleProperty',
767
+ hyphenateStyleName(key),
768
+ field.value,
769
+ key.startsWith('--') || isUnitlessStyleProp(key),
770
+ );
771
+ }
772
+ } else if (name === 'style') {
773
+ if (external || literal?.type === 'Literal')
774
+ initialize(index, 'styleAttribute', 'style', value);
775
+ } else if (literal?.type === 'Literal') {
776
+ appendTemplatePart(
777
+ attributes,
778
+ helpers.bakeStaticAttr(name, literal.value, tag, selfNs === 1 ? 'svg' : 'html'),
779
+ 'attribute',
780
+ );
781
+ } else if (
782
+ external ||
783
+ (name === 'class' && !native.bindings.some((binding) => binding[1] === 'class'))
784
+ ) {
785
+ const kind =
786
+ name === 'class'
787
+ ? 'class'
788
+ : shouldSanitizeURLAttribute(tag, name)
789
+ ? 'url'
790
+ : name.startsWith('aria-') ||
791
+ name.startsWith('data-') ||
792
+ isEnumeratedBooleanAttr(name.toLowerCase())
793
+ ? 'aria'
794
+ : BOOLEAN_ATTR_PROPS.has(name.toLowerCase())
795
+ ? 'boolean'
796
+ : 'attr';
797
+ initialize(index, kind, name, mapCow(value, native.unbound));
798
+ }
799
+ }
800
+ const children = createTemplateIr();
801
+ if (tag === 'textarea') {
802
+ const hasValue = (node.attributes ?? []).some((attr) =>
803
+ ['value', 'defaultValue'].includes(rawName(attr)),
804
+ );
805
+ if (!hasValue) {
806
+ const text = normalizedChildren;
807
+ if (
808
+ text.every(
809
+ (child) => child.type === 'Text' && unwrap(child.expression)?.type === 'Literal',
810
+ )
811
+ ) {
812
+ for (const child of text)
813
+ appendTemplatePart(
814
+ children,
815
+ helpers.escapeHtml(String(unwrap(child.expression).value)),
816
+ 'text',
817
+ );
818
+ } else if (text.length > 0)
819
+ constructionError ??= 'This textarea has external children without an initial value.';
820
+ }
821
+ } else if (nativeNode[4] !== null) {
822
+ for (const child of normalizedChildren)
823
+ appendTemplateIr(children, emit(child, index, selfNs, [...parents, tag]));
824
+ }
825
+ return templateElement(
826
+ tag,
827
+ selfNs === 1 ? 'svg' : 'html',
828
+ VOID_ELEMENTS.has(tag),
829
+ attributes,
830
+ children,
831
+ null,
832
+ null,
833
+ );
834
+ };
835
+ const template = createTemplateIr();
836
+ for (const node of normalize(rawNodes, namespace))
837
+ appendTemplateIr(template, emit(node, -1, namespace, ancestors));
838
+ if (constructionError !== null) structural = false;
839
+ if (context.annotationsOnly) return { fragment: null, structural };
840
+ const properties = {
841
+ html: b.literal(serializeTemplateIr(template).html),
842
+ ns: b.literal(namespace),
843
+ nodes: data(nodes),
844
+ bindings: data(bindings),
845
+ project: project(names, b.array(values), fn, projections),
846
+ regions: b.array(regions),
847
+ ...(restSites.length ? { restSites: b.array(restSites) } : {}),
848
+ ...(signalIndices.length ? { signalIndices: data(signalIndices) } : {}),
849
+ ...(styleIndices.length ? { styleIndices: data(styleIndices) } : {}),
850
+ ...(projectionGroups.length ? { projectionGroups: data(projectionGroups) } : {}),
851
+ };
852
+ hostOperations ||=
853
+ initializers.length > 0 ||
854
+ projectionGroups.length > 0 ||
855
+ bindings.some((binding) => binding[1] === 'control' || binding[1] === 'classGroup');
856
+ if (initializers.length > 0) {
857
+ properties.initializers = data(initializers);
858
+ properties.initialize = project(names, b.array(initialValues));
859
+ }
860
+ if (bindings.some((binding) => binding[1] === 'classGroup')) {
861
+ if (classFactory === null) {
862
+ classFactory = allocateProgramName('_bindingClassGroup');
863
+ dependencies.push(
864
+ origin(
865
+ b.imports([['createBindingClassGroup', classFactory]], 'octane/dom-binding-classes'),
866
+ fn,
867
+ ),
868
+ );
869
+ }
870
+ properties.createClassGroup = b.id(classFactory);
871
+ }
872
+ if (constructionError !== null) {
873
+ properties.constructible = b.literal(false);
874
+ properties.constructionError = b.literal(constructionError);
875
+ }
876
+ if (adapters.length > 0) {
877
+ if (activationHelper === null) {
878
+ activationHelper = allocateProgramName('_bindingAdapters');
879
+ dependencies.push(
880
+ origin(
881
+ b.imports(
882
+ [['__activateBindingAdapters', activationHelper]],
883
+ 'octane/dom-binding-program',
884
+ ),
885
+ fn,
886
+ ),
887
+ );
888
+ }
889
+ const nodesName = allocateProgramName('_bindingNodes');
890
+ const contextName = allocateProgramName('_bindingContext');
891
+ properties.activate = origin(
892
+ b.arrow(
893
+ [b.id(nodesName), b.id(contextName)],
894
+ b.call(b.id(activationHelper), b.id(nodesName), b.id(contextName), b.array(adapters)),
895
+ ),
896
+ fn,
897
+ );
898
+ }
899
+ return { fragment: object(properties), structural };
900
+ };
901
+ const { fragment: root, structural } = compileFragment([annotated], parameterNames);
902
+ for (const [call, value] of unbound) replacements.set(call, value);
903
+ const finalRender = mapCow(
904
+ annotated,
905
+ new Map([...unbound, ...classAttributes, ...restAttributes]),
906
+ );
907
+ replacements.set(render, finalRender);
908
+ if (context.annotationsOnly) return { id, replacements, structural: structural && !controls };
909
+ return {
910
+ fn,
911
+ render: finalRender,
912
+ id,
913
+ root,
914
+ // Native destructuring runs once at component preparation, shared by every
915
+ // projection and committed adapter. Replaying it in each projector would
916
+ // repeat getters and create different rest objects within one preparation.
917
+ prepareProps:
918
+ fn.params[0]?.type === 'ObjectPattern'
919
+ ? origin(b.arrow(fn.params, b.array(parameterNames.map((name) => b.id(name)))), fn)
920
+ : null,
921
+ expressions,
922
+ dependencies,
923
+ hoists,
924
+ replacements,
925
+ unbound,
926
+ signals,
927
+ controls,
928
+ hostOperations,
929
+ lists,
930
+ styles,
931
+ projectionsEnabled,
932
+ structural: structural && !controls,
933
+ childPrograms,
934
+ };
935
+ }