Skip to content

Commit

Permalink
Style(exporter-variables-scss): Set quotes with better escaping
Browse files Browse the repository at this point in the history
  • Loading branch information
literat authored and curdaj committed Sep 26, 2024
1 parent 6483542 commit 3e74fac
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 52 deletions.
12 changes: 12 additions & 0 deletions exporters/variables-scss/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,16 @@ module.exports = {
ecmaVersion: 'latest',
project: './tsconfig.eslint.json',
},

rules: {
// Conflicting with the Prettier configuration fo the line length
// We are leaving this up to developer to decide where to use braces and where implicit return
// @see { @link https://eslint.org/docs/latest/rules/arrow-body-style }
'arrow-body-style': 'off',

// Better handling quotes with escaped strings inside
// Double and backticks quotes are allowed when needed
// @see { @link https://eslint.org/docs/latest/rules/quotes }
quotes: ['warn', 'single', { avoidEscape: true }],
},
};
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { Supernova, Token, TokenGroup, TokenTheme } from '@supernovaio/sdk-exporters';
import fs from 'fs';
import path from 'path';
import { Supernova, Token, TokenGroup, TokenTheme } from '@supernovaio/sdk-exporters';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { exampleGroups } from '../../../tests/fixtures/exampleGroups';
import { nonThemedFilesData } from '../../config/fileConfig';
import {
generateFiles,
generateBarrelFile,
generateFiles,
generateOutputFilesByThemes,
generateRootThemesFileContent,
generateRootThemesFileImports,
generateThemesRootFile,
jsImportStatement,
scssImportStatement,
} from '../fileGenerator';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { nonThemedFilesData } from '../../config/fileConfig';
import { exampleGroups } from '../../../tests/fixtures/exampleGroups';

const mockedExpectedResult = fs.readFileSync(
path.join(__dirname, '../../../tests/fixtures/exampleFileContent.scss'),
'utf-8',
);
const mappedTokens: Map<string, Token> = new Map([]);
const tokenGroups: Array<TokenGroup> = exampleGroups;
const emptyFile = `/* This file was generated by Supernova, don't change manually */\n\n`;
const emptyFile = "/* This file was generated by Supernova, don't change manually */\n\n";
const barrelFile = fs.readFileSync(path.join(__dirname, '../__fixtures__/barrelFileMock.scss'), 'utf-8');
const barrelColorFile = `@forward 'colors';\n`;
const barrelColorFile = "@forward 'colors';\n";
const barrelJsFile = `export * from './borders';
export * from './other';
export * from './radii';
Expand All @@ -32,7 +32,7 @@ export * from './shadows';
export * from './gradients';
export * from './typography';
`;
const barrelJsColorFile = `export * from './colors';\n`;
const barrelJsColorFile = "export * from './colors';\n";

