babel-plugin-transform-react-styled-components-qa
Advanced tools
Comparing version
@@ -8,47 +8,47 @@ import pluginTester from 'babel-plugin-tester' | ||
const common = { | ||
plugin, | ||
pluginName: 'babel-plugin-transform-react-styled-components-qa', | ||
tests: [ | ||
{ | ||
fixture: path.join(__dirname, '__fixtures__', 'code'), | ||
snapshot: true | ||
} | ||
] | ||
plugin, | ||
pluginName: 'babel-plugin-transform-react-styled-components-qa', | ||
tests: [ | ||
{ | ||
fixture: path.join(__dirname, '__fixtures__', 'code'), | ||
snapshot: true, | ||
}, | ||
], | ||
} | ||
pluginTester({ | ||
...common, | ||
title: 'without plugin options' | ||
...common, | ||
title: 'without plugin options', | ||
}) | ||
pluginTester({ | ||
...common, | ||
title: 'format kebab', | ||
pluginOptions: { | ||
format: 'kebab' | ||
} | ||
...common, | ||
title: 'format kebab', | ||
pluginOptions: { | ||
format: 'kebab', | ||
}, | ||
}) | ||
pluginTester({ | ||
...common, | ||
title: 'format camel', | ||
pluginOptions: { | ||
format: 'camel' | ||
} | ||
...common, | ||
title: 'format camel', | ||
pluginOptions: { | ||
format: 'camel', | ||
}, | ||
}) | ||
pluginTester({ | ||
...common, | ||
title: 'format snake', | ||
pluginOptions: { | ||
format: 'snake' | ||
} | ||
...common, | ||
title: 'format snake', | ||
pluginOptions: { | ||
format: 'snake', | ||
}, | ||
}) | ||
pluginTester({ | ||
...common, | ||
title: 'custom attrubute', | ||
pluginOptions: { | ||
attribute: 'data-wn-qa' | ||
} | ||
...common, | ||
title: 'custom attrubute', | ||
pluginOptions: { | ||
attribute: 'data-wn-qa', | ||
}, | ||
}) |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -6,4 +6,19 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
exports.default = _default; | ||
exports.default = function ({ types: t }) { | ||
var _options = require("./options"); | ||
var babelType = _interopRequireWildcard(require("@babel/types")); | ||
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; if (obj != null) { var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
/** | ||
* | ||
* @param {{ types: typeof babelType }} | ||
*/ | ||
function _default({ | ||
types: t | ||
}) { | ||
return { | ||
@@ -19,12 +34,14 @@ visitor: { | ||
const format = (0, _options.getComponentNameFormatter)(state.opts); | ||
const attributeName = (0, _options.getAttributeName)(state.opts); | ||
const attributeName = (0, _options.getAttributeName)(state.opts); // tag part of the template literal | ||
// tag part of the template literal | ||
const tag = init.tag; | ||
const tag = init.tag; // styled.div , styled.p , styled[<computed_value>], etc | ||
// styled.div , styled.p , styled[<computed_value>], etc | ||
if (t.isMemberExpression(tag)) { | ||
const { object, property } = tag; | ||
const { | ||
object, | ||
property | ||
} = tag; | ||
if (object.name === 'styled') { | ||
init.tag = t.callExpression(t.memberExpression(t.memberExpression(object, property, tag.computed), t.identifier('attrs')), [t.objectExpression([t.objectProperty(t.stringLiteral(attributeName), t.stringLiteral(format(path.node.id.name)))])]); | ||
init.tag = t.callExpression(t.memberExpression(t.memberExpression(object, property, tag.computed), t.identifier('attrs')), [t.arrowFunctionExpression([t.identifier('props')], t.blockStatement([t.returnStatement(t.objectExpression([t.objectProperty(t.stringLiteral(attributeName), t.logicalExpression('||', t.memberExpression(t.identifier('props'), t.stringLiteral(attributeName), true), t.stringLiteral(format(path.node.id.name))))]))]))]); | ||
} | ||
@@ -36,10 +53,9 @@ } | ||
if (t.isMemberExpression(tag.callee) && t.isIdentifier(tag.callee.property) && tag.callee.property.name === 'attrs' && t.isMemberExpression(tag.callee.object) && t.isIdentifier(tag.callee.object.object) && tag.callee.object.object.name === 'styled') { | ||
tag.arguments = [t.objectExpression(tag.arguments[0].properties.concat(t.objectProperty(t.stringLiteral(attributeName), t.stringLiteral(format(path.node.id.name)))))]; | ||
tag.arguments = [t.arrowFunctionExpression([t.identifier('props')], t.blockStatement([t.returnStatement(t.objectExpression(tag.arguments[0].properties.concat(t.objectProperty(t.stringLiteral(attributeName), t.logicalExpression('||', t.memberExpression(t.identifier('props'), t.stringLiteral(attributeName), true), t.stringLiteral(format(path.node.id.name)))))))]))]; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
var _options = require('./options'); | ||
} |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -6,30 +6,25 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
exports.getComponentNameFormatter = exports.getAttributeName = undefined; | ||
exports.getComponentNameFormatter = exports.getAttributeName = void 0; | ||
var _lodash = require('lodash.isstring'); | ||
var _lodash = _interopRequireDefault(require("lodash.isstring")); | ||
var _lodash2 = _interopRequireDefault(_lodash); | ||
var _lodash2 = _interopRequireDefault(require("lodash.camelcase")); | ||
var _lodash3 = require('lodash.camelcase'); | ||
var _lodash3 = _interopRequireDefault(require("lodash.kebabcase")); | ||
var _lodash4 = _interopRequireDefault(_lodash3); | ||
var _lodash4 = _interopRequireDefault(require("lodash.snakecase")); | ||
var _lodash5 = require('lodash.kebabcase'); | ||
var _lodash6 = _interopRequireDefault(_lodash5); | ||
var _lodash7 = require('lodash.snakecase'); | ||
var _lodash8 = _interopRequireDefault(_lodash7); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const getAttributeName = exports.getAttributeName = opts => (0, _lodash2.default)(opts.attribute) ? opts.attribute : 'data-qa'; | ||
const getAttributeName = opts => (0, _lodash.default)(opts.attribute) ? opts.attribute : 'data-qa'; | ||
exports.getAttributeName = getAttributeName; | ||
const formattersByName = { | ||
camel: _lodash4.default, | ||
kebab: _lodash6.default, | ||
snake: _lodash8.default | ||
camel: _lodash2.default, | ||
kebab: _lodash3.default, | ||
snake: _lodash4.default | ||
}; | ||
const getComponentNameFormatter = exports.getComponentNameFormatter = opts => (0, _lodash2.default)(opts.format) && opts.format in formattersByName ? formattersByName[opts.format] : _lodash6.default; | ||
const getComponentNameFormatter = opts => (0, _lodash.default)(opts.format) && opts.format in formattersByName ? formattersByName[opts.format] : _lodash3.default; | ||
exports.getComponentNameFormatter = getComponentNameFormatter; |
{ | ||
"name": "babel-plugin-transform-react-styled-components-qa", | ||
"version": "1.0.3", | ||
"version": "2.0.0", | ||
"description": "Add data-qa property to styled-components via .attrs using the component name", | ||
@@ -28,5 +28,7 @@ "main": "lib/index.js", | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-plugin-tester": "^5.0.0", | ||
"babel-preset-env": "^1.6.1", | ||
"@babel/cli": "7.6.4", | ||
"@babel/core": "7.6.4", | ||
"@babel/types": "^7.6.3", | ||
"babel-plugin-tester": "7.0.1", | ||
"babel-preset-env": "7.0.0-beta.3", | ||
"eslint": "^4.19.0", | ||
@@ -39,3 +41,3 @@ "eslint-config-standard": "^11.0.0", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"jest": "^22.4.2" | ||
"jest": "25.0.0" | ||
}, | ||
@@ -42,0 +44,0 @@ "dependencies": { |
@@ -8,54 +8,66 @@ # babel-plugin-transform-react-styled-components-qa | ||
### Standard HTML Tags | ||
In | ||
```js | ||
const Component = styled.p` | ||
color: red; | ||
` | ||
color: red; | ||
`; | ||
``` | ||
Out | ||
```js | ||
const Component = styled.p.attrs({ | ||
"data-qa": "Component" | ||
})` | ||
color: red; | ||
` | ||
const Component = styled.p.attrs(props => ({ | ||
"data-qa": props["data-qa"] || "Component" | ||
}))` | ||
color: red; | ||
`; | ||
``` | ||
### Computed Property is also supported | ||
In | ||
```js | ||
const tagName = 'h1' | ||
const tagName = "h1"; | ||
const Component = styled[tagName]` | ||
background: 'pink'; | ||
` | ||
background: "pink"; | ||
`; | ||
``` | ||
Out | ||
```js | ||
const tagName = 'h1' | ||
const Component = styled[tagName].attrs({ | ||
"data-qa": "Component" | ||
})` | ||
background: 'pink'; | ||
` | ||
const tagName = "h1"; | ||
const Component = styled[tagName].attrs(props => ({ | ||
"data-qa": props["data-qa"] || "Component" | ||
}))` | ||
background: "pink"; | ||
`; | ||
``` | ||
### `data-qa` is append after other attributes defined by users | ||
In | ||
```js | ||
const PasswordInput = styled.input.attrs({ | ||
type: 'password' | ||
type: "password" | ||
})` | ||
font-size: 14px; | ||
line-height: 2em; | ||
` | ||
font-size: 14px; | ||
line-height: 2em; | ||
`; | ||
``` | ||
Out | ||
```js | ||
const PasswordInput = styled.input.attrs({ | ||
type: 'password', | ||
"data-qa": "PasswordInput" | ||
})` | ||
font-size: 14px; | ||
line-height: 2em; | ||
` | ||
const PasswordInput = styled.input.attrs(props => ({ | ||
type: "password", | ||
"data-qa": props["data-qa"] || "PasswordInput" | ||
}))` | ||
font-size: 14px; | ||
line-height: 2em; | ||
`; | ||
``` | ||
@@ -69,2 +81,3 @@ | ||
#### .babelrc | ||
``` | ||
@@ -86,6 +99,10 @@ { | ||
## Options | ||
#### attribute : (string) | ||
The attribute name to be used instead of `data-qa`. | ||
#### format : (string) | ||
**Support values:** `kebab`, `camel`, `snake` \ | ||
**Default value:** `kebab` | ||
**Default value:** `kebab` |
149
src/index.js
import { getAttributeName, getComponentNameFormatter } from './options' | ||
export default function ({ types: t }) { | ||
return { | ||
visitor: { | ||
VariableDeclarator (path, state) { | ||
const init = path.node.init | ||
import * as babelType from '@babel/types' | ||
if (!t.isTaggedTemplateExpression(init)) { | ||
return | ||
} | ||
/** | ||
* | ||
* @param {{ types: typeof babelType }} | ||
*/ | ||
export default function({ types: t }) { | ||
return { | ||
visitor: { | ||
VariableDeclarator(path, state) { | ||
const init = path.node.init | ||
const format = getComponentNameFormatter(state.opts) | ||
const attributeName = getAttributeName(state.opts) | ||
if (!t.isTaggedTemplateExpression(init)) { | ||
return | ||
} | ||
// tag part of the template literal | ||
const tag = init.tag | ||
const format = getComponentNameFormatter(state.opts) | ||
const attributeName = getAttributeName(state.opts) | ||
// styled.div , styled.p , styled[<computed_value>], etc | ||
if (t.isMemberExpression(tag)) { | ||
const { object, property } = tag | ||
if (object.name === 'styled') { | ||
init.tag = t.callExpression( | ||
t.memberExpression( | ||
t.memberExpression(object, property, tag.computed), | ||
t.identifier('attrs') | ||
), | ||
[ | ||
t.objectExpression([ | ||
t.objectProperty( | ||
t.stringLiteral(attributeName), | ||
t.stringLiteral(format(path.node.id.name)) | ||
) | ||
]) | ||
] | ||
) | ||
} | ||
} | ||
// tag part of the template literal | ||
const tag = init.tag | ||
if (t.isCallExpression(tag)) { | ||
// styled.div.attrs({}) or styled[tag].attrs({}) | ||
if ( | ||
t.isMemberExpression(tag.callee) && | ||
t.isIdentifier(tag.callee.property) && | ||
tag.callee.property.name === 'attrs' && | ||
t.isMemberExpression(tag.callee.object) && | ||
t.isIdentifier(tag.callee.object.object) && | ||
tag.callee.object.object.name === 'styled' | ||
) { | ||
tag.arguments = [ | ||
t.objectExpression( | ||
tag.arguments[0].properties.concat( | ||
t.objectProperty( | ||
t.stringLiteral(attributeName), | ||
t.stringLiteral(format(path.node.id.name)) | ||
) | ||
) | ||
) | ||
] | ||
} | ||
} | ||
} | ||
} | ||
} | ||
// styled.div , styled.p , styled[<computed_value>], etc | ||
if (t.isMemberExpression(tag)) { | ||
const { object, property } = tag | ||
if (object.name === 'styled') { | ||
init.tag = t.callExpression( | ||
t.memberExpression( | ||
t.memberExpression(object, property, tag.computed), | ||
t.identifier('attrs'), | ||
), | ||
[ | ||
t.arrowFunctionExpression( | ||
[t.identifier('props')], | ||
t.blockStatement([ | ||
t.returnStatement( | ||
t.objectExpression([ | ||
t.objectProperty( | ||
t.stringLiteral(attributeName), | ||
t.logicalExpression( | ||
'||', | ||
t.memberExpression( | ||
t.identifier('props'), | ||
t.stringLiteral(attributeName), | ||
true, | ||
), | ||
t.stringLiteral(format(path.node.id.name)), | ||
), | ||
), | ||
]), | ||
), | ||
]), | ||
), | ||
], | ||
) | ||
} | ||
} | ||
if (t.isCallExpression(tag)) { | ||
// styled.div.attrs({}) or styled[tag].attrs({}) | ||
if ( | ||
t.isMemberExpression(tag.callee) && | ||
t.isIdentifier(tag.callee.property) && | ||
tag.callee.property.name === 'attrs' && | ||
t.isMemberExpression(tag.callee.object) && | ||
t.isIdentifier(tag.callee.object.object) && | ||
tag.callee.object.object.name === 'styled' | ||
) { | ||
tag.arguments = [ | ||
t.arrowFunctionExpression( | ||
[t.identifier('props')], | ||
t.blockStatement([ | ||
t.returnStatement( | ||
t.objectExpression( | ||
tag.arguments[0].properties.concat( | ||
t.objectProperty( | ||
t.stringLiteral(attributeName), | ||
t.logicalExpression( | ||
'||', | ||
t.memberExpression( | ||
t.identifier('props'), | ||
t.stringLiteral(attributeName), | ||
true, | ||
), | ||
t.stringLiteral(format(path.node.id.name)), | ||
), | ||
), | ||
), | ||
), | ||
), | ||
]), | ||
), | ||
] | ||
} | ||
} | ||
}, | ||
}, | ||
} | ||
} |
@@ -7,13 +7,13 @@ import isString from 'lodash.isstring' | ||
export const getAttributeName = opts => | ||
isString(opts.attribute) ? opts.attribute : 'data-qa' | ||
isString(opts.attribute) ? opts.attribute : 'data-qa' | ||
const formattersByName = { | ||
camel: camelCase, | ||
kebab: kebabCase, | ||
snake: snakeCase | ||
camel: camelCase, | ||
kebab: kebabCase, | ||
snake: snakeCase, | ||
} | ||
export const getComponentNameFormatter = opts => | ||
isString(opts.format) && opts.format in formattersByName | ||
? formattersByName[opts.format] | ||
: kebabCase | ||
isString(opts.format) && opts.format in formattersByName | ||
? formattersByName[opts.format] | ||
: kebabCase |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
22833
13.74%222
27.59%106
20.45%13
18.18%