You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
4.6 KiB

// @flow
import nodePath from 'path'
type LabelFormatOptions = {
name: string,
path: string
}
const invalidClassNameCharacters = /[!"#$%&'()*+,./:;<=>?@[\]^`|}~{]/g
const sanitizeLabelPart = (labelPart: string) =>
labelPart.trim().replace(invalidClassNameCharacters, '-')
function getLabel(
identifierName?: string,
labelFormat?: string | (LabelFormatOptions => string),
filename: string
) {
if (!identifierName) return null
const sanitizedName = sanitizeLabelPart(identifierName)
if (!labelFormat) {
return sanitizedName
}
if (typeof labelFormat === 'function') {
return labelFormat({
name: sanitizedName,
path: filename
})
}
const parsedPath = nodePath.parse(filename)
let localDirname = nodePath.basename(parsedPath.dir)
let localFilename = parsedPath.name
if (localFilename === 'index') {
localFilename = localDirname
}
return labelFormat
.replace(/\[local\]/gi, sanitizedName)
.replace(/\[filename\]/gi, sanitizeLabelPart(localFilename))
.replace(/\[dirname\]/gi, sanitizeLabelPart(localDirname))
}
export function getLabelFromPath(path: *, state: *, t: *) {
return getLabel(
getIdentifierName(path, t),
state.opts.labelFormat,
state.file.opts.filename
)
}
const getObjPropertyLikeName = (path, t) => {
if (
(!t.isObjectProperty(path) && !t.isObjectMethod(path)) ||
path.node.computed
) {
return null
}
if (t.isIdentifier(path.node.key)) {
return path.node.key.name
}
if (t.isStringLiteral(path.node.key)) {
return path.node.key.value.replace(/\s+/g, '-')
}
return null
}
function getDeclaratorName(path, t) {
// $FlowFixMe
const parent = path.findParent(
p =>
p.isVariableDeclarator() ||
p.isAssignmentExpression() ||
p.isFunctionDeclaration() ||
p.isFunctionExpression() ||
p.isArrowFunctionExpression() ||
p.isObjectProperty() ||
p.isObjectMethod()
)
if (!parent) {
return ''
}
// we probably have a css call assigned to a variable
// so we'll just return the variable name
if (parent.isVariableDeclarator()) {
if (t.isIdentifier(parent.node.id)) {
return parent.node.id.name
}
return ''
}
if (parent.isAssignmentExpression()) {
let { left } = parent.node
if (t.isIdentifier(left)) {
return left.name
}
if (t.isMemberExpression(left)) {
let memberExpression = left
let name = ''
while (true) {
if (!t.isIdentifier(memberExpression.property)) {
return ''
}
name = `${memberExpression.property.name}${name ? `-${name}` : ''}`
if (t.isIdentifier(memberExpression.object)) {
return `${memberExpression.object.name}-${name}`
}
if (!t.isMemberExpression(memberExpression.object)) {
return ''
}
memberExpression = memberExpression.object
}
}
return ''
}
// we probably have an inline css prop usage
if (parent.isFunctionDeclaration()) {
return parent.node.id.name || ''
}
if (parent.isFunctionExpression()) {
if (parent.node.id) {
return parent.node.id.name || ''
}
return getDeclaratorName(parent, t)
}
if (parent.isArrowFunctionExpression()) {
return getDeclaratorName(parent, t)
}
// we could also have an object property
const objPropertyLikeName = getObjPropertyLikeName(parent, t)
if (objPropertyLikeName) {
return objPropertyLikeName
}
let variableDeclarator = parent.findParent(p => p.isVariableDeclarator())
if (!variableDeclarator || !variableDeclarator.get('id').isIdentifier()) {
return ''
}
return variableDeclarator.node.id.name
}
function getIdentifierName(path: *, t: *) {
let objPropertyLikeName = getObjPropertyLikeName(path.parentPath, t)
if (objPropertyLikeName) {
return objPropertyLikeName
}
// $FlowFixMe
let classOrClassPropertyParent = path.findParent(
p => t.isClassProperty(p) || t.isClass(p)
)
if (classOrClassPropertyParent) {
if (
t.isClassProperty(classOrClassPropertyParent) &&
classOrClassPropertyParent.node.computed === false &&
t.isIdentifier(classOrClassPropertyParent.node.key)
) {
return classOrClassPropertyParent.node.key.name
}
if (
t.isClass(classOrClassPropertyParent) &&
classOrClassPropertyParent.node.id
) {
return t.isIdentifier(classOrClassPropertyParent.node.id)
? classOrClassPropertyParent.node.id.name
: ''
}
}
let declaratorName = getDeclaratorName(path, t)
// if the name starts with _ it was probably generated by babel so we should ignore it
if (declaratorName.charAt(0) === '_') {
return ''
}
return declaratorName
}