const mockedTsFile = `/* This file was generated by Supernova, don't change manually */
export const gridSpacingDesktop = '32px';\n
Expand Down Expand Up @@ -97,8 +97,8 @@ describe('fileGenerator', () => {
{ path: './scss/global/', fileName: 'index.scss', content: barrelFile },
{ path: './js/global/', fileName: 'index.ts', content: barrelJsFile },
// Root barrel files
{ path: './scss/', fileName: '@global.scss', content: `@forward 'global';\n` },
{ path: './js/', fileName: '@global.ts', content: `export * from './global';\n` },
{ path: './scss/', fileName: '@global.scss', content: "@forward 'global';\n" },
{ path: './js/', fileName: '@global.ts', content: "export * from './global';\n" },
// Themes files
{ path: './scss/themes/theme-light/', fileName: '_colors.scss', content: emptyFile },
{ path: './js/themes/theme-light/', fileName: 'colors.ts', content: emptyFile },
Expand Down Expand Up @@ -140,15 +140,15 @@ describe('fileGenerator', () => {
{
files: [{ fileName: 'borders', content: emptyFile }],
description: 'should generate barrel file with one file',
expectedBarrelFile: `@forward 'borders';\n`,
expectedBarrelFile: "@forward 'borders';\n",
},
{
files: [
{ fileName: 'borders', content: emptyFile },
{ fileName: 'other', content: mockedExpectedResult },
],
description: 'should generate barrel file with multiple files',
expectedBarrelFile: `@forward 'borders';\n@forward 'other';\n`,
expectedBarrelFile: "@forward 'borders';\n@forward 'other';\n",
},
{
files: [
Expand All @@ -157,7 +157,7 @@ describe('fileGenerator', () => {
],
description: 'should generate barrel file with one file with js output',
hasJsOutput: true,
expectedBarrelFile: `export * from './borders';\nexport * from './other';\n`,
expectedBarrelFile: "export * from './borders';\nexport * from './other';\n",
},
];

Expand Down Expand Up @@ -190,7 +190,8 @@ describe('fileGenerator', () => {
const content = generateRootThemesFileContent(themes as TokenTheme[], false);

expect(content).toBe(
`theme-light: (\ncolors: theme-light.$colors,\n),\ntheme-light-inverted: (\ncolors: theme-light-inverted.$colors,\n),`,
// eslint-disable-next-line prettier/prettier, quotes -- special characters in the string
'theme-light: (\ncolors: theme-light.$colors,\n),\ntheme-light-inverted: (\ncolors: theme-light-inverted.$colors,\n),',
);
});

Expand All @@ -199,7 +200,8 @@ describe('fileGenerator', () => {
const content = generateRootThemesFileContent(themes as TokenTheme[], true);

expect(content).toBe(
`themeLight: {\ncolors: themeLight.colors\n},\nthemeLightInverted: {\ncolors: themeLightInverted.colors\n},`,
// eslint-disable-next-line prettier/prettier, quotes -- special characters in the string
'themeLight: {\ncolors: themeLight.colors\n},\nthemeLightInverted: {\ncolors: themeLightInverted.colors\n},',
);
});
});
Expand All @@ -209,15 +211,15 @@ describe('fileGenerator', () => {
const themes = [{ name: 'theme-light' }, { name: 'theme-light-inverted' }];
const content = generateRootThemesFileImports(themes as TokenTheme[], false);

expect(content).toBe(`@use 'themes/theme-light';\n@use 'themes/theme-light-inverted';`);
expect(content).toBe("@use 'themes/theme-light';\n@use 'themes/theme-light-inverted';");
});

it('should generate root themes file imports with js output', () => {
const themes = [{ name: 'theme-light' }, { name: 'theme-light-inverted' }];
const content = generateRootThemesFileImports(themes as TokenTheme[], true);

expect(content).toBe(
`import * as themeLight from './themes/theme-light';\nimport * as themeLightInverted from './themes/theme-light-inverted';`,
"import * as themeLight from './themes/theme-light';\nimport * as themeLightInverted from './themes/theme-light-inverted';",
);
});
});
Expand All @@ -226,15 +228,15 @@ describe('fileGenerator', () => {
it('should generate js import statement', () => {
const content = jsImportStatement('theme-light');

expect(content).toBe(`import * as themeLight from './themes/theme-light';`);
expect(content).toBe("import * as themeLight from './themes/theme-light';");
});
});

describe('scssImportStatement', () => {
it('should generate scss import statement', () => {
const content = scssImportStatement('theme-light');

expect(content).toBe(`@use 'themes/theme-light';`);
expect(content).toBe("@use 'themes/theme-light';");
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import {
TokenGroup,
TokenType,
} from '@supernovaio/sdk-exporters';
import { generateStylesFromTokens, tokenToStyleByType } from '../stylesGenerator';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { exampleColorsTokens } from '../../../tests/fixtures/exampleColorTokens';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { exampleGradientTokens } from '../../../tests/fixtures/exampleGradientTokens';
import { exampleGroups } from '../../../tests/fixtures/exampleGroups';
import { exampleShadowTokens } from '../../../tests/fixtures/exampleShadowTokens';
import { exampleGradientTokens } from '../../../tests/fixtures/exampleGradientTokens';
import { generateStylesFromTokens, tokenToStyleByType } from '../stylesGenerator';

const mappedTokens: Map<string, Token> = new Map([]);
const tokenGroups: Array<TokenGroup> = exampleGroups;
Expand Down Expand Up @@ -64,47 +64,48 @@ describe('stylesGenerator', () => {
description: 'dimension type token with parent prefix and js output',
hasParentPrefix: true,
hasJsOutput: true,
expectedStyles: `export const gridSpacingDesktop = '32px';`,
expectedStyles: "export const gridSpacingDesktop = '32px';",
},
{
token: exampleDimensionAndStringTokens.get('dimensionRef') as DimensionToken,
description: 'dimension type token without parent prefix and js output',
hasParentPrefix: false,
hasJsOutput: true,
expectedStyles: `export const desktop = '32px';`,
expectedStyles: "export const desktop = '32px';",
},
{
token: exampleDimensionAndStringTokens.get('stringRef') as StringToken,
description: 'string type token with parent prefix and js output',
hasParentPrefix: true,
hasJsOutput: true,
expectedStyles: `export const gridColumns = '12';`,
expectedStyles: "export const gridColumns = '12';",
},
{
token: exampleDimensionAndStringTokens.get('stringRef') as StringToken,
description: 'string type token without parent prefix and js output',
hasParentPrefix: false,
hasJsOutput: true,
expectedStyles: `export const columns = '12';`,
expectedStyles: "export const columns = '12';",
},
{
token: exampleShadowTokens.get('shadowRef') as ShadowToken,
description: 'shadow type token without parent prefix',
hasParentPrefix: false,
hasJsOutput: false,
expectedStyles: `$shadow-100: 0 2px 8px 0 #00000026 !default;`,
expectedStyles: '$shadow-100: 0 2px 8px 0 #00000026 !default;',
},
{
token: exampleGradientTokens.get('gradientRef') as GradientToken,
description: 'gradient type token without parent prefix',
hasParentPrefix: false,
hasJsOutput: false,
expectedStyles: `$basic-overlay: linear-gradient(var(--gradient-angle, 90deg), #ffffffff 0%, #ffffff00 100%) !default;`,
expectedStyles:
'$basic-overlay: linear-gradient(var(--gradient-angle, 90deg), #ffffffff 0%, #ffffff00 100%) !default;',
},
];

