What is ember-template-recast?
ember-template-recast is a tool for programmatically modifying Handlebars templates in Ember.js projects. It provides a way to parse, traverse, and transform templates, making it useful for tasks such as codemods, linting, and automated refactoring.
What are ember-template-recast's main functionalities?
Parsing Templates
This feature allows you to parse a Handlebars template string into an Abstract Syntax Tree (AST). The AST can then be traversed and manipulated.
const recast = require('ember-template-recast');
const template = '<div>{{foo}}</div>';
const ast = recast.parse(template);
console.log(ast);
Transforming Templates
This feature allows you to transform a Handlebars template by providing a transformation function. The example changes all instances of `{{foo}}` to `{{bar}}`.
const recast = require('ember-template-recast');
const template = '<div>{{foo}}</div>';
const transform = function(env) {
let { builders: b } = env.syntax;
return {
MustacheStatement(node) {
if (node.path.original === 'foo') {
return b.mustache(b.path('bar'));
}
}
};
};
const output = recast.transform(template, transform);
console.log(output);
Printing Templates
This feature allows you to convert an AST back into a Handlebars template string. This is useful after making transformations to the AST.
const recast = require('ember-template-recast');
const template = '<div>{{foo}}</div>';
const ast = recast.parse(template);
const output = recast.print(ast);
console.log(output);
Other packages similar to ember-template-recast
handlebars
Handlebars is a popular templating engine that allows you to build semantic templates. While it provides the ability to compile and render templates, it does not offer the same level of AST manipulation and transformation capabilities as ember-template-recast.
glimmer-engine
Glimmer is a high-performance rendering engine used in Ember.js. While it provides low-level rendering capabilities and some template compilation features, it does not offer the same high-level API for template transformation and manipulation as ember-template-recast.
ember-template-recast
With ember-template-recast, transform a template's AST and reprint it. Its
formatting will be preserved.
For instance, it is possible to change a component's property while preserving
its formatting:
const recast = require('ember-template-recast');
const template = `
<Sidebar
foo="bar"
item={{hmmm}}
/>
`;
let ast = recast.parse(template);
ast.body[1].attributes[1].value.path = builders.path('this.hmmm');
let ouput = recast.print(ast);
output === `
<Sidebar
foo="bar"
item={{this.hmmm}}
/>
`;
Command Line Usage
ember-template-recast comes with a binary for running a transform across multiple
files, similar to jscodeshift.
npx ember-template-recast directory/of/templates -t transform.js
Example transform plugin:
module.exports = (env) => {
let { builders: b } = env.syntax;
return {
MustacheStatement() {
return b.mustache(b.path('wat-wat'));
},
};
};
APIs
parse
Used to parse a given template string into an AST. Generally speaking, this AST
can be mutated and passed into print
(docs below).
const templateRecast = require('ember-template-recast');
const template = `
{{foo-bar
baz="stuff"
}}
`;
let ast = templateRecast.parse(template);
print
Used to generate a new template string representing the provided AST.
const templateRecast = require('ember-template-recast');
const template = `
{{foo-bar
baz="stuff"
}}
`;
let ast = templateRecast.parse(template);
ast.body[0].hash[0].key = 'derp';
templateRecast.print(ast);
{{foo-bar
derp="stuff"
}}
transform
Used to easily traverse (and possibly mutate) a given template. Returns the
resulting AST and the printed template.
The plugin argument has roughly the following interface:
export interface Syntax {
parse: typeof preprocess;
builders: typeof builders;
print: typeof print;
traverse: typeof traverse;
Walker: typeof Walker;
}
export interface TransformPluginEnv {
syntax: Syntax;
contents: string;
filePath?: string;
parseOptions: {
srcName?: string;
};
}
export interface TransformPluginBuilder {
(env: TransformPluginEnv): NodeVisitor;
}
The list of known builders on the env.syntax.builders
are found
here,
although there are a few small extensions related to formatting
in custom-nodes.ts
Example:
const { transform } = require('ember-template-recast');
const template = `
{{foo-bar
baz="stuff"
}}
`;
let { code } = transform({
template,
plugin(env) {
let { builders: b } = env.syntax;
return {
MustacheStatement() {
return b.mustache(b.path('wat-wat'));
},
};
}
});
console.log(code);
SemVer Policy
Due to usage of TypeScript and bundling external APIs this project has somewhat
unique SemVer commitments. A high level summary is:
Major Version
The following are scenarios that would cause a major version (aka breaking change) release:
- Dropping support for Node versions (e.g. dropping Node 12 support)
- Non-additive changes to the underlying AST (which we bundle from
@glimmer/syntax
) - Breaking changes to the
@glimmer/syntax
builder APIs
Minor Version
The following are scenarios that would cause a minor version (aka new feature) release:
- Changes to TypeScript version used internally by
ember-template-recast
- Changes to make the types used by
ember-template-recast
to be more accurate
(e.g. narrowing / broadening of previously published types). - Adding new features
Patch Version
The following are scenarios that would cause a patch release:
- Bug fixes to internal re-writing logic
- Bug fix releases of
@glimmer/syntax
License
This project is distributed under the MIT license, see LICENSE for details.