diff --git a/__tests__/common/formatHelpers/createPropertyFormatter.test.js b/__tests__/common/formatHelpers/createPropertyFormatter.test.js new file mode 100644 index 000000000..c9cb40bdd --- /dev/null +++ b/__tests__/common/formatHelpers/createPropertyFormatter.test.js @@ -0,0 +1,105 @@ +/* + * 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 createPropertyFormatter = require('../../../lib/common/formatHelpers/createPropertyFormatter'); +const createDictionary = require('../../../lib/utils/createDictionary'); + +const dictionary = createDictionary({ + properties: { + tokens: { + foo: { + original: { + value: '5px', + type: 'spacing' + }, + attributes: { + category: 'tokens', + type: 'foo' + }, + name: 'tokens-foo', + path: ['tokens', 'foo'], + value: '5px', + type: 'spacing' + }, + bar: { + original: { + value: '{tokens.foo}', + type: 'spacing' + }, + attributes: { + category: 'tokens', + type: 'bar' + }, + name: 'tokens-bar', + path: ['tokens', 'bar'], + value: '5px', + type: 'spacing' + }, + } + } +}); + +const transformedDictionary = createDictionary({ + properties: { + tokens: { + foo: { + original: { + value: '5px', + type: 'spacing' + }, + attributes: { + category: 'tokens', + type: 'foo' + }, + name: 'tokens-foo', + path: ['tokens', 'foo'], + value: '5px', + type: 'spacing' + }, + bar: { + original: { + value: '{tokens.foo}', + type: 'spacing' + }, + attributes: { + category: 'tokens', + type: 'bar' + }, + name: 'tokens-bar', + path: ['tokens', 'bar'], + value: 'changed by transitive transform', + type: 'spacing' + }, + } + } +}); + + + + +describe('common', () => { + describe('formatHelpers', () => { + describe('createPropertyFormatter', () => { + it('should support outputReferences', () => { + const propFormatter = createPropertyFormatter({ outputReferences: true, dictionary, format: 'css' }) + expect(propFormatter(dictionary.tokens.tokens.foo)).toEqual(' --tokens-foo: 5px;'); + expect(propFormatter(dictionary.tokens.tokens.bar)).toEqual(' --tokens-bar: var(--tokens-foo);'); + }) + + it('should support outputReferences when values are transformed by (transitive) "value" transforms', () => { + const propFormatter = createPropertyFormatter({ outputReferences: true, dictionary, format: 'css' }) + expect(propFormatter(transformedDictionary.tokens.tokens.foo)).toEqual(' --tokens-foo: 5px;'); + expect(propFormatter(transformedDictionary.tokens.tokens.bar)).toEqual(' --tokens-bar: var(--tokens-foo);'); + }) + }) + }) +}) \ No newline at end of file diff --git a/lib/common/formatHelpers/createPropertyFormatter.js b/lib/common/formatHelpers/createPropertyFormatter.js index 150785f59..01f72a727 100644 --- a/lib/common/formatHelpers/createPropertyFormatter.js +++ b/lib/common/formatHelpers/createPropertyFormatter.js @@ -106,13 +106,22 @@ function createPropertyFormatter({ // or else you will get '[object Object]' in the output if (typeof value === 'string') { const refs = dictionary.getReferences(prop.original.value); + + // original can either be string value or an object value + const originalIsString = typeof prop.original.value === 'string'; + + // Set the value to the original value with refs first, undoing value-changing transitive transforms + if (originalIsString) { + value = 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() { + const replaceFunc = function() { if (format === 'css') { if (outputReferenceFallbacks) { return `var(${prefix}${ref.name}, ${ref.value})`; @@ -122,7 +131,11 @@ function createPropertyFormatter({ } else { return `${prefix}${ref.name}`; } - }); + } + // when original is object value, we replace value by matching ref.value and putting a var instead + // when original is string value, we replace value by matching original.value and putting a var instead + // this is more friendly to transitive transforms that transform the string values + value = value.replace(originalIsString ? new RegExp(`{${ref.path.join('.')}(.value)?}`, 'g') : ref.value, replaceFunc); } }); }