Skip to content

Commit f9665ba

Browse files
wip refactor to a postcss plugin
1 parent c7d1f70 commit f9665ba

File tree

4 files changed

+142
-0
lines changed

4 files changed

+142
-0
lines changed

plugins/postcss-transparent-mapping/expected/basic.css

Whitespace-only changes.

plugins/postcss-transparent-mapping/fixtures/basic.css

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*!
2+
* Copyright 2024 Adobe. All rights reserved.
3+
*
4+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License. You may obtain a copy
6+
* of the License at <http://www.apache.org/licenses/LICENSE-2.0>
7+
*
8+
* Unless required by applicable law or agreed to in writing, software distributed under
9+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
10+
* OF ANY KIND, either express or implied. See the License for the specific language
11+
* governing permissions and limitations under the License.
12+
*/
13+
14+
/* eslint-disable no-console */
15+
16+
const fs = require("fs");
17+
// const fsp = fs.promises;
18+
const postcss = require("postcss");
19+
20+
// Read the CSS file
21+
const CSS_FILE_PATH = "tokens/dist/index.css";
22+
const css = fs.readFileSync(CSS_FILE_PATH, "utf8");
23+
24+
// Get tokens and root data
25+
const extractTokenData = (css) => {
26+
const root = postcss.parse(css);
27+
const tokens = {};
28+
29+
// Collect all custom properties
30+
root.walkDecls(decl => {
31+
const { prop, value } = decl;
32+
33+
/* Determine if this property is a custom property */
34+
const isCustomProp = prop.startsWith("--");
35+
36+
if (isCustomProp) {
37+
tokens[prop] = value;
38+
}
39+
});
40+
41+
return {root, tokens};
42+
};
43+
44+
// Creates new custom properties if the value references a `--spectrum-transparent-*` token
45+
const createNewCustomProps = (tokens) => {
46+
const newCustomProps = {};
47+
48+
/* Determine if this property has already been processed */
49+
const isProcessed = (prop) => {
50+
if (prop.endsWith("rgb") || prop.endsWith("opacity")) {
51+
return true;
52+
}
53+
return false;
54+
};
55+
56+
Object.entries(tokens).forEach(([prop, value]) => {
57+
58+
// Check if the value references a "transparent" token
59+
const match = value.match(/var\((--spectrum-transparent-[^\s)]+)\)/);
60+
if (match && (isProcessed(prop) === false)) {
61+
const referencedToken = match[1];
62+
63+
// Check if we have the required "-rgb" and "-opacity" tokens
64+
const rgbToken = `${referencedToken}-rgb`;
65+
const opacityToken = `${referencedToken}-opacity`;
66+
67+
if (tokens[rgbToken] && tokens[opacityToken]) {
68+
// create the new custom properties
69+
newCustomProps[prop] = {
70+
rgbProp: `${prop}-rgb`,
71+
rgbValue: tokens[rgbToken],
72+
opacityProp: `${prop}-opacity`,
73+
opacityValue: tokens[opacityToken],
74+
newPropValue: `rgba(var(${prop}-rgb), var(${prop}-opacity))`
75+
};
76+
}
77+
else {
78+
console.log(`Missing -rgb or -opacity tokens for ${referencedToken}`);
79+
}
80+
}
81+
});
82+
83+
return newCustomProps;
84+
};
85+
86+
87+
// Puts the newly derived tokens before the original and replaces the original value with the new tokens
88+
const injectDerivedTokens = (cssRoot, derivedTokens) => {
89+
cssRoot.walkDecls(decl => {
90+
const { prop } = decl;
91+
92+
if (derivedTokens[prop]) {
93+
const { rgbProp, rgbValue, opacityProp, opacityValue, newPropValue } = derivedTokens[prop];
94+
95+
// Insert derived tokens before the original declaration
96+
decl.before(`\n\t${rgbProp}: ${rgbValue};`);
97+
decl.before(`\n\t${opacityProp}: ${opacityValue};`);
98+
99+
// Replace the old prop with the new values
100+
decl.value = newPropValue;
101+
}
102+
});
103+
104+
return cssRoot;
105+
};
106+
107+
function transparentTokenMapping () {
108+
return {
109+
postcssPlugin: "postcss-transparent-mapping",
110+
111+
// Main function
112+
async () {
113+
try {
114+
115+
// Extract token data
116+
const { root, tokens } = extractTokenData(css);
117+
118+
// Generate derived tokens
119+
const derivedTokens = createNewCustomProps(tokens);
120+
121+
if (Object.keys(derivedTokens).length === 0) {
122+
console.log("No derived tokens found.");
123+
}
124+
else {
125+
// Inject derived tokens before their original declarations
126+
const updatedRoot = injectDerivedTokens(root, derivedTokens);
127+
128+
// Save to a file or log to console
129+
fs.writeFileSync(CSS_FILE_PATH, updatedRoot.toString(), "utf8");
130+
console.log("Derived tokens written to dist/index.css");
131+
}
132+
}
133+
catch (error) {
134+
console.error("Error:", error);
135+
}
136+
},
137+
}
138+
}
139+
140+
transparentTokenMapping.postcss = true;
141+
module.exports = transparentTokenMapping;

postcss.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ module.exports = ({
8585
"postcss-combininator": shouldCombine ? {
8686
newSelector: ".spectrum",
8787
} : false,
88+
"postcss-transparent-mapping": {},
8889
...additionalPlugins,
8990
/* --------------------------------------------------- */
9091
/* ------------------- POLYFILLS --------------------- */

0 commit comments

Comments
 (0)