@esportsplus/template 0.16.0

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 (90) hide show
  1. package/.editorconfig +9 -0
  2. package/.gitattributes +2 -0
  3. package/.github/dependabot.yml +25 -0
  4. package/.github/workflows/bump.yml +9 -0
  5. package/.github/workflows/dependabot.yml +12 -0
  6. package/.github/workflows/publish.yml +16 -0
  7. package/README.md +385 -0
  8. package/build/attributes.d.ts +5 -0
  9. package/build/attributes.js +212 -0
  10. package/build/compiler/codegen.d.ts +21 -0
  11. package/build/compiler/codegen.js +303 -0
  12. package/build/compiler/constants.d.ts +16 -0
  13. package/build/compiler/constants.js +19 -0
  14. package/build/compiler/index.d.ts +14 -0
  15. package/build/compiler/index.js +61 -0
  16. package/build/compiler/parser.d.ts +19 -0
  17. package/build/compiler/parser.js +164 -0
  18. package/build/compiler/plugins/tsc.d.ts +3 -0
  19. package/build/compiler/plugins/tsc.js +4 -0
  20. package/build/compiler/plugins/vite.d.ts +13 -0
  21. package/build/compiler/plugins/vite.js +8 -0
  22. package/build/compiler/ts-analyzer.d.ts +4 -0
  23. package/build/compiler/ts-analyzer.js +63 -0
  24. package/build/compiler/ts-parser.d.ts +24 -0
  25. package/build/compiler/ts-parser.js +67 -0
  26. package/build/constants.d.ts +12 -0
  27. package/build/constants.js +25 -0
  28. package/build/event/index.d.ts +10 -0
  29. package/build/event/index.js +90 -0
  30. package/build/event/onconnect.d.ts +3 -0
  31. package/build/event/onconnect.js +15 -0
  32. package/build/event/onresize.d.ts +3 -0
  33. package/build/event/onresize.js +26 -0
  34. package/build/event/ontick.d.ts +6 -0
  35. package/build/event/ontick.js +41 -0
  36. package/build/html.d.ts +9 -0
  37. package/build/html.js +7 -0
  38. package/build/index.d.ts +8 -0
  39. package/build/index.js +12 -0
  40. package/build/render.d.ts +3 -0
  41. package/build/render.js +8 -0
  42. package/build/slot/array.d.ts +25 -0
  43. package/build/slot/array.js +189 -0
  44. package/build/slot/cleanup.d.ts +4 -0
  45. package/build/slot/cleanup.js +23 -0
  46. package/build/slot/effect.d.ts +12 -0
  47. package/build/slot/effect.js +85 -0
  48. package/build/slot/index.d.ts +7 -0
  49. package/build/slot/index.js +14 -0
  50. package/build/slot/render.d.ts +2 -0
  51. package/build/slot/render.js +44 -0
  52. package/build/svg.d.ts +5 -0
  53. package/build/svg.js +14 -0
  54. package/build/types.d.ts +23 -0
  55. package/build/types.js +1 -0
  56. package/build/utilities.d.ts +7 -0
  57. package/build/utilities.js +31 -0
  58. package/package.json +43 -0
  59. package/src/attributes.ts +313 -0
  60. package/src/compiler/codegen.ts +492 -0
  61. package/src/compiler/constants.ts +25 -0
  62. package/src/compiler/index.ts +87 -0
  63. package/src/compiler/parser.ts +242 -0
  64. package/src/compiler/plugins/tsc.ts +6 -0
  65. package/src/compiler/plugins/vite.ts +10 -0
  66. package/src/compiler/ts-analyzer.ts +89 -0
  67. package/src/compiler/ts-parser.ts +112 -0
  68. package/src/constants.ts +44 -0
  69. package/src/event/index.ts +130 -0
  70. package/src/event/onconnect.ts +22 -0
  71. package/src/event/onresize.ts +37 -0
  72. package/src/event/ontick.ts +59 -0
  73. package/src/html.ts +18 -0
  74. package/src/index.ts +19 -0
  75. package/src/llm.txt +403 -0
  76. package/src/render.ts +13 -0
  77. package/src/slot/array.ts +257 -0
  78. package/src/slot/cleanup.ts +37 -0
  79. package/src/slot/effect.ts +114 -0
  80. package/src/slot/index.ts +17 -0
  81. package/src/slot/render.ts +61 -0
  82. package/src/svg.ts +27 -0
  83. package/src/types.ts +40 -0
  84. package/src/utilities.ts +53 -0
  85. package/storage/compiler-architecture-2026-01-13.md +420 -0
  86. package/test/dist/test.js +1912 -0
  87. package/test/dist/test.js.map +1 -0
  88. package/test/index.ts +648 -0
  89. package/test/vite.config.ts +23 -0
  90. package/tsconfig.json +8 -0
