Skip to content

Commit

Permalink
feat: Add API to exclude tokens from JSON output
Browse files Browse the repository at this point in the history
  • Loading branch information
Francesco Longo committed Jul 12, 2023
1 parent b8caa85 commit c170063
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 15 deletions.
7 changes: 7 additions & 0 deletions src/__fixtures__/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,10 @@ export const anotherPresetWithSecondaryTheme: ThemePreset = {
...preset,
secondary: [anotherSecondaryTheme],
};

export const descriptions: Record<string, string> = {
shadow: 'shadow',
buttonShadow: 'button shadow',
boxShadow: 'box shadow',
lineShadow: 'line shadow',
};
4 changes: 4 additions & 0 deletions src/build/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export interface BuildThemedComponentsInternalParams {
designTokensFileName?: string;
/** Map between design tokens and their description */
descriptions?: Record<string, string>;
/** Tokens that need to be excluded from the JSON format because their value depends on CSS variables **/
excludedFromJson?: Array<string>;
}
/**
* Builds themed components and optionally design tokens, if not skipped.
Expand Down Expand Up @@ -63,6 +65,7 @@ export async function buildThemedComponentsInternal(params: BuildThemedComponent
designTokensFileName = 'index',
skip = [],
descriptions = {},
excludedFromJson = [],
} = params;

if (!skip.includes('design-tokens') && !designTokensOutputDir) {
Expand Down Expand Up @@ -100,6 +103,7 @@ export async function buildThemedComponentsInternal(params: BuildThemedComponent
outputDir: designTokensOutputDir,
fileName: designTokensFileName,
descriptions,
excludedFromJson,
});
await Promise.all([internalTokensTask, designTokensTask, presetTask, styleTask]);
}
167 changes: 167 additions & 0 deletions src/build/tasks/__tests__/__snapshots__/public-tokens.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,170 @@ export const buttonShadow: string;
export const boxShadow: string;
export const lineShadow: string;"
`;

exports[`writeJSONfiles generates the right content basic example 1`] = `
Object {
"contexts": Object {
"navigation": Object {
"tokens": Object {
"boxShadow-var": Object {
"$value": Object {
"dark": "purple",
"light": "purple",
},
},
"buttonShadow-var": Object {
"$value": Object {
"dark": "brown",
"light": "black",
},
},
"lineShadow-var": Object {
"$value": Object {
"dark": "purple",
"light": "black",
},
},
"shadow-var": Object {
"$value": Object {
"dark": "brown",
"light": "black",
},
},
},
},
},
"tokens": Object {
"boxShadow-var": Object {
"$value": Object {
"dark": "brown",
"light": "grey",
},
},
"buttonShadow-var": Object {
"$value": Object {
"dark": "black",
"light": "grey",
},
},
"lineShadow-var": Object {
"$value": Object {
"dark": "brown",
"light": "grey",
},
},
"shadow-var": Object {
"$value": Object {
"dark": "black",
"light": "grey",
},
},
},
}
`;

exports[`writeJSONfiles generates the right content with descriptions 1`] = `
Object {
"contexts": Object {
"navigation": Object {
"tokens": Object {
"boxShadow-var": Object {
"$description": "box shadow",
"$value": Object {
"dark": "purple",
"light": "purple",
},
},
"buttonShadow-var": Object {
"$description": "button shadow",
"$value": Object {
"dark": "brown",
"light": "black",
},
},
"lineShadow-var": Object {
"$description": "line shadow",
"$value": Object {
"dark": "purple",
"light": "black",
},
},
"shadow-var": Object {
"$description": "shadow",
"$value": Object {
"dark": "brown",
"light": "black",
},
},
},
},
},
"tokens": Object {
"boxShadow-var": Object {
"$description": "box shadow",
"$value": Object {
"dark": "brown",
"light": "grey",
},
},
"buttonShadow-var": Object {
"$description": "button shadow",
"$value": Object {
"dark": "black",
"light": "grey",
},
},
"lineShadow-var": Object {
"$description": "line shadow",
"$value": Object {
"dark": "brown",
"light": "grey",
},
},
"shadow-var": Object {
"$description": "shadow",
"$value": Object {
"dark": "black",
"light": "grey",
},
},
},
}
`;

exports[`writeJSONfiles generates the right content with excluded tokens 1`] = `
Object {
"contexts": Object {
"navigation": Object {
"tokens": Object {
"buttonShadow-var": Object {
"$value": Object {
"dark": "brown",
"light": "black",
},
},
"shadow-var": Object {
"$value": Object {
"dark": "brown",
"light": "black",
},
},
},
},
},
"tokens": Object {
"buttonShadow-var": Object {
"$value": Object {
"dark": "black",
"light": "grey",
},
},
"shadow-var": Object {
"$value": Object {
"dark": "black",
"light": "grey",
},
},
},
}
`;
41 changes: 30 additions & 11 deletions src/build/tasks/__tests__/public-tokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import { join } from 'path';
import fs from 'fs';
import { preset, presetWithSecondaryTheme, defaultsResolution } from '../../../__fixtures__/common';
import { preset, presetWithSecondaryTheme, defaultsResolution, descriptions } from '../../../__fixtures__/common';
import { renderJS, renderSCSS, renderTS, writeJSONfiles } from '../public-tokens';

const propertiesMap = preset.propertiesMap;
Expand All @@ -23,16 +23,35 @@ test('renderTS matches previous snapshot', () => {

describe('writeJSONfiles', () => {
const fileName = 'index';
test('with primary theme only', async () => {
const outputDir = join(__dirname, 'out', 'first');
await writeJSONfiles(preset, outputDir, fileName);
expect(fs.readFileSync(join(outputDir, 'index-root.json'), 'utf-8')).toBeDefined();
expect(() => fs.readFileSync(join(outputDir, 'index-secondary.json'), 'utf-8')).toThrowError();
describe('generates the right files', () => {
test('with primary theme only', async () => {
const outputDir = join(__dirname, 'out', 'first');
await writeJSONfiles(preset, outputDir, fileName);
expect(fs.readFileSync(join(outputDir, 'index-root.json'), 'utf-8')).toBeDefined();
expect(() => fs.readFileSync(join(outputDir, 'index-secondary.json'), 'utf-8')).toThrowError();
});
test('with primary and secondary theme', async () => {
const outputDir = join(__dirname, 'out', 'secondary');
await writeJSONfiles(presetWithSecondaryTheme, outputDir, fileName);
expect(fs.readFileSync(join(outputDir, 'index-root.json'), 'utf-8')).toBeDefined();
expect(fs.readFileSync(join(outputDir, 'index-secondary.json'), 'utf-8')).toBeDefined();
});
});
test('with primary and secondary theme', async () => {
const outputDir = join(__dirname, 'out', 'secondary');
await writeJSONfiles(presetWithSecondaryTheme, outputDir, fileName);
expect(fs.readFileSync(join(outputDir, 'index-root.json'), 'utf-8')).toBeDefined();
expect(fs.readFileSync(join(outputDir, 'index-secondary.json'), 'utf-8')).toBeDefined();
describe('generates the right content', () => {
test('basic example', async () => {
const outputDir = join(__dirname, 'out', 'third');
await writeJSONfiles(preset, outputDir, fileName);
expect(JSON.parse(fs.readFileSync(join(outputDir, 'index-root.json'), 'utf-8'))).toMatchSnapshot();
});
test('with descriptions', async () => {
const outputDir = join(__dirname, 'out', 'fourth');
await writeJSONfiles(preset, outputDir, fileName, descriptions);
expect(JSON.parse(fs.readFileSync(join(outputDir, 'index-root.json'), 'utf-8'))).toMatchSnapshot();
});
test('with excluded tokens', async () => {
const outputDir = join(__dirname, 'out', 'fifth');
await writeJSONfiles(preset, outputDir, fileName, {}, ['boxShadow', 'lineShadow']);
expect(JSON.parse(fs.readFileSync(join(outputDir, 'index-root.json'), 'utf-8'))).toMatchSnapshot();
});
});
});
16 changes: 12 additions & 4 deletions src/build/tasks/public-tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@ import { ThemePreset, SpecificResolution } from '../../shared/theme';
import { toSassName } from '../token';
import { Token } from '../../shared/theme/interfaces';
import { getThemeJSON } from './theme-json';
import difference from 'lodash/difference';

interface PublicTokensTaskParams {
resolution: SpecificResolution;
preset: ThemePreset;
outputDir: string;
fileName: string;
descriptions?: Record<string, string>;
excludedFromJson?: Array<string>;
}

export async function createPublicTokenFiles(params: PublicTokensTaskParams) {
const { resolution, preset, outputDir, fileName, descriptions = {} } = params;
const { resolution, preset, outputDir, fileName, descriptions = {}, excludedFromJson } = params;
const { variablesMap, propertiesMap, exposed } = preset;
await Promise.all([
writeFile(join(outputDir, `${fileName}.scss`), renderSCSS(resolution, variablesMap, propertiesMap, exposed)),
writeFile(join(outputDir, `${fileName}.js`), renderJS(resolution, propertiesMap, exposed)),
writeFile(join(outputDir, `${fileName}.d.ts`), renderTS(exposed)),
writeJSONfiles(preset, outputDir, fileName, descriptions),
writeJSONfiles(preset, outputDir, fileName, descriptions, excludedFromJson),
]);
}

Expand Down Expand Up @@ -51,14 +53,20 @@ export async function writeJSONfiles(
preset: ThemePreset,
outputDir: string,
fileName: string,
descriptions?: Record<string, string>
descriptions?: Record<string, string>,
excluded?: Array<string>
) {
const { theme, secondary = [], exposed, variablesMap } = preset;
const actuallyExposed = difference(exposed, excluded || []);
return Promise.all(
[theme, ...secondary].map((currentTheme) =>
writeFile(
join(outputDir, `${fileName}-${currentTheme.id}.json`),
JSON.stringify(getThemeJSON({ theme: currentTheme, exposed, variablesMap, descriptions }), null, 2)
JSON.stringify(
getThemeJSON({ theme: currentTheme, exposed: actuallyExposed, variablesMap, descriptions }),
null,
2
)
)
)
);
Expand Down

0 comments on commit c170063

Please sign in to comment.