From 75bacc56f412ff00977aeff286783727e823212f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20S=C3=A1nchez-Mar=C3=ADn?= Date: Thu, 10 Mar 2016 22:16:38 +0100 Subject: [PATCH 1/4] allow importing JS files too --- src/index.js | 2 +- test/fixtures/include-paths/style-js.scss | 5 ++ .../include-paths/variables/variables.js | 4 + test/fixtures/lists/style-js.scss | 5 ++ test/fixtures/lists/variables.js | 3 + test/fixtures/maps/style-js.scss | 5 ++ test/fixtures/maps/variables.js | 5 ++ test/fixtures/strings/style-js.scss | 5 ++ test/fixtures/strings/variables.js | 4 + test/index.js | 87 ++++++++++--------- 10 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 test/fixtures/include-paths/style-js.scss create mode 100644 test/fixtures/include-paths/variables/variables.js create mode 100644 test/fixtures/lists/style-js.scss create mode 100644 test/fixtures/lists/variables.js create mode 100644 test/fixtures/maps/style-js.scss create mode 100644 test/fixtures/maps/variables.js create mode 100644 test/fixtures/strings/style-js.scss create mode 100644 test/fixtures/strings/variables.js diff --git a/src/index.js b/src/index.js index 21d9173..2bc51c2 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ import isThere from 'is-there'; import sass from 'node-sass'; export default function(url, prev) { - if (!/\.json$/.test(url)) { + if (!/\.(json|js)$/.test(url)) { return sass.NULL; } diff --git a/test/fixtures/include-paths/style-js.scss b/test/fixtures/include-paths/style-js.scss new file mode 100644 index 0000000..50dbc94 --- /dev/null +++ b/test/fixtures/include-paths/style-js.scss @@ -0,0 +1,5 @@ +@import 'variables.js'; + +body { + color: $color-red; +} diff --git a/test/fixtures/include-paths/variables/variables.js b/test/fixtures/include-paths/variables/variables.js new file mode 100644 index 0000000..77876c4 --- /dev/null +++ b/test/fixtures/include-paths/variables/variables.js @@ -0,0 +1,4 @@ +module.exports = { + "color-red": "#c33", + "color-blue": "#33c" +} diff --git a/test/fixtures/lists/style-js.scss b/test/fixtures/lists/style-js.scss new file mode 100644 index 0000000..9e752f3 --- /dev/null +++ b/test/fixtures/lists/style-js.scss @@ -0,0 +1,5 @@ +@import 'variables.js'; + +body { + color: nth($colors, 1); +} diff --git a/test/fixtures/lists/variables.js b/test/fixtures/lists/variables.js new file mode 100644 index 0000000..8371e6e --- /dev/null +++ b/test/fixtures/lists/variables.js @@ -0,0 +1,3 @@ +module.exports = { + "colors": ["#c33", "#33c"] +} diff --git a/test/fixtures/maps/style-js.scss b/test/fixtures/maps/style-js.scss new file mode 100644 index 0000000..36e4e70 --- /dev/null +++ b/test/fixtures/maps/style-js.scss @@ -0,0 +1,5 @@ +@import 'variables.js'; + +body { + color: map-get($colors, red); +} diff --git a/test/fixtures/maps/variables.js b/test/fixtures/maps/variables.js new file mode 100644 index 0000000..e3bb9e0 --- /dev/null +++ b/test/fixtures/maps/variables.js @@ -0,0 +1,5 @@ +module.exports = { + "colors": { + "red": "#c33" + } +} diff --git a/test/fixtures/strings/style-js.scss b/test/fixtures/strings/style-js.scss new file mode 100644 index 0000000..50dbc94 --- /dev/null +++ b/test/fixtures/strings/style-js.scss @@ -0,0 +1,5 @@ +@import 'variables.js'; + +body { + color: $color-red; +} diff --git a/test/fixtures/strings/variables.js b/test/fixtures/strings/variables.js new file mode 100644 index 0000000..77876c4 --- /dev/null +++ b/test/fixtures/strings/variables.js @@ -0,0 +1,4 @@ +module.exports = { + "color-red": "#c33", + "color-blue": "#33c" +} diff --git a/test/index.js b/test/index.js index fa3c13b..8b92287 100644 --- a/test/index.js +++ b/test/index.js @@ -6,68 +6,77 @@ import {resolve} from 'path'; const EXPECTATION = 'body {\n color: #c33; }\n'; -describe('Import type test', function() { - - it('imports strings', function() { - let result = sass.renderSync({ - file: './test/fixtures/strings/style.scss', - importer: jsonImporter +function sassRenderFile(opts = {}) { + return function(file) { + return sass.renderSync({ + file: file, + importer: jsonImporter, + ...opts }); + } +} +function testExpectedCSS(result) { expect(result.css.toString()).to.eql(EXPECTATION); +} + + +describe('Import type test', function() { + + it('imports strings', function() { + ['./test/fixtures/strings/style.scss', + './test/fixtures/strings/style-js.scss' + ].map(sassRenderFile()).forEach(testExpectedCSS); }); it('imports lists', function() { - let result = sass.renderSync({ - file: './test/fixtures/lists/style.scss', - importer: jsonImporter - }); - - expect(result.css.toString()).to.eql(EXPECTATION); + ['./test/fixtures/lists/style.scss', + './test/fixtures/lists/style-js.scss' + ].map(sassRenderFile()).forEach(testExpectedCSS); }); it('imports maps', function() { - let result = sass.renderSync({ - file: './test/fixtures/maps/style.scss', - importer: jsonImporter - }); - - expect(result.css.toString()).to.eql(EXPECTATION); + ['./test/fixtures/maps/style.scss', + './test/fixtures/maps/style-js.scss' + ].map(sassRenderFile()).forEach(testExpectedCSS); }); it('finds imports via includePaths', function() { - let result = sass.renderSync({ - file: './test/fixtures/include-paths/style.scss', - includePaths: ['./test/fixtures/include-paths/variables'], - importer: jsonImporter - }); - - expect(result.css.toString()).to.eql(EXPECTATION); + ['./test/fixtures/include-paths/style.scss', + './test/fixtures/include-paths/style-js.scss' + ].map(sassRenderFile({ + includePaths: ['./test/fixtures/include-paths/variables'] + })).forEach(testExpectedCSS); }); it('finds imports via multiple includePaths', function() { - let result = sass.renderSync({ - file: './test/fixtures/include-paths/style.scss', - includePaths: ['./test/fixtures/include-paths/variables', './some/other/path/'], - importer: jsonImporter - }); - - expect(result.css.toString()).to.eql(EXPECTATION); + ['./test/fixtures/include-paths/style.scss', + './test/fixtures/include-paths/style-js.scss' + ].map(sassRenderFile({ + includePaths: ['./test/fixtures/include-paths/variables', './some/other/path/'] + })).forEach(testExpectedCSS); }); it(`throws when an import doesn't exist`, function() { - function render() { - sass.renderSync({ - file: './test/fixtures/include-paths/style.scss', - includePaths: ['./test/fixtures/include-paths/foo'], - importer: jsonImporter - }); + function render(file) { + return function() { + sass.renderSync({ + file: file, + includePaths: ['./test/fixtures/include-paths/foo'], + importer: jsonImporter + }); + } } - expect(render).to.throw( + expect(render('./test/fixtures/include-paths/style.scss')).to.throw( 'Unable to find "variables.json" from the following path(s): ' + `${resolve(process.cwd(), 'test/fixtures/include-paths')}, ./test/fixtures/include-paths/foo. ` + 'Check includePaths.' ); + expect(render('./test/fixtures/include-paths/style-js.scss')).to.throw( + 'Unable to find "variables.js" from the following path(s): ' + + `${resolve(process.cwd(), 'test/fixtures/include-paths')}, ./test/fixtures/include-paths/foo. ` + + 'Check includePaths.' + ); }); }); From f5342042941ef8f7d196c4f9c0773791164257f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20S=C3=A1nchez-Mar=C3=ADn?= Date: Tue, 15 Mar 2016 17:18:25 +0100 Subject: [PATCH 2/4] Do not export non-valid JSON values when importing JavaScript files --- src/index.js | 11 ++++++++++- test/fixtures/wrong-js-export/style-js.scss | 5 +++++ test/fixtures/wrong-js-export/variables.js | 4 ++++ test/index.js | 11 +++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/wrong-js-export/style-js.scss create mode 100644 test/fixtures/wrong-js-export/variables.js diff --git a/src/index.js b/src/index.js index 2bc51c2..2224332 100644 --- a/src/index.js +++ b/src/index.js @@ -26,8 +26,17 @@ export default function(url, prev) { // https://github.com/Updater/node-sass-json-importer/issues/21 delete require.cache[require.resolve(file)]; + var contents = require(file); + try { + if (/\.js$/.test(url)) { + contents = JSON.parse(JSON.stringify(contents)); + } + } catch(e) { + return sass.NULL; + } + return { - contents: parseJSON(require(file)) + contents: parseJSON(contents) }; } diff --git a/test/fixtures/wrong-js-export/style-js.scss b/test/fixtures/wrong-js-export/style-js.scss new file mode 100644 index 0000000..50dbc94 --- /dev/null +++ b/test/fixtures/wrong-js-export/style-js.scss @@ -0,0 +1,5 @@ +@import 'variables.js'; + +body { + color: $color-red; +} diff --git a/test/fixtures/wrong-js-export/variables.js b/test/fixtures/wrong-js-export/variables.js new file mode 100644 index 0000000..a90266f --- /dev/null +++ b/test/fixtures/wrong-js-export/variables.js @@ -0,0 +1,4 @@ +module.exports = { + "color-red": function() {}, + "color-blue": "#33c" +} diff --git a/test/index.js b/test/index.js index 8b92287..fc3e77d 100644 --- a/test/index.js +++ b/test/index.js @@ -57,6 +57,17 @@ describe('Import type test', function() { })).forEach(testExpectedCSS); }); + it(`JS imports do not export non valid JSON values`, function() { + function render() { + sass.renderSync({ + file: './test/fixtures/wrong-js-export/style-js.scss', + importer: jsonImporter + }); + } + + expect(render).to.throw(`Undefined variable: "$color-red".`) + }); + it(`throws when an import doesn't exist`, function() { function render(file) { return function() { From 520f7e8828e0eaf9a583c1da25339a4a8e485684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20S=C3=A1nchez-Mar=C3=ADn?= Date: Tue, 15 Mar 2016 16:51:33 +0100 Subject: [PATCH 3/4] Improve string support Quote strings except for valid CSS colors and number/floats with units --- package.json | 1 + src/index.js | 15 ++++++++++++++- test/fixtures/convert-strings/style-js.scss | 7 +++++++ test/fixtures/convert-strings/style.scss | 7 +++++++ test/fixtures/convert-strings/variables.js | 10 ++++++++++ test/fixtures/convert-strings/variables.json | 10 ++++++++++ test/index.js | 8 ++++++++ 7 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/convert-strings/style-js.scss create mode 100644 test/fixtures/convert-strings/style.scss create mode 100644 test/fixtures/convert-strings/variables.js create mode 100644 test/fixtures/convert-strings/variables.json diff --git a/package.json b/package.json index 3cc7160..35cccd4 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "prepublish": "npm run compile" }, "dependencies": { + "is-color": "^0.2.0", "is-there": "^4.0.0", "lodash": "^3.10.1", "node-sass": "^3.0.0" diff --git a/src/index.js b/src/index.js index 2224332..569706c 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import _ from 'lodash'; import {resolve} from 'path'; import isThere from 'is-there'; import sass from 'node-sass'; +import isColor from 'is-color'; export default function(url, prev) { if (!/\.(json|js)$/.test(url)) { @@ -40,6 +41,10 @@ export default function(url, prev) { }; } +function isCSSUnit(value) { + return /^\d*\.*\d+(em|ex|ch|rem|vh|vw|vmin|vmax|px|mm|cm|in|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)$/.test(value); +} + function parseJSON(json) { return Object.keys(json) .map(key => `$${key}: ${parseValue(json[key])};`) @@ -52,7 +57,7 @@ function parseValue(value) { } else if (_.isPlainObject(value)) { return parseMap(value); } else { - return value; + return parseEndValue(value); } } @@ -67,3 +72,11 @@ function parseMap(map) { .map(key => `${key}: ${parseValue(map[key])}`) .join(',')})`; } + +function parseEndValue(value) { + if (typeof value === 'string' && !isColor(value) && !isCSSUnit(value)) { + return JSON.stringify(value); + } + + return value; +} \ No newline at end of file diff --git a/test/fixtures/convert-strings/style-js.scss b/test/fixtures/convert-strings/style-js.scss new file mode 100644 index 0000000..cc63ea0 --- /dev/null +++ b/test/fixtures/convert-strings/style-js.scss @@ -0,0 +1,7 @@ +@import 'variables.js'; + +body { + content: $string; + color: $hex-color, $hsl-color, $rgba-color, $rgb-color, $css-color; + font-size: $em-unit; +} diff --git a/test/fixtures/convert-strings/style.scss b/test/fixtures/convert-strings/style.scss new file mode 100644 index 0000000..e403993 --- /dev/null +++ b/test/fixtures/convert-strings/style.scss @@ -0,0 +1,7 @@ +@import 'variables.json'; + +body { + content: $string; + color: $hex-color, $hsl-color, $rgba-color, $rgb-color, $css-color; + font-size: $em-unit; +} diff --git a/test/fixtures/convert-strings/variables.js b/test/fixtures/convert-strings/variables.js new file mode 100644 index 0000000..84f1901 --- /dev/null +++ b/test/fixtures/convert-strings/variables.js @@ -0,0 +1,10 @@ +module.exports = { + "hex-color": "#c33", + "hsl-color": "hsl(100, 100%, 100%)", + "rgba-color": "rgba(0, 0, 0, 1)", + "rgb-color": "rgb(10, 0, 0)", + "css-color": "blue", + "px-unit": "10px", + "em-unit": "2.3em", + "string": "Lorem ipsum, (\"foo\", bar)" +} diff --git a/test/fixtures/convert-strings/variables.json b/test/fixtures/convert-strings/variables.json new file mode 100644 index 0000000..59371ca --- /dev/null +++ b/test/fixtures/convert-strings/variables.json @@ -0,0 +1,10 @@ +{ + "hex-color": "#c33", + "hsl-color": "hsl(100, 100%, 100%)", + "rgba-color": "rgba(0, 0, 0, 1)", + "rgb-color": "rgb(10, 0, 0)", + "css-color": "blue", + "px-unit": "10px", + "em-unit": "2.3em", + "string": "Lorem ipsum, (\"foo\", bar)" +} diff --git a/test/index.js b/test/index.js index fc3e77d..da0fe1d 100644 --- a/test/index.js +++ b/test/index.js @@ -57,6 +57,14 @@ describe('Import type test', function() { })).forEach(testExpectedCSS); }); + it('converts JS/JSON strings to Sass strings', function() { + ['./test/fixtures/convert-strings/style-js.scss', + './test/fixtures/convert-strings/style.scss' + ].map(sassRenderFile()).forEach(function(result) { + expect(result.css.toString()).to.eql(`body {\n content: 'Lorem ipsum, ("foo", bar)';\n color: #c33, white, black, #0a0000, blue;\n font-size: 2.3em; }\n`); + }); + }); + it(`JS imports do not export non valid JSON values`, function() { function render() { sass.renderSync({ From 75b222e6d37ba76015731495c676b31452672843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20S=C3=A1nchez-Mar=C3=ADn?= Date: Tue, 15 Mar 2016 22:01:08 +0100 Subject: [PATCH 4/4] Better wording and improve test --- test/fixtures/convert-strings/style-js.scss | 2 ++ test/fixtures/convert-strings/style.scss | 2 ++ test/fixtures/convert-strings/variables.js | 2 ++ test/fixtures/convert-strings/variables.json | 2 ++ test/index.js | 7 +++---- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/test/fixtures/convert-strings/style-js.scss b/test/fixtures/convert-strings/style-js.scss index cc63ea0..eb6551c 100644 --- a/test/fixtures/convert-strings/style-js.scss +++ b/test/fixtures/convert-strings/style-js.scss @@ -4,4 +4,6 @@ body { content: $string; color: $hex-color, $hsl-color, $rgba-color, $rgb-color, $css-color; font-size: $em-unit; + margin-top: #{$number}px; + margin-bottom: #{$float}em; } diff --git a/test/fixtures/convert-strings/style.scss b/test/fixtures/convert-strings/style.scss index e403993..6e90c0b 100644 --- a/test/fixtures/convert-strings/style.scss +++ b/test/fixtures/convert-strings/style.scss @@ -4,4 +4,6 @@ body { content: $string; color: $hex-color, $hsl-color, $rgba-color, $rgb-color, $css-color; font-size: $em-unit; + margin-top: #{$number}px; + margin-bottom: #{$float}em; } diff --git a/test/fixtures/convert-strings/variables.js b/test/fixtures/convert-strings/variables.js index 84f1901..8eec4fa 100644 --- a/test/fixtures/convert-strings/variables.js +++ b/test/fixtures/convert-strings/variables.js @@ -6,5 +6,7 @@ module.exports = { "css-color": "blue", "px-unit": "10px", "em-unit": "2.3em", + "number": 5, + "float": 5.5, "string": "Lorem ipsum, (\"foo\", bar)" } diff --git a/test/fixtures/convert-strings/variables.json b/test/fixtures/convert-strings/variables.json index 59371ca..4ffdb19 100644 --- a/test/fixtures/convert-strings/variables.json +++ b/test/fixtures/convert-strings/variables.json @@ -6,5 +6,7 @@ "css-color": "blue", "px-unit": "10px", "em-unit": "2.3em", + "number": 5, + "float": 5.5, "string": "Lorem ipsum, (\"foo\", bar)" } diff --git a/test/index.js b/test/index.js index da0fe1d..065ab55 100644 --- a/test/index.js +++ b/test/index.js @@ -57,22 +57,21 @@ describe('Import type test', function() { })).forEach(testExpectedCSS); }); - it('converts JS/JSON strings to Sass strings', function() { + it('quotes strings and preserves numbers, floats, colors, and values with units', function() { ['./test/fixtures/convert-strings/style-js.scss', './test/fixtures/convert-strings/style.scss' ].map(sassRenderFile()).forEach(function(result) { - expect(result.css.toString()).to.eql(`body {\n content: 'Lorem ipsum, ("foo", bar)';\n color: #c33, white, black, #0a0000, blue;\n font-size: 2.3em; }\n`); + expect(result.css.toString()).to.eql(`body {\n content: 'Lorem ipsum, ("foo", bar)';\n color: #c33, white, black, #0a0000, blue;\n font-size: 2.3em;\n margin-top: 5px;\n margin-bottom: 5.5em; }\n`); }); }); - it(`JS imports do not export non valid JSON values`, function() { + it(`strips non-valid JSON values from JS exports`, function() { function render() { sass.renderSync({ file: './test/fixtures/wrong-js-export/style-js.scss', importer: jsonImporter }); } - expect(render).to.throw(`Undefined variable: "$color-red".`) });