babel-plugin-cssta-stylename
Advanced tools
Comparing version 0.1.1 to 0.1.2
176
index.js
@@ -1,7 +0,6 @@ | ||
const fs = require('fs') | ||
const css = require('css') | ||
const nodePath = require('path') | ||
const utils = require('./utils') | ||
const DEFAULT_CLASS_ATTRIBUTE = 'styleName' | ||
const CSSTA_TEMPLATE = 'styled' | ||
const NEW_TAG_PREFIX = 'Styled' | ||
@@ -22,3 +21,3 @@ function isTargetAttr (attribute, classAttribute) { | ||
let ast | ||
const processItems = [] | ||
const processedItems = [] | ||
@@ -36,2 +35,68 @@ function isRequire (node) { | ||
function getUniqueStyledTag (className) { | ||
const capitalized = className.charAt(0).toUpperCase() + className.slice(1) | ||
const uniqueName = program.scope.generateUidIdentifier(capitalized).name | ||
return NEW_TAG_PREFIX + uniqueName | ||
} | ||
function processItem (JSXOpeningElement, className) { | ||
const oldTag = JSXOpeningElement.node.name.name | ||
let item = processedItems.find(i => ( | ||
i.className === className && i.oldTag === oldTag | ||
)) | ||
let initNewTag = false | ||
if (!item) { | ||
initNewTag = true | ||
const newTag = getUniqueStyledTag(className) | ||
item = { | ||
className, | ||
oldTag, | ||
newTag | ||
} | ||
processedItems.push(item) | ||
} | ||
replaceWithNewTag(JSXOpeningElement, item.newTag) | ||
if (initNewTag) { | ||
let styles = utils.getStylesMatchingClassFromAst(ast, className) | ||
styles = utils.transformStylesForCssta(styles, className) | ||
const animate = utils.hasAnimation(styles) && utils.isAnimatable(item.oldTag) | ||
const oldTagExpr = getOldTagExpr(item.oldTag, animate) | ||
const newTagExpr = getNewTagExpr(item.newTag, oldTagExpr, styles) | ||
lastImport.insertAfter(newTagExpr) | ||
} | ||
} | ||
function replaceWithNewTag (JSXOpeningElement, newTag) { | ||
JSXOpeningElement.get('name').replaceWith(t.jSXIdentifier(newTag)) | ||
if (!JSXOpeningElement.node.selfClosing) { | ||
JSXOpeningElement.getSibling('closingElement').get('name').replaceWith(t.jSXIdentifier(newTag)) | ||
} | ||
} | ||
function getOldTagExpr (oldTag, animate) { | ||
if (animate) { | ||
// TODO: add import Animated from 'react-native' | ||
importAnimated = true | ||
return t.memberExpression(t.identifier('Animated'), t.identifier(oldTag)) | ||
} else { | ||
return t.identifier(oldTag) | ||
} | ||
} | ||
function getNewTagExpr (newTag, oldTagExpr, styles) { | ||
const styled = t.taggedTemplateExpression( | ||
t.callExpression(csstaTemplate, [oldTagExpr]), | ||
t.templateLiteral([ | ||
t.templateElement({ raw: '\n' + styles + '\n' }) | ||
], []) | ||
) | ||
const d = t.variableDeclarator(t.identifier(newTag), styled) | ||
return t.variableDeclaration('const', [d]) | ||
} | ||
function processClass (JSXOpeningElement, opts) { | ||
@@ -59,81 +124,3 @@ var className = null | ||
hasTransformedClassName = true | ||
const tag = JSXOpeningElement.node.name.name | ||
let item = processItems.find(i => i.className === className && i.tag === tag) | ||
if (!item) { | ||
const newTag = 'Styled' + program.scope.generateUidIdentifier(className[0].toUpperCase() + className.slice(1)).name | ||
item = { | ||
className, | ||
tag, | ||
newTag | ||
} | ||
processItems.push(item) | ||
} | ||
JSXOpeningElement.get('name').replaceWith(t.jSXIdentifier(item.newTag)) | ||
if (!JSXOpeningElement.node.selfClosing) { | ||
JSXOpeningElement.getSibling('closingElement').get('name').replaceWith(t.jSXIdentifier(item.newTag)) | ||
} | ||
const regex = new RegExp(`\\.${className}(?:[^\\w\\-]|$)`) | ||
const newAst = { | ||
type: 'stylesheet', | ||
stylesheet: { | ||
rules: [] | ||
} | ||
} | ||
newAst.stylesheet.rules = ast.stylesheet.rules.map(rule => { | ||
if (rule.type === 'media') { | ||
const rules = rule.rules.map(rule => { | ||
if (rule.type === 'rule') { | ||
const selectors = rule.selectors.map(selector => { | ||
if (regex.test(selector)) return selector | ||
}).filter(Boolean) | ||
if (selectors.length > 0) return { ...rule, selectors } | ||
} | ||
}).filter(Boolean) | ||
if (rules.length > 0) return { ...rule, rules } | ||
} else if (rule.type === 'keyframes') { | ||
return rule | ||
} else if (rule.type === 'rule') { | ||
const selectors = rule.selectors.map(selector => { | ||
if (regex.test(selector)) return selector | ||
}).filter(Boolean) | ||
if (selectors.length > 0) return { ...rule, selectors } | ||
} | ||
}).filter(Boolean) | ||
let declarations = css.stringify(newAst) | ||
// replace class with & | ||
const replaceClassPattern = `\\.${className}([^\\w\\-]|$)` | ||
declarations = declarations.replace(new RegExp(replaceClassPattern, 'g'), '&$1') | ||
// prepend @ to all attribute names | ||
declarations = declarations.replace(/\[/g, '[@') | ||
const hasAnimation = /(?:animation:|transition:)/.test(declarations) | ||
let newTagExpression | ||
if (hasAnimation && isAnimatable(item.tag)) { | ||
// TODO: add import Animated from 'react-native' | ||
importAnimated = true | ||
newTagExpression = t.memberExpression(t.identifier('Animated'), t.identifier(item.tag)) | ||
} else { | ||
newTagExpression = t.identifier(item.tag) | ||
} | ||
const styled = t.taggedTemplateExpression( | ||
t.callExpression(csstaTemplate, [newTagExpression]), | ||
t.templateLiteral([ | ||
t.templateElement({ raw: '\n' + declarations + '\n' }) | ||
], []) | ||
) | ||
const d = t.variableDeclarator(t.identifier(item.newTag), styled) | ||
const definition = t.variableDeclaration('var', [d]) | ||
lastImport.insertAfter(definition) | ||
processItem(JSXOpeningElement, className) | ||
} | ||
@@ -165,3 +152,3 @@ } | ||
stylesImport = path | ||
ast = parseAst(state.file.opts.filename, path.node.source.value) | ||
ast = utils.parseAst(state.file.opts.filename, path.node.source.value) | ||
path.insertBefore(t.importDeclaration([ | ||
@@ -181,22 +168,1 @@ t.importDefaultSpecifier(csstaTemplate) | ||
} | ||
function parseAst (modulePath, cssPath) { | ||
const pathHint = modulePath.charAt(0) | ||
const pathReference = pathHint === '/' | ||
? nodePath.dirname(modulePath) | ||
: nodePath.join(process.cwd(), nodePath.dirname(modulePath)) | ||
const cssPathHint = cssPath.charAt(0) | ||
const cssPathReference = (cssPathHint === '/' | ||
? cssPath | ||
: cssPathHint === '.' | ||
? nodePath.join(pathReference, cssPath) | ||
: require.resolve(cssPath) | ||
) | ||
const cssString = fs.readFileSync(cssPathReference, 'utf-8') | ||
return css.parse(cssString, { source: cssPathReference }) | ||
} | ||
function isAnimatable (tag) { | ||
return ['View', 'Text', 'Image'].includes(tag) | ||
} |
{ | ||
"name": "babel-plugin-cssta-stylename", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "Transform css imports into cssta template components", | ||
@@ -32,2 +32,3 @@ "keywords": [ | ||
"index.js", | ||
"utils.js", | ||
"README.md" | ||
@@ -34,0 +35,0 @@ ], |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
10952
5
205
1