.gitignore 파일 추가 및 파일 이름 정규화 기능 구현

This commit is contained in:
2024-12-16 20:05:22 +09:00
commit d8c15b6653
5 changed files with 371 additions and 0 deletions

178
.gitignore vendored Normal file
View File

@@ -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

82
normalize.js Normal file
View File

@@ -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));

89
normalize_ko.js Normal file
View File

@@ -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));

3
run.bat Normal file
View File

@@ -0,0 +1,3 @@
@echo off
cd /d %~dp0
normalize-win.exe

19
run.sh Executable file
View File

@@ -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