-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BD-46] feat: move CLI design tokens commands to paragon CLI #2609
Changes from 9 commits
b6feb1b
6b74e21
9381af4
ff2569c
21c659d
ebba492
3032258
e9eedf9
1de83ba
db966ac
bca0f30
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,7 +61,10 @@ The Paragon CLI (Command Line Interface) is a tool that provides various utility | |
|
||
### Available Commands | ||
|
||
- `paragon install-theme [theme]`: Installs the specific @edx/brand package. | ||
- `paragon install-theme [theme]`: Installs the specific [@edx/brand](https://github.com/edx/brand-edx.org) package. | ||
- `build-tokens`: Build Paragon's design tokens. | ||
- `replace-variables`: Replace SCSS variables usages or definitions to CSS variables and vice versa in `.scss` files. | ||
- `build-scss`: Compile Paragon's core and themes SCSS into CSS. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it makes sense to be consistent, updated it to |
||
|
||
Use `paragon help` to see more information. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,9 @@ | |
const chalk = require('chalk'); | ||
const themeCommand = require('../lib/install-theme'); | ||
const helpCommand = require('../lib/help'); | ||
const buildTokensCommand = require('../lib/build-tokens'); | ||
const replaceVariablesCommand = require('../lib/replace-variables'); | ||
const buildScssCommand = require('../lib/build-scss'); | ||
|
||
const HELP_COMMAND = 'help'; | ||
|
||
|
@@ -25,6 +28,9 @@ const COMMANDS = { | |
* { | ||
* name: '--optionName', | ||
* description: 'optionDescription', | ||
* choices: 'optionChoices', | ||
* defaultValue: 'optionDefaultValue', | ||
* required: true/false, | ||
* }, | ||
* ... | ||
* ], | ||
|
@@ -43,14 +49,130 @@ const COMMANDS = { | |
}, | ||
], | ||
}, | ||
'build-tokens': { | ||
executor: buildTokensCommand, | ||
description: 'CLI to build Paragon design tokens.', | ||
options: [ | ||
{ | ||
name: '-s, --source', | ||
description: 'Specify the source directory for design tokens.', | ||
defaultValue: '\'\'', | ||
}, | ||
{ | ||
name: '-b, --build-dir', | ||
description: 'Specify the build directory for the generated tokens.', | ||
defaultValue: './build/', | ||
}, | ||
{ | ||
name: '--source-tokens-only', | ||
description: 'Include only source design tokens in the build.', | ||
defaultValue: false, | ||
}, | ||
{ | ||
name: '-t, --themes', | ||
description: 'Specify themes to include in the token build.', | ||
defaultValue: 'light', | ||
}, | ||
], | ||
}, | ||
'replace-variables': { | ||
executor: replaceVariablesCommand, | ||
description: 'CLI to replace SCSS variables usages or definitions to CSS variables and vice versa in .scss files.', | ||
parameters: [ | ||
{ | ||
name: '-p, --filePath', | ||
description: 'Path to the file or directory where to replace variables.', | ||
defaultValue: '\'\'', | ||
}, | ||
], | ||
options: [ | ||
{ | ||
name: '-s, --source', | ||
description: 'Type of replacement: usage or definition. If set to "definition" the command will only update SCSS variables definitions with CSS variables, if set to "usage" - all occurrences of SCSS variables will we replaced', | ||
defaultValue: '\'\'', | ||
}, | ||
{ | ||
name: '-t, --replacementType', | ||
description: 'Type of replacement: usage or definition. If set to "definition" the command will only update SCSS variables definitions with CSS variables, if set to "usage" - all occurrences of SCSS variables will we replaced', | ||
choices: '[usage|definition]', | ||
defaultValue: 'definition', | ||
}, | ||
{ | ||
name: '-d, --direction', | ||
description: 'Map direction: css-to-scss or scss-to-css, if replacement type parameter is set to "definition" this has no effect.', | ||
choices: '[scss-to-css|css-to-scss]', | ||
defaultValue: 'scss-to-css', | ||
}, | ||
], | ||
}, | ||
'build-scss': { | ||
executor: buildScssCommand, | ||
description: 'CLI to compile Paragon\'s core and themes SCSS into CSS.', | ||
options: [ | ||
{ | ||
name: '--corePath', | ||
description: 'Path to the theme\'s core SCSS file, defaults to Paragon\'s core.scss.', | ||
defaultValue: 'styles/scss/core/core.scss', | ||
}, | ||
{ | ||
name: '--themesPath', | ||
description: `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. | ||
`, | ||
defaultValue: 'styles/css/themes', | ||
}, | ||
{ | ||
name: '--outDir', | ||
description: 'Specifies directory where to out resulting CSS files.', | ||
defaultValue: './dist', | ||
}, | ||
{ | ||
name: '--defaultThemeVariants', | ||
description: `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\` | ||
`, | ||
defaultValue: 'light', | ||
}, | ||
], | ||
}, | ||
help: { | ||
executor: helpCommand, | ||
parameters: [ | ||
{ | ||
name: 'command', | ||
description: 'Specifies command name.', | ||
defaultValue: '\'\'', | ||
choices: '[install-theme|build-tokens|replace-variables|build-scss]', | ||
required: false, | ||
}, | ||
], | ||
description: 'Displays help for available commands.', | ||
}, | ||
}; | ||
|
||
/** | ||
* Executes a Paragon CLI command based on the provided command-line arguments. | ||
* | ||
* @async | ||
* @function executeParagonCommand | ||
*/ | ||
viktorrusakov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(async () => { | ||
const [command] = process.argv.slice(2); | ||
const [command, ...commandArgs] = process.argv.slice(2); | ||
const executor = COMMANDS[command]; | ||
|
||
if (!executor) { | ||
|
@@ -60,12 +182,12 @@ const COMMANDS = { | |
} | ||
|
||
if (command === HELP_COMMAND) { | ||
helpCommand(COMMANDS); | ||
helpCommand(COMMANDS, commandArgs); | ||
return; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can remove this code if you define help's executor as follows: help: {
executor: (args) => helpCommand(COMMANDS, args),
... then try / catch below will be able to correctly execute help command There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Corrected |
||
|
||
try { | ||
await executor.executor(); | ||
await executor.executor(commandArgs); | ||
} catch (error) { | ||
// eslint-disable-next-line no-console | ||
console.error(chalk.red.bold('An error occurred:', error.message)); | ||
|
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'); | ||
|
@@ -8,7 +7,10 @@ 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 chalk = require('chalk'); | ||
const ora = require('ora'); | ||
const { capitalize } = require('./utils'); | ||
|
||
const paragonThemeOutputFilename = 'theme-urls.json'; | ||
|
||
|
@@ -92,17 +94,19 @@ const compileAndWriteStyleSheets = ({ | |
}, | ||
}], | ||
}); | ||
|
||
const commonPostCssPlugins = [ | ||
postCSSImport(), | ||
postCSSCustomMedia({ preserve: true }), | ||
combineSelectors({ removeDuplicatedProperties: true }), | ||
]; | ||
|
||
const postCSSCompilation = ora(`Compilation for ${capitalize(name)} stylesheet...`).start(); | ||
postCSS(commonPostCssPlugins) | ||
.process(compiledStyleSheet.css, { from: stylesPath, map: false }) | ||
.then((result) => { | ||
postCSSCompilation.succeed(`Success compilation for ${capitalize(name)} stylesheet`); | ||
fs.writeFileSync(`${outDir}/${name}.css`, result.css); | ||
|
||
postCSS([postCSSMinify()]) | ||
.process(result.css, { from: `${name}.css`, map: { inline: false } }) | ||
.then((minifiedResult) => { | ||
|
@@ -129,83 +133,50 @@ const compileAndWriteStyleSheets = ({ | |
isDefaultThemeVariant, | ||
}); | ||
} | ||
|
||
fs.writeFileSync(`${outDir}/${paragonThemeOutputFilename}`, `${JSON.stringify(paragonThemeOutput, null, 2)}\n`); | ||
}) | ||
.then(() => { | ||
ora().succeed(chalk.underline.bold.green(`Stylesheets for ${capitalize(name)} build successfully!`)); | ||
// eslint-disable-next-line no-console | ||
console.log(); | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can avoid using Also, right now it says the following when I run the command I think it would be better to change the wording to something like this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it looks better |
||
.catch((error) => { | ||
ora().fail(chalk.bold(`Failed to build stylesheets for ${capitalize(name)}: ${error.message}`)); | ||
}); | ||
}; | ||
|
||
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\` | ||
`, | ||
), | ||
); | ||
|
||
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; | ||
/** | ||
* Builds SCSS stylesheets based on the provided command arguments. | ||
* | ||
* @param {Array<string>} commandArgs - Command line arguments for building SCSS stylesheets. | ||
*/ | ||
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']; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reading through minimist docs I found that you can provide default values to args, I think we should try doing that, right now it looks a little dirty this seems to work for me locally (also, I don't think you need to split function buildScssCommand(commandArgs) {
const defaultArgs = {
corePath: path.resolve(process.cwd(), 'styles/scss/core/core.scss'),
themesPath: path.resolve(process.cwd(), 'styles/css/themes'),
outDir: './dist',
defaultThemeVariants: 'light',
};
const {
corePath,
themesPath,
outDir,
defaultThemeVariants,
} = minimist(commandArgs, { default: defaultArgs }); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks |
||
// 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should reference the openedx brand package instead of the edx.org one
https://github.com/openedx/brand-openedx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, updated, thanks.