diff --git a/changelog_unreleased/scss/10005.md b/changelog_unreleased/scss/10005.md new file mode 100644 index 000000000..17b441df8 --- /dev/null +++ b/changelog_unreleased/scss/10005.md @@ -0,0 +1,17 @@ +#### Fix maps with keys that are lists or maps (#10005 by @fisker) + + +```scss +// Input +$map: ( + ('my list'): 'hello world', +); + +// Prettier stable +TypeError: Cannot read property 'length' of undefined + +// Prettier main +$map: ( + ("my list"): "hello world", +); +``` diff --git a/src/language-css/printer-postcss.js b/src/language-css/printer-postcss.js index b21297d1c..10a2f0971 100644 --- a/src/language-css/printer-postcss.js +++ b/src/language-css/printer-postcss.js @@ -57,6 +57,7 @@ const { hasParensAroundNode, hasEmptyRawBefore, isKeyValuePairNode, + isKeyInValuePairNode, isDetachedRulesetCallNode, isTemplatePlaceholderNode, isTemplatePropNode, @@ -856,8 +857,9 @@ function genericPrint(path, options, print) { const lastItem = node.groups[node.groups.length - 1]; const isLastItemComment = lastItem && lastItem.type === "value-comment"; + const isKey = isKeyInValuePairNode(node, parentNode); - return group( + const printed = group( [ node.open ? path.call(print, "open") : "", indent([ @@ -873,6 +875,7 @@ function genericPrint(path, options, print) { isKeyValuePairNode(node) && node.type === "value-comma_group" && node.groups && + node.groups[0].type !== "value-paren_group" && node.groups[2] && node.groups[2].type === "value-paren_group" ) { @@ -898,9 +901,11 @@ function genericPrint(path, options, print) { node.close ? path.call(print, "close") : "", ], { - shouldBreak: isSCSSMapItem, + shouldBreak: isSCSSMapItem && !isKey, } ); + + return isKey ? dedent(printed) : printed; } case "value-func": { return [ @@ -934,7 +939,9 @@ function genericPrint(path, options, print) { return [ node.value, // Don't add spaces on escaped colon `:`, e.g: grid-template-rows: [row-1-00\:00] auto; - (prevNode && prevNode.value[prevNode.value.length - 1] === "\\") || + (prevNode && + typeof prevNode.value === "string" && + prevNode.value[prevNode.value.length - 1] === "\\") || // Don't add spaces on `:` in `url` function (i.e. `url(fbglyph: cross-outline, fig-white)`) insideValueFunctionNode(path, "url") ? "" diff --git a/src/language-css/utils.js b/src/language-css/utils.js index 20e1bff38..1843cffde 100644 --- a/src/language-css/utils.js +++ b/src/language-css/utils.js @@ -401,7 +401,22 @@ function isWordNode(node) { } function isColonNode(node) { - return node.type === "value-colon"; + return node && node.type === "value-colon"; +} + +function isKeyInValuePairNode(node, parentNode) { + if (!isKeyValuePairNode(parentNode)) { + return false; + } + + const { groups } = parentNode; + const index = groups.indexOf(node); + + if (index === -1) { + return false; + } + + return isColonNode(groups[index + 1]); } function isMediaAndSupportsKeywords(node) { @@ -503,6 +518,7 @@ module.exports = { isPostcssSimpleVarNode, isKeyValuePairNode, isKeyValuePairInParenGroupNode, + isKeyInValuePairNode, isSCSSMapItemNode, isInlineValueCommentNode, isHashNode, diff --git a/tests/scss/map/__snapshots__/jsfmt.spec.js.snap b/tests/scss/map/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..729e8d5a7 --- /dev/null +++ b/tests/scss/map/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,261 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`key-values.scss - {"trailingComma":"none"} format 1`] = ` +====================================options===================================== +parsers: ["scss"] +printWidth: 80 +trailingComma: "none" + | printWidth +=====================================input====================================== +$map: ( + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + ('key': 'value',), + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + ('list'), + ('list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list'): + ('list'), + ('list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list'): + ('key': 'value',), + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + 1, +); + +=====================================output===================================== +$map: ( + ( + "key": "value", + "key": "value", + "key": "value", + "key": "value", + "key": "value" + ): + ( + "key": "value" + ), + ( + "key": "value", + "key": "value", + "key": "value", + "key": "value", + "key": "value" + ): + ( + "list" + ), + ( + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list" + ): + ( + "list" + ), + ( + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list" + ): + ( + "key": "value" + ), + ( + "key": "value", + "key": "value", + "key": "value", + "key": "value", + "key": "value" + ): + 1 +); + +================================================================================ +`; + +exports[`key-values.scss format 1`] = ` +====================================options===================================== +parsers: ["scss"] +printWidth: 80 + | printWidth +=====================================input====================================== +$map: ( + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + ('key': 'value',), + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + ('list'), + ('list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list'): + ('list'), + ('list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list'): + ('key': 'value',), + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + 1, +); + +=====================================output===================================== +$map: ( + ( + "key": "value", + "key": "value", + "key": "value", + "key": "value", + "key": "value", + ): + ( + "key": "value", + ), + ( + "key": "value", + "key": "value", + "key": "value", + "key": "value", + "key": "value", + ): + ( + "list", + ), + ( + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + ): + ( + "list", + ), + ( + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + "list", + ): + ( + "key": "value", + ), + ( + "key": "value", + "key": "value", + "key": "value", + "key": "value", + "key": "value", + ): + 1, +); + +================================================================================ +`; + +exports[`keys.scss - {"trailingComma":"none"} format 1`] = ` +====================================options===================================== +parsers: ["scss"] +printWidth: 80 +trailingComma: "none" + | printWidth +=====================================input====================================== +$map: ( + 'string': 'hello world', + ('list'): 'hello world', + ('key': 'value'): 'hello world', + ('list', 'long long long long long long long long long long long long long list'): 'hello world', + ('key': 'value','long long long long long long long long long long long long long map': 'value',): 'hello world', +); + +// #10000 +$map: ( + ('my list'): 'hello world', +); + +=====================================output===================================== +$map: ( + "string": "hello world", + ("list"): "hello world", + ("key": "value"): "hello world", + ( + "list", + "long long long long long long long long long long long long long list" + ): + "hello world", + ( + "key": "value", + "long long long long long long long long long long long long long map": + "value" + ): + "hello world" +); + +// #10000 +$map: ( + ("my list"): "hello world" +); + +================================================================================ +`; + +exports[`keys.scss format 1`] = ` +====================================options===================================== +parsers: ["scss"] +printWidth: 80 + | printWidth +=====================================input====================================== +$map: ( + 'string': 'hello world', + ('list'): 'hello world', + ('key': 'value'): 'hello world', + ('list', 'long long long long long long long long long long long long long list'): 'hello world', + ('key': 'value','long long long long long long long long long long long long long map': 'value',): 'hello world', +); + +// #10000 +$map: ( + ('my list'): 'hello world', +); + +=====================================output===================================== +$map: ( + "string": "hello world", + ("list"): "hello world", + ("key": "value"): "hello world", + ( + "list", + "long long long long long long long long long long long long long list", + ): + "hello world", + ( + "key": "value", + "long long long long long long long long long long long long long map": + "value", + ): + "hello world", +); + +// #10000 +$map: ( + ("my list"): "hello world", +); + +================================================================================ +`; diff --git a/tests/scss/map/jsfmt.spec.js b/tests/scss/map/jsfmt.spec.js new file mode 100644 index 000000000..f2558a4a9 --- /dev/null +++ b/tests/scss/map/jsfmt.spec.js @@ -0,0 +1,2 @@ +run_spec(__dirname, ["scss"], { trailingComma: "none" }); +run_spec(__dirname, ["scss"]); diff --git a/tests/scss/map/key-values.scss b/tests/scss/map/key-values.scss new file mode 100644 index 000000000..2041334cd --- /dev/null +++ b/tests/scss/map/key-values.scss @@ -0,0 +1,12 @@ +$map: ( + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + ('key': 'value',), + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + ('list'), + ('list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list'): + ('list'), + ('list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list', 'list'): + ('key': 'value',), + ('key': 'value', 'key': 'value','key': 'value','key': 'value','key': 'value',): + 1, +); diff --git a/tests/scss/map/keys.scss b/tests/scss/map/keys.scss new file mode 100644 index 000000000..fe008a5d4 --- /dev/null +++ b/tests/scss/map/keys.scss @@ -0,0 +1,12 @@ +$map: ( + 'string': 'hello world', + ('list'): 'hello world', + ('key': 'value'): 'hello world', + ('list', 'long long long long long long long long long long long long long list'): 'hello world', + ('key': 'value','long long long long long long long long long long long long long map': 'value',): 'hello world', +); + +// #10000 +$map: ( + ('my list'): 'hello world', +);