Codemod to help you migrate away from partials
MIT License
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
.
Yarn
yarn add ember-partial-codemod
Npm
npm install ember-partial-codemod
./node_modules/.bin/ember-partial-codemod
Given a folder structure like so
base
└── addon
├── components
│ ├── parent.js
└── templates
└── components
├── parent.hbs
└── partials
├── child.hbs
└── nested-child.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")}}
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")}}
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.hbs
Notice 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.
import Component from '@ember/component';
import { tryInvoke } from '@ember/utils';
export default Component.extend({
actions: {
action2() {
tryInvoke(this, 'action2');
},
}
});
import Component from '@ember/component';
import { tryInvoke } from '@ember/utils';
export default Component.extend({
actions: {
action2() {
tryInvoke(this, 'action2');
},
}
});
This codemod parses the template file using the glimmerVM AST.
The codemod is broken into two major phases.
templates
starting with your current working directory, cwd
, gathering all the information on each template
.partial
usage inside the current template
it's crawling, it will intelligently infer the physical disk path of the partial
from the module name
and build a dependency tree/graph, where the current template
is the parent of the partial
.templates
. One common case is when it infers correctly that a partial
's physical disk path lives outside of the cwd
. The codemod will skip this partial
and continue.Phase 1
to transform the partials
accordingly using ember-template-recast
internally.get-attributes
is correct for all use cases.actions
in a better way.Any contribution is appreciated!