Showing the changes to scripts (1 of 62 files). Show all
Unified · Split
| @@ -1,153 +0,0 @@ | ||
| 1 | −#!/usr/bin/env node | |
| 2 | − | |
| 3 | −import fs from "node:fs/promises"; | |
| 4 | −import os from "node:os"; | |
| 5 | −import path from "node:path"; | |
| 6 | −import vm from "node:vm"; | |
| 7 | −import { execFile } from "node:child_process"; | |
| 8 | −import { promisify } from "node:util"; | |
| 9 | − | |
| 10 | −const execFileAsync = promisify(execFile); | |
| 11 | − | |
| 12 | −const VERSION = process.argv[2] ?? "12.17.0"; | |
| 13 | −const VERSION_TAG = `v${VERSION}`; | |
| 14 | −const VSIX_URL = `https://open-vsx.org/api/vscode-icons-team/vscode-icons/${VERSION}/file/vscode-icons-team.vscode-icons-${VERSION}.vsix`; | |
| 15 | −const LANGUAGES_URL = `https://raw.githubusercontent.com/vscode-icons/vscode-icons/${VERSION_TAG}/src/iconsManifest/languages.ts`; | |
| 16 | − | |
| 17 | −const REPO_ROOT = process.cwd(); | |
| 18 | −const MANIFEST_PATH = path.join(REPO_ROOT, "apps/web/src/vscode-icons-manifest.json"); | |
| 19 | −const ASSOCIATIONS_PATH = path.join( | |
| 20 | − REPO_ROOT, | |
| 21 | − "apps/web/src/vscode-icons-language-associations.json", | |
| 22 | −); | |
| 23 | − | |
| 24 | −function normalizeExtension(value) { | |
| 25 | − return value.trim().toLowerCase().replace(/^\./, ""); | |
| 26 | −} | |
| 27 | − | |
| 28 | −function normalizeFileName(value) { | |
| 29 | − return value.trim().toLowerCase(); | |
| 30 | −} | |
| 31 | − | |
| 32 | −function putIfAbsent(target, key, value) { | |
| 33 | − if (!(key in target)) { | |
| 34 | − target[key] = value; | |
| 35 | − } | |
| 36 | −} | |
| 37 | − | |
| 38 | −async function downloadVsix(tmpDir) { | |
| 39 | − const vsixPath = path.join(tmpDir, `vscode-icons-${VERSION}.vsix`); | |
| 40 | − const response = await fetch(VSIX_URL); | |
| 41 | − if (!response.ok) { | |
| 42 | − throw new Error(`Failed to download VSIX: ${response.status} ${response.statusText}`); | |
| 43 | − } | |
| 44 | − const bytes = Buffer.from(await response.arrayBuffer()); | |
| 45 | − await fs.writeFile(vsixPath, bytes); | |
| 46 | − return vsixPath; | |
| 47 | −} | |
| 48 | − | |
| 49 | −async function extractManifestFromVsix(vsixPath) { | |
| 50 | − const { stdout } = await execFileAsync("unzip", [ | |
| 51 | − "-p", | |
| 52 | − vsixPath, | |
| 53 | − "extension/dist/src/vsicons-icon-theme.json", | |
| 54 | − ]); | |
| 55 | − if (!stdout || stdout.trim().length === 0) { | |
| 56 | − throw new Error("Could not extract vsicons-icon-theme.json from VSIX"); | |
| 57 | − } | |
| 58 | − return JSON.parse(stdout); | |
| 59 | −} | |
| 60 | − | |
| 61 | −async function loadLanguagesCollection() { | |
| 62 | − const response = await fetch(LANGUAGES_URL); | |
| 63 | − if (!response.ok) { | |
| 64 | − throw new Error(`Failed to fetch languages.ts: ${response.status} ${response.statusText}`); | |
| 65 | − } | |
| 66 | − const rawSource = await response.text(); | |
| 67 | − const source = rawSource | |
| 68 | − .replace(/^import[^;]+;\s*/gm, "") | |
| 69 | − .replace(/export const languages(?:\s*:\s*[^=]+)?\s*=/, "const languages =") | |
| 70 | − .replace(/\}\s*satisfies\s*Record<[^;]+>;/, "};"); | |
| 71 | − | |
| 72 | − const context = {}; | |
| 73 | − vm.createContext(context); | |
| 74 | − vm.runInContext(`${source}\n;globalThis.__languages = languages;`, context); | |
| 75 | − const languages = context.__languages; | |
| 76 | − if (!languages || typeof languages !== "object") { | |
| 77 | − throw new Error("Failed to parse languages.ts into a collection"); | |
| 78 | − } | |
| 79 | − return languages; | |
| 80 | −} | |
| 81 | − | |
| 82 | −function buildLanguageAssociations(manifest, languages) { | |
| 83 | − const availableLanguageIds = new Set(Object.keys(manifest.languageIds ?? {})); | |
| 84 | − const extensionToLanguageId = {}; | |
| 85 | − const fileNameToLanguageId = {}; | |
| 86 | − | |
| 87 | − for (const entry of Object.values(languages)) { | |
| 88 | − if (!entry || typeof entry !== "object") continue; | |
| 89 | − const idsRaw = entry.ids; | |
| 90 | − const ids = Array.isArray(idsRaw) ? idsRaw : [idsRaw]; | |
| 91 | − const knownExtensions = Array.isArray(entry.knownExtensions) ? entry.knownExtensions : []; | |
| 92 | − const knownFilenames = Array.isArray(entry.knownFilenames) ? entry.knownFilenames : []; | |
| 93 | − | |
| 94 | − for (const idValue of ids) { | |
| 95 | − if (typeof idValue !== "string") continue; | |
| 96 | − const languageId = idValue.trim(); | |
| 97 | − if (languageId.length === 0) continue; | |
| 98 | − if (!availableLanguageIds.has(languageId)) continue; | |
| 99 | − | |
| 100 | − for (const extensionValue of knownExtensions) { | |
| 101 | − if (typeof extensionValue !== "string") continue; | |
| 102 | − const extension = normalizeExtension(extensionValue); | |
| 103 | − if (extension.length === 0) continue; | |
| 104 | − putIfAbsent(extensionToLanguageId, extension, languageId); | |
| 105 | − } | |
| 106 | − | |
| 107 | − for (const fileNameValue of knownFilenames) { | |
| 108 | − if (typeof fileNameValue !== "string") continue; | |
| 109 | − const fileName = normalizeFileName(fileNameValue); | |
| 110 | − if (fileName.length === 0) continue; | |
| 111 | − putIfAbsent(fileNameToLanguageId, fileName, languageId); | |
| 112 | − } | |
| 113 | − } | |
| 114 | − } | |
| 115 | − | |
| 116 | − return { | |
| 117 | − version: VERSION, | |
| 118 | − source: LANGUAGES_URL, | |
| 119 | − generatedAt: new Date().toISOString(), | |
| 120 | − extensionToLanguageId, | |
| 121 | − fileNameToLanguageId, | |
| 122 | − }; | |
| 123 | −} | |
| 124 | − | |
| 125 | −async function main() { | |
| 126 | − const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "t3-vscode-icons-sync-")); | |
| 127 | − try { | |
| 128 | − const vsixPath = await downloadVsix(tmpDir); | |
| 129 | − const manifest = await extractManifestFromVsix(vsixPath); | |
| 130 | − const languages = await loadLanguagesCollection(); | |
| 131 | − const associations = buildLanguageAssociations(manifest, languages); | |
| 132 | − | |
| 133 | − await fs.writeFile(MANIFEST_PATH, `${JSON.stringify(manifest)}\n`, "utf8"); | |
| 134 | − await fs.writeFile(ASSOCIATIONS_PATH, `${JSON.stringify(associations)}\n`, "utf8"); | |
| 135 | − | |
| 136 | − process.stdout.write( | |
| 137 | − [ | |
| 138 | − `Synced vscode-icons ${VERSION}`, | |
| 139 | − `manifest: ${MANIFEST_PATH}`, | |
| 140 | − `language associations: ${ASSOCIATIONS_PATH}`, | |
| 141 | − `extension mappings: ${Object.keys(associations.extensionToLanguageId).length}`, | |
| 142 | − `filename mappings: ${Object.keys(associations.fileNameToLanguageId).length}`, | |
| 143 | − ].join("\n") + "\n", | |
| 144 | − ); | |
| 145 | − } finally { | |
| 146 | − await fs.rm(tmpDir, { recursive: true, force: true }); | |
| 147 | − } | |
| 148 | −} | |
| 149 | − | |
| 150 | −main().catch((error) => { | |
| 151 | − process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); | |
| 152 | − process.exit(1); | |
| 153 | −}); | |