auto-organize 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Christian Mathías Rincón
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.es.md ADDED
@@ -0,0 +1,198 @@
1
+ ![Auto Organize CLI Banner](assets/banner.png)
2
+
3
+ <br>
4
+
5
+ # Auto Organize CLI
6
+
7
+ Leer en: [Inglés](README.md) | **Español**
8
+
9
+ <br>
10
+
11
+ Una herramienta de línea de comandos (CLI) para **organizar automáticamente archivos** en cualquier carpeta del sistema.
12
+
13
+ <br>
14
+
15
+ ## ¿Qué problema resuelve?
16
+
17
+ Cuando trabajamos con carpetas que acumulan archivos (Descargas, Escritorio, proyectos, etc), el orden se suele alterar y vemos:
18
+
19
+ * Archivos mezclados por tipo.
20
+ * Pérdida de tiempo clasificando los archivos manualmente.
21
+ * Movemos o borramos archivos incorrectos.
22
+
23
+ <br>
24
+
25
+ > **Auto Organize CLI** automatiza y corrige ese proceso.
26
+
27
+ <br>
28
+
29
+ ## Características principales
30
+
31
+ * Organización automática por tipo de archivo (clasificación por extensión).
32
+ * Modo simulación (`--preview`) para previsualizar.
33
+ * Filtros por tipo (`--only`, `--exclude`).
34
+ * **Solo mueve archivos — nunca los elimina.**
35
+ * Probado en **Windows** y **Linux** (Se espera compatibilidad con **macOS** gracias al soporte multiplataforma de **Node.js**)
36
+
37
+ <br>
38
+
39
+ ## Instalación
40
+
41
+ Requiere **Node.js >= 16**
42
+
43
+ > [Descarga Node aquí](https://nodejs.org/es/download)
44
+
45
+ ### Opción 1: Uso sin instalación (Para uso puntual)
46
+ ```bash
47
+ npx auto-organize
48
+ ```
49
+
50
+ ### Opción 2: Instalación Global (Para uso continuo)
51
+ ```bash
52
+ npm install -g auto-organize
53
+ ```
54
+
55
+ <br>
56
+
57
+ ## Uso básico
58
+
59
+ Ubicate en cualquier carpeta del sistema. Por ejemplo '/descargas'
60
+
61
+ ```bash
62
+ cd /users/descargas
63
+ ```
64
+
65
+ y ejecuta:
66
+
67
+ ```bash
68
+ auto-organize
69
+ ```
70
+
71
+ Esto, dependiendo del tipo de archivos presentes, creará carpetas como:
72
+
73
+ ```txt
74
+ Images/
75
+ Documents/
76
+ Audio/
77
+ Video/
78
+ Archives/
79
+ Others/
80
+ ```
81
+
82
+ y clasificará los archivos en la carpeta correspondiente.
83
+
84
+ ```txt
85
+ foto.jpg -> Images/
86
+
87
+ documento.pdf -> Documents/
88
+
89
+ canción.mp3 -> Audio/
90
+
91
+ video.mp4 -> Video/
92
+
93
+ archivo.rar -> Archives/
94
+
95
+ config.json -> Others/
96
+ ```
97
+
98
+ <br>
99
+
100
+ ## Modo simulación (preview)
101
+
102
+ Antes de ejecutar cambios reales, se puede previsualizar si la clasificación es correcta:
103
+
104
+ ```bash
105
+ auto-organize --preview
106
+ ```
107
+
108
+ Salida de ejemplo:
109
+
110
+ ```txt
111
+ Images/
112
+ foto.jpg
113
+
114
+ Documents/
115
+ contrato.pdf
116
+
117
+ Audio/
118
+ cancion.mp3
119
+ ```
120
+
121
+ <br>
122
+
123
+ ## Configuraciones disponibles (flags)
124
+
125
+ ### `--only <type>`
126
+
127
+ Organiza **solo** un tipo específico de archivo.
128
+
129
+ ```bash
130
+ auto-organize --only images
131
+ ```
132
+
133
+ ---
134
+
135
+ ### `--exclude <type>`
136
+
137
+ Excluye un tipo de archivo de la organización.
138
+
139
+ ```bash
140
+ auto-organize --exclude archives
141
+ ```
142
+
143
+ ---
144
+
145
+ ### `--help`
146
+
147
+ Muestra una guía completa y los tipos disponibles.
148
+
149
+ ```bash
150
+ auto-organize --help
151
+ ```
152
+
153
+ <br>
154
+
155
+ ## Tipos soportados
156
+
157
+ * images
158
+ * documents
159
+ * spreadsheets
160
+ * presentations
161
+ * archives
162
+ * audio
163
+ * video
164
+ * others
165
+
166
+ <br>
167
+
168
+ ## Casos típicos de uso
169
+
170
+ * Organizar la carpeta de Descargas.
171
+ * Limpieza rápida del Escritorio.
172
+ * Automatizar la clasificación de archivos de un proyecto (por ejemplo la carpeta '/public').
173
+
174
+ <br>
175
+
176
+ ## Contribuciones
177
+
178
+ Las contribuciones son bienvenidas. Por favor:
179
+ 1. Realiza un fork del proyecto.
180
+ 2. Crea una rama con tu feature: `git checkout -b feature/{tu-feature}`
181
+ 3. Haz commit de tus cambios: `git commit -m 'Add some feature'`
182
+ 4. Haz push a la rama: `git push origin feature/{tu-feature}`
183
+ 5. Abre un Pull Request.
184
+
185
+ <br>
186
+
187
+ ## Licencia
188
+
189
+ * MIT
190
+
191
+ <br>
192
+
193
+ ## Autor
194
+
195
+ * LinkedIn: https://www.linkedin.com/in/christian-math%C3%ADas-rinc%C3%B3n-037a90297/
196
+
197
+ * GitHub: https://github.com/ChristianRincon
198
+
package/README.md ADDED
@@ -0,0 +1,199 @@
1
+ ![Auto Organize CLI Banner](assets/banner.png)
2
+
3
+ <br>
4
+
5
+ # Auto Organize CLI
6
+
7
+ Read this in: **English** | [Spanish](README.es.md)
8
+
9
+ <br>
10
+
11
+ A command-line tool (CLI) to **automatically organize files** in any directory on your system.
12
+
13
+ <br>
14
+
15
+ ## What problem does it solve?
16
+
17
+ When working with folders that accumulate files (Downloads, Desktop, projects, etc.), things usually get messy:
18
+
19
+ * Files mixed by type.
20
+ * Time wasted manually sorting files.
21
+ * Risk of moving or deleting the wrong files.
22
+
23
+ <br>
24
+
25
+ > **Auto Organize CLI** automates and fixes this process.
26
+
27
+ <br>
28
+
29
+ ## Key Features
30
+
31
+ * Automatic file organization by type (based on file extensions).
32
+ * Simulation mode (`--preview`) to preview changes.
33
+ * Type filters (`--only`, `--exclude`).
34
+ * **Only moves files — never deletes them.**
35
+ * Tested on **Windows** and **Linux** (**macOS** compatibility is expected due to **Node.js** cross-platform support).
36
+
37
+
38
+ <br>
39
+
40
+ ## Installation
41
+
42
+ Requires **Node.js >= 16**
43
+
44
+ > [Download Node here](https://nodejs.org/en/download)
45
+
46
+ ### Option 1: Without installation (For one-time use)
47
+ ```bash
48
+ npx auto-organize
49
+ ```
50
+
51
+ ### Option 2: Global Installation (For regular use)
52
+ ```bash
53
+ npm install -g auto-organize
54
+ ```
55
+
56
+ <br>
57
+
58
+ ## Basic Usage
59
+
60
+ Navigate to any directory on your system. For example:
61
+
62
+ ```bash
63
+ cd /users/downloads
64
+ ```
65
+
66
+ Then run:
67
+
68
+ ```bash
69
+ auto-organize
70
+ ```
71
+
72
+ Depending on the files present, it will create folders such as:
73
+
74
+ ```txt
75
+ Images/
76
+ Documents/
77
+ Audio/
78
+ Video/
79
+ Archives/
80
+ Others/
81
+ ```
82
+
83
+ And move files into their corresponding folders.
84
+
85
+ ```txt
86
+ photo.jpg -> Images/
87
+
88
+ document.pdf -> Documents/
89
+
90
+ song.mp3 -> Audio/
91
+
92
+ video.mp4 -> Video/
93
+
94
+ archive.rar -> Archives/
95
+
96
+ config.json -> Others/
97
+ ```
98
+
99
+ <br>
100
+
101
+ ## Simulation Mode (preview)
102
+
103
+ Preview the organization before applying real changes:
104
+
105
+ ```bash
106
+ auto-organize --preview
107
+ ```
108
+
109
+ Example output:
110
+
111
+ ```txt
112
+ Images/
113
+ photo.jpg
114
+
115
+ Documents/
116
+ contract.pdf
117
+
118
+ Audio/
119
+ song.mp3
120
+ ```
121
+
122
+ <br>
123
+
124
+ ## Available Flags
125
+
126
+ ### `--only <type>`
127
+
128
+ Organize **only** a specific file type.
129
+
130
+ ```bash
131
+ auto-organize --only images
132
+ ```
133
+
134
+ ---
135
+
136
+ ### `--exclude <type>`
137
+
138
+ Exclude a specific file type from organization.
139
+
140
+ ```bash
141
+ auto-organize --exclude archives
142
+ ```
143
+
144
+ ---
145
+
146
+ ### `--help`
147
+
148
+ Display the help guide and available types.
149
+
150
+ ```bash
151
+ auto-organize --help
152
+ ```
153
+
154
+ <br>
155
+
156
+ ## Supported Types
157
+
158
+ * images
159
+ * documents
160
+ * spreadsheets
161
+ * presentations
162
+ * archives
163
+ * audio
164
+ * video
165
+ * others
166
+
167
+ <br>
168
+
169
+ ## Common Use Cases
170
+
171
+ * Organizing the Downloads folder
172
+ * Quick Desktop cleanup
173
+ * Automatically classifying project files (e.g. a `/public` directory)
174
+
175
+ <br>
176
+
177
+ ## Contributing
178
+
179
+ Contributions are welcome:
180
+
181
+ 1. Fork the project.
182
+ 2. Create a feature branch: `git checkout -b feature/{your-feature}`
183
+ 3. Commit your changes: `git commit -m 'Add your feature'`
184
+ 4. Push the branch: `git push origin feature/{your-feature}`
185
+ 5. Open a pull request.
186
+
187
+ <br>
188
+
189
+ ## License
190
+
191
+ * MIT
192
+
193
+ <br>
194
+
195
+ ## Author
196
+
197
+ * LinkedIn: https://www.linkedin.com/in/christian-math%C3%ADas-rinc%C3%B3n-037a90297/
198
+
199
+ * GitHub: https://github.com/ChristianRincon
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ try {
4
+ await import('../src/index.js');
5
+ } catch (error) {
6
+ console.error('Error running auto-organize');
7
+ console.error(error.message);
8
+ process.exit(1);
9
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "auto-organize",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool to organize files in a directory based on their file types.",
5
+ "main": "./bin/auto-organize.js",
6
+ "bin": {
7
+ "auto-organize": "./bin/auto-organize.js"
8
+ },
9
+ "type": "module",
10
+ "files": [
11
+ "bin",
12
+ "src"
13
+ ],
14
+ "keywords": [
15
+ "cli",
16
+ "automation",
17
+ "file-organizer",
18
+ "file-management",
19
+ "organize",
20
+ "sort",
21
+ "cleanup",
22
+ "files",
23
+ "folders",
24
+ "directories",
25
+ "command-line",
26
+ "terminal",
27
+ "nodejs",
28
+ "filesystem",
29
+ "productivity"
30
+ ],
31
+ "author": {
32
+ "name": "Christian Mathías Rincón",
33
+ "url": "https://www.linkedin.com/in/christian-math%C3%ADas-rinc%C3%B3n-037a90297/"
34
+ },
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/ChristianRincon/auto-organize.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/ChristianRincon/auto-organize/issues"
42
+ },
43
+ "homepage": "https://github.com/ChristianRincon/auto-organize",
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "dependencies": {
48
+ "chalk": "^5.6.2"
49
+ }
50
+ }
@@ -0,0 +1,20 @@
1
+ import { showHelp } from '../utils/helpMenu.js';
2
+ import { validateFlags, validateTypes, validateFlagsAndTypes } from '../utils/validators.js';
3
+ import { renderBanners } from './renderBanners.js';
4
+
5
+ function cliActions(cliFlags, availableTypes) {
6
+ validateFlags(cliFlags);
7
+ validateTypes(availableTypes);
8
+ validateFlagsAndTypes(cliFlags, availableTypes);
9
+
10
+ if (cliFlags.help) {
11
+ showHelp(availableTypes);
12
+ return { exit: true, code: 0 };
13
+ }
14
+
15
+ renderBanners(cliFlags);
16
+
17
+ return { exit: false };
18
+ }
19
+
20
+ export { cliActions };
@@ -0,0 +1,22 @@
1
+ import chalk from 'chalk';
2
+
3
+ function renderBanners(cliFlags) {
4
+ const currentDir = process.cwd();
5
+
6
+ const scannedDirectoryText = 'SCANNED DIRECTORY';
7
+ let textMargin = 0;
8
+
9
+ if(currentDir.length > scannedDirectoryText.length){
10
+ textMargin = (currentDir.length - scannedDirectoryText.length) / 2 + 2;
11
+ }
12
+
13
+ console.log(chalk.yellow("\n" + " ".repeat(textMargin) + scannedDirectoryText + "\n"));
14
+ console.log(chalk.yellow('* ') + currentDir + chalk.yellow(' *'));
15
+
16
+ if (cliFlags.preview) {
17
+ const previewModeText = 'PREVIEW MODE';
18
+ console.log("\n" + " ".repeat(textMargin) + chalk.blueBright(previewModeText));
19
+ }
20
+ }
21
+
22
+ export { renderBanners };
@@ -0,0 +1,12 @@
1
+ import chalk from 'chalk';
2
+
3
+ function renderEmptyFolderText() {
4
+ const emptyDirectoryText = 'NO FILES TO ORGANIZE';
5
+ const emptyDirectoryTextMargin = 10;
6
+
7
+ console.log("\n" + " ".repeat(emptyDirectoryTextMargin) + chalk.bgRed(" ".repeat(emptyDirectoryText.length + 2)));
8
+ console.log(" ".repeat(emptyDirectoryTextMargin) + chalk.bgRed.whiteBright(" " +emptyDirectoryText+ " "));
9
+ console.log(" ".repeat(emptyDirectoryTextMargin) + chalk.bgRed(" ".repeat(emptyDirectoryText.length + 2)) + "\n");
10
+ }
11
+
12
+ export { renderEmptyFolderText };
@@ -0,0 +1,31 @@
1
+ import chalk from 'chalk';
2
+
3
+ function renderFoldersSummary(summary) {
4
+ const { foldersByExtensionType, folderWasCreated, previewMode } = summary;
5
+
6
+ Object.entries(foldersByExtensionType).forEach(([folder, files]) => {
7
+ if (previewMode) {
8
+ console.log(`\n${chalk.blueBright('o ')}${folder}/`);
9
+ }else{
10
+ console.log(`\n${chalk.green('o ')}${folder}/`);
11
+ }
12
+
13
+ files.forEach(file => {
14
+ const FILE_TAB = 4;
15
+ const line = `${' '.repeat(FILE_TAB)}• ${file}`;
16
+
17
+ if (previewMode) {
18
+ console.log(chalk.blueBright(line));
19
+ } else {
20
+ console.log(chalk.greenBright(line));
21
+ }
22
+ });
23
+ });
24
+
25
+ if (folderWasCreated && !previewMode) {
26
+ const foldersCreatedTab = 1;
27
+ console.log(`\n${' '.repeat(foldersCreatedTab)} ${Object.keys(foldersByExtensionType).length} Folder(s) created\n`);
28
+ }
29
+ }
30
+
31
+ export { renderFoldersSummary };
package/src/index.js ADDED
@@ -0,0 +1,32 @@
1
+ import { organizeDirectory } from './organizer/organizeDirectory.js';
2
+ import { renderFoldersSummary } from './cli/renderSummary.js';
3
+ import { parseArgs } from './utils/parseArgs.js';
4
+ import { getAvailableTypes } from './rules/byType.js';
5
+ import { cliActions } from './cli/cliActions.js';
6
+
7
+ function main() {
8
+ try {
9
+ const cliArguments = process.argv.slice(2);
10
+ const cliFlags = parseArgs(cliArguments);
11
+ const availableTypes = getAvailableTypes();
12
+ const currentDir = process.cwd();
13
+
14
+ const cliResult = cliActions(cliFlags, availableTypes);
15
+
16
+ if (cliResult.exit) {
17
+ process.exit(cliResult.code);
18
+ }
19
+
20
+ const summary = organizeDirectory(currentDir, cliFlags);
21
+
22
+ if(!summary) return;
23
+
24
+ renderFoldersSummary(summary);
25
+
26
+ } catch (error) {
27
+ console.error(`\nError: ${error.message}`);
28
+ process.exit(1);
29
+ }
30
+ }
31
+
32
+ main();
@@ -0,0 +1,54 @@
1
+ import path from 'path';
2
+ import { getFilesFromDirectory, ensureDirectoryExists, moveFile } from '../utils/fsHelpers.js';
3
+ import { getFolderNameByExtensionType } from '../rules/byType.js';
4
+ import { shouldSkipFile } from '../utils/filesFilters.js';
5
+ import { renderEmptyFolderText } from '../cli/renderEmptyFolderText.js';
6
+
7
+ function organizeDirectory(baseDir, cliFlags = {}) {
8
+ try{
9
+ const files = getFilesFromDirectory(baseDir);
10
+ const fileIsEmpty = files.length === 0;
11
+
12
+ if(fileIsEmpty){
13
+ renderEmptyFolderText();
14
+ return null;
15
+ }
16
+
17
+ const outputFoldersSummary = {};
18
+ let folderByExtensionTypeCreated = false;
19
+
20
+ files.forEach(file => {
21
+ const fileExtension = path.extname(file.name);
22
+ const folderNameByExtensionType = getFolderNameByExtensionType(fileExtension);
23
+
24
+ if (shouldSkipFile(folderNameByExtensionType, cliFlags)) return;
25
+
26
+ if (!outputFoldersSummary[folderNameByExtensionType]) {
27
+ outputFoldersSummary[folderNameByExtensionType] = [];
28
+ }
29
+
30
+ outputFoldersSummary[folderNameByExtensionType].push(file.name);
31
+
32
+ if (cliFlags.preview) return;
33
+
34
+ const folderPathByExtensionType = path.join(baseDir, folderNameByExtensionType);
35
+ const filePathByExtension = path.join(folderPathByExtensionType, file.name);
36
+ const folderByExtensionTypeWasCreated = ensureDirectoryExists(folderPathByExtensionType);
37
+
38
+ if (folderByExtensionTypeWasCreated) folderByExtensionTypeCreated = true;
39
+
40
+ moveFile(file.path, filePathByExtension);
41
+ });
42
+
43
+ return {
44
+ foldersByExtensionType: outputFoldersSummary,
45
+ folderWasCreated: folderByExtensionTypeCreated,
46
+ previewMode: cliFlags.preview,
47
+ };
48
+ }
49
+ catch(error){
50
+ throw new Error(`Error organizing directory: ${error.message}`);
51
+ }
52
+ }
53
+
54
+ export { organizeDirectory };
@@ -0,0 +1,29 @@
1
+ const RULES_BY_TYPE = {
2
+ Images: ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.tiff', '.ico', '.heic', '.psd', '.eps'],
3
+ Documents: ['.pdf', '.doc', '.docx', '.txt', '.md', '.rtf', '.odt', '.tex', '.wpd', '.epub', '.fb2', '.djvu', '.xps', '.pages'],
4
+ Spreadsheets: ['.xls', '.xlsx', '.csv', '.ods', '.tsv', '.xlsm', '.xltx', '.xltm', '.xlsb', '.xlam', '.xla', '.xlw', '.xlc', '.xlt'],
5
+ Presentations: ['.ppt', '.pptx', '.odp', '.key', '.ppsx', '.potx', '.pptm', '.ppsm', '.potm', '.pps', '.pot', '.ppa', '.thmx', '.sldx', '.sldm'],
6
+ Archives: ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.xz', '.tgz', '.tbz2'],
7
+ Audio: ['.mp3', '.wav', '.ogg', '.flac', '.aac', '.m4a'],
8
+ Video: ['.mp4', '.mov', '.avi', '.mkv', '.webm', '.wmv', '.flv']
9
+ };
10
+
11
+ const DEFAULT_FOLDER_NAME = 'Others';
12
+
13
+ function getFolderNameByExtensionType(extension) {
14
+ const extensionToLowerCase = extension.toLowerCase();
15
+
16
+ for (const [folderName, extensionsList] of Object.entries(RULES_BY_TYPE)) {
17
+ if (extensionsList.includes(extensionToLowerCase)) {
18
+ return folderName;
19
+ }
20
+ }
21
+
22
+ return DEFAULT_FOLDER_NAME;
23
+ }
24
+
25
+ function getAvailableTypes() {
26
+ return Object.keys(RULES_BY_TYPE).map(availableType => availableType.toLowerCase());
27
+ }
28
+
29
+ export { getFolderNameByExtensionType, getAvailableTypes };
@@ -0,0 +1,11 @@
1
+ function shouldSkipFile(folder, cliFlags) {
2
+ const { only, exclude } = cliFlags;
3
+ const normalizedFolder = folder.toLowerCase();
4
+
5
+ if (only && normalizedFolder !== only.toLowerCase()) return true;
6
+ if (exclude && normalizedFolder === exclude.toLowerCase()) return true;
7
+
8
+ return false;
9
+ }
10
+
11
+ export { shouldSkipFile };
@@ -0,0 +1,33 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ function getFilesFromDirectory(dirPath) {
5
+ const dirPathList = fs.readdirSync(dirPath);
6
+
7
+ return dirPathList
8
+ .map(dirPathItemName => {
9
+ const fullPath = path.join(dirPath, dirPathItemName);
10
+ const stats = fs.statSync(fullPath);
11
+
12
+ return {
13
+ name: dirPathItemName,
14
+ path: fullPath,
15
+ isFile: stats.isFile()
16
+ };
17
+ })
18
+ .filter(dirPathItemName => dirPathItemName.isFile);
19
+ }
20
+
21
+ function ensureDirectoryExists(dirPath) {
22
+ if (!fs.existsSync(dirPath)) {
23
+ fs.mkdirSync(dirPath);
24
+ return true;
25
+ }
26
+ return false;
27
+ }
28
+
29
+ function moveFile(sourcePath, targetPath) {
30
+ fs.renameSync(sourcePath, targetPath);
31
+ }
32
+
33
+ export { getFilesFromDirectory, ensureDirectoryExists, moveFile };
@@ -0,0 +1,28 @@
1
+ import chalk from "chalk";
2
+
3
+ function showHelp(availableTypes) {
4
+ console.log(`
5
+ ${chalk.blueBright('Auto Organize CLI Help Menu')}
6
+
7
+ Usage:
8
+ auto-organize [${chalk.green('options')}]
9
+
10
+ Options:
11
+ ${chalk.green('--preview, -p')} Show a preview without making changes
12
+ ${chalk.green('--only, -o <type>')} Organize only a specific file type
13
+ ${chalk.green('--exclude, -e <type>')} Exclude a file type from organization
14
+ ${chalk.green('--help, -h')} Show this help message
15
+
16
+ Available types:
17
+ ${chalk.yellow(availableTypes.join(', '))}
18
+
19
+ Examples:
20
+ auto-organize ${chalk.green('--preview')} || auto-organize ${chalk.green('-p')}
21
+
22
+ auto-organize ${chalk.green('--only')} ${chalk.yellow('images')} || auto-organize ${chalk.green('-o')} ${chalk.yellow('images')}
23
+
24
+ auto-organize ${chalk.green('--exclude')} ${chalk.yellow('archives')} || auto-organize ${chalk.green('-e')} ${chalk.yellow('archives')}
25
+ `);
26
+ }
27
+
28
+ export { showHelp };
@@ -0,0 +1,72 @@
1
+ import chalk from "chalk";
2
+
3
+ function parseArgs(cliArguments) {
4
+ const cliFlags = {
5
+ preview: false,
6
+ only: null,
7
+ exclude: null,
8
+ help: false
9
+ };
10
+
11
+ if (cliArguments.length === 0) {
12
+ return cliFlags;
13
+ }
14
+
15
+ const allowedFlags = [
16
+ '--preview', '-p',
17
+ '--only', '-o',
18
+ '--exclude', '-e',
19
+ '--help', '-h'
20
+ ];
21
+
22
+ for (let i = 0; i < cliArguments.length; i++) {
23
+ const cliArgument = cliArguments[i];
24
+
25
+ if (!cliArgument.startsWith('-')) {
26
+ throw new Error(`\n'${chalk.red(cliArgument)}' is invalid. Run ${chalk.green('auto-organize --help')} to see available options.`);
27
+ }
28
+
29
+ if (!allowedFlags.includes(cliArgument)) {
30
+ throw new Error(`\nUnknown flag '${chalk.red(cliArgument)}'. Run ${chalk.green('auto-organize --help')} to see available flags.`);
31
+ }
32
+
33
+ if (cliArgument === '--preview' || cliArgument === '-p') {
34
+ cliFlags.preview = true;
35
+ continue;
36
+ }
37
+
38
+ if (cliArgument === '--help' || cliArgument === '-h') {
39
+ cliFlags.help = true;
40
+ continue;
41
+ }
42
+
43
+
44
+ if (cliArgument === '--only' || cliArgument === '-o') {
45
+ const onlyFlagArgument = cliArguments[i + 1];
46
+
47
+ if (!onlyFlagArgument || onlyFlagArgument.startsWith('-')) {
48
+ throw new Error(chalk.red(`\n--only requires a valid type.`));
49
+ }
50
+
51
+ cliFlags.only = onlyFlagArgument.toLowerCase();
52
+ i++;
53
+ continue;
54
+ }
55
+
56
+ if (cliArgument === '--exclude' || cliArgument === '-e') {
57
+ const excludeFlagArgument = cliArguments[i + 1];
58
+
59
+ if (!excludeFlagArgument || excludeFlagArgument.startsWith('-')) {
60
+ throw new Error(chalk.red(`\n--exclude requires a valid type.`));
61
+ }
62
+
63
+ cliFlags.exclude = excludeFlagArgument.toLowerCase();
64
+ i++;
65
+ continue;
66
+ }
67
+ }
68
+
69
+ return cliFlags;
70
+ }
71
+
72
+ export { parseArgs };
@@ -0,0 +1,33 @@
1
+ import chalk from 'chalk';
2
+
3
+ function validateFlags(cliFlags) {
4
+ if (!cliFlags || typeof cliFlags !== 'object') {
5
+ throw new Error("Missing or invalid 'cliFlags'");
6
+ }
7
+ }
8
+
9
+ function validateTypes(availableTypes) {
10
+ if (!Array.isArray(availableTypes) || availableTypes.length === 0) {
11
+ throw new Error("Missing or invalid 'availableTypes'");
12
+ }
13
+ }
14
+
15
+ function validateFlagsAndTypes(cliFlags, availableTypes) {
16
+ const { only, exclude } = cliFlags;
17
+
18
+ if (only && !availableTypes.includes(only)) {
19
+ throw new Error(
20
+ `'${chalk.red(only)}' is not a valid type for ${chalk.green('--only')}\n` +
21
+ `Valid types: ${chalk.yellow(availableTypes.join(', '))}`
22
+ );
23
+ }
24
+
25
+ if (exclude && !availableTypes.includes(exclude)) {
26
+ throw new Error(
27
+ `'${chalk.red(exclude)}' is not a valid type for ${chalk.green('--exclude')}\n` +
28
+ `Valid types: ${chalk.yellow(availableTypes.join(', '))}`
29
+ );
30
+ }
31
+ }
32
+
33
+ export { validateFlags, validateTypes, validateFlagsAndTypes };