tokens-studio / sd-transforms

Custom transforms for Style-Dictionary, to work with Design Tokens that are exported from Tokens Studio
MIT License
185 stars 28 forks source link

[Bug]: Suisse Int'l font family transform issue / special character transform issue #222

Closed niborium closed 9 months ago

niborium commented 9 months ago

What happened?

In my token.json i have:

      "suisse-intl": {
        "value": "Suisse Int'l",
        "type": "fontFamilies"
      }
    },

Which include special character `

css is like this (as example):
--sdFontFamilySuisseIntl: 'Suisse Int'l';

Which is not valid CSS (it breaks the CSS syntax).
When you have a font name that contains spaces or special characters, you need to wrap it in quotes. replace ' ' with " " or should we try to esacpeing \ the single quote by adding like: 'Suisse Int\'l'

Wrote to Joren on Slack and he confirmed this: "I think that should be handled by the font family transform, which is the function that introduces the single quotes when a font-family has spaces"

"It should escape any occurences of ' automatically, but we don't have this logic implemented yet,"

"https://github.com/tokens-studio/sd-transforms/blob/main/src/css/transformTypography.ts#L19 this is the function btw that wraps font-families in '' which needs to deal with escaping already existing ' in the font family name"

Reproduction

link to reprod

Expected output

Should probable be esacpeing \ the single quote by adding like: 'Suisse Int\'l'

for this kind of cases (as described above).

Version

@tokens-studio/sd-transforms": "^0.11.6" in React

niborium commented 9 months ago

@jorenbroekema My proposal to resolve the issue would be something like:

export function escapeApostrophes(value: string): string {
  return value.replace(/'/g, "\\'");
}

function quoteWrapWhitespacedFont(fontString: string) {
    let escapedFontString = escapeApostrophes(fontString);
    return hasWhiteSpace(escapedFontString) && !isAlreadyQuoted(escapedFontString) ? `'${escapedFontString}'` : escapedFontString;
}

In this updated version:

escapeApostrophes is a new function that takes a string and replaces every apostrophe with an escaped apostrophe. It uses the replace method with a regular expression /'/g that matches all occurrences of an apostrophe and replaces them with \' (the double backslash is needed because backslash is an escape character in JavaScript strings).

In the quoteWrapWhitespacedFont (exisiting function), the input string is first passed to escapeApostrophes to ensure all apostrophes are properly escaped. Then, the rest of the function proceeds as before, but uses the escaped string for the checks and final return value.

This should resolve the issue with breaking CSS when the string contains apostrophes.

Don't know if there is a more eloquent way but this seem minimalistic :) escapeApostrophes can also be reused in other functions as needed in cases with special characters (to escape apostrophes).

If you don't want it in quoteWrapWhitespacedFont it can be added to processFontFamily function and use the escapeApostrophes instead there also.

[2023-11-16] Updated quoteWrapWhitespacedFont function after found issue (See PR/commits).