feat: use global variable and helper script

This commit is contained in:
Baptiste Augrain
2026-02-19 17:10:12 +01:00
parent 15cc1eadd2
commit 5ea412eee4
14 changed files with 9731 additions and 82 deletions

2
.gitignore vendored
View File

@@ -17,3 +17,5 @@ build/windows/msi/Files*.wixobj
sourcemaps/ sourcemaps/
stores/snapcraft/insider/*.snap stores/snapcraft/insider/*.snap
stores/snapcraft/stable/*.snap stores/snapcraft/stable/*.snap
font-size/node_modules/
font-size/generate-css.js

View File

@@ -0,0 +1,7 @@
artifacts:
"@daiyam/artifact-lang-js":
version: 0.9.3
requires:
- "22"
"@daiyam/artifact-lang-ts":
version: 0.6.3

17
font-size/.editorconfig Normal file
View File

@@ -0,0 +1,17 @@
root = true
[*]
indent_style = tab
tab_width = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.yml,*.yaml}]
indent_style = space
indent_size = 2
[*.md]
indent_style = space
indent_size = 4

29
font-size/.fixpackrc Normal file
View File

@@ -0,0 +1,29 @@
{
"sortToTop": [
"name",
"displayName",
"description",
"version",
"private",
"author",
"publisher",
"license",
"homepage",
"repository",
"bugs",
"engines",
"type",
"bin",
"exports",
"main",
"module",
"types",
"typesVersions",
"scripts",
"dependencies",
"devDependencies",
"optionalDependencies",
"keywords"
],
"finalNewLine": true
}

2
font-size/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/node_modules/
/lib/

1
font-size/.nvmrc Normal file
View File

@@ -0,0 +1 @@
v22.21.1

9
font-size/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"search.exclude": {
"package-lock.json": true,
"lib/**": true,
},
"taskExplorer.exclude": [
".husky",
],
}

153
font-size/.xo-config.json Normal file
View File

@@ -0,0 +1,153 @@
{
"ignores": [
"*.config.js",
"*.config.ts"
],
"rules": {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/brace-style": [
"error",
"stroustrup"
],
"@typescript-eslint/class-literal-property-style": [
"error",
"fields"
],
"@typescript-eslint/keyword-spacing": [
"error",
{
"overrides": {
"if": {
"after": false
},
"for": {
"after": false
},
"switch": {
"after": false
},
"while": {
"after": false
}
}
}
],
"@typescript-eslint/member-ordering": [
"error",
{
"default": [
"field",
"constructor",
"get",
"set",
"method"
]
}
],
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"modifiers": ["const", "global"],
"format": ["camelCase", "UPPER_CASE"],
"filter": {
"regex": "^(__filename|__dirname)$",
"match": false
}
},
{
"selector": "variable",
"format": ["camelCase"],
"filter": {
"regex": "^(__filename|__dirname)$",
"match": false
}
}
],
"@typescript-eslint/no-confusing-void-expression": "off",
"@typescript-eslint/no-dynamic-delete": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/object-curly-spacing": [
"error",
"always"
],
"@typescript-eslint/parameter-properties": "off",
"@typescript-eslint/prefer-promise-reject-errors": "off",
"@typescript-eslint/return-await": "off",
"arrow-parens": [
"error",
"always"
],
"capitalized-comments": "off",
"complexity": "off",
"default-case": "off",
"import/extensions": [
"error",
"never"
],
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index",
"object"
],
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}
],
"max-depth": [
"error",
8
],
"max-params": [
"error",
12
],
"no-await-in-loop": "off",
"no-else-return": "off",
"no-lonely-if": "off",
"no-negated-condition": "off",
"object-curly-newline": "off",
"one-var": [
"error",
"never"
],
"unicorn/empty-brace-spaces": "off",
"unicorn/no-array-callback-reference": "off",
"unicorn/no-length-as-slice-end": "off",
"unicorn/no-object-as-default-parameter": "off",
"unicorn/prefer-json-parse-buffer": "off",
"unicorn/prefer-module": "off",
"unicorn/prefer-node-protocol": "off",
"unicorn/prefer-switch": "off",
"unicorn/prefer-ternary": "off",
"unicorn/prevent-abbreviations": [
"error",
{
"replacements": {
"arg": false,
"args": false,
"dir": false,
"err": false,
"fn": false,
"func": false,
"i": false,
"j": false,
"mod": false,
"num": false,
"pkg": false,
"str": false
}
}
]
}
}

139
font-size/generate-css.ts Executable file
View File

@@ -0,0 +1,139 @@
#!/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();

7436
font-size/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

30
font-size/package.json Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "font-size",
"description": "",
"version": "1.0.0",
"author": {
"name": "Baptiste Augrain",
"email": "daiyam@zokugun.org"
},
"license": "MIT",
"type": "module",
"main": "generate-css.ts",
"scripts": {
"clean": "rimraf lib",
"lint": "xo",
"lint:fix": "xo --fix",
"prepare": "fixpack || true"
},
"dependencies": {
"@zokugun/fs-extra-plus": "^0.3.3",
"@zokugun/xtry": "^0.10.1",
"fast-glob": "^3.3.3",
"postcss": "^8.5.6"
},
"devDependencies": {
"@types/node": "^22.9.0",
"fixpack": "^4.0.0",
"xo": "0.60.0"
},
"keywords": []
}

View File

@@ -0,0 +1,78 @@
{
"compilerOptions": {
/* Language and Environment */
"target": "ES2022", /* Specify ECMAScript target version. */
"lib": [ /* Specify library files to be included in the compilation. */
"ES2022",
],
/* Modules */
"module": "node16", /* Specify what module code is generated. */
/* Basic Options */
// "allowJs": false, /* Allow javascript files to be compiled. */
// "checkJs": false, /* Report errors in '.js' files. */
// "jsx": undefined, /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
// "declaration": false, /* Generates corresponding '.d.ts' file. */
// "declarationDir": "" /* Specify the output directory for generated declaration files. */
// "declarationMap": false, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "outFile": "", /* Specify a file that bundles all outputs into one JavaScript file. */
// "outDir": "", /* Specify an output folder for all emitted files. */
// "rootDir": "", /* Specify the root directory of input files. */
// "incremental": false, /* Save '.tsbuildinfo' files to allow for incremental compilation of projects. */
// "composite": false, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": ".tsbuildinfo", /* Specify the folder for '.tsbuildinfo' incremental compilation files. */
// "removeComments": false, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting file from a compilation. */
// "importHelpers": false, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "downlevelIteration": false, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": false, /* Ensure that each file can be safely transpiled without relying on other imports. */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"strictNullChecks": true, /* When type checking, take into account null and undefined. */
// "strictFunctionTypes": false, /* Enable strict checking of function types. */
// "strictBindCallApply": false, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": false, /* Enable error reporting when 'this' is given the type 'any'. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": false, /* Report errors on unused parameters. */
"noImplicitAny": false, /* Report error for expressions and declarations with an implied any type.. */
"noImplicitReturns": false, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": false, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": false, /* Include 'undefined' in index signature results */
// "noImplicitOverride": false, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
// "noPropertyAccessFromIndexSignature": false, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
// "preserveSymlinks": false, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
// "allowUmdGlobalAccess": false, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": false, /* Enable importing .json files */
/* Source Map Options */
// "sourceMap": false, /* Create source map files for emitted JavaScript files. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": false, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": false, /* Include source code in the sourcemaps inside the emitted JavaScript. */
/* Experimental Options */
// "experimentalDecorators": false, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": false, /* Emit design-type metadata for decorated declarations in source files. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
},
}

15
font-size/tsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
/* Basic Options */
"outDir": ".",
"rootDir": ".",
"declaration": true,
/* Module Resolution Options */
"resolveJsonModule": true, /* Enable importing .json files */
},
"files": [
"package.json",
],
}

File diff suppressed because it is too large Load Diff