/* * 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. */ const defaultFormatting = { prefix: '', commentStyle: 'long', indentation: '', separator: ' =', suffix: ';' } /** * Creates a function that can be used to format a property. This can be useful * to use as the function on `dictionary.allTokens.map`. The formatting * is configurable either by supplying a `format` option or a `formatting` object * which uses: prefix, indentation, separator, suffix, and commentStyle. * @memberof module:formatHelpers * @example * ```javascript * StyleDictionary.registerFormat({ * name: 'myCustomFormat', * formatter: function({ dictionary, options }) { * const { outputReferences } = options; * const formatProperty = createPropertyFormatter({ * outputReferences, * dictionary, * format: 'css' * }); * return dictionary.allTokens.map(formatProperty).join('\n'); * } * }); * ``` * @param {Object} options * @param {Boolean} options.outputReferences - Whether or not to output references. You will want to pass this from the `options` object sent to the formatter function. * @param {Dictionary} options.dictionary - The dictionary object sent to the formatter function * @param {String} options.format - Available formats are: 'css', 'sass', 'less', and 'stylus'. If you want to customize the format and can't use one of those predefined formats, use the `formatting` option * @param {Object} options.formatting - Custom formatting properties that define parts of a declaration line in code. The configurable strings are: prefix, indentation, separator, suffix, and commentStyle. Those are used to generate a line like this: `${indentation}${prefix}${prop.name}${separator} ${prop.value}${suffix}` * @returns {Function} */ function createPropertyFormatter({outputReferences, dictionary, format, formatting={}}) { let {prefix, commentStyle, indentation, separator, suffix} = Object.assign({}, defaultFormatting, formatting); switch(format) { case 'css': prefix = '--'; indentation = ' '; separator = ':'; break; case 'sass': prefix = '$'; commentStyle = 'short'; indentation = ''; separator = ':'; break; case 'less': prefix = '@'; commentStyle = 'short'; indentation = ''; separator = ':'; break; case 'stylus': prefix = '$'; commentStyle = 'short'; indentation = ''; separator = '='; break; } return function(prop) { let to_ret_prop = `${indentation}${prefix}${prop.name}${separator} `.replace('--dark-', '--').replace('--light-', '--'); let value = prop.value; /** * A single value can have multiple references either by interpolation: * "value": "{size.border.width.value} solid {color.border.primary.value}" * or if the value is an object: * "value": { * "size": "{size.border.width.value}", * "style": "solid", * "color": "{color.border.primary.value"} * } * This will see if there are references and if there are, replace * the resolved value with the reference's name. */ if (outputReferences && dictionary.usesReference(prop.original.value)) { // Formats that use this function expect `value` to be a string // or else you will get '[object Object]' in the output if (typeof value === 'string') { const refs = dictionary.getReferences(prop.original.value); refs.forEach(ref => { // value should be a string that contains the resolved reference // because Style Dictionary resolved this in the resolution step. // Here we are undoing that by replacing the value with // the reference's name if (ref.value && ref.name) { value = value.replace(ref.value, function() { if (format === 'css') { return `var(${prefix}${ref.name})` } else { return `${prefix}${ref.name}`; } }); } }); } } to_ret_prop += prop.attributes.category === 'asset' ? `"${value}"` : value; if (format == 'sass' && prop.themeable === true) { to_ret_prop += ' !default'; } to_ret_prop += suffix; if (prop.comment && commentStyle !== 'none') { if (commentStyle === 'short') { to_ret_prop = to_ret_prop.concat(` // ${prop.comment}`); } else { to_ret_prop = to_ret_prop.concat(` /* ${prop.comment} */`); } } return to_ret_prop; } } module.exports = createPropertyFormatter;