From fba450ce7248ebee48bfc483792b796b05f2dd05 Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sun, 3 Dec 2023 14:41:41 +0100 Subject: [PATCH 1/2] pretty-print values --- index.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- test.js | 34 ++++++++++++++++++++++++++------ 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index b7673d7..5422742 100644 --- a/index.js +++ b/index.js @@ -246,7 +246,7 @@ function print_atrule(node, indent_level, css) { let buffer = indent(indent_level) + '@' + node.name // @font-face has no prelude - if (node.prelude) { + if (node.prelude !== null) { buffer += ' ' + substr(node.prelude, css) } @@ -267,7 +267,58 @@ function print_atrule(node, indent_level, css) { * @returns {string} A formatted Declaration */ function print_declaration(node, indent_level, css) { - return indent(indent_level) + node.property + ': ' + substr(node.value, css) + ';' + return indent(indent_level) + node.property.toLowerCase() + ': ' + print_value(node.value, indent_level, css).trim() + ';' +} + +function print_list(children, indent_level, css) { + let buffer = '' + + for (let node of children) { + if (node !== children.first && node.type !== 'Operator') { + buffer += ' ' + } + + if (node.type === 'Identifier') { + // TODO: new CSS keywork NaN should not be lowercased + buffer += node.name.toLowerCase() + } else if (node.type === 'Function') { + buffer += print_function(node, 0, css) + } else if (node.type === 'Dimension') { + buffer += node.value + node.unit.toLowerCase() + } else if (node.type === 'Value') { + // Values can be inside var() as fallback + // var(--prop, VALUE) + buffer += print_value(node, 0, css) + } else { + buffer += print_unknown(node, 0, css) + } + } + return buffer +} + +/** + * @param {import('css-tree').Value | import('css-tree').Raw} node + * @param {number} indent_level + * @param {string} css + */ +function print_value(node, indent_level, css) { + if (node.type === 'Raw') { + return print_unknown(node, 0, css) + } + + return print_list(node.children, 0, css) +} + +/** + * @param {import('css-tree').FunctionNode} node + * @param {number} indent_level + * @param {string} css + */ +function print_function(node, indent_level, css) { + let buffer = node.name.toLowerCase() + '(' + buffer += print_list(node.children, 0, css) + buffer += ')' + return buffer } /** @@ -316,8 +367,8 @@ export function format(css) { let ast = parse(css, { positions: true, parseAtrulePrelude: false, - parseCustomProperty: false, - parseValue: false, + parseCustomProperty: true, + parseValue: true, }) return print(ast, 0, css) } diff --git a/test.js b/test.js index 1ad3696..c8aa6b4 100644 --- a/test.js +++ b/test.js @@ -117,7 +117,7 @@ test('Declarations end with a semicolon (;)', () => { `) let expected = `@font-face { src: url('test'); - font-family: Test; + font-family: test; } css { @@ -277,7 +277,7 @@ test { a: 1} no-layer-2 { color: red; font-size: 1rem; - COLOR: green; + color: green; } @layer components, deep; @@ -443,7 +443,7 @@ a.b color: green } `) let expected = `a { - background: linear-gradient( red, 10% blue, 20% green,100% yellow); + background: linear-gradient(red, 10% blue, 20% green, 100% yellow); } a.b .c .d .e .f { @@ -499,32 +499,54 @@ test('formats selectors with Nth', () => { } }) -test.skip('formats simple value lists', () => { +test('formats simple value lists', () => { let actual = format(` a { transition-property: all,opacity; transition: all 100ms ease,opacity 10ms 20ms linear; + transition: all 100ms ease; + ANIMATION: COLOR 123MS EASE-OUT; color: rgb(0,0,0); + color: HSL(0%,10%,50%); + content: 'Test'; + background-image: url("EXAMPLE.COM"); } `) let expected = `a { transition-property: all, opacity; transition: all 100ms ease, opacity 10ms 20ms linear; + transition: all 100ms ease; + animation: color 123ms ease-out; color: rgb(0, 0, 0); + color: hsl(0%, 10%, 50%); + content: 'Test'; + background-image: url("EXAMPLE.COM"); }` assert.equal(actual, expected) }) -test.skip('formats nested value lists', () => { +test('formats nested value lists', () => { let actual = format(` a { background: red,linear-gradient(to bottom,red 10%,green 50%,blue 100%); - color: var(--test1,var(--test2,green)); } `) let expected = `a { background: red, linear-gradient(to bottom, red 10%, green 50%, blue 100%); +}` + assert.equal(actual, expected) +}) + +test('formats nested var()', () => { + let actual = format(` + a { + color: var(--test1,var(--test2,green)); + color: var(--test3,rgb(0,0,0)); + } + `) + let expected = `a { color: var(--test1, var(--test2, green)); + color: var(--test3, rgb(0, 0, 0)); }` assert.equal(actual, expected) }) From 8353e571e0eb4a45a0eec922dd06591061527013 Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sun, 3 Dec 2023 14:45:23 +0100 Subject: [PATCH 2/2] jsdoc --- index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/index.js b/index.js index 5422742..7879037 100644 --- a/index.js +++ b/index.js @@ -270,6 +270,11 @@ function print_declaration(node, indent_level, css) { return indent(indent_level) + node.property.toLowerCase() + ': ' + print_value(node.value, indent_level, css).trim() + ';' } +/** + * @param {import('css-tree').List} children + * @param {number} indent_level + * @param {string} css + */ function print_list(children, indent_level, css) { let buffer = ''