commit d8c15b66530515a500bd2d904cdedc011c63d058 Author: jung-geun Date: Mon Dec 16 20:05:22 2024 +0900 .gitignore 파일 추가 및 파일 이름 정규화 기능 구현 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3699a3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,178 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node,visualstudiocode,git +# Edit at https://www.toptal.com/developers/gitignore?templates=node,visualstudiocode,git + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/node,visualstudiocode,git \ No newline at end of file diff --git a/normalize.js b/normalize.js new file mode 100644 index 0000000..33ff2a8 --- /dev/null +++ b/normalize.js @@ -0,0 +1,82 @@ +const fs = require("fs").promises; +const path = require("path"); + +// 특정 파일/디렉토리를 무시하는 기능 추가 +function shouldIgnore(itemName) { + const ignoredItems = [".git", "node_modules", ".env"]; + return ignoredItems.includes(itemName); +} + +async function normalizeFileName(filePath) { + const dir = path.dirname(filePath); + const oldName = path.basename(filePath); + + const newName = oldName.normalize("NFC"); + + if (oldName !== newName && !shouldIgnore(oldName)) { + const newPath = path.join(dir, newName); + try { + // 경로에 공백이 있을 경우를 대비해 이스케이프 처리 + const escapedOldPath = filePath.replace(/ /g, "\\ "); + const escapedNewPath = newPath.replace(/ /g, "\\ "); + await fs.rename(escapedOldPath, escapedNewPath); + console.log(`이름 변경: "${oldName}" -> "${newName}"`); + return newPath; + } catch (error) { + console.error(`이름 변경 실패 ("${oldName}"):`, error); + return filePath; + } + } + return filePath; +} + +async function processDirectory(dirPath) { + try { + // 경로에 공백이 있을 경우를 대비해 이스케이프 처리 + const escapedDirPath = dirPath.replace(/ /g, "\\ "); + const entries = await fs.readdir(escapedDirPath, { withFileTypes: true }); + + const items = entries.map((entry) => ({ + name: entry.name, + fullPath: path.join(dirPath, entry.name), + isDirectory: entry.isDirectory(), + })); + + for (const item of items) { + if (item.isDirectory) { + await processDirectory(item.fullPath); + await normalizeFileName(item.fullPath); + } else { + await normalizeFileName(item.fullPath); + } + } + } catch (error) { + console.error(`디렉토리 처리 중 오류 발생 ("${dirPath}"):`, error); + } +} + +async function processRoot(rootPath) { + try { + // 경로에 공백이 있을 경우를 대비해 이스케이프 처리 + const escapedRootPath = path.resolve(rootPath); + const stats = await fs.stat(escapedRootPath); + + if (stats.isDirectory()) { + const normalizedRootPath = await normalizeFileName(rootPath); + await processDirectory(normalizedRootPath); + } else { + await normalizeFileName(rootPath); + } + } catch (error) { + console.error(`처리 중 오류 발생 ("${rootPath}"):`, error); + } +} + +// 명령줄 인자로 경로를 받거나 기본값 사용 +// 경로에 공백이 있을 경우를 대비해 따옴표로 감싸진 경로도 처리 +const targetPath = process.argv[2] || "./convert"; + +// 프로그램 실행 +processRoot(targetPath) + .then(() => console.log("모든 처리가 완료되었습니다.")) + .catch((error) => console.error("프로그램 실행 중 오류 발생:", error)); diff --git a/normalize_ko.js b/normalize_ko.js new file mode 100644 index 0000000..d324a9a --- /dev/null +++ b/normalize_ko.js @@ -0,0 +1,89 @@ +const fs = require("fs").promises; +const path = require("path"); +function containsKorean(text) { + // 한글 유니코드 범위: 가-힣, ㄱ-ㅎ, ㅏ-ㅣ + return /[가-힣ㄱ-ㅎㅏ-ㅣ]/.test(text); +} +// 특정 파일/디렉토리를 무시하는 기능 추가 +function shouldIgnore(itemName) { + const ignoredItems = [".git", "node_modules", ".env"]; + return ignoredItems.includes(itemName); +} + +async function normalizeFileName(filePath) { + const dir = path.dirname(filePath); + const oldName = path.basename(filePath); + + if (!containsKorean(oldName)) { + return filePath; + } + + const newName = oldName.normalize("NFC"); + + if (oldName !== newName && !shouldIgnore(oldName)) { + const newPath = path.join(dir, newName); + try { + // 경로에 공백이 있을 경우를 대비해 이스케이프 처리 + const escapedOldPath = filePath.replace(/ /g, "\\ "); + const escapedNewPath = newPath.replace(/ /g, "\\ "); + await fs.rename(escapedOldPath, escapedNewPath); + console.log(`이름 변경: "${oldName}" -> "${newName}"`); + return newPath; + } catch (error) { + console.error(`이름 변경 실패 ("${oldName}"):`, error); + return filePath; + } + } + return filePath; +} + +async function processDirectory(dirPath) { + try { + // 경로에 공백이 있을 경우를 대비해 이스케이프 처리 + const escapedDirPath = dirPath.replace(/ /g, "\\ "); + const entries = await fs.readdir(escapedDirPath, { withFileTypes: true }); + + const items = entries.map((entry) => ({ + name: entry.name, + fullPath: path.join(dirPath, entry.name), + isDirectory: entry.isDirectory(), + })); + + for (const item of items) { + if (item.isDirectory) { + await processDirectory(item.fullPath); + await normalizeFileName(item.fullPath); + } else { + await normalizeFileName(item.fullPath); + } + } + } catch (error) { + console.error(`디렉토리 처리 중 오류 발생 ("${dirPath}"):`, error); + } +} + +async function processRoot(rootPath) { + try { + // 경로에 공백이 있을 경우를 대비해 이스케이프 처리 + const escapedRootPath = path.resolve(rootPath); + const stats = await fs.stat(escapedRootPath); + + if (stats.isDirectory()) { + const normalizedRootPath = await normalizeFileName(rootPath); + await processDirectory(normalizedRootPath); + } else { + await normalizeFileName(rootPath); + } + } catch (error) { + console.error(`처리 중 오류 발생 ("${rootPath}"):`, error); + } +} + +// 명령줄 인자로 경로를 받거나 기본값 사용 +// 경로에 공백이 있을 경우를 대비해 따옴표로 감싸진 경로도 처리 +const targetPath = process.argv[2] || "./convert"; + +// 프로그램 실행 +processRoot(targetPath) + .then(() => console.log("모든 처리가 완료되었습니다.")) + .catch((error) => console.error("프로그램 실행 중 오류 발생:", error)); diff --git a/run.bat b/run.bat new file mode 100644 index 0000000..1ee8b75 --- /dev/null +++ b/run.bat @@ -0,0 +1,3 @@ +@echo off +cd /d %~dp0 +normalize-win.exe \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..45f0528 --- /dev/null +++ b/run.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Detect the operating system +OS="$(uname -s)" + +case "$OS" in + Darwin) + echo "Running on macOS" + ./normalize-macos $@ + ;; + Linux) + echo "Running on Linux" + ./normalize-linux $@ + ;; + *) + echo "Unknown OS: $OS" + exit 1 + ;; +esac