Skip to content

Commit fe5c16a

Browse files
committed
Handle Sass values
Currently we coerce all values into quoted Sass Strings. This PR coerces the JSON value into the appropriate Sass value type. If the value type cannot be determined we fallback to a quoted Sass String to avoid errors. This differs from [prior work][1] in that no attempt is made to mangle JSON arrays and maps into a JSON string value. [1]: pmowrer/node-sass-json-importer#5 Fixes #3
1 parent 2a65e5a commit fe5c16a

File tree

5 files changed

+77
-4
lines changed

5 files changed

+77
-4
lines changed

index.js

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fs = require('fs');
22
const path = require('path');
3+
const csscolors = require('css-color-names');
34

45
const exists = (file) => {
56
try {
@@ -10,14 +11,33 @@ const exists = (file) => {
1011
}
1112
}
1213

14+
const reValue = new RegExp([
15+
// ---- hex colors
16+
'^#[0-9a-z]{3}$', // #def
17+
'^#[0-9a-z]{4}$', // #def0
18+
'^#[0-9a-z]{6}$', // #ddeeff
19+
'^#[0-9a-z]{8}$', // #ddeeff00
20+
// ---- numbers
21+
'^[0-9]+(?:\\.[0-9]+)?(?:%|[a-z]+)?$', // 12.34 + unit
22+
// ---- function calls
23+
'^[a-z][a-z0-9-_]*\\(', // foo(...)
24+
].join('|'), 'i');
25+
26+
const looksLikeString = (value) => {
27+
return !reValue.test(value) || csscolors[value];
28+
}
29+
1330
const buildSassValue = (value) => {
1431
if (Array.isArray(value)) {
15-
return `(${value.reduce((prev, cur) => prev + `"${cur}",`, '')})`;
32+
return `(${value.reduce((prev, cur) => prev + `${buildSassValue(cur)},`, '')})`;
1633
}
1734
if (typeof value === "object") {
1835
return `(${buildSassMap(value)})`;
1936
}
20-
return `"${value}"`;
37+
if (looksLikeString(value)) {
38+
return `"${value}"`;
39+
}
40+
return value;
2141
}
2242

2343
const buildSassMap = (json) => {

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,8 @@
2424
"devDependencies": {
2525
"jest": "^23.4.0",
2626
"node-sass": "^4.9.2"
27+
},
28+
"dependencies": {
29+
"css-color-names": "0.0.4"
2730
}
2831
}

tests/__snapshots__/index.test.js.snap

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`json-importer async should not resolve Sass values to quoted strings 1`] = `
4+
"output {
5+
contents: (\\"short-hex-color\\": #def, \\"short-hex-color-with-alpha\\": #def0, \\"long-hex-color\\": #ddeeff, \\"long-hex-color-with-alpha\\": #ddeeff00, \\"named-color\\": \\"red\\", \\"number\\": 16, \\"number-with-percentage\\": 16%, \\"number-with-word-unit\\": 16rem, \\"decimal\\": 12.34, \\"decimal-with-percentage\\": 12.34%, \\"decimal-with-word-unit\\": 12.34rem, \\"function-call\\": black, \\"string\\": \\"foo\\", \\"string-with-spaces\\": \\"who are you\\", \\"array\\": (16, 16px, 16%, 12.34, 12.34px, 12.34%, #def, black, \\"foo\\", \\"who are you\\"), \\"map\\": (\\"short-hex-color\\": #def, \\"short-hex-color-with-alpha\\": #def0, \\"string\\": \\"foo\\", \\"string-with-spaces\\": \\"who are you\\")); }
6+
"
7+
`;
8+
39
exports[`json-importer async should resolve flat json strings as Sass map 1`] = `
410
"output {
511
contents: (\\"color\\": \\"red\\", \\"size\\": \\"small\\"); }
@@ -20,7 +26,13 @@ exports[`json-importer async should resolve json files in includePaths 1`] = `
2026

