amzn / style-dictionary

A build system for creating cross-platform styles.
https://styledictionary.com
Apache License 2.0
3.93k stars 557 forks source link

Documentation for getReferences #1202

Open okadurin opened 6 months ago

okadurin commented 6 months ago

Here is a proposal for the documentation update for getReferences (it is not actual documentation but the description of the topic that could be explained more detailed). In v4 getReferences throws the error if it cannot find a reference definition in the given dictionary. In v3 as a fallback it was fetching the value from the include array.

Consider the following configuration after migrating to v4 from v3:

const config = {
    include,
    source,
    platforms: {
      css: {
        buildPath,
        files: [
          {
            //...            
            filter: (/** @type {{ isSource: boolean; }} */ token) => token.isSource,
          },
        ],
      },
    },
  };

And then there is a formatter defined as follows:

StyleDictionary.registerFormat({
    name: 'test-ts/android/test',
    async format({ dictionary, file, options }) {
      const { outputReferences } = options;
      return (
        `<?xml version="1.0" encoding="UTF-8"?>` +
        `\n${await fileHeader({ file, commentStyle: 'xml' })}\n` +
        `<resources>` +
        `\n` +
        `${dictionary.allTokens          
          .map(token => {
            // ...
            if (outputReferences) {
              if (usesReferences(token.original.value, dictionary.tokens)) {
                const refs = getReferences(token.original.value, dictionary.tokens);
                refs.forEach(ref => {
                    // do some tasks with refs
                });
              }
            }
            //...
            return parsedValue;
          })
          .join(`\n`)}` +
        `\n</resources>`
      );
    },

This code is going to fail when calling getReferences and when the source array does not contain one of references definition which is defined in the include array. In v3 that was not an issue since getReferences was fetching the value from the include array as a fallback. The new code appoach in v4 for the case above would be removing token.isSource filter from the file configuration and move it into the registerFormat as follows:

StyleDictionary.registerFormat({
    name: 'test-ts/android/test',
    async format({ dictionary, file, options }) {
      const { outputReferences } = options;
      return (
        `<?xml version="1.0" encoding="UTF-8"?>` +
        `\n${await fileHeader({ file, commentStyle: 'xml' })}\n` +
        `<resources>` +
        `\n` +
        `${dictionary.allTokens      
          .filter(token => token.isSource)     //<------------------ This filter was moved from `files` JSON configuration into `registerFormat`         
          .map(token => {
          //...

Not sure though how much of a value this kind of information will bring to other customers. Hence feel free to close the issue if you think it is too specific and does not target the majority of users.

jorenbroekema commented 6 months ago

The fix here that you could have used is:

getReferences(token.original.value, dictionary.unfilteredTokens);

The tokens property is the tokens object after it's been filtered, same for allTokens, that's filtered, and just a flattened version of it. There's also a property unfilteredTokens which is the tokens object without it being filtered, and you can use the flattenTokens utility if you want it in flat array structure similar to allTokens (maybe we should add an unfilteredAllTokens prop for ease of use)

I definitely agree that should be documented, perhaps someone would like to contribute this?

okadurin commented 6 months ago

Thank you a lot! I will use your solution