it.each(dataProvider)(
`should correctly generate styles for $description`,
'should correctly generate styles for $description',
({ token, expectedStyles, hasParentPrefix, hasJsOutput }) => {
const styles = tokenToStyleByType(token, mappedTokens, tokenGroups, hasParentPrefix, hasJsOutput);

Expand All @@ -129,39 +130,40 @@ describe('stylesGenerator', () => {
hasJsOutput: true,
hasParentPrefix: true,
description: 'should generate styles from tokens with js output',
expectedStyles: `export const gridColumns = '12';\n\nexport const gridSpacingDesktop = '32px';`,
expectedStyles: "export const gridColumns = '12';\n\nexport const gridSpacingDesktop = '32px';",
},
{
tokens: exampleColorsTokens,
groupName: '',
hasJsOutput: false,
hasParentPrefix: false,
description: 'should generate styles from tokens with colors',
expectedStyles: `$active: #ca2026 !default;\n\n$primary: #fff !default;`,
expectedStyles: '$active: #ca2026 !default;\n\n$primary: #fff !default;',
},
{
tokens: exampleColorsTokens,
groupName: '',
hasJsOutput: true,
hasParentPrefix: false,
description: 'should generate styles from tokens with colors with js output',
expectedStyles: `export const active = '#ca2026';\n\nexport const primary = '#fff';`,
expectedStyles: "export const active = '#ca2026';\n\nexport const primary = '#fff';",
},
{
tokens: exampleShadowTokens,
groupName: '',
hasJsOutput: false,
hasParentPrefix: false,
description: 'should generate styles from tokens with shadows',
expectedStyles: `$shadow-100: 0 2px 8px 0 #00000026 !default;`,
expectedStyles: '$shadow-100: 0 2px 8px 0 #00000026 !default;',
},
{
tokens: exampleGradientTokens,
groupName: '',
hasJsOutput: false,
hasParentPrefix: false,
description: 'should generate styles from tokens with gradients',
expectedStyles: `$basic-overlay: linear-gradient(var(--gradient-angle, 90deg), #ffffffff 0%, #ffffff00 100%) !default;`,
expectedStyles:
'$basic-overlay: linear-gradient(var(--gradient-angle, 90deg), #ffffffff 0%, #ffffff00 100%) !default;',
},
];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Token, TokenGroup, TypographyToken } from '@supernovaio/sdk-exporters';
import { exampleColorsTokens } from '../../../tests/fixtures/exampleColorTokens';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { exampleGroups } from '../../../tests/fixtures/exampleGroups';
import { exampleTypographyTokens } from '../../../tests/fixtures/exampleTypographyTokens';
import {
colorGroupsReducer,
createGlobalColorsObject,
createGlobalTypographyObject,
createStylesObjectStructureFromTokenNameParts,
StylesObjectType,
generateStylesObjectFromTokens,
handleTypographyTokens,
parseGroupName,
createGlobalTypographyObject,
StylesObjectType,
typographyGroupReducer,
handleTypographyTokens,
} from '../stylesObjectGenerator';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { exampleColorsTokens } from '../../../tests/fixtures/exampleColorTokens';
import { exampleTypographyTokens } from '../../../tests/fixtures/exampleTypographyTokens';
import { exampleGroups } from '../../../tests/fixtures/exampleGroups';

const mappedTokens: Map<string, Token> = new Map([]);
const tokenGroups: Array<TokenGroup> = exampleGroups;
Expand Down Expand Up @@ -93,10 +93,12 @@ describe('stylesObjectGenerator', () => {
moveToTheEnd: 'true',
},
headingXlargeBold: {
desktop: `{\nfontFamily: "'Inter', sans-serif",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}`,
desktop:
"{\nfontFamily: \"'Inter', sans-serif\",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}",
},
headingXlargeBoldUnderline: {
desktop: `{\nfontFamily: "'Inter', sans-serif",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}`,
desktop:
"{\nfontFamily: \"'Inter', sans-serif\",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}",
},
},
description: 'should generate object from typography tokens with js output',
Expand Down Expand Up @@ -170,14 +172,17 @@ describe('stylesObjectGenerator', () => {
token: exampleTypographyTokens.get('typographyRef1') as Token,
expectedObject: {
headingXlargeBold: {
desktop: `{\nfontFamily: "'Inter', sans-serif",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}`,
tablet: `{\nfontFamily: "'Inter', sans-serif",\nfontSize: '32px',\nfontStyle: 'normal',\nfontWeight: 500,\nlineHeight: 1,\n}`,
desktop:
"{\nfontFamily: \"'Inter', sans-serif\",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}",
tablet:
"{\nfontFamily: \"'Inter', sans-serif\",\nfontSize: '32px',\nfontStyle: 'normal',\nfontWeight: 500,\nlineHeight: 1,\n}",
},
},
description: 'should create object structure from typography token with js output',
stylesObjectRef: {
headingXlargeBold: {
tablet: `{\nfontFamily: "'Inter', sans-serif",\nfontSize: '32px',\nfontStyle: 'normal',\nfontWeight: 500,\nlineHeight: 1,\n}`,
tablet:
"{\nfontFamily: \"'Inter', sans-serif\",\nfontSize: '32px',\nfontStyle: 'normal',\nfontWeight: 500,\nlineHeight: 1,\n}",
},
} as StylesObjectType,
hasJsOutput: true,
Expand Down Expand Up @@ -218,7 +223,8 @@ describe('stylesObjectGenerator', () => {
expectedStyles: {
exampleRef: 'exampleRef',
headingXlargeBold: {
desktop: `{\nfontFamily: "'Inter', sans-serif",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}`,
desktop:
"{\nfontFamily: \"'Inter', sans-serif\",\nfontSize: '64px',\nfontStyle: 'normal',\nfontWeight: 700,\nlineHeight: 1.2,\n}",
},
},
description: 'should generate object from typography tokens with js output',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Token, TokenGroup, TypographyToken } from '@supernovaio/sdk-exporters';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { exampleGroups } from '../../../tests/fixtures/exampleGroups';
import { exampleTypographyTokens, expectedTypographyValue } from '../../../tests/fixtures/exampleTypographyTokens';
import {
addAngleVarToGradient,
addEmptyLineBetweenTokenGroups,
Expand All @@ -7,9 +10,6 @@ import {
tokenVariableName,
typographyValue,
} from '../tokenHelper';
import { exampleDimensionAndStringTokens } from '../../../tests/fixtures/exampleDimensionAndStringTokens';
import { exampleTypographyTokens, expectedTypographyValue } from '../../../tests/fixtures/exampleTypographyTokens';
import { exampleGroups } from '../../../tests/fixtures/exampleGroups';

const dataProvider = [
{
Expand Down Expand Up @@ -63,7 +63,7 @@ describe('tokenHelper', () => {

const result = formatTokenStyleByOutput(name, value, true, unit);

expect(result).toBe(`export const gridSpacingDesktop = '32px';`);
expect(result).toBe("export const gridSpacingDesktop = '32px';");
});

it('should return the expected formatted token name for js output without unit', () => {
Expand All @@ -72,7 +72,7 @@ describe('tokenHelper', () => {

const result = formatTokenStyleByOutput(name, value, true);

expect(result).toBe(`export const gridColumns = 12;`);
expect(result).toBe('export const gridColumns = 12;');
});

it('should return the expected formatted token for zero values with unit', () => {
Expand Down

0 comments on commit 3e74fac

Please sign in to comment.