2127
exports[`json-importer async should resolve nested json strings as Sass map 1`] = `
2228
"output {
23-
contents: (\\"colors\\": (\\"red\\": \\"#f00\\", \\"blue\\": \\"#00f\\"), \\"sizes\\": (\\"small\\": \\"16px\\", \\"big\\": \\"30px\\")); }
29+
contents: (\\"colors\\": (\\"red\\": #f00, \\"blue\\": #00f), \\"sizes\\": (\\"small\\": 16px, \\"big\\": 30px)); }
30+
"
31+
`;
32+
33+
exports[`json-importer sync should not resolve Sass values to quoted strings 1`] = `
34+
"output {
35+
contents: (\\"short-hex-color\\": #def, \\"short-hex-color-with-alpha\\": #def0, \\"long-hex-color\\": #ddeeff, \\"long-hex-color-with-alpha\\": #ddeeff00, \\"named-color\\": \\"red\\", \\"number\\": 16, \\"number-with-percentage\\": 16%, \\"number-with-word-unit\\": 16rem, \\"decimal\\": 12.34, \\"decimal-with-percentage\\": 12.34%, \\"decimal-with-word-unit\\": 12.34rem, \\"function-call\\": black, \\"string\\": \\"foo\\", \\"string-with-spaces\\": \\"who are you\\", \\"array\\": (16, 16px, 16%, 12.34, 12.34px, 12.34%, #def, black, \\"foo\\", \\"who are you\\"), \\"map\\": (\\"short-hex-color\\": #def, \\"short-hex-color-with-alpha\\": #def0, \\"string\\": \\"foo\\", \\"string-with-spaces\\": \\"who are you\\")); }
2436
"
2537
`;
2638

@@ -44,6 +56,6 @@ exports[`json-importer sync should resolve json files in includePaths 1`] = `
4456

4557
exports[`json-importer sync should resolve nested json strings as Sass map 1`] = `
4658
"output {
47-
contents: (\\"colors\\": (\\"red\\": \\"#f00\\", \\"blue\\": \\"#00f\\"), \\"sizes\\": (\\"small\\": \\"16px\\", \\"big\\": \\"30px\\")); }
59+
contents: (\\"colors\\": (\\"red\\": #f00, \\"blue\\": #00f), \\"sizes\\": (\\"small\\": 16px, \\"big\\": 30px)); }
4860
"
4961
`;

tests/fixtures/values.json

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"short-hex-color": "#def",
3+
"short-hex-color-with-alpha": "#def0",
4+
"long-hex-color": "#ddeeff",
5+
"long-hex-color-with-alpha": "#ddeeff00",
6+
"named-color": "red",
7+
"number": "16",
8+
"number-with-percentage": "16%",
9+
"number-with-word-unit": "16rem",
10+
"decimal": "12.34",
11+
"decimal-with-percentage": "12.34%",
12+
"decimal-with-word-unit": "12.34rem",
13+
"function-call": "hsl(0,0,0)",
14+
"string": "foo",
15+
"string-with-spaces": "who are you",
16+
"array": [
17+
16,
18+
"16px",
19+
"16%",
20+
12.34,
21+
"12.34px",
22+
"12.34%",
23+
"#def",
24+
"hsl(0,0,0)",
25+
"foo",
26+
"who are you"
27+
],
28+
"map": {
29+
"short-hex-color": "#def",
30+
"short-hex-color-with-alpha": "#def0",
31+
"string": "foo",
32+
"string-with-spaces": "who are you"
33+
}
34+
}

tests/index.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ describe('json-importer', () => {
4242
func(generate('tests/fixtures/list.json'))
4343
.then(result => expect(result).toMatchSnapshot())
4444
));
45+
it('should not resolve Sass values to quoted strings', () => (
46+
func(generate('tests/fixtures/values.json'))
47+
.then(result => expect(result).toMatchSnapshot())
48+
));
4549
it('should resolve json files in includePaths', () => (
4650
func(generate('fixtures/flat.json'), { includePaths: ['tests']})
4751
.then(result => expect(result).toMatchSnapshot())

0 commit comments

Comments
 (0)