From 72a71e0b93cf153e60b55020523bb70fb1b34f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Wed, 20 Mar 2019 19:40:56 +0100 Subject: [PATCH] Emit TS types for variables extracted from sass --- package.json | 2 +- scripts/compile-scss.js | 40 ++++++++++++-- scripts/derive-sass-variable-types.js | 75 +++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 scripts/derive-sass-variable-types.js diff --git a/package.json b/package.json index cb77c589009e..d7444155a9d5 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test-docker": "docker pull $npm_package_docker_image && docker run --rm -i -e GIT_COMMITTER_NAME=test -e GIT_COMMITTER_EMAIL=test --user=$(id -u):$(id -g) -e HOME=/tmp -v $(pwd):/app -w /app $npm_package_docker_image bash -c 'npm config set spin false && /opt/yarn*/bin/yarn && npm run test && npm run build'", "sync-docs": "node ./scripts/docs-sync.js", "build-docs": "webpack --config=src-docs/webpack.config.js", - "build": "yarn extract-i18n-strings && node ./scripts/compile-clean.js && node ./scripts/compile-eui.js && node ./scripts/compile-scss.js", + "build": "yarn extract-i18n-strings && node ./scripts/compile-clean.js && node ./scripts/compile-eui.js && node ./scripts/compile-scss.js $npm_package_name", "extract-i18n-strings": "node ./scripts/babel/fetch-i18n-strings", "lint": "yarn lint-es && yarn lint-ts && yarn lint-sass && yarn lint-framer", "lint-fix": "yarn lint-es-fix && yarn lint-ts-fix", diff --git a/scripts/compile-scss.js b/scripts/compile-scss.js index 5b55277893ac..c66b2ea2bd73 100755 --- a/scripts/compile-scss.js +++ b/scripts/compile-scss.js @@ -6,6 +6,7 @@ const globModule = require('glob'); const chalk = require('chalk'); const postcss = require('postcss'); const sassExtract = require('sass-extract'); +const { deriveSassVariableTypes } = require('./derive-sass-variable-types'); const sassExtractJsPlugin = require('./sass-extract-js-plugin'); const postcssConfiguration = require('../src-docs/postcss.config.js'); @@ -22,7 +23,11 @@ const postcssConfigurationWithMinification = { ], }; -async function compileScssFiles(sourcePattern, destinationDirectory) { +async function compileScssFiles( + sourcePattern, + destinationDirectory, + packageName +) { try { await mkdir(destinationDirectory); } catch (err) { @@ -42,7 +47,9 @@ async function compileScssFiles(sourcePattern, destinationDirectory) { const outputFilenames = await compileScssFile( inputFilename, path.join(destinationDirectory, `eui_${name}.css`), - path.join(destinationDirectory, `eui_${name}.json`) + path.join(destinationDirectory, `eui_${name}.json`), + path.join(destinationDirectory, `eui_${name}.json.d.ts`), + packageName ); console.log( @@ -64,7 +71,9 @@ async function compileScssFiles(sourcePattern, destinationDirectory) { async function compileScssFile( inputFilename, outputCssFilename, - outputVarsFilename + outputVarsFilename, + outputVarTypesFilename, + packageName ) { const outputCssMinifiedFilename = outputCssFilename.replace( /\.css$/, @@ -81,6 +90,12 @@ async function compileScssFile( } ); + const extractedVarTypes = await deriveSassVariableTypes( + extractedVars, + `${packageName}/${outputVarsFilename}`, + outputVarTypesFilename + ); + const { css: postprocessedCss } = await postcss(postcssConfiguration).process( renderedCss, { @@ -100,9 +115,24 @@ async function compileScssFile( writeFile(outputCssFilename, postprocessedCss), writeFile(outputCssMinifiedFilename, postprocessedMinifiedCss), writeFile(outputVarsFilename, JSON.stringify(extractedVars, undefined, 2)), + writeFile(outputVarTypesFilename, extractedVarTypes), ]); - return [outputCssFilename, outputVarsFilename]; + return [ + outputCssFilename, + outputCssMinifiedFilename, + outputVarsFilename, + outputVarTypesFilename, + ]; } -compileScssFiles(path.join('src', 'theme_*.scss'), 'dist'); +if (require.main === module) { + const [nodeBin, scriptName, euiPackageName] = process.argv; + + if (process.argv.length < 3) { + console.log(chalk`{bold Usage:} ${nodeBin} ${scriptName} eui-package-name`); + process.exit(1); + } + + compileScssFiles(path.join('src', 'theme_*.scss'), 'dist', euiPackageName); +} diff --git a/scripts/derive-sass-variable-types.js b/scripts/derive-sass-variable-types.js new file mode 100644 index 000000000000..f910421f62d5 --- /dev/null +++ b/scripts/derive-sass-variable-types.js @@ -0,0 +1,75 @@ +const ts = require('typescript'); +const prettier = require('prettier'); + +async function deriveSassVariableTypes( + extractedVars, + extractedVarsModuleName, + extractedVarTypesFilename +) { + const extractedVarsModuleDeclaration = ts.createModuleDeclaration( + undefined, + [ts.createModifier(ts.SyntaxKind.DeclareKeyword)], + ts.createStringLiteral(extractedVarsModuleName), + ts.createModuleBlock([ + ts.createVariableStatement( + undefined, + ts.createVariableDeclarationList( + [ + ts.createVariableDeclaration( + 'sassVariables', + deriveValueType(extractedVars) + ), + ], + ts.NodeFlags.Const + ) + ), + ts.createExportAssignment( + undefined, + undefined, + undefined, + ts.createIdentifier('sassVariables') + ), + ]), + ts.NodeFlags.None + ); + + const moduleSource = ts + .createPrinter({ newLine: ts.NewLineKind.LineFeed }) + .printNode( + ts.EmitHint.Unspecified, + extractedVarsModuleDeclaration, + ts.createSourceFile(extractedVarTypesFilename, '', ts.ScriptTarget.Latest) + ); + + const prettierOptions = await prettier.resolveConfig(extractedVarTypesFilename); + const prettifiedModuleSource = prettier.format(moduleSource, prettierOptions); + + return prettifiedModuleSource; +} + +function deriveValueType(extractedValue) { + switch (typeof extractedValue) { + case 'object': + return ts.createTypeLiteralNode( + Object.keys(extractedValue).map(key => + ts.createPropertySignature( + undefined, + ts.createStringLiteral(key), + undefined, + deriveValueType(extractedValue[key]), + undefined + ) + ) + ); + case 'string': + return ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); + case 'number': + return ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); + default: + return ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); + } +} + +module.exports = { + deriveSassVariableTypes, +};