Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(formats): add support for Microsoft's JSONC format #732

Merged
Merged
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
98 changes: 98 additions & 0 deletions __tests__/__configs/test.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
// some comment
"source": ["test/properties/**/*.json"],
"platforms": {
"web": {
"transformGroup": "web",
"prefix": "smop",
"buildPath": "test/output/web/",
"files": [
{
"destination": "_icons.css",
"format": "scss/icons"
},
{
"destination": "_variables.css",
"format": "scss/variables"
},
{
"destination": "_styles.js",
"format": "javascript/module"
}
]
},
"scss": {
"transformGroup": "scss",
"prefix": "smop",
"buildPath": "test/output/scss/",
"files": [
{
"destination": "_icons.scss",
"format": "scss/icons"
},
{
"destination": "_variables.scss",
"format": "scss/variables"
}
]
},
"less": {
"transformGroup": "less",
"prefix": "smop",
"buildPath": "test/output/less/",
"files": [
{
"destination": "_icons.less",
"format": "less/icons"
},
{
"destination": "_variables.less",
"format": "less/variables"
}
]
},
"android": {
"transformGroup": "android",
"buildPath": "test/output/",
"files": [
{
"destination": "android/colors.xml",
"template": "android/colors"
},
{
"destination": "android/font_dimen.xml",
"template": "android/fontDimens"
},
{
"destination": "android/dimens.xml",
"template": "android/dimens"
}
],
"actions": ["android/copyImages"]
},
"ios": {
"transformGroup": "ios",
"buildPath": "test/output/ios/",
"files": [
{
"destination": "style_dictionary.plist",
"template": "ios/plist"
},
{
"destination": "style_dictionary.h",
"template": "ios/macros"
}
]
},
"react-native": {
"transformGroup": "react-native",
"buildPath": "__tests__/__output/react-native/",
"files": [
{
"destination": "style_dictionary.js",
"format": "javascript/es6"
}
]
}
}
}
7 changes: 7 additions & 0 deletions __tests__/__json_files/shallow/4.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"jsonCA": 5,
// some comment
"d": {
"jsonCe": 1
}
}
5 changes: 5 additions & 0 deletions __tests__/extend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ describe('extend', () => {
expect(StyleDictionaryExtended).toHaveProperty('platforms.web');
});

it('should accept a string as a path to a JSONC file', function() {
Copy link
Member

Choose a reason for hiding this comment

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

Nice unit tests!

var StyleDictionaryExtended = StyleDictionary.extend(__dirname + '/__configs/test.jsonc');
expect(StyleDictionaryExtended).toHaveProperty('platforms.web');
});

it('should allow for chained extends and not mutate the original', function() {
var StyleDictionary1 = StyleDictionary.extend({
foo: 'bar'
Expand Down
6 changes: 6 additions & 0 deletions __tests__/utils/combineJSON.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ describe('utils', () => {
expect(test.d).toHaveProperty('json5e', 1);
});

it('should support jsonc', () => {
var test = combineJSON(["__tests__/__json_files/shallow/*.jsonc"]);
expect(test).toHaveProperty('jsonCA', 5);
expect(test.d).toHaveProperty('jsonCe', 1);
});

describe('custom parsers', () => {
it('should support yaml.parse', () => {
const parsers = [{
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ When you are managing user experiences, it can be quite challenging to keep styl

## The Basics
__A style dictionary consists of:__
1. [Design tokens](tokens.md), organized in JSON, JSON5, or JS files
1. [Design tokens](tokens.md), organized in JSON, JSONC, JSON5, or JS files
1. Static assets (e.g. fonts, icons, images, sounds, etc.), organized into folders
1. [Configuration](config.md), defining the [transformation](transforms.md) and [formatting](formats.md) of the tokens and assets for each output platform

Expand Down
1 change: 1 addition & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Here is an example configuration:
Style Dictionary supports configuration files in these file formats:

* JSON
* JSONC
* JSON5
* Javascript (CommonJS)

Expand Down
1 change: 1 addition & 0 deletions docs/tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ See more in the advanced [referencing-aliasing example](https://github.com/amzn/
Design token files can included inline in the configuration, or be written in separate files. Style Dictionary supports these languages for design token files:

* JSON
* [JSONC](https://code.visualstudio.com/docs/languages/json#_json-with-comments)
* [JSON5](https://json5.org)
* CommonJS modules
* Potentially any language with [custom parsers](#customfileparsers)
Expand Down
1 change: 1 addition & 0 deletions lib/extend.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

require('json5/lib/register');
require.extensions[".jsonc"] = require("./utils/jsonc").register;
Copy link
Member

Choose a reason for hiding this comment

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

Nice!


var combineJSON = require('./utils/combineJSON'),
deepExtend = require('./utils/deepExtend'),
Expand Down
1 change: 1 addition & 0 deletions lib/utils/combineJSON.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

require('json5/lib/register');
require.extensions[".jsonc"] = require("./jsonc").register;

var glob = require('glob'),
deepExtend = require('./deepExtend'),
Expand Down
14 changes: 14 additions & 0 deletions lib/utils/jsonc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const fs = require("fs");
const jsonc = require("jsonc-parser");

module.exports = {
register(module, filename) {
const content = fs.readFileSync(filename, "utf8");
try {
module.exports = jsonc.parse(content);
} catch (err) {
err.message = filename + ": " + err.message;
throw err;
}
},
};
15 changes: 14 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
],
"transform": {
"^.+\\.json5$": "json5-jest",
"^.+\\.jsonc$": "json5-jest",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here I've taken advantage of the fact that JSON5 is a superset of JSONC, so the same transform satisfies Jest. I initially writing my own JSONC transform, based on the JSON5 one—it's basically a one-liner—but for some reason I couldn't get Jest to actually run it. 🤷‍♂️

"^.+\\.jsx?$": "babel-jest"
}
},
Expand Down Expand Up @@ -141,6 +142,7 @@
"jsdoc-escape-at": "^1.0.1",
"jsdoc-to-markdown": "^7.0.1",
"json5-jest": "^1.0.1",
"jsonc-parser": "^3.0.0",
"less": "^3.11.2",
"lint-staged": "^10.2.7",
"node-sass": "^6.0.1",
Expand Down
2 changes: 1 addition & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ declare namespace StyleDictionary {
/**
* Adds a custom parser to parse style dictionary files. This allows you to modify
* the design token data before it gets to Style Dictionary or write your
* token files in a language other than JSON, JSON5, or CommonJS modules.
* token files in a language other than JSON, JSONC, JSON5, or CommonJS modules.
*
* @param {Regex} parser.pattern - A file path regular expression to match which files this parser should be be used on. This is similar to how webpack loaders work. `/\.json$/` will match any file ending in '.json', for example.
* @param {Function} parser.parse - Function to parse the file contents. Takes 1 argument, which is an object with 2 attributes: contents which is the string of the file contents and filePath. The function should return a plain Javascript object.
Expand Down