mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-02 20:44:13 +01:00 
			
		
		
		
	Use the file extension mapping from VSCode's extensions. Otherwise js/ts/vba/... files won't get correct icons.
		
			
				
	
	
		
			112 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env node
 | 
						|
import fastGlob from 'fast-glob';
 | 
						|
import {optimize} from 'svgo';
 | 
						|
import {parse} from 'node:path';
 | 
						|
import {readFile, writeFile, mkdir} from 'node:fs/promises';
 | 
						|
import {fileURLToPath} from 'node:url';
 | 
						|
import {exit} from 'node:process';
 | 
						|
import * as fs from 'node:fs';
 | 
						|
 | 
						|
const glob = (pattern) => fastGlob.sync(pattern, {
 | 
						|
  cwd: fileURLToPath(new URL('..', import.meta.url)),
 | 
						|
  absolute: true,
 | 
						|
});
 | 
						|
 | 
						|
async function processAssetsSvgFile(file, {prefix, fullName} = {}) {
 | 
						|
  let name = fullName;
 | 
						|
  if (!name) {
 | 
						|
    name = parse(file).name;
 | 
						|
    if (prefix) name = `${prefix}-${name}`;
 | 
						|
    if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons
 | 
						|
  }
 | 
						|
  // Set the `xmlns` attribute so that the files are displayable in standalone documents
 | 
						|
  // The svg backend module will strip the attribute during startup for inline display
 | 
						|
  const {data} = optimize(await readFile(file, 'utf8'), {
 | 
						|
    plugins: [
 | 
						|
      {name: 'preset-default'},
 | 
						|
      {name: 'removeDimensions'},
 | 
						|
      {name: 'prefixIds', params: {prefix: () => name}},
 | 
						|
      {name: 'addClassesToSVGElement', params: {classNames: ['svg', name]}},
 | 
						|
      {
 | 
						|
        name: 'addAttributesToSVGElement', params: {
 | 
						|
          attributes: [
 | 
						|
            {'xmlns': 'http://www.w3.org/2000/svg'},
 | 
						|
            {'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'},
 | 
						|
          ],
 | 
						|
        },
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  });
 | 
						|
  await writeFile(fileURLToPath(new URL(`../public/assets/img/svg/${name}.svg`, import.meta.url)), data);
 | 
						|
}
 | 
						|
 | 
						|
function processAssetsSvgFiles(pattern, opts) {
 | 
						|
  return glob(pattern).map((file) => processAssetsSvgFile(file, opts));
 | 
						|
}
 | 
						|
 | 
						|
async function processMaterialFileIcons() {
 | 
						|
  const files = glob('node_modules/material-icon-theme/icons/*.svg');
 | 
						|
  const svgSymbols = {};
 | 
						|
  for (const file of files) {
 | 
						|
    // remove all unnecessary attributes, only keep "viewBox"
 | 
						|
    const {data} = optimize(await readFile(file, 'utf8'), {
 | 
						|
      plugins: [
 | 
						|
        {name: 'preset-default'},
 | 
						|
        {name: 'removeDimensions'},
 | 
						|
        {name: 'removeXMLNS'},
 | 
						|
        {name: 'removeAttrs', params: {attrs: 'xml:space', elemSeparator: ','}},
 | 
						|
      ],
 | 
						|
    });
 | 
						|
    const svgName = parse(file).name;
 | 
						|
    // intentionally use single quote here to avoid escaping
 | 
						|
    svgSymbols[svgName] = data.replace(/"/g, `'`);
 | 
						|
  }
 | 
						|
  fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
 | 
						|
 | 
						|
  const vscodeExtensionsJson = await readFile(fileURLToPath(new URL(`generate-svg-vscode-extensions.json`, import.meta.url)));
 | 
						|
  const vscodeExtensions = JSON.parse(vscodeExtensionsJson);
 | 
						|
  const iconRulesJson = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)));
 | 
						|
  const iconRules = JSON.parse(iconRulesJson);
 | 
						|
  // The rules are from VSCode material-icon-theme, we need to adjust them to our needs
 | 
						|
  // 1. We only use lowercase filenames to match (it should be good enough for most cases and more efficient)
 | 
						|
  // 2. We do not have a "Language ID" system:
 | 
						|
  //    * https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers
 | 
						|
  //    * https://github.com/microsoft/vscode/tree/1.98.0/extensions
 | 
						|
  delete iconRules.iconDefinitions;
 | 
						|
  for (const [k, v] of Object.entries(iconRules.fileNames)) iconRules.fileNames[k.toLowerCase()] = v;
 | 
						|
  for (const [k, v] of Object.entries(iconRules.folderNames)) iconRules.folderNames[k.toLowerCase()] = v;
 | 
						|
  for (const [k, v] of Object.entries(iconRules.fileExtensions)) iconRules.fileExtensions[k.toLowerCase()] = v;
 | 
						|
  // Use VSCode's "Language ID" mapping from its extensions
 | 
						|
  for (const [_, langIdExtMap] of Object.entries(vscodeExtensions)) {
 | 
						|
    for (const [langId, names] of Object.entries(langIdExtMap)) {
 | 
						|
      for (const name of names) {
 | 
						|
        const nameLower = name.toLowerCase();
 | 
						|
        if (nameLower[0] === '.') {
 | 
						|
          iconRules.fileExtensions[nameLower.substring(1)] ??= langId;
 | 
						|
        } else {
 | 
						|
          iconRules.fileNames[nameLower] ??= langId;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  const iconRulesPretty = JSON.stringify(iconRules, null, 2);
 | 
						|
  fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
 | 
						|
}
 | 
						|
 | 
						|
async function main() {
 | 
						|
  await mkdir(fileURLToPath(new URL('../public/assets/img/svg', import.meta.url)), {recursive: true});
 | 
						|
  await Promise.all([
 | 
						|
    ...processAssetsSvgFiles('node_modules/@primer/octicons/build/svg/*-16.svg', {prefix: 'octicon'}),
 | 
						|
    ...processAssetsSvgFiles('web_src/svg/*.svg'),
 | 
						|
    ...processAssetsSvgFiles('public/assets/img/gitea.svg', {fullName: 'gitea-gitea'}),
 | 
						|
    processMaterialFileIcons(),
 | 
						|
  ]);
 | 
						|
}
 | 
						|
 | 
						|
try {
 | 
						|
  await main();
 | 
						|
} catch (err) {
 | 
						|
  console.error(err);
 | 
						|
  exit(1);
 | 
						|
}
 |