Skip to content

Commit

Permalink
fix(transforms): fix transitive transforms (#476)
Browse files Browse the repository at this point in the history
backwards compatibility for the transitive transforms functionality, turns it from a breaking change into a non-breaking change
  • Loading branch information
dbanksdesign authored Oct 12, 2020
1 parent 3edbb17 commit ac0c515
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 27 deletions.
1 change: 1 addition & 0 deletions __tests__/exportPlatform.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ describe('exportPlatform', () => {
StyleDictionaryExtended.registerTransform({
type: 'value',
name: 'color/darken',
transitive: true,
matcher: function(prop) { return !!prop.original.transformColor; },
transformer: function(prop) { return prop.value + '-darker'; }
});
Expand Down
2 changes: 2 additions & 0 deletions lib/register/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var transformTypes = ['name', 'value', 'attribute'];
* @param {Object} transform - Transform object
* @param {String} transform.type - Type of transform, can be: name, attribute, or value
* @param {String} transform.name - Name of the transformer (used by transformGroup to call a list of transforms).
* @param {Boolean} transform.transitive - If the value transform should be applied transitively, i.e. should be applied to referenced values as well as absolute values.
* @param {Function} [transform.matcher] - Matcher function, return boolean if transform should be applied. If you omit the matcher function, it will match all properties.
* @param {Function} transform.transformer Performs a transform on a property object, should return a string or object depending on the type. Will only update certain properties by which you can't mess up property objects on accident.
* @returns {module:style-dictionary}
Expand Down Expand Up @@ -59,6 +60,7 @@ function registerTransform(options) {
this.transform[options.name] = {
type: options.type,
matcher: options.matcher,
transitive: !!options.transitive,
transformer: options.transformer
};

Expand Down
59 changes: 34 additions & 25 deletions lib/transform/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,50 +42,59 @@ function transformObject(obj, options, transformationContext = {}, path, transfo
}

path.push(name);

const pathName = getName(path);
const objProp = obj[name];
const alreadyTransformed = transformedPropRefs.indexOf(pathName) !== -1;
const isPlainObject = _.isPlainObject(objProp);
const transformationNeeded = !alreadyTransformed && isPlainObject;

if (!transformationNeeded) {
transformedObj[name] = objProp;
path.pop();
continue;
}

// is the objProp a style property?
// {
// value: "#ababab"
// ...
// }
if ('value' in objProp) {
if (isPlainObject && 'value' in objProp) {
const pathName = getName(path);
const alreadyTransformed = transformedPropRefs.indexOf(pathName) !== -1;

// If the property is already transformed, just pass assign it to the
// transformed object and move on.
if (alreadyTransformed) {
transformedObj[name] = objProp;
path.pop();
continue;
}

// Note: propertySetup won't re-run if property has already been setup
// it is safe to run this multiple times on the same property.
const setupProperty = propertySetup(objProp, name, path);

// If property has a reference, defer its transformations until later
if (usesValueReference(setupProperty.value, options)) {
deferredPropValueTransforms.push(pathName);
// If property path isn't in the deferred array, add it now.
if (deferredPropValueTransforms.indexOf(pathName) === -1) {
deferredPropValueTransforms.push(pathName);
}

transformedObj[name] = setupProperty;
path.pop();
continue;
}

const transformedObjectValue = transformProperty(setupProperty, options);
// If we got here, the property hasn't been transformed yet and
// does not use a value reference. Transform the property now and assign it.
transformedObj[name] = transformProperty(setupProperty, options);
// Remove the property path from the deferred transform list
_.pull(deferredPropValueTransforms, pathName);

// transformed anything?
if (setupProperty.value !== transformedObjectValue.value) {
transformedPropRefs.push(pathName);
}

transformedObj[name] = transformedObjectValue;
path.pop();
continue;
// Add the property path to the transformed list so we don't transform it again.
transformedPropRefs.push(pathName);
} else if (isPlainObject) {
// objProp is not a token -> go deeper down the object tree
transformedObj[name] = transformObject(objProp, options, transformationContext, path, transformedObj[name]);
} else {
// objProp is not a token or an object then it is some other data in the
// object we should just copy over. There might be metadata
// like documentation in the object that is not part of a token/property.
transformedObj[name] = objProp;
}

// objectValue is not a property -> go deeper down the object tree
transformedObj[name] = {};
transformObject(objProp, options, transformationContext, path, transformedObj[name]);
path.pop();
}

Expand Down
10 changes: 8 additions & 2 deletions lib/transform/property.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,14 @@ function transformProperty(property, options) {
to_ret.name = transform.transformer(to_ret, options);
// Don't try to transform the value if it is referencing another value
// Only try to transform if the value is not a string or if it has '{}'
if (transform.type === 'value' && !usesReference(property.value, options))
to_ret.value = transform.transformer(to_ret, options);
if (transform.type === 'value' && !usesReference(property.value, options)) {
// Only transform non-referenced values (from original)
// and transitive transforms if the value has been resolved
if (!usesReference(property.original.value, options) || transform.transitive) {
to_ret.value = transform.transformer(to_ret, options);
}
}

if (transform.type === 'attribute')
to_ret.attributes = _.extend({}, to_ret.attributes, transform.transformer(to_ret, options));
}
Expand Down

0 comments on commit ac0c515

Please sign in to comment.