From 6aaa9a45175620a68ca50c0190cce25699479a12 Mon Sep 17 00:00:00 2001 From: Tw93 Date: Tue, 16 Sep 2025 10:20:50 +0800 Subject: [PATCH] :bug: Support Chinese naming and fix the use of local icons --- bin/helpers/merge.ts | 31 ++++++++++++++++--------------- bin/options/icon.ts | 8 +++++--- bin/options/index.ts | 9 ++++----- bin/utils/name.ts | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 bin/utils/name.ts diff --git a/bin/helpers/merge.ts b/bin/helpers/merge.ts index a154fca..d9b96d3 100644 --- a/bin/helpers/merge.ts +++ b/bin/helpers/merge.ts @@ -3,6 +3,7 @@ import fsExtra from 'fs-extra'; import combineFiles from '@/utils/combine'; import logger from '@/options/logger'; +import { generateSafeFilename, generateIdentifierSafeName } from '@/utils/name'; import { PakeAppOptions, PlatformMap } from '@/types'; import { tauriConfigDirectory, npmDirectory } from '@/utils/dir'; @@ -91,7 +92,7 @@ export async function mergeConfig( tauriConf.version = appVersion; if (platform === 'linux') { - tauriConf.mainBinaryName = `pake-${name.toLowerCase()}`; + tauriConf.mainBinaryName = `pake-${generateIdentifierSafeName(name)}`; } if (platform == 'win32') { @@ -151,8 +152,8 @@ export async function mergeConfig( delete tauriConf.bundle.linux.deb.files; // Generate correct desktop file configuration - const appNameLower = name.toLowerCase(); - const identifier = `com.pake.${appNameLower}`; + const appNameSafe = generateSafeFilename(name).toLowerCase(); + const identifier = `com.pake.${appNameSafe}`; const desktopFileName = `${identifier}.desktop`; // Create desktop file content @@ -161,8 +162,8 @@ Version=1.0 Type=Application Name=${name} Comment=${name} -Exec=pake-${appNameLower} -Icon=${appNameLower}_512 +Exec=pake-${appNameSafe} +Icon=${appNameSafe}_512 Categories=Network;WebBrowser; MimeType=text/html;text/xml;application/xhtml_xml; StartupNotify=true @@ -213,28 +214,29 @@ StartupNotify=true const platformIconMap: PlatformMap = { win32: { fileExt: '.ico', - path: `png/${name.toLowerCase()}_256.ico`, + path: `png/${generateSafeFilename(name).toLowerCase()}_256.ico`, defaultIcon: 'png/icon_256.ico', message: 'Windows icon must be .ico and 256x256px.', }, linux: { fileExt: '.png', - path: `png/${name.toLowerCase()}_512.png`, + path: `png/${generateSafeFilename(name).toLowerCase()}_512.png`, defaultIcon: 'png/icon_512.png', message: 'Linux icon must be .png and 512x512px.', }, darwin: { fileExt: '.icns', - path: `icons/${name.toLowerCase()}.icns`, + path: `icons/${generateSafeFilename(name).toLowerCase()}.icns`, defaultIcon: 'icons/icon.icns', message: 'macOS icon must be .icns type.', }, }; const iconInfo = platformIconMap[platform]; - const exists = options.icon && (await fsExtra.pathExists(options.icon)); + const resolvedIconPath = options.icon ? path.resolve(options.icon) : null; + const exists = resolvedIconPath && (await fsExtra.pathExists(resolvedIconPath)); if (exists) { let updateIconPath = true; - let customIconExt = path.extname(options.icon).toLowerCase(); + let customIconExt = path.extname(resolvedIconPath).toLowerCase(); if (customIconExt !== iconInfo.fileExt) { updateIconPath = false; @@ -245,10 +247,9 @@ StartupNotify=true tauriConf.bundle.resources = [iconInfo.path]; // Avoid copying if source and destination are the same - const absoluteIconPath = path.resolve(options.icon); const absoluteDestPath = path.resolve(iconPath); - if (absoluteIconPath !== absoluteDestPath) { - await fsExtra.copy(options.icon, iconPath); + if (resolvedIconPath !== absoluteDestPath) { + await fsExtra.copy(resolvedIconPath, iconPath); } } @@ -275,9 +276,9 @@ StartupNotify=true if (iconExt == '.png' || iconExt == '.ico') { const trayIcoPath = path.join( npmDirectory, - `src-tauri/png/${name.toLowerCase()}${iconExt}`, + `src-tauri/png/${generateSafeFilename(name).toLowerCase()}${iconExt}`, ); - trayIconPath = `png/${name.toLowerCase()}${iconExt}`; + trayIconPath = `png/${generateSafeFilename(name).toLowerCase()}${iconExt}`; await fsExtra.copy(systemTrayIcon, trayIcoPath); } else { logger.warn( diff --git a/bin/options/icon.ts b/bin/options/icon.ts index 953d33e..4664bf0 100644 --- a/bin/options/icon.ts +++ b/bin/options/icon.ts @@ -43,9 +43,11 @@ const API_KEYS = { /** * Generates platform-specific icon paths and handles copying for Windows */ +import { generateSafeFilename } from '@/utils/name'; + function generateIconPath(appName: string, isDefault = false): string { - const safeName = appName.toLowerCase().replace(/[^a-z0-9-_]/g, '_'); - const baseName = isDefault ? 'icon' : safeName; + const safeName = isDefault ? 'icon' : generateSafeFilename(appName).toLowerCase(); + const baseName = safeName; if (IS_WIN) { return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_256.ico`); @@ -122,7 +124,7 @@ async function convertIconFormat( await fsExtra.ensureDir(platformOutputDir); const processedInputPath = await preprocessIcon(inputPath); - const iconName = appName.toLowerCase(); + const iconName = generateSafeFilename(appName).toLowerCase(); // Generate platform-specific format if (IS_WIN) { diff --git a/bin/options/index.ts b/bin/options/index.ts index a0e4ef1..c0a2a52 100644 --- a/bin/options/index.ts +++ b/bin/options/index.ts @@ -4,6 +4,7 @@ import logger from '@/options/logger'; import { handleIcon } from './icon'; import { getDomain } from '@/utils/url'; import { getIdentifier, promptText, capitalizeFirstLetter } from '@/utils/info'; +import { generateLinuxPackageName } from '@/utils/name'; import { PakeAppOptions, PakeCliOptions, PlatformMap } from '@/types'; function resolveAppName(name: string, platform: NodeJS.Platform): string { @@ -13,8 +14,8 @@ function resolveAppName(name: string, platform: NodeJS.Platform): string { function isValidName(name: string, platform: NodeJS.Platform): boolean { const platformRegexMapping: PlatformMap = { - linux: /^[a-z0-9][a-z0-9-]*$/, - default: /^[a-zA-Z0-9][a-zA-Z0-9- ]*$/, + linux: /^[a-z0-9\u4e00-\u9fff][a-z0-9\u4e00-\u9fff-]*$/, + default: /^[a-zA-Z0-9\u4e00-\u9fff][a-zA-Z0-9\u4e00-\u9fff- ]*$/, }; const reg = platformRegexMapping[platform] || platformRegexMapping.default; return !!name && reg.test(name); @@ -36,10 +37,8 @@ export default async function handleOptions( name = namePrompt || defaultName; } - // Handle platform-specific name formatting if (name && platform === 'linux') { - // Convert to lowercase and replace spaces with dashes for Linux - name = name.toLowerCase().replace(/\s+/g, '-'); + name = generateLinuxPackageName(name); } if (!isValidName(name, platform)) { diff --git a/bin/utils/name.ts b/bin/utils/name.ts new file mode 100644 index 0000000..2d7ded7 --- /dev/null +++ b/bin/utils/name.ts @@ -0,0 +1,34 @@ +export function generateSafeFilename(name: string): string { + return name + .replace(/[<>:"/\\|?*]/g, '_') + .replace(/\s+/g, '_') + .replace(/\.+$/g, '') + .slice(0, 255); +} + +export function generateLinuxPackageName(name: string): string { + return name + .toLowerCase() + .replace(/[^a-z0-9\u4e00-\u9fff]+/g, '-') + .replace(/^-+|-+$/g, '') + .replace(/-+/g, '-'); +} + +export function generateIdentifierSafeName(name: string): string { + return name + .replace(/[^a-zA-Z0-9]/g, '') + .toLowerCase(); +} + +export function generateWindowsFilename(name: string): string { + return name + .replace(/[<>:"/\\|?*]/g, '_') + .replace(/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i, '${name}_') + .slice(0, 255); +} + +export function generateMacOSFilename(name: string): string { + return name + .replace(/[:]/g, '_') + .slice(0, 255); +} \ No newline at end of file