diff --git a/.changeset/large-snakes-ring.md b/.changeset/large-snakes-ring.md new file mode 100644 index 0000000000..8e90494d76 --- /dev/null +++ b/.changeset/large-snakes-ring.md @@ -0,0 +1,6 @@ +--- +'babel-plugin-emotion': minor +'@emotion/babel-preset-css-prop': minor +--- + +Allow `labelFormat` option to be a function. diff --git a/packages/babel-plugin-emotion/__tests__/__snapshots__/css-requires-options.js.snap b/packages/babel-plugin-emotion/__tests__/__snapshots__/css-requires-options.js.snap index b7571b5794..41812a6f07 100644 --- a/packages/babel-plugin-emotion/__tests__/__snapshots__/css-requires-options.js.snap +++ b/packages/babel-plugin-emotion/__tests__/__snapshots__/css-requires-options.js.snap @@ -66,6 +66,30 @@ _keyframes(process.env.NODE_ENV === \\"production\\" ? { });" `; +exports[`babel css inline label format function 1`] = ` +" + import { css } from 'emotion' + let cls = css({color:'hotpink'}) + + + ↓ ↓ ↓ ↓ ↓ ↓ + +function _EMOTION_STRINGIFIED_CSS_ERROR__() { return \\"You have tried to stringify object returned from \`css\` function. It isn't supposed to be used directly (e.g. as value of the \`className\` prop), but rather handed to emotion so it can handle it (e.g. as value of \`css\` prop).\\"; } + +import { css } from 'emotion'; +let cls = +/*#__PURE__*/ +css(process.env.NODE_ENV === \\"production\\" ? { + name: \\"1rm02zb-CLS_CSS-REQUIRES-OPTIONS\\", + styles: \\"color:hotpink;;label:CLS_CSS-REQUIRES-OPTIONS;\\" +} : { + name: \\"1rm02zb-CLS_CSS-REQUIRES-OPTIONS\\", + styles: \\"color:hotpink;;label:CLS_CSS-REQUIRES-OPTIONS;\\", + map: \\"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNzcy1yZXF1aXJlcy1vcHRpb25zLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVjIiwiZmlsZSI6ImNzcy1yZXF1aXJlcy1vcHRpb25zLmpzIiwic291cmNlc0NvbnRlbnQiOlsiXG4gICAgaW1wb3J0IHsgY3NzIH0gZnJvbSAnZW1vdGlvbidcbiAgICBsZXQgY2xzID0gY3NzKHtjb2xvcjonaG90cGluayd9KVxuICAgICJdfQ== */\\", + toString: _EMOTION_STRINGIFIED_CSS_ERROR__ +});" +`; + exports[`babel css inline label format with dirname, filename, and local 1`] = ` " import { css } from 'emotion' diff --git a/packages/babel-plugin-emotion/__tests__/css-requires-options.js b/packages/babel-plugin-emotion/__tests__/css-requires-options.js index f25bf38eb9..c64b0ebc5a 100644 --- a/packages/babel-plugin-emotion/__tests__/css-requires-options.js +++ b/packages/babel-plugin-emotion/__tests__/css-requires-options.js @@ -2,6 +2,8 @@ import babelTester from 'babel-tester' import plugin from 'babel-plugin-emotion' +const last = arr => arr[arr.length - 1] + const cases = { 'label format with only local': { code: ` @@ -70,6 +72,26 @@ const cases = { babelFileName: __filename }, + 'label format function': { + code: ` + import { css } from 'emotion' + let cls = css({color:'hotpink'}) + `, + plugins: [ + [ + plugin, + { + labelFormat: ({ name, path }) => + `${name.toUpperCase()}_${last( + path.replace(/\..+$/, '').split('/') + ).toUpperCase()}`, + autoLabel: true + } + ] + ], + babelFileName: __filename + }, + // this test has better readability for label alone than other ones which include source maps 'label on code transpiled by TS': { code: ` diff --git a/packages/babel-plugin-emotion/src/utils/label.js b/packages/babel-plugin-emotion/src/utils/label.js index 3f3aba35be..04833600d7 100644 --- a/packages/babel-plugin-emotion/src/utils/label.js +++ b/packages/babel-plugin-emotion/src/utils/label.js @@ -1,6 +1,11 @@ // @flow import nodePath from 'path' +type LabelFormatOptions = { + name: string, + path: string +} + const invalidClassNameCharacters = /[!"#$%&'()*+,./:;<=>?@[\]^`|}~{]/g const sanitizeLabelPart = (labelPart: string) => @@ -9,11 +14,23 @@ const sanitizeLabelPart = (labelPart: string) => function getLabel( identifierName?: string, autoLabel: boolean, - labelFormat?: string, + labelFormat?: string | (LabelFormatOptions => string), filename: string ) { if (!identifierName || !autoLabel) return null - if (!labelFormat) return sanitizeLabelPart(identifierName) + + 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) @@ -24,7 +41,7 @@ function getLabel( } return labelFormat - .replace(/\[local\]/gi, sanitizeLabelPart(identifierName)) + .replace(/\[local\]/gi, sanitizedName) .replace(/\[filename\]/gi, sanitizeLabelPart(localFilename)) .replace(/\[dirname\]/gi, sanitizeLabelPart(localDirname)) }