diff --git a/src/classnames.macro.js b/src/classnames.macro.js index 45ef694..1423548 100644 --- a/src/classnames.macro.js +++ b/src/classnames.macro.js @@ -91,6 +91,10 @@ export default createMacro(({ babel, references: { default: paths } }) => { return unpackLogicalExpression(node) } + if (babel.types.isNullLiteral(node)) { + return babel.types.stringLiteral("") + } + if ( babel.types.isMemberExpression(node) || babel.types.isIdentifier(node) @@ -98,7 +102,11 @@ export default createMacro(({ babel, references: { default: paths } }) => { return babel.types.binaryExpression( "+", babel.types.stringLiteral(" "), - node + babel.types.logicalExpression( + "||", + node, + babel.types.stringLiteral(""), + ) ) } @@ -141,6 +149,11 @@ export default createMacro(({ babel, references: { default: paths } }) => { function getValue(input) { const { elements } = unpackArray(input) + const filteredElements = elements.filter( + (element) => !babel.types.isNullLiteral(element) + && !(babel.types.isIdentifier(element) && element.name === 'undefined' ) + && !(babel.types.isBooleanLiteral(element) && element.value === false) + ); const values = groupBy((node) => { if (babel.types.isStringLiteral(node)) { @@ -148,7 +161,7 @@ export default createMacro(({ babel, references: { default: paths } }) => { } return "dynamic" - }, elements) + }, filteredElements) return concatNodes([ concatStringNodes(values.static), diff --git a/tests/classnames.macro.test.js b/tests/classnames.macro.test.js index 0c328f1..0fcc728 100644 --- a/tests/classnames.macro.test.js +++ b/tests/classnames.macro.test.js @@ -11,6 +11,22 @@ function run(code) { }).code.trim() } +test("variable", (t) => { + const input = stripIndent` + import classNames from '../src/classnames.macro'; + const something = false; + const CLASS_NAMES = classNames(something, "py-2"); + ` + + const expected = stripIndent` + const something = false; + const CLASS_NAMES = "py-2" + (" " + (something || "")); + ` + + const output = run(input) + t.is(output, expected) +}) + test("strings", (t) => { const input = stripIndent` import classNames from '../src/classnames.macro'; @@ -25,6 +41,48 @@ test("strings", (t) => { t.is(output, expected) }) +test("null", (t) => { + const input = stripIndent` + import classNames from '../src/classnames.macro'; + const CLASS_NAMES = classNames(null); + ` + + const expected = stripIndent` + const CLASS_NAMES = ""; + ` + + const output = run(input) + t.is(output, expected) +}) + +test("undefined", (t) => { + const input = stripIndent` + import classNames from '../src/classnames.macro'; + const CLASS_NAMES = classNames(undefined); + ` + + const expected = stripIndent` + const CLASS_NAMES = ""; + ` + + const output = run(input) + t.is(output, expected) +}) + +test("false", (t) => { + const input = stripIndent` + import classNames from '../src/classnames.macro'; + const CLASS_NAMES = classNames(false); + ` + + const expected = stripIndent` + const CLASS_NAMES = ""; + ` + + const output = run(input) + t.is(output, expected) +}) + test("arrays", (t) => { const input = stripIndent` import classNames from '../src/classnames.macro'; @@ -82,7 +140,7 @@ test("variables", (t) => { ` const expected = stripIndent` - const CLASS_NAMES = "px-1" + (" " + props.className); + const CLASS_NAMES = "px-1" + (" " + (props.className || "")); ` const output = run(input) @@ -95,12 +153,15 @@ test("mixed", (t) => { const CLASS_NAMES = classNames( props.foo && ["foo", "fighters"], "bar", - ["qux", { "baz": props.baz }, props.className] + undefined, + ["qux", { "baz": props.baz }, props.className], + null, + false ); ` const expected = stripIndent` - const CLASS_NAMES = "bar qux" + ((props.foo ? " foo fighters" : "") + ((props.baz ? " baz" : "") + (" " + props.className))); + const CLASS_NAMES = "bar qux" + ((props.foo ? " foo fighters" : "") + ((props.baz ? " baz" : "") + (" " + (props.className || "")))); ` const output = run(input)