From f897e5132c29532034d7fe3d59a1dc53e02c62a3 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 14 Mar 2022 12:11:46 +0530 Subject: [PATCH] Implement url to variables plugin --- package.json | 2 +- scripts/postcss/css-url-to-variables.js | 54 +++++++++++++++++++ .../css-compile-variables.test.js} | 4 +- .../tests/css-url-to-variables.test.js | 48 +++++++++++++++++ 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 scripts/postcss/css-url-to-variables.js rename scripts/postcss/{test.js => tests/css-compile-variables.test.js} (98%) create mode 100644 scripts/postcss/tests/css-url-to-variables.test.js diff --git a/package.json b/package.json index d506d872..af863ced 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 scripts/postcss/test.js ", + "test:postcss": "impunity --entry-point scripts/postcss/tests/css-compile-variables.test.js scripts/postcss/tests/css-url-to-variables.test.js", "start": "vite --port 3000", "build": "vite build", "build:sdk": "./scripts/sdk/build.sh" diff --git a/scripts/postcss/css-url-to-variables.js b/scripts/postcss/css-url-to-variables.js new file mode 100644 index 00000000..a9370117 --- /dev/null +++ b/scripts/postcss/css-url-to-variables.js @@ -0,0 +1,54 @@ +const valueParser = require("postcss-value-parser"); +let counter = 0; +const variableMap = new Map(); +const format = "icon-url" + +function extractUrl(decl) { + const value = decl.value; + const parsed = valueParser(value); + const variables = []; + parsed.walk(node => { + if (node.type !== "function" || node.value !== "url") { + return; + } + const urlStringNode = node.nodes[0]; + const variableName = `--${format}-${counter++}`; + variableMap.set(variableName, `"${urlStringNode.value}"`); + const varNode = { + type: "function", + value: "var", + nodes: [{ type: "word", value: variableName }], + }; + //replace the url-string node with this var-node + node.nodes[0] = varNode; + }); + decl.assign({prop: decl.prop, value: parsed.toString()}) + return variables; +} + +function addResolvedVariablesToRootSelector(root, { Rule, Declaration }) { + const newRule = new Rule({ selector: ":root", source: root.source }); + // Add derived css variables to :root + variableMap.forEach((value, key) => { + const declaration = new Declaration({ prop: key, value }); + newRule.append(declaration); + }); + root.append(newRule); +} + +/* * + * @type {import('postcss').PluginCreator} + */ +module.exports = (opts = {}) => { + return { + postcssPlugin: "postcss-url-to-variable", + + Once(root, { Rule, Declaration }) { + root.walkDecls(decl => extractUrl(decl)); + addResolvedVariablesToRootSelector(root, { Rule, Declaration }); + }, + }; +}; + +module.exports.postcss = true; + diff --git a/scripts/postcss/test.js b/scripts/postcss/tests/css-compile-variables.test.js similarity index 98% rename from scripts/postcss/test.js rename to scripts/postcss/tests/css-compile-variables.test.js index cccb3ea7..945d5d4d 100644 --- a/scripts/postcss/test.js +++ b/scripts/postcss/tests/css-compile-variables.test.js @@ -16,8 +16,8 @@ limitations under the License. const offColor = require("off-color").offColor; const postcss = require("postcss"); -const plugin = require("./css-compile-variables"); -const derive = require("./color").derive; +const plugin = require("../css-compile-variables"); +const derive = require("../color").derive; async function run(input, output, opts = {}, assert) { let result = await postcss([plugin({ ...opts, derive })]).process(input, { from: undefined, }); diff --git a/scripts/postcss/tests/css-url-to-variables.test.js b/scripts/postcss/tests/css-url-to-variables.test.js new file mode 100644 index 00000000..36a38345 --- /dev/null +++ b/scripts/postcss/tests/css-url-to-variables.test.js @@ -0,0 +1,48 @@ +/* +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 postcss = require("postcss"); +const plugin = require("../css-url-to-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 { + "url is replaced with variable": async (assert) => { + const inputCSS = `div { + background: no-repeat center/80% url("../img/image.png"); + }`; + const outputCSS = + `div { + background: no-repeat center/80% url(var(--icon-url-0)); + }`+ + ` + :root { + --icon-url-0: "../img/image.png"; + } + `; + await run( inputCSS, outputCSS, { }, assert); + }, + }; +}; +