summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiDeoo2024-12-11 19:42:33 +0100
committerGitHub2024-12-11 19:42:33 +0100
commitc27f12893092acb81c1272d29b79e65ba60e9725 (patch)
tree33f831908621d08104df078b2ad05c3990ef952c
parentcf12beb91b4cb2f212dbcc0cc1ed56e79d055ff0 (diff)
downloadIT.starlight-c27f12893092acb81c1272d29b79e65ba60e9725.tar.gz
IT.starlight-c27f12893092acb81c1272d29b79e65ba60e9725.tar.bz2
IT.starlight-c27f12893092acb81c1272d29b79e65ba60e9725.zip
fix: use seti ui repo to generate file icons (#2648)
-rw-r--r--packages/file-icons-generator/index.ts24
-rw-r--r--packages/file-icons-generator/utils/font.ts10
-rw-r--r--packages/file-icons-generator/utils/seti.ts69
3 files changed, 71 insertions, 32 deletions
diff --git a/packages/file-icons-generator/index.ts b/packages/file-icons-generator/index.ts
index 195d3165..11642cee 100644
--- a/packages/file-icons-generator/index.ts
+++ b/packages/file-icons-generator/index.ts
@@ -1,24 +1,28 @@
import { writeDefinitionsAndSVGs } from './utils/file';
import { getIconSvgPaths } from './utils/font';
-import { fetchFont, fetchMapping, parseMapping } from './utils/seti';
+import { deleteRepo, parseMapping, setupRepo } from './utils/seti';
/**
* Script generating definitions used by the Starlight `<FileTree>` component and associated SVGs.
*
- * To do so, it fetches the Seti UI icon mapping file and font from GitHub, parses the mapping to
- * generate the definitions and a list of icons to extract as SVGs, and finally extracts the SVGs
- * from the font and writes the definitions and SVGs to the Starlight package in a file ready to be
- * consumed by Starlight.
+ * To do so, it clones the Seti UI repository, installs dependencies, generates icons, parses the
+ * mapping to generate the definitions and a list of icons to extract as SVGs, and finally extracts
+ * the SVGs from the font and writes the definitions and SVGs to the Starlight package in a file
+ * ready to be consumed by Starlight.
*
* @see {@link file://./config.ts} for the configuration used by this script.
* @see {@link file://../starlight/user-components/file-tree-icons.ts} for the generated file.
* @see {@link https://opentype.js.org/glyph-inspector.html} for a font glyph inspector.
*/
-const mapping = await fetchMapping();
-const { definitions, icons } = parseMapping(mapping);
+const repoPath = await setupRepo();
-const font = await fetchFont();
-const svgPaths = getIconSvgPaths(icons, definitions, font);
+try {
+ const { definitions, icons } = await parseMapping(repoPath);
-await writeDefinitionsAndSVGs(definitions, svgPaths);
+ const svgPaths = await getIconSvgPaths(repoPath, icons, definitions);
+
+ await writeDefinitionsAndSVGs(definitions, svgPaths);
+} finally {
+ await deleteRepo(repoPath);
+}
diff --git a/packages/file-icons-generator/utils/font.ts b/packages/file-icons-generator/utils/font.ts
index a9518e1b..64ce32cf 100644
--- a/packages/file-icons-generator/utils/font.ts
+++ b/packages/file-icons-generator/utils/font.ts
@@ -1,17 +1,15 @@
import opentype, { type Font, Glyph } from 'opentype.js';
import { seti, starlight } from '../config';
import type { Definitions } from '../../starlight/user-components/rehype-file-tree';
-import { getSetiIconName } from './seti';
+import { getFont, getSetiIconName } from './seti';
// This matches the default precision used by the SVGO default preset.
const pathDecimalPrecision = 3;
/** Extract SVG paths from the Seti UI icon font from a list of icon names matching font glyphs. */
-export function getIconSvgPaths(
- icons: string[],
- definitions: Definitions,
- fontBuffer: ArrayBuffer
-) {
+export async function getIconSvgPaths(repoPath: string, icons: string[], definitions: Definitions) {
+ const fontBuffer = await getFont(repoPath);
+
const iconSvgs: Record<string, string> = {};
let font: Font;
diff --git a/packages/file-icons-generator/utils/seti.ts b/packages/file-icons-generator/utils/seti.ts
index 283353e5..fa4d4642 100644
--- a/packages/file-icons-generator/utils/seti.ts
+++ b/packages/file-icons-generator/utils/seti.ts
@@ -1,3 +1,7 @@
+import { spawnSync, type SpawnSyncOptions } from 'node:child_process';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
import { seti, starlight } from '../config';
import type { Definitions } from '../../starlight/user-components/rehype-file-tree.ts';
@@ -7,33 +11,56 @@ import type { Definitions } from '../../starlight/user-components/rehype-file-tr
const mappingRegex =
/^\.icon-(?<type>(set|partial))\((?<quote>['"])(?<identifier>.+)\k<quote>, \k<quote>(?<lang>.+)\k<quote>, @.+\);$/;
-/** Fetch the Seti UI icon mapping file from GitHub. */
-export async function fetchMapping() {
+/** Clone the Seti UI repository, install dependencies, and generate the Seti UI icons. */
+export async function setupRepo() {
try {
- const result = await fetch(getGitHubDownloadLink(seti.repo, seti.mapping));
- return await result.text();
+ const repoPath = await fs.mkdtemp(path.join(os.tmpdir(), 'starlight-file-icons-'));
+
+ const spawnOptions: SpawnSyncOptions = {
+ cwd: repoPath,
+ encoding: 'utf8',
+ };
+
+ let result = spawnSync('git', ['clone', `https://github.com/${seti.repo}`, '.'], spawnOptions);
+ if (result.error) throw new Error('Failed to clone the Seti UI repository.');
+
+ result = spawnSync('npm', ['install'], spawnOptions);
+ if (result.error) throw new Error('Failed to install the Seti UI dependencies.');
+
+ result = spawnSync('npm', ['run', 'createIcons'], spawnOptions);
+ if (result.error) throw new Error('Failed to generate the Seti UI icons.');
+
+ return repoPath;
} catch (error) {
throw new Error(
- 'Failed to download Seti UI icon mapping file. Make sure the repository URL and mapping path are correct.',
+ 'Failed to setup the Seti UI repo. Make sure the repository URL and font path are correct.',
{ cause: error }
);
}
}
+/** Delete the Seti UI repository. */
+export async function deleteRepo(repoPath: string) {
+ try {
+ await fs.rm(repoPath, { force: true, recursive: true });
+ } catch (error) {
+ throw new Error('Failed to remove the Seti UI repo.', { cause: error });
+ }
+}
+
/**
- * Fetch the Seti UI icon font from GitHub.
+ * Get the Seti UI icon font from a local repository.
* Note that the `woff` font format is used and not `woff2` as we would manually need to decompress
* it and we do not need the compression benefits for this use case.
*/
-export async function fetchFont() {
+export async function getFont(repoPath: string) {
try {
- const result = await fetch(getGitHubDownloadLink(seti.repo, seti.font));
- return await result.arrayBuffer();
+ const result = await fs.readFile(path.join(repoPath, seti.font));
+ return new Uint8Array(result).buffer;
} catch (error) {
- throw new Error(
- 'Failed to download Seti UI font. Make sure the repository URL and font path are correct.',
- { cause: error }
- );
+ throw new Error('Failed to read Seti UI font. Make sure the font path is correct.', {
+ cause: error,
+ });
}
}
@@ -42,7 +69,9 @@ export async function fetchFont() {
* component and a list of Seti UI icons to extract as SVGs.
* @see https://github.com/elviswolcott/seti-icons/blob/master/build/extract.ts
*/
-export function parseMapping(mapping: string) {
+export async function parseMapping(repoPath: string) {
+ const mapping = await getMapping(repoPath);
+
const lines = mapping.split('\n');
// Include the `folder` icon by default as it is not defined in the mapping file.
const icons = new Set<string>(['folder']);
@@ -87,6 +116,14 @@ export function getSetiIconName(icon: string) {
return `${starlight.prefix}${name}`;
}
-function getGitHubDownloadLink(repo: string, path: string) {
- return `https://raw.githubusercontent.com/${repo}/${seti.branch}/${path}`;
+/** Get the Seti UI icon mapping file from a local repository. */
+async function getMapping(repoPath: string) {
+ try {
+ return await fs.readFile(path.join(repoPath, seti.mapping), 'utf8');
+ } catch (error) {
+ throw new Error(
+ 'Failed to read Seti UI icon mapping file. Make sure the mapping file path is correct.',
+ { cause: error }
+ );
+ }
}