ember-partial-codemod v1.2.0
ember-partial-codemod
THIS IS AN EXPERIMENTAL WORK IN PROGRESS. USE AT YOUR OWN RISK. ISSUES ARE WELCOME
Given an Ember app or addon, this codemod will transform all your partials into components.
Table of Contents
Installation
Yarn
yarn add ember-partial-codemodNpm
npm install ember-partial-codemodUsage
./node_modules/.bin/ember-partial-codemodExample
Given a folder structure like so
base
└── addon
├── components
│ ├── parent.js
└── templates
└── components
├── parent.hbs
└── partials
├── child.hbs
└── nested-child.hbsbase/addon/templates/components/parent.hbs
Before
{{some-component attr=attr}}
{{partial "base@partials/child"}}
{{partial "base$partials/child"}}
{{partial "base::partials/child"}}After
{{some-component attr=attr}}
{{base@partials/child bar=bar baz=baz action2=(action "action2")}}
{{base$partials/child bar=bar baz=baz action2=(action "action2")}}
{{base::partials/child bar=bar baz=baz action2=(action "action2")}}base/addon/templates/components/partials/child.hbs
Before
{{bar}}
{{partial "base@partials/nested-child"}}
{{partial "base$partials/nested-child"}}
{{partial "base::partials/nested-child"}}After
{{bar}}
{{base@partials/nested-child baz=baz action2=(action "action2")}}
{{base$partials/nested-child baz=baz action2=(action "action2")}}
{{base::partials/nested-child baz=baz action2=(action "action2")}}base/addon/templates/components/partials/nested-child.hbs
Before
{{baz}}
{{fizz
action1=(action "action2")
}}After Nothing changed!
{{baz}}
{{fizz
action1=(action "action2")
}}Note that in our example, we have actions!
The codemod will handle this by creating a new .js file for the component and intelligently infer its location to write to. This way the actions are properly passed to the new component.
So for our example, the codemod will generate the following structure.
base
└── addon
├── components
│ ├── parent.js
│ └── partials <- new folder
│ └── child.js <- new file!
│ └── nested-child.js <- new file!
└── templates
└── components
├── parent.hbs
└── partials
├── child.hbs
└── nested-child.hbsNotice how we have two new files now, base/addon/components/partials/child.js and base/addon/components/partials/nested-child.js.
They are both generated because we lost the parent.js scope, so actions will not be discovered anymore. Therefore, we faciliate the ability for actions to be passed down correctly by generating the associated .js files, so the actions are discoverable again.
base/addon/templates/components/partials/child.hbs
import Component from '@ember/component';
import { tryInvoke } from '@ember/utils';
export default Component.extend({
actions: {
action2() {
tryInvoke(this, 'action2');
},
}
});base/addon/templates/components/partials/nested-child.hbs
import Component from '@ember/component';
import { tryInvoke } from '@ember/utils';
export default Component.extend({
actions: {
action2() {
tryInvoke(this, 'action2');
},
}
});Explanation
This codemod parses the template file using the glimmerVM AST.
The codemod is broken into two major phases.
Phase 1
- By default, the codemod will crawl through all the
templatesstarting with your current working directory,cwd, gathering all the information on eachtemplate. - If it finds a
partialusage inside the currenttemplateit's crawling, it will intelligently infer the physical disk path of thepartialfrom themodule nameand build a dependency tree/graph, where the currenttemplateis the parent of thepartial. - NOTE There are cases where the codemod fails to crawl certain
templates. One common case is when it infers correctly that apartial's physical disk path lives outside of thecwd. The codemod will skip thispartialand continue.
Phase 2
- The codemod will use the information from
Phase 1to transform thepartialsaccordingly usingember-template-recastinternally.
Todo
- Make sure
get-attributesis correct for all use cases. - Optimize Phase 1.
- Handle
actionsin a better way. - Write tests.
Contribution
Any contribution is appreciated!