Helpers and builders
vue-metamorph provides a set of helper functions and builder functions through the utils object that it passes to the transform() or find() function of your plugin.
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. This function works with both script ASTs 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 there's no match.
findAll
Finds every node in an AST that matches 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 the 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 if there's no match.
createNamedImport
Adds a named import to a script AST. If an import declaration for the module already exists, this function adds the new specifier to that declaration. It doesn't create duplicate imports.
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. This function 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. This function follows the same merging and deduplication logic as createNamedImport.
const { astHelpers } = utils;
// import * as _ from 'lodash-es';
astHelpers.createNamespaceImport(scriptAST, 'lodash-es', '_');findVueComponentOptions
Finds every Options API object expression in a script. This function detects defineComponent(), Vue.extend(), Vue.component(), Vue.mixin(), and new Vue(). When isSfc is true, it also detects 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 that create new template AST nodes. Use them when your codemod needs to insert new elements, attributes, or directives into the <template>.
TIP
After you build new nodes and insert them into the AST, call builders.setParents() on the root of the new subtree. Builder functions leave parent references unset, and setParents() fills them in.
const newElement = builders.vElement('div', builders.vStartTag([], false), []);
builders.setParents(sfcAST); // fix parent referencesvElement
Creates a new element node. This function creates an end tag 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, directives, or both.
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 a VDirective node 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, which is either 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 an attribute name, a directive name, a directive argument, or a directive modifier. The optional rawName parameter controls what vue-metamorph prints, which is 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 a static attribute value.
const { builders } = utils;
builders.vLiteral('my-class'); // used with vAttribute for: class="my-class"htmlComment
Creates an HTML comment node. To attach the comment to another node, set the leadingComment property of that node.
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 every descendant. Call this function after you build new nodes and insert them.
const { builders } = utils;
// after inserting new nodes into sfcAST:
builders.setParents(sfcAST);Script builders
The utils.builders object also includes all the script AST builders from ast-types. Use them to create JavaScript and 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'), []);For the full list of available builders, see the ast-types documentation. To see the node shapes that these builders need to produce, use the Playground.
