Skip to content

Instantly share code, notes, and snippets.

@arrdem
Last active July 15, 2022 06:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arrdem/673433b60b5ec5048e3a618727b40f63 to your computer and use it in GitHub Desktop.
Save arrdem/673433b60b5ec5048e3a618727b40f63 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""
Usage:
find src/app -name "*.scss" -exec ./scss-use-vars -I <your-theme.scss> {} \+
About:
This is a quick and dirty implementation of part of an SCSS decompiler.
It parses obvious color definitions, and replaces inline colors with definitions where possible.
Limitations:
- No attempt is made to ensure that relevant imports exist.
- Does not understand #FFFFFF is rgb(255, 255, 255) or otherwise normalize color representations. Including capitalization.
- Does not consider rgb() and rgba(..., 1) calls equivalent.
- Many more I'm sure you can find
"""
import argparse
import re
import sys
parser = argparse.ArgumentParser()
parser.add_argument("-I", "--incldue", action="append", dest="includes")
parser.add_argument("files", nargs="+")
DEF_PAT = re.compile(r'(?P<name>\$.*?):\s*(?P<val>(#|rgb|rgba|hls|hsv|hwb|cmyk).*?);')
def parse_defs(text: str) -> dict:
defs = {}
for match in re.finditer(DEF_PAT, text):
defs[match.group('name')] = match.group('val')
return defs
assert(parse_defs("""
// Ignored
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
);
// Should match
$elten-red: #EA5454;
$elten-normal-text: rgba(0, 0, 0, 0.6);
$el-important-text: #D84315;
""") == {
"$elten-red": "#EA5454",
"$elten-normal-text": "rgba(0, 0, 0, 0.6)",
"$el-important-text": "#D84315",
})
INSTANCE_PAT = re.compile(r'(?P<val>(#|rgb|rgba|hls|hsv|hwb|cmyk).*?)(?=;)')
def fix_usages(defs: dict, text: str) -> str:
inv_defs = {v: k for k, v in defs.items()}
def munge(match: re.Match) -> str:
return inv_defs.get(match.group(1), match.group(1))
return re.sub(INSTANCE_PAT, munge, text)
assert(fix_usages({
"$elten-red": "#EA5454",
"$elten-normal-text": "rgba(0, 0, 0, 0.6)",
"$el-important-text": "#D84315",
}, """
.elten-red {
color: #EA5454;
}
.dv-fill {
fill-color: #D84315;
}
.mat-border {
border-color: rgba(0, 0, 0, 0.6);
}
""") == """
.elten-red {
color: $elten-red;
}
.dv-fill {
fill-color: $el-important-text;
}
.mat-border {
border-color: $elten-normal-text;
}
""")
if __name__ == "__main__":
opts, args = parser.parse_known_args()
defs = {}
for f in opts.includes:
with open(f, "r") as fp:
defs.update(parse_defs(fp.read()))
for f in opts.files:
with open(f, 'r') as fp:
buff = fp.read()
with open(f, 'w') as fp:
fp.write(fix_usages(defs, buff))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment