From b13ebd36f14fdd9c2f8ed6282996ac2084eacb88 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 13 Dec 2016 16:13:38 +0000 Subject: [PATCH 1/5] fix: added escape hatch when testing attribute that do not have a name property (#11) --- src/index.js | 2 +- src/resolveStringLiteral.js | 2 +- .../actual.js | 7 +++++++ .../bar.css | 1 + .../expected.js | 7 +++++++ .../options.json | 10 ++++++++++ 6 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json diff --git a/src/index.js b/src/index.js index 0d49ae1..8be9ce7 100644 --- a/src/index.js +++ b/src/index.js @@ -88,7 +88,7 @@ export default ({ JSXElement (path: Object): void { const styleNameAttribute = path.node.openingElement.attributes .find((attribute) => { - return attribute.name.name === 'styleName'; + return typeof attribute.name !== 'undefined' && attribute.name.name === 'styleName'; }); if (!styleNameAttribute) { diff --git a/src/resolveStringLiteral.js b/src/resolveStringLiteral.js index 580be36..47800a3 100644 --- a/src/resolveStringLiteral.js +++ b/src/resolveStringLiteral.js @@ -11,7 +11,7 @@ import type { export default (path: Object, styleModuleImportMap: StyleModuleImportMapType, styleNameAttribute: JSXAttribute): void => { const classNameAttribute = path.node.openingElement.attributes .find((attribute) => { - return attribute.name.name === 'className'; + return typeof attribute.name !== 'undefined' && attribute.name.name === 'className'; }); const resolvedStyleName = getClassName(styleNameAttribute.value.value, styleModuleImportMap); diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js new file mode 100644 index 0000000..4e99b7b --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js @@ -0,0 +1,7 @@ +import './bar.css'; + +const props = { + foo: 'bar' +}; + +
; diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css new file mode 100644 index 0000000..5512dae --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css @@ -0,0 +1 @@ +.a {} diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js new file mode 100644 index 0000000..5d797f4 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js @@ -0,0 +1,7 @@ +import './bar.css'; + +const props = { + foo: 'bar' +}; + +
; diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json new file mode 100644 index 0000000..6f54db7 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]" + } + ] + ] +} From 6be1c6aaf6fc41c592a2778eb59cfc2c6dba9545 Mon Sep 17 00:00:00 2001 From: Pierre Criulanscy Date: Wed, 14 Dec 2016 17:13:20 +0000 Subject: [PATCH 2/5] fix: object expression generated on dynamic resolution now use quote to escape properties' name (#14) --- package.json | 2 +- src/createObjectExpression.js | 2 +- src/index.js | 3 ++- .../actual.js | 9 ++++++--- .../bar.css | 2 +- .../expected.js | 16 +++++++++++----- .../foo.css | 1 + 7 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css diff --git a/package.json b/package.json index bf7b051..5c274a5 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "build": "rm -fr ./dist && NODE_ENV=production babel ./src --out-dir ./dist --source-maps && npm run build-helper", "lint": "eslint ./src", "precommit": "npm run test", - "test": "NODE_ENV=development npm run lint && npm run build && mocha --compilers js:babel-register && flow" + "test": "NODE_ENV=development npm run lint && npm run build && NODE_ENV=test mocha --compilers js:babel-register && flow" }, "version": "1.0.0" } diff --git a/src/createObjectExpression.js b/src/createObjectExpression.js index 765340d..802a033 100644 --- a/src/createObjectExpression.js +++ b/src/createObjectExpression.js @@ -25,7 +25,7 @@ const createObjectExpression = (t: BabelTypes, object: Object): ObjectExpression properties.push( t.objectProperty( - t.identifier(name), + t.identifier('\'' + name + '\''), newValue ) ); diff --git a/src/index.js b/src/index.js index 8be9ce7..2a6f1b6 100644 --- a/src/index.js +++ b/src/index.js @@ -71,7 +71,8 @@ export default ({ let styleImportName: string; if (path.node.specifiers.length === 0) { - styleImportName = 'random-' + Math.random(); + // eslint-disable-next-line no-process-env + styleImportName = process.env.NODE_ENV === 'test' ? 'random-test' : 'random-' + Math.random(); } else if (path.node.specifiers.length === 1) { styleImportName = path.node.specifiers[0].local.name; } else { diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js index 21c0bae..f284d12 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js @@ -1,5 +1,8 @@ -import foo from './bar.css'; +import bar from './bar.css'; +import './foo.css'; -const styleNameValue = 'a'; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; -
; +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css index 5512dae..794d0af 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css @@ -1 +1 @@ -.a {} +.a-b {} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js index dcc41ef..41d4f3e 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js @@ -1,11 +1,17 @@ import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; -import foo from './bar.css'; +import bar from './bar.css'; +import './foo.css'; const _styleModuleImportMap = { - foo: { - a: 'bar__a' + 'bar': { + 'a-b': 'bar__a-b' + }, + 'random-test': { + 'a-b': 'foo__a-b' } }; -const styleNameValue = 'a'; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; -
; +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css new file mode 100644 index 0000000..794d0af --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css @@ -0,0 +1 @@ +.a-b {} From f14a4f47f269eea138543aa76f4e6852006d4062 Mon Sep 17 00:00:00 2001 From: Pierre Criulanscy Date: Fri, 16 Dec 2016 08:41:16 +0000 Subject: [PATCH 3/5] fix: getClassName now works as expected when multiple file use runtime resolution --- src/index.js | 50 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/index.js b/src/index.js index 2a6f1b6..b8bcbed 100644 --- a/src/index.js +++ b/src/index.js @@ -16,24 +16,22 @@ export default ({ }: { types: BabelTypes }) => { - let styleModuleImportMap; - let importedHelperIndentifier; - let styleModuleImportMapIdentifier; + const filenameMap = {}; - const setupFileForRuntimeResolution = (path) => { + const setupFileForRuntimeResolution = (path, filename) => { const programPath = path.findParent((parentPath) => { return parentPath.isProgram(); }); - importedHelperIndentifier = programPath.scope.generateUidIdentifier('getClassName'); - styleModuleImportMapIdentifier = programPath.scope.generateUidIdentifier('styleModuleImportMap'); + filenameMap[filename].importedHelperIndentifier = programPath.scope.generateUidIdentifier('getClassName'); + filenameMap[filename].styleModuleImportMapIdentifier = programPath.scope.generateUidIdentifier('styleModuleImportMap'); programPath.unshiftContainer( 'body', t.importDeclaration( [ t.importDefaultSpecifier( - importedHelperIndentifier + filenameMap[filename].importedHelperIndentifier ) ], t.stringLiteral('babel-plugin-react-css-modules/dist/browser/getClassName') @@ -49,12 +47,14 @@ export default ({ 'const', [ t.variableDeclarator( - styleModuleImportMapIdentifier, - createObjectExpression(t, styleModuleImportMap) + filenameMap[filename].styleModuleImportMapIdentifier, + createObjectExpression(t, filenameMap[filename].styleModuleImportMap) ) ] ) ); + // eslint-disable-next-line + // console.log('setting up', filename, util.inspect(filenameMap,{depth: 5})) }; return { @@ -65,6 +65,7 @@ export default ({ return; } + const filename = stats.file.opts.filename; const targetFileDirectoryPath = dirname(stats.file.opts.filename); const targetResourcePath = resolve(targetFileDirectoryPath, path.node.source.value); @@ -82,11 +83,12 @@ export default ({ throw new Error('Unexpected use case.'); } - styleModuleImportMap[styleImportName] = requireCssModule(targetResourcePath, { + filenameMap[filename].styleModuleImportMap[styleImportName] = requireCssModule(targetResourcePath, { generateScopedName: stats.opts.generateScopedName }); }, - JSXElement (path: Object): void { + JSXElement (path: Object, stats: Object): void { + const filename = stats.file.opts.filename; const styleNameAttribute = path.node.openingElement.attributes .find((attribute) => { return typeof attribute.name !== 'undefined' && attribute.name.name === 'styleName'; @@ -97,21 +99,33 @@ export default ({ } if (t.isStringLiteral(styleNameAttribute.value)) { - resolveStringLiteral(path, styleModuleImportMap, styleNameAttribute); + resolveStringLiteral( + path, + filenameMap[filename].styleModuleImportMap, + styleNameAttribute + ); return; } if (t.isJSXExpressionContainer(styleNameAttribute.value)) { - if (!importedHelperIndentifier) { - setupFileForRuntimeResolution(path); + if (!filenameMap[filename].importedHelperIndentifier) { + setupFileForRuntimeResolution(path, filename); } - - replaceJsxExpressionContainer(t, styleNameAttribute, importedHelperIndentifier, styleModuleImportMapIdentifier); + replaceJsxExpressionContainer( + t, + styleNameAttribute, + filenameMap[filename].importedHelperIndentifier, + filenameMap[filename].styleModuleImportMapIdentifier + ); } }, - Program () { - styleModuleImportMap = {}; + Program (path: Object, stats: Object): void { + const filename = stats.file.opts.filename; + + filenameMap[filename] = { + styleModuleImportMap: {} + }; } } }; From 12eecfa2fecebdfee1b9a7e3b5214db7d511d363 Mon Sep 17 00:00:00 2001 From: Pierre Criulanscy Date: Fri, 16 Dec 2016 08:44:21 +0000 Subject: [PATCH 4/5] fix: getClassName now works as expected when multiple file use runtime resolution --- .../actual.js | 8 ++++++++ .../bar.css | 1 + .../expected.js | 17 +++++++++++++++++ .../foo.css | 1 + .../options.json | 10 ++++++++++ 5 files changed, 37 insertions(+) create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js new file mode 100644 index 0000000..f284d12 --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js @@ -0,0 +1,8 @@ +import bar from './bar.css'; +import './foo.css'; + +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; + +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css new file mode 100644 index 0000000..794d0af --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css @@ -0,0 +1 @@ +.a-b {} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js new file mode 100644 index 0000000..41d4f3e --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js @@ -0,0 +1,17 @@ +import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; +import bar from './bar.css'; +import './foo.css'; + +const _styleModuleImportMap = { + 'bar': { + 'a-b': 'bar__a-b' + }, + 'random-test': { + 'a-b': 'foo__a-b' + } +}; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; + +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css new file mode 100644 index 0000000..794d0af --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css @@ -0,0 +1 @@ +.a-b {} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json new file mode 100644 index 0000000..6f54db7 --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]" + } + ] + ] +} From cadc6cbb4abc98f818130c150b79ce4d2f50f812 Mon Sep 17 00:00:00 2001 From: Pierre Criulanscy Date: Mon, 19 Dec 2016 10:31:07 +0000 Subject: [PATCH 5/5] fix: className attribute is now correctly generated when using runtime resolution (#18) --- src/index.js | 1 + src/replaceJsxExpressionContainer.js | 33 ++++++++++++++----- .../actual.js | 2 +- .../bar.css | 0 .../expected.js | 4 +-- .../foo.css | 0 .../options.json | 0 .../expected.js | 4 +-- 8 files changed, 31 insertions(+), 13 deletions(-) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/actual.js (72%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/bar.css (100%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/expected.js (68%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/foo.css (100%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/options.json (100%) diff --git a/src/index.js b/src/index.js index b8bcbed..f4963e0 100644 --- a/src/index.js +++ b/src/index.js @@ -114,6 +114,7 @@ export default ({ } replaceJsxExpressionContainer( t, + path, styleNameAttribute, filenameMap[filename].importedHelperIndentifier, filenameMap[filename].styleModuleImportMapIdentifier diff --git a/src/replaceJsxExpressionContainer.js b/src/replaceJsxExpressionContainer.js index 1eb0b45..3faf4e6 100644 --- a/src/replaceJsxExpressionContainer.js +++ b/src/replaceJsxExpressionContainer.js @@ -5,16 +5,33 @@ import BabelTypes, { Identifier } from 'babel-types'; -export default (t: BabelTypes, styleNameAttribute: JSXAttribute, importedHelperIndentifier: Identifier, styleModuleImportMapIdentifier: Identifier): void => { +export default (t: BabelTypes, path: Object, styleNameAttribute: JSXAttribute, importedHelperIndentifier: Identifier, styleModuleImportMapIdentifier: Identifier): void => { const expressionContainerValue = styleNameAttribute.value; + const classNameAttribute = path.node.openingElement.attributes + .find((attribute) => { + return typeof attribute.name !== 'undefined' && attribute.name.name === 'className'; + }); + const classNameAttributeValue = classNameAttribute ? classNameAttribute.value.value : ''; + + if (classNameAttribute) { + path.node.openingElement.attributes.splice(path.node.openingElement.attributes.indexOf(classNameAttribute), 1); + } + + const styleNameExpression = t.callExpression( + importedHelperIndentifier, + [ + expressionContainerValue.expression, + styleModuleImportMapIdentifier + ] + ); styleNameAttribute.value = t.jSXExpressionContainer( - t.callExpression( - importedHelperIndentifier, - [ - expressionContainerValue.expression, - styleModuleImportMapIdentifier - ] - ) + classNameAttribute ? + t.binaryExpression( + '+', + t.stringLiteral(classNameAttributeValue + ' '), + styleNameExpression + ) : styleNameExpression ); + styleNameAttribute.name.name = 'className'; }; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js similarity index 72% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js index f284d12..cb49c7a 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js @@ -5,4 +5,4 @@ const styleNameBar = 'bar.a-b'; const styleNameFoo = 'a-b';
; -
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/bar.css similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/bar.css diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js similarity index 68% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js index 41d4f3e..e9f288f 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js @@ -13,5 +13,5 @@ const _styleModuleImportMap = { const styleNameBar = 'bar.a-b'; const styleNameFoo = 'a-b'; -
; -
; +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/foo.css similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/foo.css diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js index 41d4f3e..336e388 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js @@ -13,5 +13,5 @@ const _styleModuleImportMap = { const styleNameBar = 'bar.a-b'; const styleNameFoo = 'a-b'; -
; -
; +
; +
;