From c621a8543579627b4dcac38542e1cc66cccab100 Mon Sep 17 00:00:00 2001 From: jorenbroekema Date: Fri, 12 Apr 2024 15:33:46 +0200 Subject: [PATCH] fix: outputReferencesTransformed util not handling object-value tokens properly --- .changeset/ninety-meals-hug.md | 5 +++++ lib/common/formatHelpers/createPropertyFormatter.js | 12 +++++++++--- lib/utils/references/outputReferencesTransformed.js | 13 +++++++++---- 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 .changeset/ninety-meals-hug.md diff --git a/.changeset/ninety-meals-hug.md b/.changeset/ninety-meals-hug.md new file mode 100644 index 000000000..32839040d --- /dev/null +++ b/.changeset/ninety-meals-hug.md @@ -0,0 +1,5 @@ +--- +'style-dictionary': patch +--- + +Hotfix to address outputReferencesTransformed util not handling object-value tokens properly. diff --git a/lib/common/formatHelpers/createPropertyFormatter.js b/lib/common/formatHelpers/createPropertyFormatter.js index fa88b101a..bc38faa12 100644 --- a/lib/common/formatHelpers/createPropertyFormatter.js +++ b/lib/common/formatHelpers/createPropertyFormatter.js @@ -193,12 +193,16 @@ export default function createPropertyFormatter({ const originalIsObject = typeof originalValue === 'object' && originalValue !== null; if (!originalIsObject) { + // TODO: find a better way to deal with object-value tokens and outputting refs + // e.g. perhaps it is safer not to output refs when the value is transformed to a non-object + // for example for CSS-like formats we always flatten to e.g. strings + // when original is object value, we replace value by matching ref.value and putting a var instead. // Due to the original.value being an object, it requires transformation, so undoing the transformation - // by replacing value with original.value is not possible. + // by replacing value with original.value is not possible. (this is the early v3 approach to outputting refs) // 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 + // this is more friendly to transitive transforms that transform the string values (v4 way of outputting refs) value = originalValue; } @@ -220,7 +224,9 @@ export default function createPropertyFormatter({ return `${prefix}${ref.name}`; } }; - value = value.replace( + // TODO: add test + // technically speaking a reference can be made to a number or boolean token, in this case we stringify it first + value = `${value}`.replace( originalIsObject ? refVal : new RegExp(`{${ref.path.join('\\.')}(\\.\\$?value)?}`, 'g'), replaceFunc, ); diff --git a/lib/utils/references/outputReferencesTransformed.js b/lib/utils/references/outputReferencesTransformed.js index fac16612e..a855f605f 100644 --- a/lib/utils/references/outputReferencesTransformed.js +++ b/lib/utils/references/outputReferencesTransformed.js @@ -12,8 +12,13 @@ export function outputReferencesTransformed(token, { dictionary, usesDtcg }) { const originalValue = usesDtcg ? token.original.$value : token.original.value; const value = usesDtcg ? token.$value : token.value; - // Check if the token's value is the same as if we were resolve references on the original value - // This checks whether the token's value has been transformed e.g. transitive transforms. - // If it has been, that means we should not be outputting refs because this would undo the work of those transforms. - return value === resolveReferences(originalValue, dictionary.tokens, { usesDtcg }); + // double check if this is a string, technically speaking the token could also be an object + // and pass the usesReferences check + if (typeof originalValue === 'string') { + // Check if the token's value is the same as if we were resolve references on the original value + // This checks whether the token's value has been transformed e.g. transitive transforms. + // If it has been, that means we should not be outputting refs because this would undo the work of those transforms. + return value === resolveReferences(originalValue, dictionary.tokens, { usesDtcg }); + } + return true; }