-
Notifications
You must be signed in to change notification settings - Fork 571
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a4542f4
commit c222e47
Showing
16 changed files
with
454 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* | ||
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with | ||
* the License. A copy of the License is located at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | ||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions | ||
* and limitations under the License. | ||
*/ | ||
import { expect } from 'chai'; | ||
import StyleDictionary from 'style-dictionary'; | ||
|
||
describe('register/transformGroup', async () => { | ||
let StyleDictionaryExtended; | ||
beforeEach(async () => { | ||
StyleDictionary.preprocessors = {}; | ||
StyleDictionaryExtended = new StyleDictionary({}); | ||
await StyleDictionaryExtended.hasInitialized; | ||
}); | ||
|
||
it('should support registering preprocessor on StyleDictionary class', () => { | ||
StyleDictionary.registerPreprocessor({ | ||
name: 'example-preprocessor', | ||
preprocessor: (dict) => dict, | ||
}); | ||
expect(StyleDictionary.preprocessors['example-preprocessor']).to.not.be.undefined; | ||
expect(StyleDictionaryExtended.preprocessors['example-preprocessor']).to.not.be.undefined; | ||
}); | ||
|
||
it('should support registering preprocessor on StyleDictionary instance, which registers it on the class', () => { | ||
StyleDictionaryExtended.registerPreprocessor({ | ||
name: 'example-preprocessor', | ||
preprocessor: (dict) => dict, | ||
}); | ||
expect(StyleDictionary.preprocessors['example-preprocessor']).to.not.be.undefined; | ||
expect(StyleDictionaryExtended.preprocessors['example-preprocessor']).to.not.be.undefined; | ||
}); | ||
|
||
it('should throw if the preprocessor name is not a string', () => { | ||
expect(() => { | ||
StyleDictionaryExtended.registerPreprocessor({ | ||
name: true, | ||
preprocessor: (dict) => dict, | ||
}); | ||
}).to.throw('Cannot register preprocessor; Preprocessor.name must be a string'); | ||
}); | ||
|
||
it('should throw if the preprocessor is not a function', () => { | ||
expect(() => { | ||
StyleDictionaryExtended.registerPreprocessor({ | ||
name: 'example-preprocessor', | ||
preprocessor: 'foo', | ||
}); | ||
}).to.throw('Cannot register preprocessor; Preprocessor.preprocessor must be a function'); | ||
}); | ||
|
||
it('should preprocess the dictionary as specified', async () => { | ||
StyleDictionary.registerPreprocessor({ | ||
name: 'strip-descriptions', | ||
preprocessor: (dict) => { | ||
// recursively traverse token objects and delete description props | ||
function removeDescription(slice) { | ||
delete slice.description; | ||
Object.values(slice).forEach((value) => { | ||
if (typeof value === 'object') { | ||
removeDescription(value); | ||
} | ||
}); | ||
return slice; | ||
} | ||
return removeDescription(dict); | ||
}, | ||
}); | ||
|
||
StyleDictionaryExtended = new StyleDictionary({ | ||
tokens: { | ||
foo: { | ||
value: '4px', | ||
type: 'dimension', | ||
description: 'Foo description', | ||
}, | ||
description: 'My dictionary', | ||
}, | ||
}); | ||
await StyleDictionaryExtended.hasInitialized; | ||
expect(StyleDictionaryExtended.tokens).to.eql({ | ||
foo: { | ||
value: '4px', | ||
type: 'dimension', | ||
}, | ||
}); | ||
}); | ||
|
||
it('should support async preprocessors', async () => { | ||
StyleDictionary.registerPreprocessor({ | ||
name: 'strip-descriptions', | ||
preprocessor: async (dict) => { | ||
// recursively traverse token objects and delete description props | ||
async function removeDescription(slice) { | ||
// Arbitrary delay, act as though this action is asynchronous and takes some time | ||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||
delete slice.description; | ||
|
||
await Promise.all( | ||
Object.values(slice).map((value) => { | ||
if (typeof value === 'object') { | ||
return removeDescription(value); | ||
} else { | ||
return Promise.resolve(); | ||
} | ||
}), | ||
); | ||
return slice; | ||
} | ||
return removeDescription(dict); | ||
}, | ||
}); | ||
|
||
StyleDictionaryExtended = new StyleDictionary({ | ||
tokens: { | ||
foo: { | ||
value: '4px', | ||
type: 'dimension', | ||
description: 'Foo description', | ||
}, | ||
description: 'My dictionary', | ||
}, | ||
}); | ||
await StyleDictionaryExtended.hasInitialized; | ||
expect(StyleDictionaryExtended.tokens).to.eql({ | ||
foo: { | ||
value: '4px', | ||
type: 'dimension', | ||
}, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# Preprocessors | ||
|
||
Starting in version 4.0, you can define custom preprocessors to process the dictionary object as a whole, after it all token files have been parsed and combined into one. | ||
This is useful if you want to do more complex transformations on the dictionary as a whole, when all other ways are not powerful enough. | ||
|
||
It should be clear that using this feature should be a last resort. Using custom parsers to parse per file or using transforms to do transformations on a per token basis, | ||
gives more granular control and reduces the risks of making mistakes. That said, preprocessing the full dictionary gives ultimate flexibility when needed. | ||
|
||
--- | ||
|
||
## Preprocessor structure | ||
|
||
A preprocessor is an object with two props: | ||
|
||
- `name`: the name of the preprocessor | ||
- `preprocessor` a callback function that receives the dictionary as a parameter, and returns the processed dictionary | ||
|
||
```javascript | ||
const myPreprocessor = { | ||
name: 'strip-third-party-meta', | ||
preprocessor: (dictionary) => { | ||
delete dictionary.thirdPartyMetadata; | ||
return dictionary; | ||
}, | ||
}; | ||
``` | ||
|
||
Asynchronous callback functions are also supported, giving even more flexibility. | ||
|
||
```javascript | ||
const myPreprocessor = { | ||
name: 'strip-props', | ||
preprocessor: async (dictionary) => { | ||
const propsToDelete = await someAPICall(); | ||
|
||
propsToDelete.forEach((propName) => { | ||
delete dictionary[propName]; | ||
}); | ||
|
||
return dictionary; | ||
}, | ||
}; | ||
``` | ||
|
||
--- | ||
|
||
## Using parsers | ||
|
||
First you will need to tell Style Dictionary about your parser. You can do this in two ways: | ||
|
||
1. Using the `.registerPreprocessor` method | ||
1. Inline in the [configuration](config.md) | ||
|
||
### .registerPreprocessor | ||
|
||
```javascript | ||
import StyleDictionary from 'style-dictionary'; | ||
|
||
StyleDictionary.registerPreprocessor(myPreprocessor); | ||
``` | ||
|
||
### Inline | ||
|
||
```javascript | ||
export default { | ||
preprocessors: { | ||
'strip-props': myPreprocessor, | ||
}, | ||
// ... the rest of the configuration | ||
}; | ||
``` | ||
|
||
--- | ||
|
||
## Preprocessor examples | ||
|
||
Stripping description property recursively in the entire dictionary object: | ||
|
||
```js | ||
StyleDictionary.registerPreprocessor({ | ||
name: 'strip-descriptions', | ||
preprocessor: (dict) => { | ||
// recursively traverse token objects and delete description props | ||
function removeDescription(slice) { | ||
delete slice.description; | ||
Object.values(slice).forEach((value) => { | ||
if (typeof value === 'object') { | ||
removeDescription(value); | ||
} | ||
}); | ||
return slice; | ||
} | ||
return removeDescription(dict); | ||
}, | ||
}); | ||
``` |
Oops, something went wrong.