Skip to content

Commit f0a1584

Browse files
suchitadoshi1987tylerturdenpants
authored andcommitted
Add support to skip prefixing @ for user provided attributes (#226)
* Add support to skip prefixing @ for user provided attributes * add readme
1 parent f8ca1fa commit f0a1584

3 files changed

Lines changed: 90 additions & 20 deletions

File tree

README.md

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Ember Observer Score](https://emberobserver.com/badges/ember-angle-brackets-codemod.svg)](https://emberobserver.com/addons/ember-angle-brackets-codemod)
44
[![Build Status](https://travis-ci.org/ember-codemods/ember-angle-brackets-codemod.svg?branch=master)](https://travis-ci.org/ember-codemods/ember-angle-brackets-codemod)
55
[![Coverage Status](https://coveralls.io/repos/github/ember-codemods/ember-angle-brackets-codemod/badge.svg?branch=master)](https://coveralls.io/github/ember-codemods/ember-angle-brackets-codemod?branch=master)
6-
[![npm version](http://img.shields.io/npm/v/ember-angle-brackets-codemod.svg?style=flat)](https://npmjs.org/package/ember-angle-brackets-codemod "View this project on npm")
6+
[![npm version](http://img.shields.io/npm/v/ember-angle-brackets-codemod.svg?style=flat)](https://npmjs.org/package/ember-angle-brackets-codemod 'View this project on npm')
77
[![dependencies Status](https://david-dm.org/ember-codemods/ember-angle-brackets-codemod/status.svg)](https://david-dm.org/ember-codemods/ember-angle-brackets-codemod)
88
[![devDependencies Status](https://david-dm.org/ember-codemods/ember-angle-brackets-codemod/dev-status.svg)](https://david-dm.org/ember-codemods/ember-angle-brackets-codemod?type=dev)
99

@@ -25,12 +25,14 @@ running this tool.
2525

2626
1. Start your ember development server
2727
2. Run Codemod, pointing it at the address of the development server
28+
2829
```sh
2930
$ cd my-ember-app-or-addon
3031
$ npx ember-angle-brackets-codemod http://localhost:4200 ./path/of/files/ or ./some**/*glob.hbs
3132
```
3233

3334
## From
35+
3436
```hbs
3537
{{site-header user=this.user class=(if this.user.isAdmin "admin")}}
3638
@@ -44,6 +46,7 @@ $ npx ember-angle-brackets-codemod http://localhost:4200 ./path/of/files/ or ./s
4446
```
4547

4648
## To
49+
4750
```hbs
4851
<SiteHeader @user={{this.user}} class={{if this.user.isAdmin "admin"}} />
4952
<SuperSelect @selected={{this.user.country}} as |s|>
@@ -73,6 +76,7 @@ To help the codemod disambiguate components and helpers, you can define a list o
7376
]
7477
}
7578
```
79+
7680
The codemod will then ignore the above list of helpers and prevent them from being transformed into the new angle-brackets syntax.
7781

7882
You can also disable the conversion of the built-in components `{{link-to}}`, `{{input}}` and `{{textarea}}` as follows:
@@ -94,15 +98,19 @@ $ npx ember-angle-brackets-codemod angle-brackets app/templates --config ./confi
9498
```
9599

96100
To get a list of helpers in your app you can do this in the Developer Console in your browser inside of your app:
101+
97102
```js
98103
var componentLikeHelpers = Object.keys(require.entries)
99-
.filter(name=>(name.includes('/helpers/')|| name.includes('/helper')))
100-
.filter(name=>!name.includes('/-')).map(name=>{
101-
let path = name.split('/helpers/');
102-
return path.pop();
103-
}).filter(name=>!name.includes('/')).uniq();
104-
105-
copy(JSON.stringify(componentLikeHelpers))
104+
.filter(name => name.includes('/helpers/') || name.includes('/helper'))
105+
.filter(name => !name.includes('/-'))
106+
.map(name => {
107+
let path = name.split('/helpers/');
108+
return path.pop();
109+
})
110+
.filter(name => !name.includes('/'))
111+
.uniq();
112+
113+
copy(JSON.stringify(componentLikeHelpers));
106114
```
107115

108116
### Skipping some files
@@ -119,13 +127,42 @@ If there are files that don't convert well, you can skip them by specifying an o
119127
}
120128
```
121129

130+
### Skipping some attributes
131+
132+
If there are cases where some attributes should not be prefixed with `@`, you can skip them by specifying an optional `skipAttributesThatMatchRegex` configuration setting.
133+
For example, with the configuration below, all attributes that matches either `/data-/gim` or `/aria-/gim` will not be prefixed with `@`:
134+
135+
**config/anglebrackets-codemod-config.json**
136+
137+
```js
138+
{
139+
"helpers": [],
140+
"skipBuiltInComponents": true,
141+
"skipAttributesThatMatchRegex": [/data-/gim, /aria-/gim]
142+
}
143+
```
144+
145+
Input:
146+
147+
```js
148+
{{some-component data-test-foo=true aria-label="bar" foo=true}}
149+
```
150+
151+
Output:
152+
153+
```js
154+
<SomeComponent data-test-foo={{true}} aria-label="bar" @foo={{true}} />
155+
```
156+
122157
## Debugging Workflow
158+
123159
Oftentimes, you want to debug the codemod or the transform to identify issues with the code or to understand
124160
how the transforms are working, or to troubleshoot why some tests are failing.
125161

126162
Hence we recommend a debugging work-flow like below to quickly find out what is causing the issue.
127163

128164
### 1. Place `debugger` statements
165+
129166
Add `debugger` statements, in appropriate places in the code. For example:
130167

131168
```js
@@ -138,6 +175,7 @@ const params = a.value.params.map(p => {
138175
```
139176
140177
### 2. Inspect the process with node debug
178+
141179
Here we are going to start the tests selectively in node debug mode. Since the
142180
codemod is bootstrapped using [codemod-cli](https://github.com/rwjblue/codemod-cli) which is using [jest](https://jestjs.io/) in turn
143181
to run the tests, jest is having an option `-t <name-of-spec>` to run a particular
@@ -162,23 +200,23 @@ Once you run the above command, your tests will start running in debug mode and
162200
triggered appropriately when that particular block of code gets executed. You can run the debugger inside
163201
Chrome browser dev-tools. More details on [here](https://developers.google.com/web/tools/chrome-devtools/javascript/)
164202
165-
166203
## AST Explorer playground
167204
168205
1. Go to the [AST Explorer](https://astexplorer.net/#/gist/b128d5545d7ccc52400b922f3b5010b4/642c6a8d3cc021257110bcf6b1714d1065891aec)
169206
2. Paste your curly brace syntax code in the top left corner window (Source)
170207
3. You will get the converted angle bracket syntax in the bottom right corner window (Transform Output)
171208
172-
173209
## RFC
210+
174211
- [Angle Bracket Invocation](https://github.com/emberjs/rfcs/blob/master/text/0311-angle-bracket-invocation.md)
175212
- [Angle Bracket Invocations For Built-in Components](https://github.com/emberjs/rfcs/blob/32a25b31d67d67bc7581dd0bead559063b06f076/text/0459-angle-bracket-built-in-components.md)
176213
177-
178214
## Known issues
215+
179216
- No formatting preserved
180217
181218
## References:
182-
- https://github.com/glimmerjs/glimmer-vm/issues/685
183-
- https://github.com/q2ebanking/ember-template-rewrite
184-
- https://github.com/ember-template-lint/ember-template-recast
219+
220+
- https://github.com/glimmerjs/glimmer-vm/issues/685
221+
- https://github.com/q2ebanking/ember-template-rewrite
222+
- https://github.com/ember-template-lint/ember-template-recast

transforms/angle-brackets/transform.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ function isAttribute(key) {
1717
return HTML_ATTRIBUTES.includes(key) || isDataAttribute(key);
1818
}
1919

20+
/**
21+
* Returns true if the key matches any of the user provided regex from the
22+
* `skipAttributesThatMatchRegex` array.
23+
* @param {*} key
24+
* @param {*} config
25+
*/
26+
function shouldSkipAttribute(key, config) {
27+
if (config.skipAttributesThatMatchRegex && config.skipAttributesThatMatchRegex.length) {
28+
return config.skipAttributesThatMatchRegex.some(rx => rx.test(key));
29+
}
30+
return false;
31+
}
32+
2033
function isDataAttribute(key) {
2134
return key.startsWith('data-');
2235
}
@@ -104,12 +117,15 @@ function shouldSkipFile(fileInfo, config) {
104117
return false;
105118
}
106119

107-
function transformAttrs(tagName, attrs) {
120+
function transformAttrs(tagName, attrs, config) {
108121
return attrs.map(a => {
109122
let _key = a.key;
110123
let _valueType = a.value.type;
111124
let _value;
112-
if (!isAttribute(_key) || !isBuiltInComponent(tagName)) {
125+
if (
126+
(!isAttribute(_key) || !isBuiltInComponent(tagName)) &&
127+
!shouldSkipAttribute(_key, config)
128+
) {
113129
_key = `@${_key}`;
114130
}
115131

@@ -257,8 +273,8 @@ function hasValuelessDataParams(params) {
257273
return getDataAttributesFromParams(params).length > 0;
258274
}
259275

260-
function transformNodeAttributes(tagName, node) {
261-
let attributes = transformAttrs(tagName, node.hash.pairs);
276+
function transformNodeAttributes(tagName, node, config) {
277+
let attributes = transformAttrs(tagName, node.hash.pairs, config);
262278
return node.params.concat(attributes);
263279
}
264280

@@ -348,7 +364,7 @@ function transformNode(node, fileInfo, config) {
348364
attributes = transformLinkToAttrs(node.params);
349365
}
350366

351-
let namesParams = transformAttrs(tagName, node.hash.pairs);
367+
let namesParams = transformAttrs(tagName, node.hash.pairs, config);
352368
attributes = attributes.concat(namesParams);
353369
} else {
354370
if (nodeHasPositionalParameters(node)) {
@@ -361,7 +377,7 @@ function transformNode(node, fileInfo, config) {
361377
if (inAttr) {
362378
return;
363379
}
364-
attributes = transformNodeAttributes(tagName, node);
380+
attributes = transformNodeAttributes(tagName, node, config);
365381
}
366382
return b.element(
367383
{ name: newTagName, selfClosing },

transforms/angle-brackets/transform.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,22 @@ test('custom-options', () => {
951951
`);
952952
});
953953

954+
test('skip-attributes', () => {
955+
let input = `
956+
{{some-component data-test-foo=true aria-label="bar" foo=true}}
957+
`;
958+
959+
let options = {
960+
skipAttributesThatMatchRegex: [/data-/gim, /aria-/gim],
961+
};
962+
963+
expect(runTest('ignore-attributes.hbs', input, options)).toMatchInlineSnapshot(`
964+
"
965+
<SomeComponent data-test-foo={{true}} aria-label=\\"bar\\" @foo={{true}} />
966+
"
967+
`);
968+
});
969+
954970
test('regex-options', () => {
955971
let input = `
956972
{{some-component foo=true}}

0 commit comments

Comments
 (0)