Skip to content

Commit

Permalink
feat: move cli design tokens to paragon cli
Browse files Browse the repository at this point in the history
  • Loading branch information
monteri committed Sep 8, 2023
1 parent 09570d7 commit 4b3e0b0
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 200 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ build:
rm -rf dist/**/__snapshots__
rm -rf dist/__mocks__
rm -rf dist/setupTest.js
node build-scss.js
./bin/paragon-scripts.js build-scss

export TRANSIFEX_RESOURCE = paragon
transifex_langs = "ar,ca,es_419,fr,he,id,ko_KR,pl,pt_BR,ru,th,uk,zh_CN,es_AR,es_ES,pt_PT,tr_TR,it_IT"
Expand Down
10 changes: 8 additions & 2 deletions bin/paragon-scripts.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
#!/usr/bin/env node
const chalk = require('chalk');
const themeCommand = require('../lib/install-theme');
const buildTokensCommand = require('../lib/build-tokens');
const replaceVariablesCommand = require('../lib/replace-variables');
const buildScssCommand = require('../lib/build-scss');

// command: executor function
const COMMANDS = {
'install-theme': themeCommand,
'build-tokens': buildTokensCommand,
'replace-variables': replaceVariablesCommand,
'build-scss': buildScssCommand,
};

(async () => {
const [command] = process.argv.slice(2);
const [command, ...commandArgs] = process.argv.slice(2);
const executor = COMMANDS[command];

if (!executor) {
Expand All @@ -18,7 +24,7 @@ const COMMANDS = {
}

try {
await executor();
await executor(commandArgs);
} catch (error) {
// eslint-disable-next-line no-console
console.error(chalk.red.bold('An error occurred:', error.message));
Expand Down
102 changes: 27 additions & 75 deletions build-scss.js → lib/build-scss.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env node
const fs = require('fs');
const sass = require('sass');
const postCSS = require('postcss');
Expand All @@ -8,7 +7,7 @@ const postCSSMinify = require('postcss-minify');
const combineSelectors = require('postcss-combine-duplicated-selectors');
const { pathToFileURL } = require('url');
const path = require('path');
const { program, Option } = require('commander');
const minimist = require('minimist');

const paragonThemeOutputFilename = 'theme-urls.json';

Expand Down Expand Up @@ -133,79 +132,32 @@ const compileAndWriteStyleSheets = ({
});
};

program
.version('0.0.1')
.description('CLI to compile Paragon\'s core and themes\' SCSS into CSS.')
.addOption(
new Option(
'--corePath <corePath>',
'Path to the theme\'s core SCSS file, defaults to Paragon\'s core.scss.',
),
)
.addOption(
new Option(
'--themesPath <themesPath>',
`Path to the directory that contains themes' files. Expects directory to have following structure:
themes/
light/
│ ├─ index.css
│ ├─ other_css_files
dark/
│ ├─ index.css
│ ├─ other_css_files
some_other_custom_theme/
│ ├─ index.css
│ ├─ other_css_files
...
where index.css has imported all other CSS files in the theme's subdirectory. The script will output
light.css, dark.css and some_other_custom_theme.css files (together with maps and minified versions).
You can provide any amount of themes. Default to paragon's themes.
`,
),
)
.addOption(
new Option(
'--outDir <outDir>',
'Specifies directory where to out resulting CSS files.',
),
)
.addOption(
new Option(
'--defaultThemeVariants <defaultThemeVariants...>',
`Specifies default theme variants. Defaults to a single 'light' theme variant.
You can provide multiple default theme variants by passing multiple values, for
example: \`--defaultThemeVariants light dark\`
`,
),
);
function buildScssCommand(commandArgs) {
const argv = minimist(commandArgs);
const corePath = argv.corePath || path.resolve(process.cwd(), 'styles/scss/core/core.scss');
const themesPath = argv.themesPath || path.resolve(process.cwd(), 'styles/css/themes');
const outDir = argv.outDir || './dist';
const defaultThemeVariants = argv.defaultThemeVariants ? argv.defaultThemeVariants.split(',') : ['light'];

program.parse(process.argv);

const options = program.opts();
const {
corePath = path.resolve(__dirname, 'styles/scss/core/core.scss'),
themesPath = path.resolve(__dirname, 'styles/css/themes'),
outDir = './dist',
defaultThemeVariants = ['light'],
} = options;

// Core CSS
compileAndWriteStyleSheets({
name: 'core',
stylesPath: corePath,
outDir,
});
// Core CSS
compileAndWriteStyleSheets({
name: 'core',
stylesPath: corePath,
outDir,
});

// Theme Variants CSS
fs.readdirSync(themesPath, { withFileTypes: true })
.filter((item) => item.isDirectory())
.forEach((themeDir) => {
compileAndWriteStyleSheets({
name: themeDir.name,
stylesPath: `${themesPath}/${themeDir.name}/index.css`,
outDir,
isThemeVariant: true,
isDefaultThemeVariant: defaultThemeVariants.includes(themeDir.name),
// Theme Variants CSS
fs.readdirSync(themesPath, { withFileTypes: true })
.filter((item) => item.isDirectory())
.forEach((themeDir) => {
compileAndWriteStyleSheets({
name: themeDir.name,
stylesPath: `${themesPath}/${themeDir.name}/index.css`,
outDir,
isThemeVariant: true,
isDefaultThemeVariant: defaultThemeVariants.includes(themeDir.name),
});
});
});
}

module.exports = buildScssCommand;
99 changes: 99 additions & 0 deletions lib/build-tokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const path = require('path');
const minimist = require('minimist');
const { StyleDictionary, colorTransform, createCustomCSSVariables } = require('../tokens/style-dictionary');
const { createIndexCssFile } = require('../tokens/utils');

async function buildTokensCommand(commandArgs) {
const args = minimist(commandArgs);
const buildDir = args['build-dir'] || './build/';
const tokensSource = args.source;
const hasSourceTokensOnly = Boolean(args['source-tokens-only']);
const themes = args.themes || ['light'];

const coreConfig = {
include: [path.resolve(__dirname, 'src/core/**/*.json')],
source: tokensSource ? [`${tokensSource}/core/**/*.json`] : [],
platforms: {
css: {
prefix: 'pgn',
transformGroup: 'css',
// NOTE: buildPath must end with a slash
buildPath: buildDir.slice(-1) === '/' ? buildDir : `${buildDir}/`,
files: [
{
format: 'css/custom-variables',
destination: 'core/variables.css',
filter: hasSourceTokensOnly ? 'isSource' : undefined,
options: {
outputReferences: !hasSourceTokensOnly,
},
},
{
format: 'css/custom-media-breakpoints',
destination: 'core/custom-media-breakpoints.css',
filter: hasSourceTokensOnly ? 'isSource' : undefined,
options: {
outputReferences: !hasSourceTokensOnly,
},
},
],
transforms: StyleDictionary.transformGroup.css.filter(item => item !== 'size/rem').concat('color/sass-color-functions', 'str-replace'),
options: {
fileHeader: 'customFileHeader',
},
},
},
};

const getStyleDictionaryConfig = (themeVariant) => ({
...coreConfig,
include: [...coreConfig.include, path.resolve(__dirname, `src/themes/${themeVariant}/**/*.json`)],
source: tokensSource ? [`${tokensSource}/themes/${themeVariant}/**/*.json`] : [],
transform: {
'color/sass-color-functions': {
...StyleDictionary.transform['color/sass-color-functions'],
transformer: (token) => colorTransform(token, themeVariant),
},
},
format: {
'css/custom-variables': formatterArgs => createCustomCSSVariables({
formatterArgs,
themeVariant,
}),
},
platforms: {
css: {
...coreConfig.platforms.css,
files: [
{
format: 'css/custom-variables',
destination: `themes/${themeVariant}/variables.css`,
filter: hasSourceTokensOnly ? 'isSource' : undefined,
options: {
outputReferences: !hasSourceTokensOnly,
},
},
{
format: 'css/utility-classes',
destination: `themes/${themeVariant}/utility-classes.css`,
filter: hasSourceTokensOnly ? 'isSource' : undefined,
options: {
outputReferences: !hasSourceTokensOnly,
},
},
],
},
},
});

StyleDictionary.extend(coreConfig).buildAllPlatforms();
createIndexCssFile({ buildDir, isTheme: false });

themes.forEach((themeVariant) => {
const config = getStyleDictionaryConfig(themeVariant);
StyleDictionary.extend(config).buildAllPlatforms();
createIndexCssFile({ buildDir, isTheme: true, themeVariant });
});
}

module.exports = buildTokensCommand;
21 changes: 21 additions & 0 deletions lib/replace-variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const minimist = require('minimist');
const { transformInPath } = require('../tokens/utils');
const mapSCSStoCSS = require('../tokens/map-scss-to-css');

async function replaceVariablesCommand(commandArgs) {
const args = minimist(commandArgs);
const filePath = args.p || args.filePath;
const sourcePath = args.s || args.source;
const replacementType = args.t || args.replacementType;
const direction = args.d || args.direction;

const variablesMap = mapSCSStoCSS(sourcePath);

if (replacementType === 'usage') {
await transformInPath(filePath, variablesMap, 'usage', [], direction);
} else {
await transformInPath(filePath, variablesMap);
}
}

module.exports = replaceVariablesCommand;
9 changes: 4 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 5 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
"module": "dist/index.js",
"license": "Apache-2.0",
"bin": {
"build-design-tokens": "./tokens/build-tokens.js",
"replace-scss-with-css": "./tokens/replace-variables.js",
"build-scss": "./build-scss.js",
"paragon": "./bin/paragon-scripts.js"
},
"publishConfig": {
Expand Down Expand Up @@ -51,9 +48,9 @@
"build-types": "tsc --emitDeclarationOnly",
"playroom:start": "npm run playroom:start --workspace=www",
"playroom:build": "npm run playroom:build --workspace=www",
"build-tokens": "node tokens/build-tokens.js --build-dir ./styles/css",
"replace-variables-usage-with-css": "node tokens/replace-variables.js -p src -t usage",
"replace-variables-definition-with-css": "node tokens/replace-variables.js -p src -t definition"
"build-tokens": "./bin/paragon-scripts.js build-tokens --build-dir ./styles/css",
"replace-variables-usage-with-css": "./bin/paragon-scripts.js replace-variables -p src -t usage",
"replace-variables-definition-with-css": "./bin/paragon-scripts.js replace-variables -p src -t definition"
},
"dependencies": {
"@popperjs/core": "^2.11.4",
Expand All @@ -65,10 +62,11 @@
"commander": "^9.4.1",
"email-prop-type": "^3.0.0",
"file-selector": "^0.6.0",
"inquirer": "^8.2.5",
"glob": "^8.0.3",
"inquirer": "^8.2.5",
"lodash.uniqby": "^4.7.0",
"mailto-link": "^2.0.0",
"minimist": "^1.2.8",
"postcss": "^8.4.21",
"postcss-combine-duplicated-selectors": "^10.0.3",
"postcss-custom-media": "^9.1.2",
Expand Down
Loading

0 comments on commit 4b3e0b0

Please sign in to comment.