-
Notifications
You must be signed in to change notification settings - Fork 0
(testing around) Add gfcli remove command to uninstall installed Google Fonts
#3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -187,6 +187,36 @@ googleFont.prototype.installAsync = async function(variants) { | |
| return resultList; | ||
| }; | ||
|
|
||
| /** | ||
| * Remove installed font variants from the system font folder | ||
| * @param {string[] | false} [variants] - Variants to remove, or false for all | ||
| * @returns {Promise<FontResult[]>} Results of removed fonts (one entry per variant) | ||
| */ | ||
| googleFont.prototype.uninstallAsync = async function(variants) { | ||
| const fileList = await this._getFileMapAsync(DEFAULT_FORMAT); | ||
| const requested = (variants && variants.length) ? variants : Object.keys(fileList); | ||
| const resultList = []; | ||
| const fileName = await toPascalCase(this.getFamily()); | ||
|
|
||
| for (const v of requested) { | ||
| const norm = this._normalizeVariant(v); | ||
| const url = fileList[norm]; | ||
|
|
||
| if (url) { | ||
| try { | ||
| const paths = await systemFont.uninstall(fileName + '-' + norm); | ||
| for (const p of paths) { | ||
| resultList.push({ family: this.getFamily(), variant: norm, path: p }); | ||
| } | ||
| } catch (err) { | ||
| throw err; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return resultList; | ||
| }; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uninstall aborts on first missing variant, losing deletionsHigh Severity
|
||
|
|
||
| /** | ||
| * Save font variants to a specified folder | ||
| * @param {string[] | false} [variants] - Variants to download, or false for all | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -240,6 +240,74 @@ SystemFont.prototype.install = async function(remoteFile, fileName) { | |
| } | ||
| }; | ||
|
|
||
| /** | ||
| * Candidate paths for an installed font file (TTF and WOFF2) for the current platform. | ||
| * @param {string} fileBase - Base filename without extension (e.g. OpenSans-regular) | ||
| * @returns {string[]} | ||
| */ | ||
| SystemFont.prototype._uninstallCandidatePaths = function(fileBase) { | ||
| /** @type {string[]} */ | ||
| const dirs = []; | ||
| switch (platform) { | ||
| case 'linux': { | ||
| const xdgDataHome = process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share'); | ||
| dirs.push(path.join(xdgDataHome, 'fonts')); | ||
| break; | ||
| } | ||
| case 'darwin': | ||
| dirs.push(path.join(os.homedir(), 'Library', 'Fonts')); | ||
| break; | ||
| case 'win32': { | ||
| const localAppData = process.env.LOCALAPPDATA; | ||
| if (localAppData) { | ||
| dirs.push(path.join(localAppData, 'Microsoft', 'Windows', 'Fonts')); | ||
| } | ||
| break; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Windows uninstall path mismatches install destinationMedium Severity On Windows, Additional Locations (1) |
||
| } | ||
|
Comment on lines
+260
to
+266
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify the Windows install path behavior by checking the PowerShell namespace constant
# Search for how install handles Windows to understand the target directory
rg -n -A 10 "Namespace\(0x14\)" --type js
# Check if there are any comments or documentation about Windows font paths
rg -n -i "windows.*font" --type js --type mdRepository: t2sever/gfcli Length of output: 1599 🌐 Web query:
💡 Result: In Windows 10 and Windows 11,
Citations:
Windows install/uninstall path mismatch prevents font removal. The Fonts installed via this tool will not be found during uninstall on Windows, causing "Font file not found" errors. Update the uninstall path to match the system folder where install places fonts. 🤖 Prompt for AI Agents |
||
| default: | ||
| throw new Error('Platform not supported.'); | ||
| } | ||
| /** @type {string[]} */ | ||
| const out = []; | ||
| for (const d of dirs) { | ||
| out.push(path.join(d, fileBase + '.ttf')); | ||
| out.push(path.join(d, fileBase + '.woff2')); | ||
| } | ||
| return out; | ||
| }; | ||
|
|
||
| /** | ||
| * Remove installed font files matching the same basename used by install (TTF or WOFF2). | ||
| * @param {string} fileBase - Base filename without extension | ||
| * @returns {Promise<string[]>} Paths that were removed | ||
| */ | ||
| SystemFont.prototype.uninstall = async function(fileBase) { | ||
| const candidates = this._uninstallCandidatePaths(fileBase); | ||
| /** @type {string[]} */ | ||
| const removed = []; | ||
| for (const p of candidates) { | ||
| try { | ||
| await fs.unlink(p); | ||
| removed.push(p); | ||
| } catch (err) { | ||
| if (/** @type {NodeJS.ErrnoException} */ (err).code !== 'ENOENT') { | ||
| throw err; | ||
| } | ||
| } | ||
| } | ||
| if (removed.length === 0) { | ||
| throw new Error('Font file not found for: ' + fileBase); | ||
| } | ||
| if (platform === 'linux') { | ||
| try { | ||
| await util.promisify(exec)('fc-cache -f'); | ||
| } catch (err) { | ||
| // fc-cache might not be available | ||
| } | ||
| } | ||
| return removed; | ||
| }; | ||
|
|
||
| /** | ||
| * Get a supported extension from the remote URL. | ||
| * @param {string} remoteFile | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove silently succeeds when no files are deleted
Medium Severity
In
uninstallAsync, theif (url)guard silently skips any variant whose name doesn't match a key in the GWFH API file map. If all user-specified variants are skipped (e.g., typos or API changes since installation), the function returns an empty array without error. Incli.js, this incrementssuccessCountand produces zero output — the user gets no feedback and nothing was removed, yet the command appears to succeed.Additional Locations (1)
cli.js#L232-L235