0
# Transform System
1
2
Vue Compiler Core's transform system provides a flexible plugin architecture for processing and modifying AST nodes. The system includes built-in transforms for Vue directives, structural elements, and optimizations, as well as extensibility for custom transforms.
3
4
## Capabilities
5
6
### Transform Context
7
8
The central context object that manages transformation state and provides utilities.
9
10
```typescript { .api }
11
/**
12
* Context object passed through all transformations
13
*/
14
interface TransformContext {
15
/** Root AST node being transformed */
16
root: RootNode;
17
/** Map of runtime helpers to usage count */
18
helpers: Map<symbol, number>;
19
/** Set of component names referenced */
20
components: Set<string>;
21
/** Set of directive names referenced */
22
directives: Set<string>;
23
/** Array of hoisted expressions */
24
hoists: (JSChildNode | null)[];
25
/** Import statements needed */
26
imports: ImportItem[];
27
/** Cache for constant expressions */
28
constantCache: WeakMap<TemplateChildNode, ConstantTypes>;
29
/** Number of temporary variables */
30
temps: number;
31
/** Number of cached expressions */
32
cached: number;
33
/** Identifier tracking for scoping */
34
identifiers: { [name: string]: number | undefined };
35
/** Scope counters for different directive types */
36
scopes: {
37
vFor: number;
38
vSlot: number;
39
vPre: number;
40
vOnce: number;
41
};
42
/** Current parent node */
43
parent: ParentNode | null;
44
/** Index of current node in parent's children */
45
childIndex: number;
46
/** Current node being processed */
47
currentNode: RootNode | TemplateChildNode | null;
48
/** Whether currently inside v-once */
49
inVOnce: boolean;
50
51
/** Add a runtime helper and return its name */
52
helper(name: symbol): string;
53
/** Remove a runtime helper */
54
removeHelper(name: symbol): void;
55
/** Get string representation of helper */
56
helperString(name: symbol): string;
57
/** Replace the current node */
58
replaceNode(node: TemplateChildNode): void;
59
/** Remove the current node */
60
removeNode(node?: TemplateChildNode): void;
61
/** Callback when node is removed */
62
onNodeRemoved: (() => void) | undefined;
63
/** Add identifiers to scope tracking */
64
addIdentifiers(exp: ExpressionNode | string): void;
65
/** Remove identifiers from scope tracking */
66
removeIdentifiers(exp: ExpressionNode | string): void;
67
/** Hoist an expression for static optimization */
68
hoist(exp: string | JSChildNode | ArrayExpression): SimpleExpressionNode;
69
/** Cache an expression */
70
cache<T extends JSChildNode>(exp: T, isVNode?: boolean): CacheExpression | T;
71
}
72
73
/**
74
* Creates a new transform context
75
*/
76
function createTransformContext(
77
root: RootNode,
78
options: TransformOptions
79
): TransformContext;
80
```
81
82
### Transform Functions
83
84
Core functions for applying transformations to AST nodes.
85
86
```typescript { .api }
87
/**
88
* Traverses and transforms a single AST node and its children
89
* @param node - AST node to process
90
* @param context - Transform context
91
*/
92
function traverseNode(
93
node: RootNode | TemplateChildNode,
94
context: TransformContext
95
): void;
96
97
/**
98
* Creates a structural directive transform
99
* @param name - Directive name or pattern to match
100
* @param fn - Transform function to apply
101
* @returns Node transform function
102
*/
103
function createStructuralDirectiveTransform(
104
name: string | RegExp,
105
fn: StructuralDirectiveTransform
106
): NodeTransform;
107
```
108
109
**Usage Examples:**
110
111
```typescript
112
import {
113
createTransformContext,
114
traverseNode,
115
createStructuralDirectiveTransform
116
} from "@vue/compiler-core";
117
118
// Create transform context
119
const context = createTransformContext(ast, {
120
nodeTransforms: [/* transforms */],
121
directiveTransforms: {/* directive transforms */}
122
});
123
124
// Traverse and transform nodes
125
traverseNode(ast, context);
126
127
// Create custom structural directive transform
128
const customIfTransform = createStructuralDirectiveTransform(
129
'custom-if',
130
(node, dir, context) => {
131
// Transform logic here
132
}
133
);
134
```
135
136
### Transform Function Types
137
138
Type definitions for different kinds of transform functions.
139
140
```typescript { .api }
141
/**
142
* Node transform function signature
143
*/
144
type NodeTransform = (
145
node: RootNode | TemplateChildNode,
146
context: TransformContext
147
) => void | (() => void) | (() => void)[];
148
149
/**
150
* Directive transform function signature
151
*/
152
type DirectiveTransform = (
153
dir: DirectiveNode,
154
node: ElementNode,
155
context: TransformContext,
156
augmentor?: (ret: DirectiveTransformResult) => DirectiveTransformResult
157
) => DirectiveTransformResult;
158
159
/**
160
* Structural directive transform function signature
161
*/
162
type StructuralDirectiveTransform = (
163
node: ElementNode,
164
dir: DirectiveNode,
165
context: TransformContext
166
) => void | (() => void);
167
168
/**
169
* Hoist transform function signature
170
*/
171
type HoistTransform = (
172
children: TemplateChildNode[],
173
context: TransformContext,
174
parent: ParentNode
175
) => void;
176
```
177
178
## Built-in Directive Transforms
179
180
Pre-built transforms for Vue's core directives.
181
182
### v-model Transform
183
184
Handles two-way data binding transformation.
185
186
```typescript { .api }
187
/**
188
* Transform for v-model directive
189
*/
190
const transformModel: DirectiveTransform;
191
```
192
193
**Usage Examples:**
194
195
```typescript
196
// Template: <input v-model="value" />
197
// Transforms to: <input :modelValue="value" @update:modelValue="value = $event" />
198
199
// Custom v-model transform in directive transforms map
200
const directiveTransforms = {
201
model: transformModel
202
};
203
```
204
205
### v-on Transform
206
207
Handles event listener transformation.
208
209
```typescript { .api }
210
/**
211
* Transform for v-on directive
212
*/
213
const transformOn: DirectiveTransform;
214
```
215
216
**Usage Examples:**
217
218
```typescript
219
// Template: <button v-on:click="handler" />
220
// Template: <button @click="handler" />
221
// Transforms to event listener binding
222
223
const directiveTransforms = {
224
on: transformOn
225
};
226
```
227
228
### v-bind Transform
229
230
Handles attribute and property binding.
231
232
```typescript { .api }
233
/**
234
* Transform for v-bind directive
235
*/
236
const transformBind: DirectiveTransform;
237
```
238
239
**Usage Examples:**
240
241
```typescript
242
// Template: <div v-bind:class="classes" />
243
// Template: <div :class="classes" />
244
// Transforms to property binding
245
246
const directiveTransforms = {
247
bind: transformBind
248
};
249
```
250
251
### No-op Transform
252
253
Placeholder transform for directives that don't need processing.
254
255
```typescript { .api }
256
/**
257
* No-operation directive transform
258
*/
259
const noopDirectiveTransform: DirectiveTransform;
260
```
261
262
## Structural Directive Processing
263
264
Functions for handling structural directives like v-if and v-for.
265
266
### v-if Processing
267
268
Handles conditional rendering transformation.
269
270
```typescript { .api }
271
/**
272
* Processes v-if structural directive
273
* @param node - Element node with v-if
274
* @param branch - If branch node
275
* @param context - Transform context
276
*/
277
function processIf(
278
node: ElementNode,
279
branch: IfBranchNode,
280
context: TransformContext,
281
processCodegen?: (node: IfNode, branch: IfBranchNode, isRoot: boolean) => () => void
282
): () => void;
283
```
284
285
**Usage Examples:**
286
287
```typescript
288
// Template: <div v-if="condition">Content</div>
289
// Processes into conditional render structure
290
291
import { processIf } from "@vue/compiler-core";
292
293
// Used within node transforms to handle v-if
294
const ifTransform: NodeTransform = (node, context) => {
295
if (node.type === NodeTypes.ELEMENT && hasDirective(node, 'if')) {
296
return processIf(node, branch, context);
297
}
298
};
299
```
300
301
### v-for Processing
302
303
Handles list rendering transformation.
304
305
```typescript { .api }
306
/**
307
* Processes v-for structural directive
308
* @param node - Element node with v-for
309
* @param context - Transform context
310
*/
311
function processFor(
312
node: ElementNode,
313
context: TransformContext,
314
processCodegen?: (forNode: ForNode, child: ElementNode, context: TransformContext) => (() => void) | undefined
315
): (() => void) | undefined;
316
317
/**
318
* Creates parameters for v-for loops
319
* @param parseResult - Parsed v-for expression
320
* @param context - Transform context
321
*/
322
function createForLoopParams(
323
parseResult: ForParseResult,
324
context: TransformContext
325
): ExpressionNode[];
326
```
327
328
**Usage Examples:**
329
330
```typescript
331
// Template: <li v-for="item in items" :key="item.id">{{ item.name }}</li>
332
// Processes into render list structure
333
334
import { processFor, createForLoopParams } from "@vue/compiler-core";
335
336
// Used within node transforms to handle v-for
337
const forTransform: NodeTransform = (node, context) => {
338
if (node.type === NodeTypes.ELEMENT && hasDirective(node, 'for')) {
339
return processFor(node, context);
340
}
341
};
342
```
343
344
## Expression Processing
345
346
Functions for handling JavaScript expressions within templates.
347
348
### Expression Transform
349
350
Main transform for processing JavaScript expressions.
351
352
```typescript { .api }
353
/**
354
* Node transform for JavaScript expressions
355
*/
356
const transformExpression: NodeTransform;
357
358
/**
359
* Processes JavaScript expressions in templates
360
* @param node - Expression node to process
361
* @param context - Transform context
362
* @param asParams - Whether to treat as function parameters
363
* @param asRawStatements - Whether to treat as raw statements
364
* @param localVars - Local variable context
365
*/
366
function processExpression(
367
node: SimpleExpressionNode,
368
context: TransformContext,
369
asParams?: boolean,
370
asRawStatements?: boolean,
371
localVars?: Record<string, number>
372
): ExpressionNode;
373
374
/**
375
* Stringifies expressions for static analysis
376
* @param exp - Expression to stringify
377
*/
378
function stringifyExpression(exp: ExpressionNode | string): string;
379
```
380
381
**Usage Examples:**
382
383
```typescript
384
import { transformExpression, processExpression } from "@vue/compiler-core";
385
386
// Include in node transforms for expression processing
387
const nodeTransforms = [
388
transformExpression, // Handles {{ expressions }} and directive values
389
// ... other transforms
390
];
391
392
// Manual expression processing
393
const processedExp = processExpression(simpleExp, context);
394
```
395
396
## Slot Processing
397
398
Functions for handling Vue slots and scoped slots.
399
400
### Slot Building
401
402
Functions for constructing slot expressions.
403
404
```typescript { .api }
405
/**
406
* Builds slot expressions from v-slot directives
407
* @param node - Element node with slots
408
* @param context - Transform context
409
* @param buildSlotFn - Function to build individual slots
410
*/
411
function buildSlots(
412
node: ElementNode,
413
context: TransformContext,
414
buildSlotFn?: SlotFnBuilder
415
): SlotsExpression;
416
417
/**
418
* Function signature for building individual slot functions
419
*/
420
type SlotFnBuilder = (
421
slotProps: ExpressionNode | undefined,
422
slotChildren: TemplateChildNode[],
423
loc: SourceLocation
424
) => FunctionExpression;
425
426
/**
427
* Processes slot outlet elements (<slot> tags)
428
* @param node - Slot outlet node
429
* @param context - Transform context
430
* @returns Slot name and props information
431
*/
432
function processSlotOutlet(
433
node: SlotOutletNode,
434
context: TransformContext
435
): { slotName: string | ExpressionNode; slotProps: PropsExpression | undefined };
436
437
/**
438
* Tracks v-for scope variables in slots
439
*/
440
const trackVForSlotScopes: NodeTransform;
441
442
/**
443
* Tracks slot scope variables
444
*/
445
const trackSlotScopes: NodeTransform;
446
```
447
448
**Usage Examples:**
449
450
```typescript
451
import { buildSlots, trackVForSlotScopes, trackSlotScopes } from "@vue/compiler-core";
452
453
// Include slot tracking in transforms
454
const nodeTransforms = [
455
trackSlotScopes,
456
trackVForSlotScopes,
457
// ... other transforms
458
];
459
460
// Build slots for component
461
const slots = buildSlots(componentNode, context);
462
```
463
464
## Element and Component Processing
465
466
Functions for processing element nodes and component resolution.
467
468
### Element Transform
469
470
Main transform for element processing.
471
472
```typescript { .api }
473
/**
474
* Main node transform for element processing
475
*/
476
const transformElement: NodeTransform;
477
478
/**
479
* Resolves component names to runtime references
480
* @param node - Element node
481
* @param context - Transform context
482
* @param ssr - Whether in SSR mode
483
*/
484
function resolveComponentType(
485
node: ElementNode,
486
context: TransformContext,
487
ssr?: boolean
488
): string | symbol;
489
490
/**
491
* Builds props expression from attributes and directives
492
* @param node - Element node
493
* @param context - Transform context
494
* @param props - Props array to process
495
* @param ssr - Whether in SSR mode
496
*/
497
function buildProps(
498
node: ElementNode,
499
context: TransformContext,
500
props?: ElementNode['props'],
501
ssr?: boolean
502
): PropsExpression | undefined;
503
504
/**
505
* Builds directive arguments array
506
* @param props - Props array containing directives
507
* @param context - Transform context
508
*/
509
function buildDirectiveArgs(
510
props: ElementNode['props'],
511
context: TransformContext
512
): DirectiveArguments | undefined;
513
514
/**
515
* Type for props expressions
516
*/
517
type PropsExpression = ObjectExpression | CallExpression | ExpressionNode;
518
```
519
520
### Slot Outlet Processing
521
522
Function for processing slot outlet elements.
523
524
```typescript { .api }
525
/**
526
* Processes slot outlet elements (<slot>)
527
* @param node - Slot outlet element
528
* @param context - Transform context
529
*/
530
function processSlotOutlet(
531
node: ElementNode,
532
context: TransformContext
533
): void;
534
```
535
536
### Static Analysis
537
538
Function for determining constant types for optimization.
539
540
```typescript { .api }
541
/**
542
* Determines if a node can be statically analyzed and cached
543
* @param node - AST node to analyze
544
* @param context - Transform context
545
*/
546
function getConstantType(
547
node: TemplateChildNode | TemplateChildNode[],
548
context: TransformContext
549
): ConstantTypes;
550
```
551
552
## Transform Result Types
553
554
Types for transform function results.
555
556
```typescript { .api }
557
/**
558
* Result of directive transform
559
*/
560
interface DirectiveTransformResult {
561
/** Generated props */
562
props: Property[];
563
/** Whether this directive needs runtime */
564
needRuntime?: boolean | symbol;
565
/** SSR-specific properties */
566
ssrTagParts?: TemplateLiteral['elements'];
567
}
568
569
/**
570
* Import item for transform context
571
*/
572
interface ImportItem {
573
/** Expression to import */
574
exp: string | ExpressionNode;
575
/** Path to import from */
576
path: string;
577
}
578
```
579
580
## Usage Patterns
581
582
### Custom Node Transform
583
584
```typescript
585
import { type NodeTransform, NodeTypes } from "@vue/compiler-core";
586
587
const customTransform: NodeTransform = (node, context) => {
588
if (node.type === NodeTypes.ELEMENT && node.tag === 'custom-element') {
589
// Transform custom elements
590
node.tag = 'div'; // Replace with div
591
return () => {
592
// Exit function called after children are processed
593
console.log('Custom element processed');
594
};
595
}
596
};
597
```
598
599
### Custom Directive Transform
600
601
```typescript
602
import { type DirectiveTransform } from "@vue/compiler-core";
603
604
const customDirectiveTransform: DirectiveTransform = (dir, node, context) => {
605
if (dir.name === 'custom') {
606
return {
607
props: [
608
// Generate props for the directive
609
createObjectProperty('customProp', dir.exp || createSimpleExpression('true', true))
610
]
611
};
612
}
613
return { props: [] };
614
};
615
```