@@ -0,0 +1,59 @@
1
+ import { Attributes, Element } from '../types';
2
+ import { raf } from '../utilities';
3
+
4
+
5
+ let tasks = Object.assign(new Set<VoidFunction>(), { running: false });
6
+
7
+
8
+ function tick() {
9
+ if (tasks.size === 0) {
10
+ tasks.running = false;
11
+ return;
12
+ }
13
+
14
+ for (let task of tasks) {
15
+ task();
16
+ }
17
+
18
+ raf(tick);
19
+ }
20
+
21
+
22
+ const add = (task: VoidFunction) => {
23
+ tasks.add(task);
24
+
25
+ if (!tasks.running) {
26
+ tasks.running = true;
27
+ raf(tick);
28
+ }
29
+ };
30
+
31
+ const remove = (task: VoidFunction) => {
32
+ tasks.delete(task);
33
+ };
34
+
35
+
36
+ export default (element: Element, listener: NonNullable<Attributes['ontick']>) => {
37
+ let connected = false,
38
+ fn = () => {
39
+ if (connected === false) {
40
+ if (element.isConnected) {
41
+ connected = true;
42
+ }
43
+ else if (retry--) {
44
+ return;
45
+ }
46
+ }
47
+
48
+ if (!element.isConnected) {
49
+ remove(fn);
50
+ return;
51
+ }
52
+
53
+ listener(() => remove(fn), element);
54
+ },
55
+ retry = 60;
56
+
57
+ add(fn);
58
+ };
59
+ export { add, remove };
package/src/html.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { Reactive } from '@esportsplus/reactivity';
2
+ import { Attribute, Attributes, Renderable } from './types';
3
+ import { ArraySlot } from './slot';
4
+
5
+
6
+ type Values<T> = ArraySlot<T extends unknown[] ? T : never> | Attribute | Attributes<any> | Renderable<T>;
7
+
8
+
9
+ const html = <T>(_literals: TemplateStringsArray, ..._values: (Values<T> | Values<T>[])[]): DocumentFragment => {
10
+ throw new Error('html`` templates must be compiled. Ensure vite-plugin is configured.');
11
+ };
12
+
13
+ html.reactive = <T>(_arr: Reactive<T[]>, _template: (value: T) => DocumentFragment): ArraySlot<T[]> => {
14
+ throw new Error('html.reactive() must be compiled. Ensure vite-plugin is configured.');
15
+ };
16
+
17
+
18
+ export default html;
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { CLEANUP, STORE } from './constants';
2
+
3
+
4
+ // Pre-allocate on Node prototype to optimize property access
5
+ if (typeof Node !== 'undefined') {
6
+ (Node.prototype as any)[CLEANUP] = null;
7
+ (Node.prototype as any)[STORE] = null;
8
+ }
9
+
10
+
11
+ export * from './attributes';
12
+ export * from './event';
13
+ export * from './utilities';
14
+
15
+ export { default as html } from './html';
16
+ export { default as render } from './render';
17
+ export { default as slot, ArraySlot, EffectSlot } from './slot';
18
+ export { default as svg } from './svg';
19
+ export type { Attributes, Element, Renderable } from './types';
package/src/llm.txt ADDED
@@ -0,0 +1,403 @@
1
+ # Template Library - LLM Context Guide
2
+
3
+ This document provides comprehensive context for LLMs to understand, maintain, and refactor this template compilation and rendering library.
4
+
5
+ ## Overview
6
+
7
+ A compile-time template system that transforms `html` tagged template literals into optimized DOM construction code. The system consists of:
8
+
9
+ 1. **Compiler** (`compiler/`) - TypeScript transformer that runs at build time
10
+ 2. **Runtime** (`*.ts` in root) - Minimal runtime for DOM manipulation, slots, and events
11
+
12
+ ## Architecture
13
+
14
+ ```
15
+ ┌─────────────────────────────────────────────────────────────────┐
16
+ │ BUILD TIME │
17
+ ├─────────────────────────────────────────────────────────────────┤
18
+ │ Source: html`<div>${expr}</div>` │
19
+ │ ↓ │
20
+ │ ts-parser.ts → Find html`` tags in AST │
21
+ │ ↓ │
22
+ │ parser.ts → Parse HTML, extract slots, generate paths │
23
+ │ ↓ │
24
+ │ ts-analyzer.ts → Analyze expression types (Effect, Static..) │
25
+ │ ↓ │
26
+ │ codegen.ts → Generate optimized JS code │
27
+ │ ↓ │
28
+ │ Output: template_xxx().firstChild.nextSibling... │
29
+ ├─────────────────────────────────────────────────────────────────┤
30
+ │ RUNTIME │
31
+ ├─────────────────────────────────────────────────────────────────┤
32
+ │ utilities.ts → template(), clone(), fragment() │
33
+ │ attributes.ts → setList(), setProperty(), reactive bindings │
34
+ │ slot/ → ArraySlot, EffectSlot, static rendering │
35
+ │ event/ → Event delegation, lifecycle hooks │
36
+ └─────────────────────────────────────────────────────────────────┘
37
+ ```
38
+
39
+ ## Compiler Pipeline
40
+
41
+ ### Entry Point: `compiler/index.ts`
42
+
43
+ The transform function:
44
+ 1. Finds all `html` tagged templates via `findHtmlTemplates()`
45
+ 2. Finds all `html.reactive()` calls via `findReactiveCalls()`
46
+ 3. Generates replacement code via `generateCode()`
47
+ 4. Outputs import statements and template factory definitions
48
+
49
+ ### HTML Parser: `compiler/parser.ts`
50
+
51
+ **Purpose**: Parse HTML string, identify dynamic slots, generate DOM traversal paths.
52
+
53
+ **Key Data Structures**:
54
+
55
+ ```typescript
56
+ type NodePath = ('firstChild' | 'firstElementChild' | 'nextElementSibling' | 'nextSibling')[];
57
+
58
+ // Level tracking for nested elements
59
+ type Level = {
60
+ children: number; // Text/comment node count (for firstChild/nextSibling)
61
+ elements: number; // Element count (for firstElementChild/nextElementSibling)
62
+ path: NodePath; // Path to reach this level from root
63
+ };
64
+ ```
65
+
66
+ **Slot Marker**: `{{$}}` represents dynamic expression positions in the template.
67
+
68
+ **Node Types**:
69
+ - `NODE_ELEMENT` (3) - Regular HTML elements
70
+ - `NODE_VOID` (5) - Self-closing elements (img, input, br, etc.)
71
+ - `NODE_SLOT` (4) - Dynamic content position (`{{$}}`)
72
+ - `NODE_CLOSING` (1) - Closing tags (`</div>`)
73
+ - `NODE_COMMENT` (2) - Comments
74
+
75
+ **Path Generation Algorithm**:
76
+
77
+ ```typescript
78
+ // At root level (empty parent.path):
79
+ // Use firstChild/nextSibling with parent.children count
80
+ // At nested levels (non-empty parent.path):
81
+ // Use firstElementChild/nextElementSibling with parent.elements count
82
+
83
+ path = parent.path.length
84
+ ? methods(parent.elements, parent.path, 'firstElementChild', 'nextElementSibling')
85
+ : methods(parent.children, [], 'firstChild', 'nextSibling');
86
+ ```
87
+
88
+ **Critical Bug Fix (Line 217)**:
89
+
90
+ Self-closing tags like `<path/>`, `<circle/>` in SVG must decrement level:
91
+
92
+ ```typescript
93
+ // IMPORTANT: Check for self-closing syntax before NODE_CLOSING
94
+ if (match[0].at(-2) === '/' || type === NODE_CLOSING) {
95
+ level--;
96
+ }
97
+ ```
98
+
99
+ Without this fix, self-closing tags increment `level` but never decrement, causing all subsequent paths to be offset incorrectly.
100
+
101
+ ### Code Generator: `compiler/codegen.ts`
102
+
103
+ **Purpose**: Transform parsed template data into executable JavaScript.
104
+
105
+ **Key Functions**:
106
+
107
+ - `generateTemplateCode()` - Main code generation
108
+ - `generateAttributeBinding()` - Attribute/event binding code
109
+ - `generateNodeBinding()` - Slot content binding code
110
+
111
+ **Path Optimization**:
112
+
113
+ The codegen optimizes traversal by finding common ancestors:
114
+
115
+ ```typescript
116
+ // If element A has path [a, b, c, d]
117
+ // And element B has path [a, b, c, d, e, f]
118
+ // Then B can be declared as: A.e!.f
119
+ ```
120
+
121
+ This optimization relies on correct paths from the parser. If paths share an incorrect prefix due to level tracking bugs, the generated code will fail at runtime.
122
+
123
+ **Output Structure**:
124
+
125
+ ```javascript
126
+ (() => {
127
+ let root_xxx = template_xxx(),
128
+ element_yyy = root_xxx.firstChild!.firstElementChild as Element,
129
+ element_zzz = element_yyy.nextElementSibling!.firstChild as Element;
130
+
131
+ // Attribute bindings
132
+ namespace.delegate(element_yyy, 'click', handler);
133
+ namespace.setList(element_yyy, 'class', value, attributes_xxx);
134
+
135
+ // Slot bindings
136
+ namespace.slot(element_zzz, content);
137
+
138
+ return root_xxx;
139
+ })()
140
+ ```
141
+
142
+ ### Type Analyzer: `compiler/ts-analyzer.ts`
143
+
144
+ Analyzes expressions to determine optimal runtime binding:
145
+
146
+ | Expression Type | Result | Runtime Behavior |
147
+ |----------------|--------|------------------|
148
+ | Arrow/Function | `Effect` | Creates `EffectSlot` with reactivity |
149
+ | `html.reactive()` | `ArraySlot` | Creates `ArraySlot` for lists |
150
+ | Nested `html` tag | `DocumentFragment` | Direct insertion |
151
+ | Literal values | `Static` | Direct text assignment |
152
+ | Unknown | `Unknown` | Runtime `slot()` dispatch |
153
+
154
+ ## Runtime Components
155
+
156
+ ### Template Factory: `utilities.ts`
157
+
158
+ ```typescript
159
+ const template = (html: string) => {
160
+ let cached: DocumentFragment | undefined;
161
+ return () => {
162
+ if (!cached) {
163
+ element.innerHTML = html;
164
+ cached = element.content;
165
+ }
166
+ return clone(cached, true);
167
+ };
168
+ };
169
+ ```
170
+
171
+ Caches parsed HTML, returns cloned fragments on each call.
172
+
173
+ ### Slot System: `slot/`
174
+
175
+ **Three slot types**:
176
+
177
+ 1. **Static Slot** (`slot/index.ts`)
178
+ - One-time content insertion
179
+ - No reactivity overhead
180
+
181
+ 2. **EffectSlot** (`slot/effect.ts`)
182
+ - Wraps reactive function in `effect()`
183
+ - Updates content on dependency changes
184
+ - Batches updates via `requestAnimationFrame`
185
+
186
+ 3. **ArraySlot** (`slot/array.ts`)
187
+ - Handles reactive arrays with fine-grained updates
188
+ - Listens to array mutation events (push, pop, splice, etc.)
189
+ - Maintains DOM node groups per array item
190
+
191
+ **SlotGroup Structure**:
192
+
193
+ ```typescript
194
+ type SlotGroup = {
195
+ head: Element; // First node of rendered content
196
+ tail: Element; // Last node of rendered content
197
+ };
198
+ ```
199
+
200
+ Used to track multi-node slot content for efficient removal/replacement.
201
+
202
+ ### Attribute System: `attributes.ts`
203
+
204
+ **Attribute Types**:
205
+
206
+ 1. **List Attributes** (class, style)
207
+ - Merge static + dynamic values
208
+ - Track changes per-slot to minimize updates
209
+ - Use delimiters: class=' ', style=';'
210
+
211
+ 2. **Property Attributes**
212
+ - Direct property assignment
213
+ - Uses `element.removeAttribute()` for null/false/empty
214
+
215
+ 3. **Reactive Attributes**
216
+ - Wrapped in `effect()` for automatic updates
217
+ - Batched via RAF queue
218
+
219
+ **Update Batching**:
220
+
221
+ ```typescript
222
+ let queue = q<Context>(64); // Circular buffer
223
+ let scheduled = false;
224
+
225
+ function schedule(ctx, element, name, state, value) {
226
+ (ctx.updates ??= {})[name] = value;
227
+ if (!ctx.updating) {
228
+ queue.add(ctx);
229
+ }
230
+ if (!scheduled) {
231
+ scheduled = true;
232
+ raf(task); // Apply all updates in next frame
233
+ }
234
+ }
235
+ ```
236
+
237
+ ### Event System: `event/`
238
+
239
+ **Event Delegation**:
240
+
241
+ Most events use document-level delegation:
242
+
243
+ ```typescript
244
+ // Registration creates a symbol key for each event type
245
+ const delegate = (element, event, listener) => {
246
+ element[ keys[event] || register(element, event) ] = listener;
247
+ };
248
+
249
+ // Document listener bubbles up, checking for handler
250
+ host.addEventListener(event, (e) => {
251
+ let node = e.target;
252
+ while (node) {
253
+ if (typeof node[key] === 'function') {
254
+ return node[key].call(node, e);
255
+ }
256
+ node = node.parentElement;
257
+ }
258
+ });
259
+ ```
260
+
261
+ **Direct Attachment Events**:
262
+
263
+ Events that don't bubble properly use `addEventListener` directly:
264
+ - `blur`, `focus`, `focusin`, `focusout`
265
+ - `load`, `error`
266
+ - Media events: `play`, `pause`, `ended`, `timeupdate`
267
+ - `scroll`, `submit`, `reset`
268
+
269
+ **Lifecycle Events**:
270
+
271
+ Custom events handled specially:
272
+ - `onconnect` - Called when element enters DOM
273
+ - `ondisconnect` - Called when element leaves DOM
274
+ - `onrender` - Called after initial render
275
+ - `onresize` - ResizeObserver-based
276
+ - `ontick` - RAF-based animation loop
277
+
278
+ ### Cleanup System: `slot/cleanup.ts`
279
+
280
+ Nodes store cleanup functions via symbol key:
281
+
282
+ ```typescript
283
+ const ondisconnect = (element, fn) => {
284
+ ((element as any)[CLEANUP] ??= []).push(fn);
285
+ };
286
+
287
+ const remove = (...groups) => {
288
+ // Walk backwards through node range
289
+ // Call all cleanup functions
290
+ // Remove nodes from DOM
291
+ };
292
+ ```
293
+
294
+ ## Constants Reference
295
+
296
+ ### `constants.ts` (Runtime)
297
+
298
+ | Constant | Value | Purpose |
299
+ |----------|-------|---------|
300
+ | `CLEANUP` | Symbol | Key for cleanup function array on nodes |
301
+ | `STORE` | Symbol | Key for attribute context on nodes |
302
+ | `ARRAY_SLOT` | Symbol | Marker for ArraySlot instances |
303
+ | `SLOT_HTML` | `'<!--$-->'` | Comment marker for slot positions |
304
+ | `STATE_HYDRATING` | 0 | Initial render, apply immediately |
305
+ | `STATE_NONE` | 1 | Normal update, batch via RAF |
306
+ | `STATE_WAITING` | 2 | Array item, wait for batch |
307
+
308
+ ### `compiler/constants.ts`
309
+
310
+ | Constant | Value | Purpose |
311
+ |----------|-------|---------|
312
+ | `ENTRYPOINT` | 'html' | Tag function name to transform |
313
+ | `ENTRYPOINT_REACTIVITY` | 'reactive' | Method for array slots |
314
+ | `NAMESPACE` | uid('template') | Runtime import namespace |
315
+
316
+ ## Refactoring Guidelines
317
+
318
+ ### Safe Changes
319
+
320
+ 1. **Adding void elements to `NODE_WHITELIST`**
321
+ - Add tag name with `NODE_VOID` value
322
+ - No other changes needed
323
+
324
+ 2. **Adding lifecycle events**
325
+ - Add to `LIFECYCLE_EVENTS` set in `constants.ts`
326
+ - Implement handler in `event/on<name>.ts`
327
+ - Export from `event/index.ts`
328
+
329
+ 3. **Adding direct-attach events**
330
+ - Add to `DIRECT_ATTACH_EVENTS` set
331
+ - Uses existing `on()` function
332
+
333
+ ### Dangerous Changes
334
+
335
+ 1. **Modifying `parser.ts` level tracking**
336
+ - Level must increment for `NODE_ELEMENT` only
337
+ - Level must decrement for `NODE_CLOSING` AND self-closing tags
338
+ - Off-by-one errors cause path corruption across all templates
339
+
340
+ 2. **Modifying `codegen.ts` path optimization**
341
+ - Ancestor matching relies on exact path prefixes
342
+ - Incorrect matches cause runtime null reference errors
343
+
344
+ 3. **Modifying slot rendering order**
345
+ - Slots must be processed in document order
346
+ - Expression indices must match slot order
347
+
348
+ ### Testing Recommendations
349
+
350
+ After modifying parser/codegen:
351
+ 1. Test templates with SVG containing self-closing tags (`<path/>`, `<circle/>`)
352
+ 2. Test deeply nested structures (3+ levels)
353
+ 3. Test multiple sibling elements with event handlers
354
+ 4. Test templates with mixed slot types (attributes + content)
355
+
356
+ ### Common Failure Modes
357
+
358
+ 1. **"Cannot read property 'nextElementSibling' of null"**
359
+ - Cause: Path goes deeper than actual DOM structure
360
+ - Debug: Check level tracking in parser for self-closing tags
361
+
362
+ 2. **Wrong element receives event handler**
363
+ - Cause: Path offset, element N gets binding for element N+1
364
+ - Debug: Check `parent.elements` count at each level
365
+
366
+ 3. **Slot content appears in wrong position**
367
+ - Cause: `parent.children` count incorrect
368
+ - Debug: Check text node handling between elements
369
+
370
+ ## File Dependency Graph
371
+
372
+ ```
373
+ index.ts (runtime entry)
374
+ ├── constants.ts
375
+ ├── attributes.ts ← constants, types, utilities, event
376
+ ├── html.ts ← types, slot (stub, replaced at compile)
377
+ ├── render.ts ← types, utilities, slot
378
+ ├── svg.ts (same as html.ts)
379
+ ├── utilities.ts ← constants
380
+ ├── types.ts ← slot/array
381
+ ├── slot/
382
+ │ ├── index.ts ← types, effect, render
383
+ │ ├── array.ts ← reactivity, constants, types, utilities, cleanup, html
384
+ │ ├── effect.ts ← reactivity, types, utilities, cleanup, render
385
+ │ ├── cleanup.ts ← constants, types
386
+ │ └── render.ts ← utilities, constants, types, array
387
+ └── event/
388
+ ├── index.ts ← reactivity, utilities, constants, slot, types, onconnect/resize/tick
389
+ ├── onconnect.ts ← types
390
+ ├── onresize.ts ← types, cleanup
391
+ └── ontick.ts ← types, cleanup, utilities
392
+
393
+ compiler/
394
+ ├── index.ts ← ts, ast, constants, codegen, ts-parser
395
+ ├── constants.ts ← typescript/compiler
396
+ ├── parser.ts ← constants (from ..)
397
+ ├── codegen.ts ← typescript, utilities, ts-parser, ts-analyzer, constants, parser
398
+ ├── ts-parser.ts ← typescript, typescript/compiler, constants
399
+ ├── ts-analyzer.ts ← typescript, constants
400
+ └── plugins/
401
+ ├── vite.ts ← typescript/compiler, constants, reactivity/compiler, ..
402
+ └── tsc.ts (similar)
403
+ ```
package/src/render.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { Element, Renderable } from './types';
2
+ import { marker } from './utilities';
3
+ import slot from './slot';
4
+
5
+
6
+ export default <T>(parent: HTMLElement, renderable: Renderable<T>) => {
7
+ let anchor = marker.cloneNode() as unknown as Element;
8
+
9
+ parent.nodeValue = '';
10
+ parent.append(anchor);
11
+
12
+ slot(anchor, renderable);
13
+ };