Skip to content

Commit

Permalink
feat: add case conversion
Browse files Browse the repository at this point in the history
Closes #77
  • Loading branch information
anthonylebrun authored May 2, 2020
1 parent cfd8f12 commit ff1bec1
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 14 deletions.
45 changes: 40 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,46 @@ var jsonImporter = require('../dist/node-sass-json-importer');
sass.render({
file: './1.sass',
importer: jsonImporter({
resolver: function(dir, url) {
return url.startsWith('~/')
? path.resolve(dir, 'json', url.substr(2))
: path.resolve(dir, url);
},
resolver: function(dir, url) {
return url.startsWith('~/')
? path.resolve(dir, 'json', url.substr(2))
: path.resolve(dir, url);
},
}),
}, function(err, result) { console.log(err || result.css.toString()) });
```

## camelCase to kebab-case

If you want to convert standard JavaScript caseCase keys into CSS/SCSS compliant kebab-case keys, for example:

`variables.json`:

```JS
{
"bgBackgroundColor": 'red'
}
```

For usage like this:

`style.scss`:

```SCSS
@import "variables.json";

div {
background: $bg-background-color;
}
```

You can pass set the `convertCase` option to true as an argument to `jsonImporter` like so:

```js
sass.render({
file: './1.sass',
importer: jsonImporter({
convertCase: true,
}),
}, function(err, result) { console.log(err || result.css.toString()) });
```
Expand Down
25 changes: 16 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function(options = {}) {
const json = Array.isArray(fileContents) ? { [extensionlessFilename]: fileContents } : fileContents;

return {
contents: transformJSONtoSass(json),
contents: transformJSONtoSass(json, options),
};
} catch(error) {
return new Error(`node-sass-json-importer: Error transforming JSON/JSON5 to SASS. Check if your JSON/JSON5 parses correctly. ${error}`);
Expand All @@ -47,40 +47,47 @@ export function isJSONfile(url) {
return /\.js(on5?)?$/.test(url);
}

export function transformJSONtoSass(json) {
export function transformJSONtoSass(json, opts = {}) {
return Object.keys(json)
.filter(key => isValidKey(key))
.filter(key => json[key] !== '#')
.map(key => `$${key}: ${parseValue(json[key])};`)
.map(key => `$${opts.convertCase ? toKebabCase(key) : key}: ${parseValue(json[key], opts)};`)
.join('\n');
}

export function isValidKey(key) {
return /^[^$@:].*/.test(key)
}

export function parseValue(value) {
export function toKebabCase(key) {
return key
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2')
.toLowerCase();
}

export function parseValue(value, opts = {}) {
if (_.isArray(value)) {
return parseList(value);
return parseList(value, opts);
} else if (_.isPlainObject(value)) {
return parseMap(value);
return parseMap(value, opts);
} else if (value === '') {
return '""'; // Return explicitly an empty string (Sass would otherwise throw an error as the variable is set to nothing)
} else {
return value;
}
}

export function parseList(list) {
export function parseList(list, opts = {}) {
return `(${list
.map(value => parseValue(value))
.join(',')})`;
}

export function parseMap(map) {
export function parseMap(map, opts = {}) {
return `(${Object.keys(map)
.filter(key => isValidKey(key))
.map(key => `${key}: ${parseValue(map[key])}`)
.map(key => `${opts.convertCase ? toKebabCase(key) : key}: ${parseValue(map[key], opts)}`)
.join(',')})`;
}

Expand Down
7 changes: 7 additions & 0 deletions test/fixtures-json5/convert-case/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import 'variables.json5';

body {
color: $color-red;
color: $color-green;
color: $color-blue;
}
5 changes: 5 additions & 0 deletions test/fixtures-json5/convert-case/variables.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
'colorRed': '#c33', // Red color
'ColorGreen': '#3c3', // Green color
'COLORBlue': '#33c', // Blue color
}
7 changes: 7 additions & 0 deletions test/fixtures/convert-case/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import 'variables.json';

body {
color: $color-red;
color: $color-green;
color: $color-blue;
}
5 changes: 5 additions & 0 deletions test/fixtures/convert-case/variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"colorRed": "#c33",
"ColorGreen": "#3c3",
"COLORBlue": "#33c"
}
41 changes: 41 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import jsonImporter, {
isJSONfile,
isValidKey,
toKebabCase,
parseValue,
} from '../src'
import sass from 'node-sass';
Expand Down Expand Up @@ -149,6 +150,17 @@ describe('Import type test (JSON)', function() {

expect(result.css.toString()).to.eql('body {\n color: ""; }\n');
});

it('allows case conversion', function() {
let result = sass.renderSync({
file: './test/fixtures/convert-case/style.scss',
importer: jsonImporter({
convertCase: true,
}),
});

expect(result.css.toString()).to.eql('body {\n color: #c33;\n color: #3c3;\n color: #33c; }\n');
});
});

describe('Import type test (JSON5)', function() {
Expand Down Expand Up @@ -272,6 +284,17 @@ describe('Import type test (JSON5)', function() {

expect(result.css.toString()).to.eql('body {\n color: ""; }\n');
});

it('allows case conversion', function() {
let result = sass.renderSync({
file: './test/fixtures-json5/convert-case/style.scss',
importer: jsonImporter({
convertCase: true,
}),
});

expect(result.css.toString()).to.eql('body {\n color: #c33;\n color: #3c3;\n color: #33c; }\n');
});
});

describe('parseValue', function() {
Expand Down Expand Up @@ -339,3 +362,21 @@ describe('isValidKey', function() {
expect(isValidKey('valid')).to.be.true;
});
});

describe('toKebabCase', function() {
it('can handle camelCase', function() {
expect(toKebabCase('camelCase')).to.eql('camel-case');
});

it('can handle PascalCase', function() {
expect(toKebabCase('PascalCase')).to.eql('pascal-case');
});

it('can handle ALLCAPSCase', function() {
expect(toKebabCase('ALLCAPSCase')).to.eql('allcaps-case');
});

it('can even handle EDGECaseWELLCase', function() {
expect(toKebabCase('EDGECaseWELLCase')).to.eql('edge-case-well-case');
});
});

0 comments on commit ff1bec1

Please sign in to comment.