mirror of
https://github.com/VSCodium/vscodium.git
synced 2026-04-11 16:27:18 +10:00
140 lines
3.8 KiB
JavaScript
Executable File
140 lines
3.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import process from 'node:process';
|
|
import fse from '@zokugun/fs-extra-plus/async';
|
|
import { err, OK, type Result, stringifyError, xtry } from '@zokugun/xtry';
|
|
import fg from 'fast-glob';
|
|
import postcss, { type Rule } from 'postcss';
|
|
|
|
const PREFIX_MAIN = '.monaco-workbench .part.sidebar';
|
|
const PREFIX_AUX = '.monaco-workbench .part.auxiliarybar';
|
|
const DEFAULT_GLOB = '../vscode/**/*.css';
|
|
const PX_REGEX = /(-?\d+(\.\d+)?)px\b/g;
|
|
const COEFF_PRECISION = 6;
|
|
|
|
function formatCoefficient(n: number): string {
|
|
const fixed = n.toFixed(COEFF_PRECISION);
|
|
return fixed.replace(/\.?0+$/, '');
|
|
}
|
|
|
|
function replacePx(_match: string, numStr: string): string {
|
|
const pxValue = Number.parseFloat(numStr);
|
|
const coeff = formatCoefficient(pxValue / 13);
|
|
|
|
return `calc(var(--vscode-workbench-sidebar-font-size) * ${coeff})`;
|
|
}
|
|
|
|
function transformPxValue(value: string): string {
|
|
return value.replaceAll(PX_REGEX, replacePx);
|
|
}
|
|
|
|
async function processFile(filePath: string): Promise<Result<void, string>> {
|
|
const cssResult = await fse.readFile(filePath, 'utf8');
|
|
if(cssResult.fails) {
|
|
return err(stringifyError(cssResult.error));
|
|
}
|
|
|
|
const postcssResult = xtry(() => postcss.parse(cssResult.value, { from: filePath }));
|
|
if(postcssResult.fails) {
|
|
return err(`Failed to parse ${filePath}: ${stringifyError(postcssResult.error)}`);
|
|
}
|
|
|
|
const generatedRoot = postcss.root();
|
|
|
|
postcssResult.value.walkRules((rule: Rule) => {
|
|
let hasPx = false;
|
|
const declarationsToAdd: Array<{ prop: string; value: string }> = [];
|
|
|
|
rule.walkDecls((declaration) => {
|
|
if(PX_REGEX.test(declaration.value)) {
|
|
const newValue = transformPxValue(declaration.value);
|
|
|
|
declarationsToAdd.push({ prop: declaration.prop, value: newValue });
|
|
|
|
hasPx = true;
|
|
}
|
|
});
|
|
|
|
if(hasPx && declarationsToAdd.length > 0) {
|
|
const selectors = (rule.selectors && rule.selectors.length > 0) ? rule.selectors : [rule.selector];
|
|
const mainSelectors = selectors.map((selector) => prefixSelector(selector, PREFIX_MAIN)).join(', ');
|
|
const auxSelectors = selectors.map((selector) => prefixSelector(selector, PREFIX_AUX)).join(', ');
|
|
const newRule = postcss.rule({ selector: `${mainSelectors}, ${auxSelectors}` });
|
|
|
|
let length = 0;
|
|
|
|
for(const declaration of declarationsToAdd) {
|
|
if(!declaration.prop.startsWith('border')) {
|
|
newRule.append({ ...declaration });
|
|
length += 1;
|
|
}
|
|
}
|
|
|
|
if(length > 0) {
|
|
generatedRoot.append(newRule);
|
|
}
|
|
}
|
|
});
|
|
|
|
if(generatedRoot.nodes && generatedRoot.nodes.length > 0) {
|
|
const writeResult = await fse.writeFile(filePath, cssResult.value + '\n\n\n' + generatedRoot.toString(), 'utf8');
|
|
if(writeResult.fails) {
|
|
return err(stringifyError(cssResult.error));
|
|
}
|
|
|
|
console.log(`Generated: ${filePath}`);
|
|
}
|
|
else {
|
|
console.log(`No px sizes found in: ${filePath}`);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const pattern = process.argv[2] || DEFAULT_GLOB;
|
|
const entries = await fg(pattern, { dot: true, onlyFiles: true });
|
|
|
|
if(entries.length === 0) {
|
|
console.log(`No files matched pattern: ${pattern}`);
|
|
return;
|
|
}
|
|
|
|
for(const file of entries) {
|
|
const result = await processFile(file);
|
|
if(result.fails) {
|
|
console.error(`Error processing ${file}:`, result.error);
|
|
}
|
|
}
|
|
}
|
|
|
|
function prefixSelector(selector: string, prefix: string): string {
|
|
const parts = selector.split(' ');
|
|
if(parts[0].startsWith('.monaco-workbench')) {
|
|
if(parts[1] === '.part') {
|
|
parts.splice(0, 2);
|
|
}
|
|
else {
|
|
parts.splice(0, 1);
|
|
}
|
|
|
|
parts.unshift(prefix);
|
|
|
|
return parts.join(' ');
|
|
}
|
|
else if(parts[0] === '.mac' || parts[0] === '.linux' || parts[0] === '.windows') {
|
|
const prefixParts = prefix.split(' ');
|
|
|
|
parts[0] = `${prefixParts.shift()}${parts[0]}`;
|
|
|
|
parts.splice(1, 0, ...prefixParts);
|
|
|
|
return parts.join(' ');
|
|
}
|
|
else {
|
|
return `${prefix} ${selector}`;
|
|
}
|
|
}
|
|
|
|
await main();
|