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): output references handles interpoloated references #590

Merged
merged 6 commits into from
Apr 5, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
37 changes: 24 additions & 13 deletions docs/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ The formatter function that is called when Style Dictionary builds files.
<td>args.dictionary.usesReference</td><td><code>function</code></td><td><p>Use this function to see if a token&#39;s value uses a reference. This is the same function style dictionary uses internally to detect a reference.</p>
</td>
</tr><tr>
<td>args.dictionary.getReferences</td><td><code>function</code></td><td><p>Use this function to get the token/property that it references. You can use this to output a reference in your custom format. For example: <code>dictionary.getReferences(token.original.value) // returns an array of the referenced token objects</code></p>
<td>args.dictionary.getReferences</td><td><code>function</code></td><td><p>Use this function to get the tokens/properties that it references. You can use this to output a reference in your custom format. For example: <code>dictionary.getReferences(token.original.value) // returns an array of the referenced token objects</code></p>
</td>
</tr><tr>
<td>args.platform</td><td><code>Object</code></td><td><p>The platform configuration this format is being called in.</p>
Expand Down Expand Up @@ -309,7 +309,7 @@ StyleDictionary.registerFormat({
// the `dictionary` object now has `usesReference()` and
// `getReferences()` methods. `usesReference()` will return true if
// the value has a reference in it. `getReferences()` will return
// the reference to the whole token so that you can access its
// an array of references to the whole tokens so that you can access its
// name or any other attributes.
if (dictionary.usesReference(token.original.value)) {
// Note: make sure to use `token.original.value` because
Expand All @@ -335,9 +335,10 @@ const { fileHeader, formattedVariables } = StyleDictionary.formatHelpers;
StyleDictionary.registerFormat({
name: 'myCustomFormat',
formatter: function({dictionary, file, options}) {
return fileHeader(file) +
const { outputReferences } = options;
return fileHeader({file}) +
':root {\n' +
formattedVariables('css', dictionary, options.outputReferences) +
formattedVariables({format: 'css', dictionary, outputReferences}) +
'\n}\n';
}
});
Expand Down Expand Up @@ -396,7 +397,7 @@ StyleDictionary.registerFormat({
* * *

### fileHeader
> formatHelpers.fileHeader(file, commentStyle) ⇒ <code>String</code>
> formatHelpers.fileHeader(options) ⇒ <code>String</code>

This is for creating the comment at the top of generated files with the generated at date.
It will use the custom file header if defined on the configuration, or use the
Expand All @@ -410,10 +411,15 @@ default file header.
</thead>
<tbody>
<tr>
<td>file</td><td><code>File</code></td><td><p>The file object that is passed to the formatter.</p>
<td>options</td><td><code>Object</code></td><td></td>
</tr><tr>
<td>options.file</td><td><code>File</code></td><td><p>The file object that is passed to the formatter.</p>
</td>
</tr><tr>
<td>commentStyle</td><td><code>String</code></td><td><p>The only options are &#39;short&#39; and &#39;xml&#39;, which will use the // or &lt;!-- --&gt; style comments respectively. Anything else will use /* style comments.</p>
<td>options.commentStyle</td><td><code>String</code></td><td><p>The only options are &#39;short&#39; and &#39;xml&#39;, which will use the // or &lt;!-- --&gt; style comments respectively. Anything else will use /* style comments.</p>
</td>
</tr><tr>
<td>options.formatting</td><td><code>Object</code></td><td><p>Custom formatting properties that define parts of a comment in code. The configurable strings are: prefix, lineSeparator, header, and footer.</p>
</td>
</tr> </tbody>
</table>
Expand All @@ -423,7 +429,7 @@ default file header.
StyleDictionary.registerFormat({
name: 'myCustomFormat',
formatter: function({ dictionary, file }) {
return fileHeader(file, 'short') +
return fileHeader({file, 'short') +
dictionary.allProperties.map(token => `${token.name} = ${token.value}`)
.join('\n');
}
Expand All @@ -433,25 +439,30 @@ StyleDictionary.registerFormat({
* * *

### formattedVariables
> formatHelpers.formattedVariables(format, dictionary, outputReferences) ⇒ <code>String</code>
> formatHelpers.formattedVariables(options) ⇒ <code>String</code>

This is used to create lists of variables like Sass variables or CSS custom properties

<table>
<thead>
<tr>
<th>Param</th><th>Type</th><th>Default</th><th>Description</th>
<th>Param</th><th>Type</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>format</td><td><code>String</code></td><td></td><td><p>What type of variables to output. Options are: css, sass, less, and stylus</p>
<td>options</td><td><code>Object</code></td><td></td>
</tr><tr>
<td>options.format</td><td><code>String</code></td><td><p>What type of variables to output. Options are: css, sass, less, and stylus</p>
</td>
</tr><tr>
<td>options.dictionary</td><td><code>Object</code></td><td><p>The dictionary object that gets passed to the formatter method.</p>
</td>
</tr><tr>
<td>dictionary</td><td><code>Object</code></td><td></td><td><p>The dictionary object that gets passed to the formatter method.</p>
<td>options.outputReferences</td><td><code>Boolean</code></td><td><p>Whether or not to output references</p>
</td>
</tr><tr>
<td>outputReferences</td><td><code>Boolean</code></td><td><code>false</code></td><td><p>Whether or not to output references</p>
<td>options.formatting</td><td><code>Object</code></td><td><p>Custom formatting properties that define parts of a declaration line in code. This will get passed to <code>formatHelpers.createPropertyFormatter</code> and used for the <code>lineSeparator</code> between lines of code.</p>
</td>
</tr> </tbody>
</table>
Expand Down
2 changes: 1 addition & 1 deletion examples/advanced/custom-file-header/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const version = require('./package.json').version;
const {fileHeader} = StyleDictionary.formatHelpers;

const myCustomFormat = ({ dictionary, file }) => {
return `${fileHeader(file, 'short')}${dictionary.allProperties.map(token => {
return `${fileHeader({file, commentStyle: 'short'})}${dictionary.allProperties.map(token => {
return `--${token.name}: ${token.value};`
}).join(`\n`)}`
}
Expand Down
2 changes: 1 addition & 1 deletion examples/advanced/variables-in-outputs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function(dictionary) {
// the `dictionary` object now has `usesReference()` and
// `getReferences()` methods. `usesReference()` will return true if
// the value has a reference in it. `getReferences()` will return
// the reference to the whole token so that you can access its
// an array of references to the whole tokens so that you can access its
// name or any other attributes.
if (dictionary.usesReference(token.original.value)) {
const reference = dictionary.getReferences(token.original.value);
Expand Down
2 changes: 1 addition & 1 deletion examples/advanced/variables-in-outputs/sd.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {
// the `dictionary` object now has `usesReference()` and
// `getReferences()` methods. `usesReference()` will return true if
// the value has a reference in it. `getReferences()` will return
// the reference to the whole token so that you can access its
// an array of references to the whole tokens so that you can access its
// name or any other attributes.
if (dictionary.usesReference(token.original.value)) {
const reference = dictionary.getReferences(token.original.value);
Expand Down
54 changes: 32 additions & 22 deletions lib/common/formatHelpers/fileHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,37 @@
// no-op default
const defaultFileHeader = (arr) => arr

const defaultFormatting = {
lineSeparator: '\n',
prefix: '',
header: '',
footer: ''
}

/**
*
* This is for creating the comment at the top of generated files with the generated at date.
* It will use the custom file header if defined on the configuration, or use the
* default file header.
* @memberof module:formatHelpers
* @param {File} file - The file object that is passed to the formatter.
* @param {String} commentStyle - The only options are 'short' and 'xml', which will use the // or \<!-- --> style comments respectively. Anything else will use \/\* style comments.
* @param {Object} options
* @param {File} options.file - The file object that is passed to the formatter.
* @param {String} options.commentStyle - The only options are 'short' and 'xml', which will use the // or \<!-- --> style comments respectively. Anything else will use \/\* style comments.
* @param {Object} options.formatting - Custom formatting properties that define parts of a comment in code. The configurable strings are: prefix, lineSeparator, header, and footer.
* @returns {String}
* @example
* ```js
* StyleDictionary.registerFormat({
* name: 'myCustomFormat',
* formatter: function({ dictionary, file }) {
* return fileHeader(file, 'short') +
* return fileHeader({file, 'short') +
* dictionary.allProperties.map(token => `${token.name} = ${token.value}`)
* .join('\n');
* }
* });
* ```
*/
function fileHeader(file, commentStyle) {
function fileHeader({file, commentStyle, formatting={}}) {
// showFileHeader is true by default
let showFileHeader = true;
if (file.options && typeof file.options.showFileHeader !== 'undefined') {
Expand All @@ -55,26 +64,27 @@ function fileHeader(file, commentStyle) {
`Do not edit directly`,
`Generated on ${new Date().toUTCString()}`
];
let commentPrefix, commentHeader, commentFooter;
if (showFileHeader) {
if (commentStyle === 'short') {
commentPrefix = '// ';
commentHeader = '\n';
commentFooter = '\n\n';
} else if (commentStyle === 'xml') {
commentPrefix = ' ';
commentHeader = '<!--\n';
commentFooter = '\n-->';
} else {
commentPrefix = ' * ';
commentHeader = '/**\n';
commentFooter = '\n */\n\n';
}


let {prefix, lineSeparator, header, footer} = Object.assign({}, defaultFormatting, formatting);

if (commentStyle === 'short') {
prefix = `// `;
header = `${lineSeparator}`;
footer = `${lineSeparator}${lineSeparator}`;
} else if (commentStyle === 'xml') {
prefix = ` `;
header = `<!--${lineSeparator}`;
footer = `${lineSeparator}-->`;
} else {
prefix = ` * `;
header = `/**${lineSeparator}`;
footer = `${lineSeparator} */${lineSeparator}${lineSeparator}`;
}

return `${commentHeader}${fn(defaultHeader)
.map(line => `${commentPrefix}${line}`)
.join('\n')}${commentFooter}`;
return `${header}${fn(defaultHeader)
.map(line => `${prefix}${line}`)
.join(lineSeparator)}${footer}`;
Copy link
Collaborator

Choose a reason for hiding this comment

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

❤️

}

module.exports = fileHeader;
20 changes: 14 additions & 6 deletions lib/common/formatHelpers/formattedVariables.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@
const createPropertyFormatter = require('./createPropertyFormatter');
const sortByReference = require('./sortByReference');

const defaultFormatting = {
lineSeparator: '\n',
}

/**
*
* This is used to create lists of variables like Sass variables or CSS custom properties
* @memberof module:formatHelpers
* @param {String} format - What type of variables to output. Options are: css, sass, less, and stylus
* @param {Object} dictionary - The dictionary object that gets passed to the formatter method.
* @param {Boolean} outputReferences - Whether or not to output references
* @param {Object} options
* @param {String} options.format - What type of variables to output. Options are: css, sass, less, and stylus
* @param {Object} options.dictionary - The dictionary object that gets passed to the formatter method.
* @param {Boolean} options.outputReferences - Whether or not to output references
* @param {Object} options.formatting - Custom formatting properties that define parts of a declaration line in code. This will get passed to `formatHelpers.createPropertyFormatter` and used for the `lineSeparator` between lines of code.
* @returns {String}
* @example
* ```js
Expand All @@ -32,9 +38,11 @@ const sortByReference = require('./sortByReference');
* });
* ```
*/
function formattedVariables(format, dictionary, outputReferences = false) {
function formattedVariables({format, dictionary, outputReferences=false, formatting={}}) {
let {allProperties} = dictionary;

let {lineSeparator} = Object.assign({}, defaultFormatting, formatting);

// Some languages are imperative, meaning a variable has to be defined
// before it is used. If `outputReferences` is true, check if the token
// has a reference, and if it does send it to the end of the array.
Expand All @@ -48,9 +56,9 @@ function formattedVariables(format, dictionary, outputReferences = false) {
}

return allProperties
.map(createPropertyFormatter({ outputReferences, dictionary, format }))
.map(createPropertyFormatter({ outputReferences, dictionary, format, formatting }))
.filter(function(strVal) { return !!strVal })
.join('\n');
.join(lineSeparator);
}

module.exports = formattedVariables;
34 changes: 19 additions & 15 deletions lib/common/formats.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ module.exports = {
*/
'css/variables': function({dictionary, options={}, file}) {
const selector = options.selector ? options.selector : `:root`;
return fileHeader(file) +
const { outputReferences } = options;
return fileHeader({file}) +
`${selector} {\n` +
formattedVariables('css', dictionary, options.outputReferences) +
formattedVariables({format: 'css', dictionary, outputReferences}) +
`\n}\n`;
},

Expand Down Expand Up @@ -130,8 +131,9 @@ module.exports = {
* ```
*/
'scss/variables': function({dictionary, options, file}) {
return fileHeader(file, 'short') +
formattedVariables('sass', dictionary, options.outputReferences);
const { outputReferences } = options;
return fileHeader({file, commentStyle: 'short'}) +
formattedVariables({format: 'sass', dictionary, outputReferences});
},

/**
Expand All @@ -146,7 +148,7 @@ module.exports = {
* ```
*/
'scss/icons': function({dictionary, options, file}) {
return fileHeader(file, 'short') + iconsWithPrefix('$', dictionary.allProperties, options);
return fileHeader({file, commentStyle: 'short'}) + iconsWithPrefix('$', dictionary.allProperties, options);
},

/**
Expand All @@ -164,8 +166,9 @@ module.exports = {
* ```
*/
'less/variables': function({dictionary, options, file}) {
return fileHeader(file, 'short') +
formattedVariables('less', dictionary, options.outputReferences);
const { outputReferences } = options;
return fileHeader({file, commentStyle: 'short'}) +
formattedVariables({format: 'less', dictionary, outputReferences});
},

/**
Expand All @@ -180,7 +183,7 @@ module.exports = {
* ```
*/
'less/icons': function({dictionary, options, file}) {
return fileHeader(file, 'short') + iconsWithPrefix('@', dictionary.allProperties, options);
return fileHeader({file, commentStyle: 'short'}) + iconsWithPrefix('@', dictionary.allProperties, options);
},

/**
Expand All @@ -195,8 +198,9 @@ module.exports = {
* ```
*/
'stylus/variables': function({dictionary, options, file}) {
return fileHeader(file, 'short') +
formattedVariables('stylus', dictionary, options.outputReferences);
const { outputReferences } = options;
return fileHeader({file, commentStyle: 'short'}) +
formattedVariables({format: 'stylus', dictionary, outputReferences});
},

/**
Expand All @@ -218,7 +222,7 @@ module.exports = {
* ```
*/
'javascript/module': function({dictionary, file}) {
return fileHeader(file) +
return fileHeader({file}) +
'module.exports = ' +
JSON.stringify(dictionary.properties, null, 2) + ';';
},
Expand All @@ -236,7 +240,7 @@ module.exports = {
*```
*/
'javascript/module-flat': function({dictionary, file}) {
return fileHeader(file) +
return fileHeader({file}) +
'module.exports = ' +
module.exports['json/flat']({dictionary}) + ';';
},
Expand All @@ -261,7 +265,7 @@ module.exports = {
* ```
*/
'javascript/object': function({dictionary, file}) {
return fileHeader(file) +
return fileHeader({file}) +
'var ' +
(file.name || '_styleDictionary') +
' = ' +
Expand Down Expand Up @@ -301,7 +305,7 @@ module.exports = {
*/
'javascript/umd': function({dictionary, file}) {
var name = file.name || '_styleDictionary'
return fileHeader(file) +
return fileHeader({file}) +
'(function(root, factory) {\n' +
' if (typeof module === "object" && module.exports) {\n' +
' module.exports = factory();\n' +
Expand Down Expand Up @@ -350,7 +354,7 @@ module.exports = {
* ```
*/
'javascript/es6': function({dictionary, file}) {
return fileHeader(file) +
return fileHeader({file}) +
dictionary.allProperties.map(function(prop) {
var to_ret_prop = 'export const ' + prop.name + ' = ' + JSON.stringify(prop.value) + ';';
if (prop.comment)
Expand Down
2 changes: 1 addition & 1 deletion lib/common/templates/android/colors.template
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var props = dictionary.allProperties.filter(function(prop) {
return prop.attributes.category === 'color';
});
%>
<%= fileHeader(file, 'xml') %>
<%= fileHeader({file, commentStyle: 'xml'}) %>
<resources>
<% props.forEach(function(prop) {
%><color name="<%= prop.name %>"><%= prop.value %></color><% if (prop.comment) { %><!-- <%= prop.comment %> --><% } %>
Expand Down
2 changes: 1 addition & 1 deletion lib/common/templates/android/dimens.template
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
var props = dictionary.allProperties.filter(function(prop) {
return prop.attributes.category === 'size' && prop.attributes.type !== 'font'
}); %>
<%= fileHeader(file, 'xml') %>
<%= fileHeader({file, commentStyle: 'xml'}) %>
<resources>
<% props.forEach(function(prop) {
%><dimen name="<%= prop.name %>"><%= prop.value %></dimen><% if (prop.comment) { %><!-- <%= prop.comment %> --><% } %>
Expand Down
Loading