Helpers and Builders
vue-metamorph provides a set of helper functions and builder functions through the utils object passed to your plugin's transform() or find() function.
const myCodemod: CodemodPlugin = {
type: 'codemod',
name: 'my-codemod',
transform({ scriptASTs, sfcAST, utils }) {
// utils.astHelpers - functions for finding nodes and managing imports
// utils.builders - functions for creating new AST nodes
}
}AST Helpers
findFirst
Finds the first node in an AST that matches a partial object. Works with both script and template ASTs.
const { astHelpers } = utils;
// find the first <div> in the template
const div = astHelpers.findFirst(sfcAST, {
type: 'VElement',
name: 'div',
});
// find the first call to `console.log` in a script
const consoleLog = astHelpers.findFirst(scriptAST, {
type: 'CallExpression',
callee: {
type: 'MemberExpression',
object: { type: 'Identifier', name: 'console' },
property: { type: 'Identifier', name: 'log' },
},
});Returns the first matching node, or null if no match was found.
findAll
Finds all nodes in an AST that match a partial object.
const { astHelpers } = utils;
// find all <custom> elements in the template
const elements = astHelpers.findAll(sfcAST, {
type: 'VElement',
name: 'custom',
});
// find all call expressions in a script
const calls = astHelpers.findAll(scriptAST, {
type: 'CallExpression',
});Returns an array of all matching nodes.
findImportDeclaration
Finds an existing import declaration for a module.
const { astHelpers } = utils;
const vueImport = astHelpers.findImportDeclaration(scriptAST, 'vue');
if (vueImport) {
// an import from 'vue' exists
}Returns the ImportDeclaration node, or null.
createNamedImport
Adds a named import to a script AST. If an import declaration for the module already exists, the new specifier is added to it. Duplicate imports are not created.
const { astHelpers } = utils;
// import { defineComponent } from 'vue';
astHelpers.createNamedImport(scriptAST, 'vue', 'defineComponent');
// import { map as lodashMap } from 'lodash-es';
astHelpers.createNamedImport(scriptAST, 'lodash-es', 'map', 'lodashMap');createDefaultImport
Adds a default import to a script AST. Follows the same merging and deduplication logic as createNamedImport.
const { astHelpers } = utils;
// import Vue from 'vue';
astHelpers.createDefaultImport(scriptAST, 'vue', 'Vue');createNamespaceImport
Adds a namespace import to a script AST. Follows the same merging and deduplication logic as createNamedImport.
const { astHelpers } = utils;
// import * as _ from 'lodash-es';
astHelpers.createNamespaceImport(scriptAST, 'lodash-es', '_');findVueComponentOptions
Finds all Options API object expressions in a script. Detects defineComponent(), Vue.extend(), Vue.component(), Vue.mixin(), new Vue(), and (when isSfc is true) the default export.
const { astHelpers } = utils;
for (const scriptAST of scriptASTs) {
const optionsObjects = astHelpers.findVueComponentOptions(scriptAST, sfcAST !== null);
for (const obj of optionsObjects) {
// obj is an ObjectExpression node — the { ... } passed to defineComponent(), etc.
}
}Template Builders
The utils.builders object includes functions for creating new template AST nodes. These are useful when your codemod needs to insert new elements, attributes, or directives into the <template>.
TIP
After building new nodes and inserting them into the AST, call builders.setParents() on the root of the new subtree. Builder functions leave parent references unset — setParents fills them in.
const newElement = builders.vElement('div', builders.vStartTag([], false), []);
builders.setParents(sfcAST); // fix parent referencesvElement
Creates a new element node. An end tag is created automatically unless the tag is self-closing or a void element.
const { builders } = utils;
const div = builders.vElement(
'div',
builders.vStartTag([
builders.vAttribute(builders.vIdentifier('class'), builders.vLiteral('container')),
], false),
[builders.vText('Hello')],
);
// <div class="container">Hello</div>vStartTag
Creates a start tag with attributes and/or directives.
const { builders } = utils;
const startTag = builders.vStartTag(
[
builders.vAttribute(builders.vIdentifier('id'), builders.vLiteral('app')),
],
false, // selfClosing
);vAttribute
Creates a static attribute.
const { builders } = utils;
// class="active"
const attr = builders.vAttribute(
builders.vIdentifier('class'),
builders.vLiteral('active'),
);
// disabled (boolean attribute, no value)
const disabled = builders.vAttribute(
builders.vIdentifier('disabled'),
null,
);vDirective
Creates a Vue directive. Note that VDirective has the AST type 'VAttribute' with directive: true.
const { builders } = utils;
// v-if="visible"
const vIf = builders.vDirective(
builders.vDirectiveKey(builders.vIdentifier('if')),
builders.vExpressionContainer(builders.identifier('visible')),
);
// :key="item.id"
const vBindKey = builders.vDirective(
builders.vDirectiveKey(
builders.vIdentifier('bind', ':'),
builders.vIdentifier('key'),
),
builders.vExpressionContainer(
builders.memberExpression(
builders.identifier('item'),
builders.identifier('id'),
),
),
);vDirectiveKey
Creates the key part of a directive: v-name:argument.modifier1.modifier2.
const { builders } = utils;
// v-on:click.prevent
const key = builders.vDirectiveKey(
builders.vIdentifier('on'),
builders.vIdentifier('click'),
[builders.vIdentifier('prevent')],
);vExpressionContainer
Creates an expression container ( in text, or a directive value).
const { builders } = utils;
// {{ message }}
const interpolation = builders.vExpressionContainer(
builders.identifier('message'),
);vText
Creates a text node.
const { builders } = utils;
const text = builders.vText('Hello, world!');vIdentifier
Creates an identifier node for attribute names, directive names, etc. The optional rawName parameter controls what gets printed — useful for directive shorthands.
const { builders } = utils;
builders.vIdentifier('class'); // prints: class
builders.vIdentifier('bind', ':'); // name is 'bind', prints as ':'
builders.vIdentifier('on', '@'); // name is 'on', prints as '@'vLiteral
Creates a string literal node for static attribute values.
const { builders } = utils;
builders.vLiteral('my-class'); // used with vAttribute for: class="my-class"htmlComment
Creates an HTML comment node. Can be attached to other nodes via their leadingComment parameter.
const { builders } = utils;
const comment = builders.htmlComment('TODO: refactor this');
const text = builders.vText('Hello', comment);
// <!-- TODO: refactor this -->HellosetParents
Traverses a node tree and sets the parent property on each descendant. Call this after building and inserting new nodes.
const { builders } = utils;
// after inserting new nodes into sfcAST:
builders.setParents(sfcAST);Script Builders
utils.builders also includes all script AST builders from ast-types. These are used to create JavaScript/TypeScript AST nodes.
const { builders } = utils;
// 'hello'
builders.literal('hello');
// myVariable
builders.identifier('myVariable');
// a + b
builders.binaryExpression('+', builders.identifier('a'), builders.identifier('b'));
// myFunction()
builders.callExpression(builders.identifier('myFunction'), []);See the ast-types documentation and AST Explorer (with @babel/parser) for the full list of available builders.
