Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
28 changes: 25 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ 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$/.test(url)) {
if (!/\.(json|js)$/.test(url)) {
return sass.NULL;
}

Expand All @@ -26,11 +27,24 @@ 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)
};
}

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])};`)
Expand All @@ -43,7 +57,7 @@ function parseValue(value) {
} else if (_.isPlainObject(value)) {
return parseMap(value);
} else {
return value;
return parseEndValue(value);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseEndValue is the worst name in the world. I should rename it to parseValue or maybe you have a better proposal :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a parseValue function, thats why I chose parseEndValue... 😴 💤

}
}

Expand All @@ -58,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;
}
9 changes: 9 additions & 0 deletions test/fixtures/convert-strings/style-js.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import 'variables.js';

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;
}
9 changes: 9 additions & 0 deletions test/fixtures/convert-strings/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import 'variables.json';

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;
}
12 changes: 12 additions & 0 deletions test/fixtures/convert-strings/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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",
"number": 5,
"float": 5.5,
"string": "Lorem ipsum, (\"foo\", bar)"
}
12 changes: 12 additions & 0 deletions test/fixtures/convert-strings/variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"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",
"number": 5,
"float": 5.5,
"string": "Lorem ipsum, (\"foo\", bar)"
}
5 changes: 5 additions & 0 deletions test/fixtures/include-paths/style-js.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import 'variables.js';

body {
color: $color-red;
}
4 changes: 4 additions & 0 deletions test/fixtures/include-paths/variables/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
"color-red": "#c33",
"color-blue": "#33c"
}
5 changes: 5 additions & 0 deletions test/fixtures/lists/style-js.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import 'variables.js';

body {
color: nth($colors, 1);
}
3 changes: 3 additions & 0 deletions test/fixtures/lists/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
"colors": ["#c33", "#33c"]
}
5 changes: 5 additions & 0 deletions test/fixtures/maps/style-js.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import 'variables.js';

body {
color: map-get($colors, red);
}
5 changes: 5 additions & 0 deletions test/fixtures/maps/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
"colors": {
"red": "#c33"
}
}
5 changes: 5 additions & 0 deletions test/fixtures/strings/style-js.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import 'variables.js';

body {
color: $color-red;
}
4 changes: 4 additions & 0 deletions test/fixtures/strings/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
"color-red": "#c33",
"color-blue": "#33c"
}
5 changes: 5 additions & 0 deletions test/fixtures/wrong-js-export/style-js.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import 'variables.js';

body {
color: $color-red;
}
4 changes: 4 additions & 0 deletions test/fixtures/wrong-js-export/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
"color-red": function() {},
"color-blue": "#33c"
}
97 changes: 62 additions & 35 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,68 +6,95 @@ 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
});
['./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);
});

expect(result.css.toString()).to.eql(EXPECTATION);
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 margin-top: 5px;\n margin-bottom: 5.5em; }\n`);
});
});

it(`throws when an import doesn't exist`, function() {
it(`strips non-valid JSON values from JS exports`, function() {
function render() {
sass.renderSync({
file: './test/fixtures/include-paths/style.scss',
includePaths: ['./test/fixtures/include-paths/foo'],
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() {
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.'
);
});
});