From 60d60e95723de1e3d64ebd0bdc71d3314d67875b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Mar 2022 19:58:46 +0530 Subject: [PATCH 01/23] WIP --- package.json | 5 +- postcss/css-compile-variables.js | 87 ++++++++++++++++++++++++++++++++ yarn.lock | 30 ++++++++++- 3 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 postcss/css-compile-variables.js diff --git a/package.json b/package.json index 8fa27f47..3c007244 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "acorn": "^8.6.0", "acorn-walk": "^8.2.0", "aes-js": "^3.1.2", + "bs58": "^4.0.1", "core-js": "^3.6.5", "es6-promise": "https://github.com/bwindels/es6-promise.git#bwindels/expose-flush", "escodegen": "^2.0.0", @@ -45,13 +46,13 @@ "text-encoding": "^0.7.0", "typescript": "^4.3.5", "vite": "^2.6.14", - "xxhashjs": "^0.2.2", - "bs58": "^4.0.1" + "xxhashjs": "^0.2.2" }, "dependencies": { "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz", "another-json": "^0.2.0", "base64-arraybuffer": "^0.2.0", + "color": "^4.2.1", "dompurify": "^2.3.0" } } diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js new file mode 100644 index 00000000..2395f87d --- /dev/null +++ b/postcss/css-compile-variables.js @@ -0,0 +1,87 @@ +import { Color } from "color"; + +let aliasMap; +let resolvedMap; +const RE_VARIABLE_VALUE = /var\((--(.+)--(.+)-(.+))\)/; + +function getValueFromAlias(alias) { + const derivedVariable = aliasMap.get(`--${alias}`); + return resolvedMap.get(derivedVariable); // what if we haven't resolved this variable yet? +} + +function resolveDerivedVariable(decl, variables) { + const matches = decl.value.match(RE_VARIABLE_VALUE); + if (matches) { + const [,wholeVariable, baseVariable, operation, argument] = matches; + if (!variables[baseVariable]) { + // hmm.. baseVariable should be in config..., maybe this is an alias? + if (!aliasMap.get(`--${baseVariable}`)) { + throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); + } + } + switch (operation) { + case "darker": { + const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); + const newColorString = new Color(colorString).darken(argument / 100).hex(); + resolvedMap.set(wholeVariable, newColorString); + break; + } + case "lighter": { + const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); + const newColorString = new Color(colorString).lighten(argument / 100).hex(); + resolvedMap.set(wholeVariable, newColorString); + break; + } + } + } +} + +function extractAlias(decl) { + const RE_VARIABLE_PROP = /--(.+)/; + const wholeVariable = decl.value.match(RE_VARIABLE_VALUE)?.[1]; + if (RE_VARIABLE_PROP.test(decl.prop) && wholeVariable) { + aliasMap.set(decl.prop, wholeVariable); + } +} + +/* * + * @type {import('postcss').PluginCreator} + */ +module.exports = (opts = {}) => { + aliasMap = new Map(); + resolvedMap = new Map(); + const { variables } = opts; + return { + postcssPlugin: "postcss-compile-variables", + + Once(root) { + /* + Go through the CSS file once to extract all aliases. + We use the extracted alias when resolving derived variables + later. + */ + root.walkDecls(decl => extractAlias(decl)); + }, + + Declaration(declaration) { + resolveDerivedVariable(declaration, variables); + }, + + OnceExit(root, { Rule, Declaration }) { + const newRule = new Rule({ selector: ":root", source: root.source }) + // Add base css variables to :root + for (const [key, value] of Object.entries(variables)) { + const declaration = new Declaration({ prop: `--${key}`, value }); + newRule.append(declaration); + } + // Add derived css variables to :root + resolvedMap.forEach((value, key) => { + const declaration = new Declaration({ prop: key, value }); + newRule.append(declaration); + }); + root.append(newRule); + }, + }; +}; + +module.exports.postcss = true; diff --git a/yarn.lock b/yarn.lock index 87b8ef96..31dde2dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -332,11 +332,27 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" + integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.1.tgz#498aee5fce7fc982606c8875cab080ac0547c884" + integrity sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + colors@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -961,6 +977,11 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-core-module@^2.2.0: version "2.5.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" @@ -1342,6 +1363,13 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" From 92084e80056d5869be4f2461ed39d0013fa96452 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 7 Mar 2022 11:32:30 +0530 Subject: [PATCH 02/23] Move all code under the Once event Apparently the other events are common to all plugins. --- postcss/css-compile-variables.js | 40 +++++++++++++++----------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 2395f87d..faf46fe2 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -1,4 +1,4 @@ -import { Color } from "color"; +const Color = require("color"); let aliasMap; let resolvedMap; @@ -44,6 +44,21 @@ function extractAlias(decl) { } } +function addResolvedVariablesToRootSelector( root, variables, { Rule, Declaration }) { + const newRule = new Rule({ selector: ":root", source: root.source }); + // Add base css variables to :root + for (const [key, value] of Object.entries(variables)) { + const declaration = new Declaration({ prop: `--${key}`, value }); + newRule.append(declaration); + } + // Add derived css variables to :root + resolvedMap.forEach((value, key) => { + const declaration = new Declaration({ prop: key, value }); + newRule.append(declaration); + }); + root.append(newRule); +} + /* * * @type {import('postcss').PluginCreator} */ @@ -54,32 +69,15 @@ module.exports = (opts = {}) => { return { postcssPlugin: "postcss-compile-variables", - Once(root) { + Once(root, {Rule, Declaration}) { /* Go through the CSS file once to extract all aliases. We use the extracted alias when resolving derived variables later. */ root.walkDecls(decl => extractAlias(decl)); - }, - - Declaration(declaration) { - resolveDerivedVariable(declaration, variables); - }, - - OnceExit(root, { Rule, Declaration }) { - const newRule = new Rule({ selector: ":root", source: root.source }) - // Add base css variables to :root - for (const [key, value] of Object.entries(variables)) { - const declaration = new Declaration({ prop: `--${key}`, value }); - newRule.append(declaration); - } - // Add derived css variables to :root - resolvedMap.forEach((value, key) => { - const declaration = new Declaration({ prop: key, value }); - newRule.append(declaration); - }); - root.append(newRule); + root.walkDecls(decl => resolveDerivedVariable(decl, variables)); + addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }); }, }; }; From b6f5e68e9e1580d2b32bcb0eb74cacbd68ff4277 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 7 Mar 2022 11:33:44 +0530 Subject: [PATCH 03/23] Format file --- postcss/css-compile-variables.js | 84 ++++++++++++++++---------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index faf46fe2..125e79ca 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -5,35 +5,35 @@ let resolvedMap; const RE_VARIABLE_VALUE = /var\((--(.+)--(.+)-(.+))\)/; function getValueFromAlias(alias) { - const derivedVariable = aliasMap.get(`--${alias}`); - return resolvedMap.get(derivedVariable); // what if we haven't resolved this variable yet? + const derivedVariable = aliasMap.get(`--${alias}`); + return resolvedMap.get(derivedVariable); // what if we haven't resolved this variable yet? } function resolveDerivedVariable(decl, variables) { - const matches = decl.value.match(RE_VARIABLE_VALUE); - if (matches) { - const [,wholeVariable, baseVariable, operation, argument] = matches; - if (!variables[baseVariable]) { - // hmm.. baseVariable should be in config..., maybe this is an alias? - if (!aliasMap.get(`--${baseVariable}`)) { - throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); - } + const matches = decl.value.match(RE_VARIABLE_VALUE); + if (matches) { + const [, wholeVariable, baseVariable, operation, argument] = matches; + if (!variables[baseVariable]) { + // hmm.. baseVariable should be in config..., maybe this is an alias? + if (!aliasMap.get(`--${baseVariable}`)) { + throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); + } + } + switch (operation) { + case "darker": { + const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); + const newColorString = new Color(colorString).darken(argument / 100).hex(); + resolvedMap.set(wholeVariable, newColorString); + break; + } + case "lighter": { + const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); + const newColorString = new Color(colorString).lighten(argument / 100).hex(); + resolvedMap.set(wholeVariable, newColorString); + break; + } + } } - switch (operation) { - case "darker": { - const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = new Color(colorString).darken(argument / 100).hex(); - resolvedMap.set(wholeVariable, newColorString); - break; - } - case "lighter": { - const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = new Color(colorString).lighten(argument / 100).hex(); - resolvedMap.set(wholeVariable, newColorString); - break; - } - } - } } function extractAlias(decl) { @@ -44,7 +44,7 @@ function extractAlias(decl) { } } -function addResolvedVariablesToRootSelector( root, variables, { Rule, Declaration }) { +function addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }) { const newRule = new Rule({ selector: ":root", source: root.source }); // Add base css variables to :root for (const [key, value] of Object.entries(variables)) { @@ -63,23 +63,23 @@ function addResolvedVariablesToRootSelector( root, variables, { Rule, Declaratio * @type {import('postcss').PluginCreator} */ module.exports = (opts = {}) => { - aliasMap = new Map(); - resolvedMap = new Map(); - const { variables } = opts; - return { - postcssPlugin: "postcss-compile-variables", + aliasMap = new Map(); + resolvedMap = new Map(); + const { variables } = opts; + return { + postcssPlugin: "postcss-compile-variables", - Once(root, {Rule, Declaration}) { - /* - Go through the CSS file once to extract all aliases. - We use the extracted alias when resolving derived variables - later. - */ - root.walkDecls(decl => extractAlias(decl)); - root.walkDecls(decl => resolveDerivedVariable(decl, variables)); - addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }); - }, - }; + Once(root, { Rule, Declaration }) { + /* + Go through the CSS file once to extract all aliases. + We use the extracted alias when resolving derived variables + later. + */ + root.walkDecls(decl => extractAlias(decl)); + root.walkDecls(decl => resolveDerivedVariable(decl, variables)); + addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }); + }, + }; }; module.exports.postcss = true; From f170ef0206ec7b9a5797af103a468fc167ba52d5 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 7 Mar 2022 11:38:39 +0530 Subject: [PATCH 04/23] Switch over to off-color --- package.json | 4 ++-- postcss/css-compile-variables.js | 6 +++--- yarn.lock | 37 +++++++------------------------- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 3c007244..041100a5 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz", "another-json": "^0.2.0", "base64-arraybuffer": "^0.2.0", - "color": "^4.2.1", - "dompurify": "^2.3.0" + "dompurify": "^2.3.0", + "off-color": "^2.0.0" } } diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 125e79ca..e212ee69 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -1,4 +1,4 @@ -const Color = require("color"); +import { offColor } from 'off-color'; let aliasMap; let resolvedMap; @@ -22,13 +22,13 @@ function resolveDerivedVariable(decl, variables) { switch (operation) { case "darker": { const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = new Color(colorString).darken(argument / 100).hex(); + const newColorString = new offColor(colorString).darken(argument / 100).hex(); resolvedMap.set(wholeVariable, newColorString); break; } case "lighter": { const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = new Color(colorString).lighten(argument / 100).hex(); + const newColorString = new offColor(colorString).lighten(argument / 100).hex(); resolvedMap.set(wholeVariable, newColorString); break; } diff --git a/yarn.lock b/yarn.lock index 31dde2dd..5836b2af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -332,27 +332,11 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@^1.0.0, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" - integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-4.2.1.tgz#498aee5fce7fc982606c8875cab080ac0547c884" - integrity sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw== - dependencies: - color-convert "^2.0.1" - color-string "^1.9.0" - colors@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -977,11 +961,6 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - is-core-module@^2.2.0: version "2.5.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" @@ -1154,6 +1133,13 @@ nth-check@^2.0.0: dependencies: boolbase "^1.0.0" +off-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/off-color/-/off-color-2.0.0.tgz#ecf3bda52e9a78dde535db86361e048741a56631" + integrity sha512-JJ9ObbY2CzgT7F8PpdpHGNjQa7QbU8f4DkY3cCxYUq9NezYUMmL/oSofCc5MMaiUnNNBEFCc4w1unMA+R8syvw== + dependencies: + core-js "^3.6.5" + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1363,13 +1349,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" From a5d46bb40cd7d0ba2451476e1d9277e779da681c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 7 Mar 2022 13:10:44 +0530 Subject: [PATCH 05/23] Move over tests to Hydrogen using impunity --- package.json | 1 + postcss/css-compile-variables.js | 6 +-- postcss/test.js | 66 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 postcss/test.js diff --git a/package.json b/package.json index 041100a5..5ca5b05f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "lint-ts": "eslint src/ -c .ts-eslintrc.js --ext .ts", "lint-ci": "eslint src/", "test": "impunity --entry-point src/platform/web/main.js src/platform/web/Platform.js --force-esm-dirs lib/ src/ --root-dir src/", + "test:postcss": "impunity --entry-point postcss/test.js ", "start": "vite --port 3000", "build": "vite build", "build:sdk": "./scripts/sdk/build.sh" diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index e212ee69..8737067d 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -1,4 +1,4 @@ -import { offColor } from 'off-color'; +const offColor = require("off-color").offColor; let aliasMap; let resolvedMap; @@ -22,13 +22,13 @@ function resolveDerivedVariable(decl, variables) { switch (operation) { case "darker": { const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = new offColor(colorString).darken(argument / 100).hex(); + const newColorString = offColor(colorString).darken(argument / 100).hex(); resolvedMap.set(wholeVariable, newColorString); break; } case "lighter": { const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = new offColor(colorString).lighten(argument / 100).hex(); + const newColorString = offColor(colorString).lighten(argument / 100).hex(); resolvedMap.set(wholeVariable, newColorString); break; } diff --git a/postcss/test.js b/postcss/test.js new file mode 100644 index 00000000..104696aa --- /dev/null +++ b/postcss/test.js @@ -0,0 +1,66 @@ +const offColor = require("off-color").offColor; +const postcss = require("postcss"); +const plugin = require("./css-compile-variables"); + +async function run(input, output, opts = {}, assert) { + let result = await postcss([plugin(opts)]).process(input, { from: undefined, }); + assert.strictEqual( + result.css.replaceAll(/\s/g, ""), + output.replaceAll(/\s/g, "") + ); + assert.strictEqual(result.warnings().length, 0); +} + +module.exports.tests = function tests() { + return { + "derived variables are resolved": async (assert) => { + const inputCSS = `div { + background-color: var(--foo-color--lighter-50); + }`; + const transformedColor = offColor("#ff0").lighten(0.5); + const outputCSS = + inputCSS + + ` + :root { + --foo-color: #ff0; + --foo-color--lighter-50: ${transformedColor.hex()}; + } + `; + await run( + inputCSS, + outputCSS, + { variables: { "foo-color": "#ff0" } }, + assert + ); + }, + + "derived variables work with alias": async (assert) => { + const inputCSS = `div { + background: var(--icon-color--darker-20); + --my-alias: var(--icon-color--darker-20); + color: var(--my-alias--lighter-15); + }`; + const colorDarker = offColor("#fff").darken(0.2).hex(); + const aliasLighter = offColor(colorDarker).lighten(0.15).hex(); + const outputCSS = `div { + background: var(--icon-color--darker-20); + --my-alias: var(--icon-color--darker-20); + color: var(--my-alias--lighter-15); + } + :root { + --icon-color: #fff; + --icon-color--darker-20: ${colorDarker}; + --my-alias--lighter-15: ${aliasLighter}; + } + `; + await run(inputCSS, outputCSS, { variables: { "icon-color": "#fff" }, }, assert); + }, + + "derived variable throws if base not present in config": async (assert) => { + const css = `:root { + color: var(--icon-color--darker-20); + }`; + assert.rejects(async () => await postcss([plugin({ variables: {} })]).process(css, { from: undefined, })); + } + }; +}; From 41f6b6ab6bd52a55f024cb31d8f78c389e7f02df Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 7 Mar 2022 13:25:53 +0530 Subject: [PATCH 06/23] Use startsWith instead of regex testing --- postcss/css-compile-variables.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 8737067d..8d4b0fd9 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -37,9 +37,8 @@ function resolveDerivedVariable(decl, variables) { } function extractAlias(decl) { - const RE_VARIABLE_PROP = /--(.+)/; const wholeVariable = decl.value.match(RE_VARIABLE_VALUE)?.[1]; - if (RE_VARIABLE_PROP.test(decl.prop) && wholeVariable) { + if (decl.prop.startsWith("--") && wholeVariable) { aliasMap.set(decl.prop, wholeVariable); } } From a83850ebf38f3de28bb182470fd009b1fabade9c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 9 Mar 2022 11:48:53 +0530 Subject: [PATCH 07/23] Use postcss value parser to find variables --- package.json | 3 +- postcss/css-compile-variables.js | 58 +++++++++++++++++++++----------- postcss/test.js | 23 +++++++++++++ yarn.lock | 5 +++ 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 5ca5b05f..fa9c4344 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "another-json": "^0.2.0", "base64-arraybuffer": "^0.2.0", "dompurify": "^2.3.0", - "off-color": "^2.0.0" + "off-color": "^2.0.0", + "postcss-value-parser": "^4.2.0" } } diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 8d4b0fd9..bd952ac8 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -1,4 +1,5 @@ const offColor = require("off-color").offColor; +const valueParser = require("postcss-value-parser"); let aliasMap; let resolvedMap; @@ -9,28 +10,45 @@ function getValueFromAlias(alias) { return resolvedMap.get(derivedVariable); // what if we haven't resolved this variable yet? } -function resolveDerivedVariable(decl, variables) { - const matches = decl.value.match(RE_VARIABLE_VALUE); - if (matches) { - const [, wholeVariable, baseVariable, operation, argument] = matches; - if (!variables[baseVariable]) { - // hmm.. baseVariable should be in config..., maybe this is an alias? - if (!aliasMap.get(`--${baseVariable}`)) { - throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); - } +function parseDeclarationValue(value) { + const parsed = valueParser(value); + const variables = []; + parsed.walk(node => { + if (node.type !== "function" && node.value !== "var") { + return; } - switch (operation) { - case "darker": { - const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = offColor(colorString).darken(argument / 100).hex(); - resolvedMap.set(wholeVariable, newColorString); - break; + const variable = node.nodes[0]; + variables.push(variable.value); + }); + return variables; +} + +function resolveDerivedVariable(decl, variables) { + const RE_VARIABLE_VALUE = /--(.+)--(.+)-(.+)/; + const variableCollection = parseDeclarationValue(decl.value); + for (const variable of variableCollection) { + const matches = variable.match(RE_VARIABLE_VALUE); + if (matches) { + const [wholeVariable, baseVariable, operation, argument] = matches; + if (!variables[baseVariable]) { + // hmm.. baseVariable should be in config..., maybe this is an alias? + if (!aliasMap.get(`--${baseVariable}`)) { + throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); + } } - case "lighter": { - const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = offColor(colorString).lighten(argument / 100).hex(); - resolvedMap.set(wholeVariable, newColorString); - break; + switch (operation) { + case "darker": { + const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); + const newColorString = offColor(colorString).darken(argument / 100).hex(); + resolvedMap.set(wholeVariable, newColorString); + break; + } + case "lighter": { + const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); + const newColorString = offColor(colorString).lighten(argument / 100).hex(); + resolvedMap.set(wholeVariable, newColorString); + break; + } } } } diff --git a/postcss/test.js b/postcss/test.js index 104696aa..e67016b6 100644 --- a/postcss/test.js +++ b/postcss/test.js @@ -61,6 +61,29 @@ module.exports.tests = function tests() { color: var(--icon-color--darker-20); }`; assert.rejects(async () => await postcss([plugin({ variables: {} })]).process(css, { from: undefined, })); + }, + + "multiple derived variable in single declaration is parsed correctly": async (assert) => { + const inputCSS = `div { + background-color: linear-gradient(var(--foo-color--lighter-50), var(--foo-color--darker-20)); + }`; + const transformedColor1 = offColor("#ff0").lighten(0.5); + const transformedColor2 = offColor("#ff0").darken(0.2); + const outputCSS = + inputCSS + + ` + :root { + --foo-color: #ff0; + --foo-color--lighter-50: ${transformedColor1.hex()}; + --foo-color--darker-20: ${transformedColor2.hex()}; + } + `; + await run( + inputCSS, + outputCSS, + { variables: { "foo-color": "#ff0" } }, + assert + ); } }; }; diff --git a/yarn.lock b/yarn.lock index 5836b2af..7bcefdd4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1222,6 +1222,11 @@ postcss-flexbugs-fixes@^5.0.2: resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz#2028e145313074fc9abe276cb7ca14e5401eb49d" integrity sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ== +postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + postcss@^8.3.8: version "8.3.9" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.9.tgz#98754caa06c4ee9eb59cc48bd073bb6bd3437c31" From 79f363fb9d9e4406daf65244419849cf422df1c4 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 9 Mar 2022 17:20:05 +0530 Subject: [PATCH 08/23] Move code to callback and fix alias code --- postcss/color.js | 14 ++++++++++++++ postcss/css-compile-variables.js | 31 +++++++++---------------------- postcss/test.js | 28 +++++++++++++++++++++------- 3 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 postcss/color.js diff --git a/postcss/color.js b/postcss/color.js new file mode 100644 index 00000000..cad91019 --- /dev/null +++ b/postcss/color.js @@ -0,0 +1,14 @@ +const offColor = require("off-color").offColor; + +module.exports.derive = function (value, operation, argument) { + switch (operation) { + case "darker": { + const newColorString = offColor(value).darken(argument / 100).hex(); + return newColorString; + } + case "lighter": { + const newColorString = offColor(value).lighten(argument / 100).hex(); + return newColorString; + } + } +} diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index bd952ac8..bc91dc06 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -1,13 +1,11 @@ -const offColor = require("off-color").offColor; const valueParser = require("postcss-value-parser"); let aliasMap; let resolvedMap; -const RE_VARIABLE_VALUE = /var\((--(.+)--(.+)-(.+))\)/; -function getValueFromAlias(alias) { +function getValueFromAlias(alias, variables) { const derivedVariable = aliasMap.get(`--${alias}`); - return resolvedMap.get(derivedVariable); // what if we haven't resolved this variable yet? + return variables[derivedVariable] ?? resolvedMap.get(`--${derivedVariable}`); // what if we haven't resolved this variable yet? } function parseDeclarationValue(value) { @@ -23,7 +21,7 @@ function parseDeclarationValue(value) { return variables; } -function resolveDerivedVariable(decl, variables) { +function resolveDerivedVariable(decl, {variables, derive}) { const RE_VARIABLE_VALUE = /--(.+)--(.+)-(.+)/; const variableCollection = parseDeclarationValue(decl.value); for (const variable of variableCollection) { @@ -36,26 +34,15 @@ function resolveDerivedVariable(decl, variables) { throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); } } - switch (operation) { - case "darker": { - const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = offColor(colorString).darken(argument / 100).hex(); - resolvedMap.set(wholeVariable, newColorString); - break; - } - case "lighter": { - const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable); - const newColorString = offColor(colorString).lighten(argument / 100).hex(); - resolvedMap.set(wholeVariable, newColorString); - break; - } - } + const value = variables[baseVariable] ?? getValueFromAlias(baseVariable, variables); + const derivedValue = derive(value, operation, argument); + resolvedMap.set(wholeVariable, derivedValue); } } } function extractAlias(decl) { - const wholeVariable = decl.value.match(RE_VARIABLE_VALUE)?.[1]; + const wholeVariable = decl.value.match(/var\(--(.+)\)/)?.[1]; if (decl.prop.startsWith("--") && wholeVariable) { aliasMap.set(decl.prop, wholeVariable); } @@ -82,7 +69,7 @@ function addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration module.exports = (opts = {}) => { aliasMap = new Map(); resolvedMap = new Map(); - const { variables } = opts; + const {variables} = opts; return { postcssPlugin: "postcss-compile-variables", @@ -93,7 +80,7 @@ module.exports = (opts = {}) => { later. */ root.walkDecls(decl => extractAlias(decl)); - root.walkDecls(decl => resolveDerivedVariable(decl, variables)); + root.walkDecls(decl => resolveDerivedVariable(decl, opts)); addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }); }, }; diff --git a/postcss/test.js b/postcss/test.js index e67016b6..d07a6689 100644 --- a/postcss/test.js +++ b/postcss/test.js @@ -1,9 +1,10 @@ const offColor = require("off-color").offColor; const postcss = require("postcss"); const plugin = require("./css-compile-variables"); +const derive = require("./color").derive; async function run(input, output, opts = {}, assert) { - let result = await postcss([plugin(opts)]).process(input, { from: undefined, }); + let result = await postcss([plugin({ ...opts, derive })]).process(input, { from: undefined, }); assert.strictEqual( result.css.replaceAll(/\s/g, ""), output.replaceAll(/\s/g, "") @@ -78,12 +79,25 @@ module.exports.tests = function tests() { --foo-color--darker-20: ${transformedColor2.hex()}; } `; - await run( - inputCSS, - outputCSS, - { variables: { "foo-color": "#ff0" } }, - assert - ); + await run( inputCSS, outputCSS, { variables: { "foo-color": "#ff0" } }, assert); + }, + "multiple aliased-derived variable in single declaration is parsed correctly": async (assert) => { + const inputCSS = `div { + --my-alias: var(--foo-color); + background-color: linear-gradient(var(--my-alias--lighter-50), var(--my-alias--darker-20)); + }`; + const transformedColor1 = offColor("#ff0").lighten(0.5); + const transformedColor2 = offColor("#ff0").darken(0.2); + const outputCSS = + inputCSS + + ` + :root { + --foo-color: #ff0; + --my-alias--lighter-50: ${transformedColor1.hex()}; + --my-alias--darker-20: ${transformedColor2.hex()}; + } + `; + await run( inputCSS, outputCSS, { variables: { "foo-color": "#ff0" } }, assert); } }; }; From 96fa83b5084ac0fc76d3dad2e67ee32cc3b224a8 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 9 Mar 2022 17:22:11 +0530 Subject: [PATCH 09/23] Add license header --- postcss/color.js | 16 ++++++++++++++++ postcss/css-compile-variables.js | 16 ++++++++++++++++ postcss/test.js | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/postcss/color.js b/postcss/color.js index cad91019..2251a56e 100644 --- a/postcss/color.js +++ b/postcss/color.js @@ -1,3 +1,19 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + const offColor = require("off-color").offColor; module.exports.derive = function (value, operation, argument) { diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index bc91dc06..195526ef 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -1,3 +1,19 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + const valueParser = require("postcss-value-parser"); let aliasMap; diff --git a/postcss/test.js b/postcss/test.js index d07a6689..4ed74c67 100644 --- a/postcss/test.js +++ b/postcss/test.js @@ -1,3 +1,19 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + const offColor = require("off-color").offColor; const postcss = require("postcss"); const plugin = require("./css-compile-variables"); From 63c1f2a7a39ee9e1f3d3633d47aee49743f801ba Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 9 Mar 2022 17:22:45 +0530 Subject: [PATCH 10/23] Add node as env to eslint --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index cb28f4c8..1985ccc1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,7 @@ module.exports = { "env": { "browser": true, + "node": true, "es6": true }, "extends": "eslint:recommended", From 1663782954ef1de0e0bce0ba9d759f733bd95f2e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 16:05:13 +0530 Subject: [PATCH 11/23] Throw after fetching value --- postcss/css-compile-variables.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 195526ef..732ed8b3 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -44,13 +44,10 @@ function resolveDerivedVariable(decl, {variables, derive}) { const matches = variable.match(RE_VARIABLE_VALUE); if (matches) { const [wholeVariable, baseVariable, operation, argument] = matches; - if (!variables[baseVariable]) { - // hmm.. baseVariable should be in config..., maybe this is an alias? - if (!aliasMap.get(`--${baseVariable}`)) { - throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); - } - } const value = variables[baseVariable] ?? getValueFromAlias(baseVariable, variables); + if (!value) { + throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); + } const derivedValue = derive(value, operation, argument); resolvedMap.set(wholeVariable, derivedValue); } From 52101239773d598c3fdc94b6b6a778ad6d3db147 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 17:19:04 +0530 Subject: [PATCH 12/23] Document options --- postcss/css-compile-variables.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 732ed8b3..38f5c471 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -76,13 +76,21 @@ function addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration root.append(newRule); } -/* * - * @type {import('postcss').PluginCreator} +/** + * @callback derive + * @param {string} value - The base value on which an operation is applied + * @param {string} operation - The operation to be applied (eg: darker, lighter...) + * @param {string} argument - The argument for this operation + */ +/** + * + * @param {Object} opts - Options for the plugin + * @param {Object} opts.variables - An object with records of the form: {base_variable_name: value} + * @param {derive} opts.derive - The callback which contains the logic for resolving derived variables */ module.exports = (opts = {}) => { aliasMap = new Map(); resolvedMap = new Map(); - const {variables} = opts; return { postcssPlugin: "postcss-compile-variables", @@ -94,7 +102,7 @@ module.exports = (opts = {}) => { */ root.walkDecls(decl => extractAlias(decl)); root.walkDecls(decl => resolveDerivedVariable(decl, opts)); - addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }); + addResolvedVariablesToRootSelector(root, opts.variables, { Rule, Declaration }); }, }; }; From f732164b5fb253ad1dfe88e05d50ffdcfba2df8a Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 17:21:38 +0530 Subject: [PATCH 13/23] Formatting change --- postcss/css-compile-variables.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 38f5c471..cf2b451d 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -61,16 +61,16 @@ function extractAlias(decl) { } } -function addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }) { +function addResolvedVariablesToRootSelector(root, variables, {Rule, Declaration}) { const newRule = new Rule({ selector: ":root", source: root.source }); // Add base css variables to :root for (const [key, value] of Object.entries(variables)) { - const declaration = new Declaration({ prop: `--${key}`, value }); + const declaration = new Declaration({prop: `--${key}`, value}); newRule.append(declaration); } // Add derived css variables to :root resolvedMap.forEach((value, key) => { - const declaration = new Declaration({ prop: key, value }); + const declaration = new Declaration({prop: key, value}); newRule.append(declaration); }); root.append(newRule); @@ -94,7 +94,7 @@ module.exports = (opts = {}) => { return { postcssPlugin: "postcss-compile-variables", - Once(root, { Rule, Declaration }) { + Once(root, {Rule, Declaration}) { /* Go through the CSS file once to extract all aliases. We use the extracted alias when resolving derived variables @@ -102,7 +102,7 @@ module.exports = (opts = {}) => { */ root.walkDecls(decl => extractAlias(decl)); root.walkDecls(decl => resolveDerivedVariable(decl, opts)); - addResolvedVariablesToRootSelector(root, opts.variables, { Rule, Declaration }); + addResolvedVariablesToRootSelector(root, opts.variables, {Rule, Declaration}); }, }; }; From ff10297bf88802e35f9a11309e52ee8558348f28 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 17:22:02 +0530 Subject: [PATCH 14/23] Explicitly convert to number --- postcss/color.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/postcss/color.js b/postcss/color.js index 2251a56e..f61dac1e 100644 --- a/postcss/color.js +++ b/postcss/color.js @@ -17,13 +17,14 @@ limitations under the License. const offColor = require("off-color").offColor; module.exports.derive = function (value, operation, argument) { + const argumentAsNumber = parseInt(argument); switch (operation) { case "darker": { - const newColorString = offColor(value).darken(argument / 100).hex(); + const newColorString = offColor(value).darken(argumentAsNumber / 100).hex(); return newColorString; } case "lighter": { - const newColorString = offColor(value).lighten(argument / 100).hex(); + const newColorString = offColor(value).lighten(argumentAsNumber / 100).hex(); return newColorString; } } From 9f77df0bff2d1fd9d7f8216f7fca35a28ad08713 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 17:24:32 +0530 Subject: [PATCH 15/23] Match regex only if declaration is a variable --- postcss/css-compile-variables.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index cf2b451d..d5e78352 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -55,9 +55,11 @@ function resolveDerivedVariable(decl, {variables, derive}) { } function extractAlias(decl) { - const wholeVariable = decl.value.match(/var\(--(.+)\)/)?.[1]; - if (decl.prop.startsWith("--") && wholeVariable) { - aliasMap.set(decl.prop, wholeVariable); + if (decl.variable) { + const wholeVariable = decl.value.match(/var\(--(.+)\)/)?.[1]; + if (wholeVariable) { + aliasMap.set(decl.prop, wholeVariable); + } } } From 6f4a7e074a4f6b32a6a716957ea1adb850bb94ae Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 17:27:12 +0530 Subject: [PATCH 16/23] Change confusing doc --- postcss/css-compile-variables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index d5e78352..4adfc7b1 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -87,7 +87,7 @@ function addResolvedVariablesToRootSelector(root, variables, {Rule, Declaration} /** * * @param {Object} opts - Options for the plugin - * @param {Object} opts.variables - An object with records of the form: {base_variable_name: value} + * @param {Object} opts.variables - An object with of the form: {base_variable_name_1: value, base_variable_name_2: value, ...} * @param {derive} opts.derive - The callback which contains the logic for resolving derived variables */ module.exports = (opts = {}) => { From 2c068cc3ced36dd791bf0106ca827b13a13dcd31 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 17:42:12 +0530 Subject: [PATCH 17/23] typo --- postcss/css-compile-variables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 4adfc7b1..023c8eb7 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -87,7 +87,7 @@ function addResolvedVariablesToRootSelector(root, variables, {Rule, Declaration} /** * * @param {Object} opts - Options for the plugin - * @param {Object} opts.variables - An object with of the form: {base_variable_name_1: value, base_variable_name_2: value, ...} + * @param {Object} opts.variables - An object of the form: {base_variable_name_1: value, base_variable_name_2: value, ...} * @param {derive} opts.derive - The callback which contains the logic for resolving derived variables */ module.exports = (opts = {}) => { From 4020ade70c7cfd15b7665aa26dc07f3657cc98dd Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 10 Mar 2022 17:51:25 +0530 Subject: [PATCH 18/23] Remove redundant comment --- postcss/css-compile-variables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postcss/css-compile-variables.js b/postcss/css-compile-variables.js index 023c8eb7..d7eca7f2 100644 --- a/postcss/css-compile-variables.js +++ b/postcss/css-compile-variables.js @@ -21,7 +21,7 @@ let resolvedMap; function getValueFromAlias(alias, variables) { const derivedVariable = aliasMap.get(`--${alias}`); - return variables[derivedVariable] ?? resolvedMap.get(`--${derivedVariable}`); // what if we haven't resolved this variable yet? + return variables[derivedVariable] ?? resolvedMap.get(`--${derivedVariable}`); } function parseDeclarationValue(value) { From bca1648df6a03370fc071c1723f504cc146e8b16 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 14 Mar 2022 11:34:58 +0530 Subject: [PATCH 19/23] Move plugin to /scripts and create eslintrc --- .eslintrc.js | 1 - package.json | 2 +- scripts/.eslintrc.js | 18 ++++++++++++++++++ {postcss => scripts/postcss}/color.js | 0 .../postcss}/css-compile-variables.js | 0 {postcss => scripts/postcss}/test.js | 0 6 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 scripts/.eslintrc.js rename {postcss => scripts/postcss}/color.js (100%) rename {postcss => scripts/postcss}/css-compile-variables.js (100%) rename {postcss => scripts/postcss}/test.js (100%) diff --git a/.eslintrc.js b/.eslintrc.js index 1985ccc1..cb28f4c8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,6 @@ module.exports = { "env": { "browser": true, - "node": true, "es6": true }, "extends": "eslint:recommended", diff --git a/package.json b/package.json index fa9c4344..12c73994 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "lint-ts": "eslint src/ -c .ts-eslintrc.js --ext .ts", "lint-ci": "eslint src/", "test": "impunity --entry-point src/platform/web/main.js src/platform/web/Platform.js --force-esm-dirs lib/ src/ --root-dir src/", - "test:postcss": "impunity --entry-point postcss/test.js ", + "test:postcss": "impunity --entry-point scripts/postcss/test.js ", "start": "vite --port 3000", "build": "vite build", "build:sdk": "./scripts/sdk/build.sh" diff --git a/scripts/.eslintrc.js b/scripts/.eslintrc.js new file mode 100644 index 00000000..1cdfca84 --- /dev/null +++ b/scripts/.eslintrc.js @@ -0,0 +1,18 @@ +module.exports = { + "env": { + "node": true, + "es6": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + }, + "rules": { + "no-console": "off", + "no-empty": "off", + "no-prototype-builtins": "off", + "no-unused-vars": "warn" + }, +}; + diff --git a/postcss/color.js b/scripts/postcss/color.js similarity index 100% rename from postcss/color.js rename to scripts/postcss/color.js diff --git a/postcss/css-compile-variables.js b/scripts/postcss/css-compile-variables.js similarity index 100% rename from postcss/css-compile-variables.js rename to scripts/postcss/css-compile-variables.js diff --git a/postcss/test.js b/scripts/postcss/test.js similarity index 100% rename from postcss/test.js rename to scripts/postcss/test.js From 19a6d669a94172f38ab7dd50c8d8a95fada4bc5d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 14 Mar 2022 23:26:37 +0530 Subject: [PATCH 20/23] Extract base variables from css --- scripts/postcss/css-compile-variables.js | 37 +++++++++--------- scripts/postcss/test.js | 48 ++++++++++++------------ 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/scripts/postcss/css-compile-variables.js b/scripts/postcss/css-compile-variables.js index d7eca7f2..ea939780 100644 --- a/scripts/postcss/css-compile-variables.js +++ b/scripts/postcss/css-compile-variables.js @@ -18,10 +18,11 @@ const valueParser = require("postcss-value-parser"); let aliasMap; let resolvedMap; +let baseVariables; -function getValueFromAlias(alias, variables) { +function getValueFromAlias(alias) { const derivedVariable = aliasMap.get(`--${alias}`); - return variables[derivedVariable] ?? resolvedMap.get(`--${derivedVariable}`); + return baseVariables.get(derivedVariable) ?? resolvedMap.get(derivedVariable); } function parseDeclarationValue(value) { @@ -37,14 +38,14 @@ function parseDeclarationValue(value) { return variables; } -function resolveDerivedVariable(decl, {variables, derive}) { +function resolveDerivedVariable(decl, derive) { const RE_VARIABLE_VALUE = /--(.+)--(.+)-(.+)/; const variableCollection = parseDeclarationValue(decl.value); for (const variable of variableCollection) { const matches = variable.match(RE_VARIABLE_VALUE); if (matches) { const [wholeVariable, baseVariable, operation, argument] = matches; - const value = variables[baseVariable] ?? getValueFromAlias(baseVariable, variables); + const value = baseVariables.get(`--${baseVariable}`) ?? getValueFromAlias(baseVariable); if (!value) { throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); } @@ -54,22 +55,21 @@ function resolveDerivedVariable(decl, {variables, derive}) { } } -function extractAlias(decl) { +function extract(decl) { if (decl.variable) { - const wholeVariable = decl.value.match(/var\(--(.+)\)/)?.[1]; + // see if right side is of form "var(--foo)" + const wholeVariable = decl.value.match(/var\((--.+)\)/)?.[1]; if (wholeVariable) { aliasMap.set(decl.prop, wholeVariable); + // Since this is an alias, we shouldn't store it in baseVariables + return; } + baseVariables.set(decl.prop, decl.value); } } -function addResolvedVariablesToRootSelector(root, variables, {Rule, Declaration}) { +function addResolvedVariablesToRootSelector(root, {Rule, Declaration}) { const newRule = new Rule({ selector: ":root", source: root.source }); - // Add base css variables to :root - for (const [key, value] of Object.entries(variables)) { - const declaration = new Declaration({prop: `--${key}`, value}); - newRule.append(declaration); - } // Add derived css variables to :root resolvedMap.forEach((value, key) => { const declaration = new Declaration({prop: key, value}); @@ -87,24 +87,23 @@ function addResolvedVariablesToRootSelector(root, variables, {Rule, Declaration} /** * * @param {Object} opts - Options for the plugin - * @param {Object} opts.variables - An object of the form: {base_variable_name_1: value, base_variable_name_2: value, ...} * @param {derive} opts.derive - The callback which contains the logic for resolving derived variables */ module.exports = (opts = {}) => { aliasMap = new Map(); resolvedMap = new Map(); + baseVariables = new Map(); return { postcssPlugin: "postcss-compile-variables", Once(root, {Rule, Declaration}) { /* - Go through the CSS file once to extract all aliases. - We use the extracted alias when resolving derived variables - later. + Go through the CSS file once to extract all aliases and base variables. + We use these when resolving derived variables later. */ - root.walkDecls(decl => extractAlias(decl)); - root.walkDecls(decl => resolveDerivedVariable(decl, opts)); - addResolvedVariablesToRootSelector(root, opts.variables, {Rule, Declaration}); + root.walkDecls(decl => extract(decl)); + root.walkDecls(decl => resolveDerivedVariable(decl, opts.derive)); + addResolvedVariablesToRootSelector(root, {Rule, Declaration}); }, }; }; diff --git a/scripts/postcss/test.js b/scripts/postcss/test.js index 4ed74c67..36ff9282 100644 --- a/scripts/postcss/test.js +++ b/scripts/postcss/test.js @@ -31,7 +31,11 @@ async function run(input, output, opts = {}, assert) { module.exports.tests = function tests() { return { "derived variables are resolved": async (assert) => { - const inputCSS = `div { + const inputCSS = ` + :root { + --foo-color: #ff0; + } + div { background-color: var(--foo-color--lighter-50); }`; const transformedColor = offColor("#ff0").lighten(0.5); @@ -39,38 +43,30 @@ module.exports.tests = function tests() { inputCSS + ` :root { - --foo-color: #ff0; --foo-color--lighter-50: ${transformedColor.hex()}; } `; - await run( - inputCSS, - outputCSS, - { variables: { "foo-color": "#ff0" } }, - assert - ); + await run( inputCSS, outputCSS, {}, assert); }, "derived variables work with alias": async (assert) => { - const inputCSS = `div { + const inputCSS = ` + :root { + --icon-color: #fff; + } + div { background: var(--icon-color--darker-20); --my-alias: var(--icon-color--darker-20); color: var(--my-alias--lighter-15); }`; const colorDarker = offColor("#fff").darken(0.2).hex(); const aliasLighter = offColor(colorDarker).lighten(0.15).hex(); - const outputCSS = `div { - background: var(--icon-color--darker-20); - --my-alias: var(--icon-color--darker-20); - color: var(--my-alias--lighter-15); - } - :root { - --icon-color: #fff; + const outputCSS = inputCSS + `:root { --icon-color--darker-20: ${colorDarker}; --my-alias--lighter-15: ${aliasLighter}; } `; - await run(inputCSS, outputCSS, { variables: { "icon-color": "#fff" }, }, assert); + await run(inputCSS, outputCSS, { }, assert); }, "derived variable throws if base not present in config": async (assert) => { @@ -81,7 +77,11 @@ module.exports.tests = function tests() { }, "multiple derived variable in single declaration is parsed correctly": async (assert) => { - const inputCSS = `div { + const inputCSS = ` + :root { + --foo-color: #ff0; + } + div { background-color: linear-gradient(var(--foo-color--lighter-50), var(--foo-color--darker-20)); }`; const transformedColor1 = offColor("#ff0").lighten(0.5); @@ -90,15 +90,18 @@ module.exports.tests = function tests() { inputCSS + ` :root { - --foo-color: #ff0; --foo-color--lighter-50: ${transformedColor1.hex()}; --foo-color--darker-20: ${transformedColor2.hex()}; } `; - await run( inputCSS, outputCSS, { variables: { "foo-color": "#ff0" } }, assert); + await run( inputCSS, outputCSS, { }, assert); }, "multiple aliased-derived variable in single declaration is parsed correctly": async (assert) => { - const inputCSS = `div { + const inputCSS = ` + :root { + --foo-color: #ff0; + } + div { --my-alias: var(--foo-color); background-color: linear-gradient(var(--my-alias--lighter-50), var(--my-alias--darker-20)); }`; @@ -108,12 +111,11 @@ module.exports.tests = function tests() { inputCSS + ` :root { - --foo-color: #ff0; --my-alias--lighter-50: ${transformedColor1.hex()}; --my-alias--darker-20: ${transformedColor2.hex()}; } `; - await run( inputCSS, outputCSS, { variables: { "foo-color": "#ff0" } }, assert); + await run( inputCSS, outputCSS, { }, assert); } }; }; From 5d4323cd1dcabaacdfb98bb0b44ce09cc25a739d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 23 Mar 2022 17:12:14 +0530 Subject: [PATCH 21/23] Remove stray "--" from code --- scripts/postcss/css-compile-variables.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/postcss/css-compile-variables.js b/scripts/postcss/css-compile-variables.js index ea939780..23795145 100644 --- a/scripts/postcss/css-compile-variables.js +++ b/scripts/postcss/css-compile-variables.js @@ -21,7 +21,7 @@ let resolvedMap; let baseVariables; function getValueFromAlias(alias) { - const derivedVariable = aliasMap.get(`--${alias}`); + const derivedVariable = aliasMap.get(alias); return baseVariables.get(derivedVariable) ?? resolvedMap.get(derivedVariable); } @@ -39,13 +39,13 @@ function parseDeclarationValue(value) { } function resolveDerivedVariable(decl, derive) { - const RE_VARIABLE_VALUE = /--(.+)--(.+)-(.+)/; + const RE_VARIABLE_VALUE = /(--.+)--(.+)-(.+)/; const variableCollection = parseDeclarationValue(decl.value); for (const variable of variableCollection) { const matches = variable.match(RE_VARIABLE_VALUE); if (matches) { const [wholeVariable, baseVariable, operation, argument] = matches; - const value = baseVariables.get(`--${baseVariable}`) ?? getValueFromAlias(baseVariable); + const value = baseVariables.get(baseVariable) ?? getValueFromAlias(baseVariable); if (!value) { throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); } From 59ca8e63095d7c81e41e2e82647663a5a6e4afe8 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 23 Mar 2022 17:25:12 +0530 Subject: [PATCH 22/23] Add explanation of plugin --- scripts/postcss/css-compile-variables.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/postcss/css-compile-variables.js b/scripts/postcss/css-compile-variables.js index 23795145..a3c3aa30 100644 --- a/scripts/postcss/css-compile-variables.js +++ b/scripts/postcss/css-compile-variables.js @@ -16,6 +16,20 @@ limitations under the License. const valueParser = require("postcss-value-parser"); +/** + * This plugin derives new css variables from a given set of base variables. + * A derived css variable has the form --base--operation-argument; meaning that the derived + * variable has a value that is generated from the base variable "base" by applying "operation" + * with given "argument". + * + * eg: given the base variable --foo-color: #40E0D0, --foo-color--darker-20 is a css variable + * derived from foo-color by making it 20% more darker. + * + * All derived variables are added to the :root section. + * + * The actual derivation is done outside the plugin in a callback. + */ + let aliasMap; let resolvedMap; let baseVariables; From 72785e7c3ebc5d0ca1c5208011c14831ab859116 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 23 Mar 2022 20:39:24 +0530 Subject: [PATCH 23/23] Remove -- from everywhere --- scripts/postcss/css-compile-variables.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/postcss/css-compile-variables.js b/scripts/postcss/css-compile-variables.js index a3c3aa30..3ed34513 100644 --- a/scripts/postcss/css-compile-variables.js +++ b/scripts/postcss/css-compile-variables.js @@ -53,12 +53,12 @@ function parseDeclarationValue(value) { } function resolveDerivedVariable(decl, derive) { - const RE_VARIABLE_VALUE = /(--.+)--(.+)-(.+)/; + const RE_VARIABLE_VALUE = /--((.+)--(.+)-(.+))/; const variableCollection = parseDeclarationValue(decl.value); for (const variable of variableCollection) { const matches = variable.match(RE_VARIABLE_VALUE); if (matches) { - const [wholeVariable, baseVariable, operation, argument] = matches; + const [, wholeVariable, baseVariable, operation, argument] = matches; const value = baseVariables.get(baseVariable) ?? getValueFromAlias(baseVariable); if (!value) { throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`); @@ -72,13 +72,15 @@ function resolveDerivedVariable(decl, derive) { function extract(decl) { if (decl.variable) { // see if right side is of form "var(--foo)" - const wholeVariable = decl.value.match(/var\((--.+)\)/)?.[1]; + const wholeVariable = decl.value.match(/var\(--(.+)\)/)?.[1]; + // remove -- from the prop + const prop = decl.prop.substring(2); if (wholeVariable) { - aliasMap.set(decl.prop, wholeVariable); + aliasMap.set(prop, wholeVariable); // Since this is an alias, we shouldn't store it in baseVariables return; } - baseVariables.set(decl.prop, decl.value); + baseVariables.set(prop, decl.value); } } @@ -86,7 +88,7 @@ function addResolvedVariablesToRootSelector(root, {Rule, Declaration}) { const newRule = new Rule({ selector: ":root", source: root.source }); // Add derived css variables to :root resolvedMap.forEach((value, key) => { - const declaration = new Declaration({prop: key, value}); + const declaration = new Declaration({prop: `--${key}`, value}); newRule.append(declaration); }); root.append(newRule);