caselyjs 1.0.0 → 1.0.4
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 +21 -21
- package/README.md +104 -117
- package/package.json +50 -43
- package/src/bin.ts +0 -36
- package/src/casely.ts +0 -87
- package/src/index.ts +0 -1
- package/src/tools/case-identifier.ts +0 -12
- package/src/tools/mutate-case.ts +0 -24
- package/src/tools/resolver.ts +0 -55
- package/src/transforms/to-camel.ts +0 -70
- package/src/transforms/to-kebab.ts +0 -71
- package/src/transforms/to-pascal.ts +0 -68
- package/src/types.ts +0 -10
- package/test/hello-world/new-world.js +0 -0
- package/test/hello.json +0 -0
- package/test/hello.py +0 -0
- package/test/index.md +0 -0
- package/test/pascal.js +0 -0
- package/test/why-not/why-no/why-no.ts +0 -0
- package/test/why-not/why-not/pascal.js +0 -0
- package/test/world-book.go +0 -0
- package/tsconfig.json +0 -33
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Vikash Kumar
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Vikash Kumar
|
|
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.md
CHANGED
|
@@ -1,117 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
- kebab-case
|
|
106
|
-
- camelCase
|
|
107
|
-
- PascalCase
|
|
108
|
-
|
|
109
|
-
## 🛠️ Built With
|
|
110
|
-
|
|
111
|
-
- **TypeScript** - For type-safe filesystem operations.
|
|
112
|
-
- **Commander.js** - Robust CLI argument parsing.
|
|
113
|
-
- **Chalk** - Beautifully colored terminal output.
|
|
114
|
-
|
|
115
|
-
### 👨💻 Author
|
|
116
|
-
|
|
117
|
-
**Made with ❤️ by _codezaura_**
|
|
1
|
+
<img width="1420" height="640" alt="casely-js" src="https://github.com/user-attachments/assets/9e49a868-c644-4e8b-9c16-5759ffc35969" />
|
|
2
|
+
|
|
3
|
+
<br />
|
|
4
|
+
|
|
5
|
+
<div>
|
|
6
|
+
<h1>Caselyjs - CLI</h1>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
Tired of Codebases with Mismatched File Casing?🛠️ Meet `CaselyJS (v1.0.1)`
|
|
10
|
+
|
|
11
|
+
<div>
|
|
12
|
+
<b>caselyjs</> is a high-performance TypeScript-powered CLI and programmatic utility designed to <b>rename files and directories</b> across your entire codebase using consistent naming conventions.</b>
|
|
13
|
+
<br />
|
|
14
|
+
<br />
|
|
15
|
+
> <i>Say goodbye to manually renaming 100+ files in your project!</i>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
## ✨ New in v1.0
|
|
19
|
+
|
|
20
|
+
- **Native TypeScript Support**: Full type definitions included.
|
|
21
|
+
- **Powerful CLI**: Run transformations directly from your terminal.
|
|
22
|
+
- **Dry Run Mode**: Preview changes before they are applied to your filesystem.
|
|
23
|
+
- **Recursive Bottom-Up Renaming**: Safely renames nested directories without breaking paths.
|
|
24
|
+
- **Enhanced Extension Support**: Easily filter which file types to transform.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ⚡ The 10-Second Quick Start (No Install Required)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Rename all .js/ts files in the current folder to kebab-case
|
|
32
|
+
npx caselyjs .
|
|
33
|
+
|
|
34
|
+
# Run a full conversion to PascalCase on a specific folder
|
|
35
|
+
npx caselyjs ./src/components --case pascal --full
|
|
36
|
+
|
|
37
|
+
# Preview changes in a specific directory without actually renaming anything
|
|
38
|
+
npx caselyjs ./my-project --dry
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> [!IMPORTANT]
|
|
42
|
+
> ```bash
|
|
43
|
+
> # safe command before executing
|
|
44
|
+
> npx caselyjs --dry
|
|
45
|
+
> ```
|
|
46
|
+
|
|
47
|
+
### Why this is the "Pro" way to use CaselyJS:
|
|
48
|
+
|
|
49
|
+
- **No Clutter**: Doesn't stay on the user's machine or in their node_modules.
|
|
50
|
+
|
|
51
|
+
- **Always Fresh**: npx always pulls the latest version (v1.0.0+), so they get your newest bug fixes and case-identification logic automatically.
|
|
52
|
+
|
|
53
|
+
- **CI/CD Friendly**: Perfect for use in GitHub Actions or automation scripts where you want to enforce a naming convention during a build step without a permanent install.
|
|
54
|
+
|
|
55
|
+
## ⚙️ CLI Options
|
|
56
|
+
|
|
57
|
+
| Flag | Shorthand | Description | Default |
|
|
58
|
+
| :------- | :-------- | :------------------------------------------ | :-------------- |
|
|
59
|
+
| `--case` | -c | "Target case: camel, kebab, or pascal" | kebab |
|
|
60
|
+
| `--ext` | -e | Comma-separated list of file extensions | "js,jsx,ts,tsx" |
|
|
61
|
+
| `--full` | -f | Rename directories in addition to files | false |
|
|
62
|
+
| `--dry` | | Show intended changes without applying them | false |
|
|
63
|
+
|
|
64
|
+
## 💻 Programmatic Usage
|
|
65
|
+
|
|
66
|
+
If you prefer to integrate CaselyJS into your own build scripts or tools:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { casely } from "caselyjs";
|
|
70
|
+
|
|
71
|
+
casely.config({
|
|
72
|
+
path: "./src",
|
|
73
|
+
case: "camel",
|
|
74
|
+
file: ["ts", "tsx"],
|
|
75
|
+
operate: "full", // 'partial' (files only) or 'full' (files + folders)
|
|
76
|
+
dryRun: true, // highly recommended for testing
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await casely.execute();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## ⚙️ Advanced Configuration
|
|
83
|
+
|
|
84
|
+
- **Recursive by Default**: You only need to provide the root directory. CaselyJS automatically traverses all subdirectories.
|
|
85
|
+
- **Safety First**: When using operate: "full", CaselyJS uses a bottom-up renaming strategy to ensure directory paths remain valid during the process.
|
|
86
|
+
|
|
87
|
+
### Supported Case Types
|
|
88
|
+
|
|
89
|
+
- kebab-case
|
|
90
|
+
- camelCase
|
|
91
|
+
- PascalCase
|
|
92
|
+
|
|
93
|
+
## 🛠️ Built With
|
|
94
|
+
|
|
95
|
+
- **TypeScript** - For type-safe filesystem operations.
|
|
96
|
+
- **Commander.js** - Robust CLI argument parsing.
|
|
97
|
+
- **Chalk** - Beautifully colored terminal output.
|
|
98
|
+
|
|
99
|
+
### 🌐 Links
|
|
100
|
+
- [dev.to](https://dev.to/thatonevikash/tired-of-codebases-with-mismatched-file-casing-meet-caselyjs-v101-479n)
|
|
101
|
+
|
|
102
|
+
### 👨💻 Author
|
|
103
|
+
|
|
104
|
+
**Made with ❤️ by _thatonevikash_**
|
package/package.json
CHANGED
|
@@ -1,43 +1,50 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "caselyjs",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"bugs": {
|
|
20
|
-
"url": "https://github.com/
|
|
21
|
-
},
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "caselyjs",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"author": "thatonevikash",
|
|
5
|
+
"description": "Rename codebase files and directories with ease",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/thatonevikash/caselyjs.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"naming convention tool",
|
|
12
|
+
"file / folder renamer",
|
|
13
|
+
"case changer",
|
|
14
|
+
"kebab case to pascal case",
|
|
15
|
+
"pascal case to camel case",
|
|
16
|
+
"came case to kebab case"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/thatonevikash/caselyjs/issues"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"homepage": "https://github.com/thatonevikash/caselyjs#readme",
|
|
30
|
+
"main": "dist/index.js",
|
|
31
|
+
"types": "dist/index.d.ts",
|
|
32
|
+
"bin": {
|
|
33
|
+
"casely": "dist/bin.js"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc",
|
|
37
|
+
"start": "node dist/bin.js",
|
|
38
|
+
"dev": "ts-node src/bin.ts",
|
|
39
|
+
"prepublishOnly": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"chalk": "^5.3.0",
|
|
43
|
+
"commander": "^11.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^20.19.39",
|
|
47
|
+
"ts-node": "^10.9.1",
|
|
48
|
+
"typescript": "^5.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/bin.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command } from "commander";
|
|
3
|
-
import { casely } from "./index";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
|
|
6
|
-
const program = new Command();
|
|
7
|
-
|
|
8
|
-
program
|
|
9
|
-
.name("caselyjs")
|
|
10
|
-
.description("Transform codebase file and directory casing")
|
|
11
|
-
.version("2.0.0")
|
|
12
|
-
.argument("[path]", "Path to process", ".")
|
|
13
|
-
.option("-c, --case <type>", "Target case: camel, kebab, pascal", "kebab")
|
|
14
|
-
.option(
|
|
15
|
-
"-e, --ext <extensions>",
|
|
16
|
-
"Comma separated extensions",
|
|
17
|
-
"js,jsx,ts,tsx",
|
|
18
|
-
)
|
|
19
|
-
.option("-f, --full", "Rename directories as well", false)
|
|
20
|
-
.option("--dry", "Dry run (show changes without applying)", false)
|
|
21
|
-
.action(async (path, options) => {
|
|
22
|
-
console.log(chalk.blue.bold(`\n🚀 CaselyJS starting in ${path}...`));
|
|
23
|
-
|
|
24
|
-
casely.config({
|
|
25
|
-
path: path,
|
|
26
|
-
case: options.case,
|
|
27
|
-
file: options.ext.split(","),
|
|
28
|
-
operate: options.full ? "full" : "partial",
|
|
29
|
-
dryRun: options.dry,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
await casely.execute();
|
|
33
|
-
console.log(chalk.green.bold("\n✨ Casing transformation complete!"));
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
program.parse();
|
package/src/casely.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import { pathResolver } from "./tools/resolver";
|
|
4
|
-
import { caseIdentifier } from "./tools/case-identifier";
|
|
5
|
-
import { CaselyConfig, CaseType } from "./types";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
|
|
8
|
-
// -------------------------------------------------------------
|
|
9
|
-
|
|
10
|
-
let defaultConfig: CaselyConfig = {
|
|
11
|
-
path: process.cwd(),
|
|
12
|
-
file: ["js", "jsx", "ts", "tsx"],
|
|
13
|
-
case: "kebab",
|
|
14
|
-
operate: "partial",
|
|
15
|
-
dryRun: false,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// -------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
export const casely = {
|
|
21
|
-
config(options: Partial<CaselyConfig>) {
|
|
22
|
-
defaultConfig = { ...defaultConfig, ...options };
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
async execute() {
|
|
26
|
-
const { files, folders } = pathResolver(defaultConfig.path, {
|
|
27
|
-
recursive: true,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// 1. Handle Files
|
|
31
|
-
for (const filePath of files) {
|
|
32
|
-
const ext = path.extname(filePath).slice(1);
|
|
33
|
-
if (!defaultConfig.file.includes(ext)) continue;
|
|
34
|
-
|
|
35
|
-
const dirname = path.dirname(filePath);
|
|
36
|
-
const basename = path.basename(filePath, `.${ext}`);
|
|
37
|
-
const currentCase = caseIdentifier(basename);
|
|
38
|
-
|
|
39
|
-
if (currentCase !== defaultConfig.case) {
|
|
40
|
-
this.rename(filePath, basename, ext, currentCase);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 2. Handle Folders (Bottom-Up)
|
|
45
|
-
if (defaultConfig.operate === "full") {
|
|
46
|
-
const sortedFolders = folders.sort((a, b) => b.length - a.length);
|
|
47
|
-
for (const folderPath of sortedFolders) {
|
|
48
|
-
const basename = path.basename(folderPath);
|
|
49
|
-
const currentCase = caseIdentifier(basename);
|
|
50
|
-
|
|
51
|
-
if (currentCase !== defaultConfig.case) {
|
|
52
|
-
this.rename(folderPath, basename, "", currentCase);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
rename(fullPath: string, name: string, ext: string, currentCase: CaseType) {
|
|
59
|
-
const newName = this.transform(name, defaultConfig.case);
|
|
60
|
-
const finalName = ext ? `${newName}.${ext}` : newName;
|
|
61
|
-
const newPath = path.join(path.dirname(fullPath), finalName);
|
|
62
|
-
|
|
63
|
-
if (defaultConfig.dryRun) {
|
|
64
|
-
console.log(
|
|
65
|
-
chalk.yellow(`[DRY RUN] ${path.basename(fullPath)} ➝ ${finalName}`),
|
|
66
|
-
);
|
|
67
|
-
} else {
|
|
68
|
-
fs.renameSync(fullPath, newPath);
|
|
69
|
-
console.log(chalk.cyan(`✔ Renamed: ${finalName}`));
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
transform(str: string, target: CaseType): string {
|
|
74
|
-
// Your transformation logic (toCamel, toKebab, etc)
|
|
75
|
-
if (target === "kebab")
|
|
76
|
-
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
77
|
-
if (target === "camel")
|
|
78
|
-
return str
|
|
79
|
-
.replace(/[-_](.)/g, (_, g) => g.toUpperCase())
|
|
80
|
-
.replace(/^(.)/, (g) => g.toLowerCase());
|
|
81
|
-
if (target === "pascal")
|
|
82
|
-
return str
|
|
83
|
-
.replace(/[-_](.)/g, (_, g) => g.toUpperCase())
|
|
84
|
-
.replace(/^(.)/, (g) => g.toUpperCase());
|
|
85
|
-
return str;
|
|
86
|
-
},
|
|
87
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./casely";
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// -------------------------------------------------------------
|
|
2
|
-
|
|
3
|
-
export function caseIdentifier(val: string) {
|
|
4
|
-
const str = val.split(".")[0];
|
|
5
|
-
|
|
6
|
-
if (/^[a-z]+$/.test(str)) return "kebab";
|
|
7
|
-
if (/^[a-z]+(-[a-z]+)+$/.test(str)) return "kebab";
|
|
8
|
-
if (/^[a-z]+(?:[A-Z][a-z]*)*$/.test(str)) return "camel";
|
|
9
|
-
if (/^[A-Z][a-z]+(?:[A-Z][a-z]*)*$/.test(str)) return "pascal";
|
|
10
|
-
|
|
11
|
-
return "unknown";
|
|
12
|
-
}
|
package/src/tools/mutate-case.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { toCamel } from "../transforms/to-camel.js";
|
|
2
|
-
import { toKebab } from "../transforms/to-kebab.js";
|
|
3
|
-
import { toPascal } from "../transforms/to-pascal.js";
|
|
4
|
-
import { CaseType } from "../types.js";
|
|
5
|
-
|
|
6
|
-
// -------------------------------------------------------------
|
|
7
|
-
|
|
8
|
-
export async function mutateCase(
|
|
9
|
-
path: string,
|
|
10
|
-
currentType: Exclude<CaseType, "unknown">,
|
|
11
|
-
expectedType: Exclude<CaseType, "unknown">,
|
|
12
|
-
): Promise<void> {
|
|
13
|
-
if (expectedType === "camel") {
|
|
14
|
-
toCamel(path, currentType);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (expectedType === "kebab") {
|
|
18
|
-
toKebab(path, currentType);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (expectedType === "pascal") {
|
|
22
|
-
toPascal(path, currentType);
|
|
23
|
-
}
|
|
24
|
-
}
|
package/src/tools/resolver.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
// -------------------------------------------------------------
|
|
5
|
-
|
|
6
|
-
interface PathResolverOptions {
|
|
7
|
-
recursive?: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface PathResolverResult {
|
|
11
|
-
files: string[];
|
|
12
|
-
folders: string[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// -------------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* List all files and folders in a given path
|
|
19
|
-
* @param targetPath - The directory to scan
|
|
20
|
-
* @param options - Configuration options
|
|
21
|
-
* @param options.recursive - If true, lists recursively (default: false)
|
|
22
|
-
* @returns An object containing arrays of file and folder paths
|
|
23
|
-
*/
|
|
24
|
-
export function pathResolver(
|
|
25
|
-
targetPath: string,
|
|
26
|
-
options: PathResolverOptions = {},
|
|
27
|
-
): PathResolverResult {
|
|
28
|
-
const { recursive = false } = options;
|
|
29
|
-
|
|
30
|
-
const result: PathResolverResult = {
|
|
31
|
-
files: [],
|
|
32
|
-
folders: [],
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
function scan(dir: string): void {
|
|
36
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
37
|
-
|
|
38
|
-
for (const entry of entries) {
|
|
39
|
-
const fullPath = path.join(dir, entry.name);
|
|
40
|
-
const normalizedPath = fullPath.replace(/\\/g, "/");
|
|
41
|
-
|
|
42
|
-
if (entry.isDirectory()) {
|
|
43
|
-
result.folders.push(normalizedPath);
|
|
44
|
-
if (recursive) {
|
|
45
|
-
scan(fullPath);
|
|
46
|
-
}
|
|
47
|
-
} else if (entry.isFile()) {
|
|
48
|
-
result.files.push(normalizedPath);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
scan(targetPath);
|
|
54
|
-
return result;
|
|
55
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { type CaseType } from "../types";
|
|
4
|
-
|
|
5
|
-
// -------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
function toCamelCase(str: string): string {
|
|
8
|
-
return str
|
|
9
|
-
.replace(/[-_](.)/g, (_, group1: string) => group1.toUpperCase())
|
|
10
|
-
.replace(/^(.)/, (_, group1: string) => group1.toLowerCase());
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// -------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
function kebabToCamel(targetPath: string): void {
|
|
16
|
-
const parent = path.dirname(targetPath);
|
|
17
|
-
const currentName = path.basename(targetPath);
|
|
18
|
-
const newName = toCamelCase(currentName);
|
|
19
|
-
const newPath = path.join(parent, newName);
|
|
20
|
-
|
|
21
|
-
if (currentName === newName) {
|
|
22
|
-
console.log(`✅ Already in camelCase: ${currentName}`);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
fs.renameSync(targetPath, newPath);
|
|
28
|
-
console.log(`✨ Renamed Kebab → Camel: ${currentName} ➝ ${newName}`);
|
|
29
|
-
} catch (err) {
|
|
30
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
31
|
-
console.error(`❌ Rename failed: ${message}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// -------------------------------------------------------------
|
|
36
|
-
|
|
37
|
-
function pascalToCamel(targetPath: string): void {
|
|
38
|
-
const parent = path.dirname(targetPath);
|
|
39
|
-
const currentName = path.basename(targetPath);
|
|
40
|
-
const newName = currentName.charAt(0).toLowerCase() + currentName.slice(1);
|
|
41
|
-
const newPath = path.join(parent, newName);
|
|
42
|
-
|
|
43
|
-
if (currentName === newName) {
|
|
44
|
-
console.log(`✅ Already in camelCase: ${currentName}`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
fs.renameSync(targetPath, newPath);
|
|
50
|
-
console.log(`✨ Renamed Pascal → Camel: ${currentName} ➝ ${newName}`);
|
|
51
|
-
} catch (err) {
|
|
52
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
-
console.error(`❌ Rename failed: ${message}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// -------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
export function toCamel(
|
|
60
|
-
targetPath: string,
|
|
61
|
-
currentType: Partial<CaseType>,
|
|
62
|
-
): void {
|
|
63
|
-
if (currentType === "kebab") {
|
|
64
|
-
kebabToCamel(targetPath);
|
|
65
|
-
} else if (currentType === "pascal") {
|
|
66
|
-
pascalToCamel(targetPath);
|
|
67
|
-
} else {
|
|
68
|
-
console.log("⚠️ Unsupported case type passed.");
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { type CaseType } from "../types";
|
|
4
|
-
|
|
5
|
-
// -------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
function toKebabCase(str: string): string {
|
|
8
|
-
return str
|
|
9
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
10
|
-
.replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
|
|
11
|
-
.toLowerCase();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// -------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
function pascalToKebab(targetPath: string): void {
|
|
17
|
-
const parent = path.dirname(targetPath);
|
|
18
|
-
const currentName = path.basename(targetPath);
|
|
19
|
-
const newName = toKebabCase(currentName);
|
|
20
|
-
const newPath = path.join(parent, newName);
|
|
21
|
-
|
|
22
|
-
if (currentName === newName) {
|
|
23
|
-
console.log(`✅ Already in kebab-case: ${currentName}`);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
fs.renameSync(targetPath, newPath);
|
|
29
|
-
console.log(`✨ Renamed Pascal → Kebab: ${currentName} ➝ ${newName}`);
|
|
30
|
-
} catch (err) {
|
|
31
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
32
|
-
console.error(`❌ Rename failed: ${message}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// -------------------------------------------------------------
|
|
37
|
-
|
|
38
|
-
function camelToKebab(targetPath: string): void {
|
|
39
|
-
const parent = path.dirname(targetPath);
|
|
40
|
-
const currentName = path.basename(targetPath);
|
|
41
|
-
const newName = toKebabCase(currentName);
|
|
42
|
-
const newPath = path.join(parent, newName);
|
|
43
|
-
|
|
44
|
-
if (currentName === newName) {
|
|
45
|
-
console.log(`✅ Already in kebab-case: ${currentName}`);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
fs.renameSync(targetPath, newPath);
|
|
51
|
-
console.log(`✨ Renamed Camel → Kebab: ${currentName} ➝ ${newName}`);
|
|
52
|
-
} catch (err) {
|
|
53
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
54
|
-
console.error(`❌ Rename failed: ${message}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// -------------------------------------------------------------
|
|
59
|
-
|
|
60
|
-
export function toKebab(
|
|
61
|
-
targetPath: string,
|
|
62
|
-
currentType: Partial<CaseType>,
|
|
63
|
-
): void {
|
|
64
|
-
if (currentType === "pascal") {
|
|
65
|
-
pascalToKebab(targetPath);
|
|
66
|
-
} else if (currentType === "camel") {
|
|
67
|
-
camelToKebab(targetPath);
|
|
68
|
-
} else {
|
|
69
|
-
console.log("⚠️ Unsupported case type passed.");
|
|
70
|
-
}
|
|
71
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { type CaseType } from "../types";
|
|
4
|
-
|
|
5
|
-
// -------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
function toPascalCase(str: string): string {
|
|
8
|
-
return str
|
|
9
|
-
.replace(/[-_](.)/g, (_, group1: string) => group1.toUpperCase())
|
|
10
|
-
.replace(/^(.)/, (_, group1: string) => group1.toUpperCase());
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function kebabToPascal(targetPath: string): void {
|
|
14
|
-
const parent = path.dirname(targetPath);
|
|
15
|
-
const currentName = path.basename(targetPath);
|
|
16
|
-
const newName = toPascalCase(currentName);
|
|
17
|
-
const newPath = path.join(parent, newName);
|
|
18
|
-
|
|
19
|
-
if (currentName === newName) {
|
|
20
|
-
console.log(`✅ Already in PascalCase: ${currentName}`);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
fs.renameSync(targetPath, newPath);
|
|
26
|
-
console.log(`✨ Renamed Kebab → Pascal: ${currentName} ➝ ${newName}`);
|
|
27
|
-
} catch (err) {
|
|
28
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
29
|
-
console.error(`❌ Rename failed: ${message}`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// -------------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
function camelToPascal(targetPath: string): void {
|
|
36
|
-
const parent = path.dirname(targetPath);
|
|
37
|
-
const currentName = path.basename(targetPath);
|
|
38
|
-
const newName = currentName.charAt(0).toUpperCase() + currentName.slice(1);
|
|
39
|
-
const newPath = path.join(parent, newName);
|
|
40
|
-
|
|
41
|
-
if (currentName === newName) {
|
|
42
|
-
console.log(`✅ Already in PascalCase: ${currentName}`);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
fs.renameSync(targetPath, newPath);
|
|
48
|
-
console.log(`✨ Renamed Camel → Pascal: ${currentName} ➝ ${newName}`);
|
|
49
|
-
} catch (err) {
|
|
50
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
51
|
-
console.error(`❌ Rename failed: ${message}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// -------------------------------------------------------------
|
|
56
|
-
|
|
57
|
-
export function toPascal(
|
|
58
|
-
targetPath: string,
|
|
59
|
-
currentType: Partial<CaseType>,
|
|
60
|
-
): void {
|
|
61
|
-
if (currentType === "kebab") {
|
|
62
|
-
kebabToPascal(targetPath);
|
|
63
|
-
} else if (currentType === "camel") {
|
|
64
|
-
camelToPascal(targetPath);
|
|
65
|
-
} else {
|
|
66
|
-
console.log("⚠️ Unsupported case type passed.");
|
|
67
|
-
}
|
|
68
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export type CaseType = "camel" | "kebab" | "pascal" | "unknown";
|
|
2
|
-
export type OperationMode = "partial" | "full";
|
|
3
|
-
|
|
4
|
-
export interface CaselyConfig {
|
|
5
|
-
path: string;
|
|
6
|
-
file: string[]; // e.g. ["js", "ts"]
|
|
7
|
-
case: CaseType;
|
|
8
|
-
operate: OperationMode;
|
|
9
|
-
dryRun?: boolean;
|
|
10
|
-
}
|
|
File without changes
|
package/test/hello.json
DELETED
|
File without changes
|
package/test/hello.py
DELETED
|
File without changes
|
package/test/index.md
DELETED
|
File without changes
|
package/test/pascal.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/world-book.go
DELETED
|
File without changes
|
package/tsconfig.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
/* Base Options */
|
|
4
|
-
"target": "ES2022",
|
|
5
|
-
"module": "nodenext",
|
|
6
|
-
"allowSyntheticDefaultImports": true,
|
|
7
|
-
|
|
8
|
-
"moduleResolution": "nodenext",
|
|
9
|
-
"lib": ["ES2022"],
|
|
10
|
-
"declaration": true /* Generates .d.ts files for your library users */,
|
|
11
|
-
"sourceMap": true /* Helps with debugging */,
|
|
12
|
-
|
|
13
|
-
/* Output Settings */
|
|
14
|
-
"outDir": "./dist" /* Where the compiled JS goes */,
|
|
15
|
-
"rootDir": "./src" /* Where your TS source lives */,
|
|
16
|
-
"removeComments": true,
|
|
17
|
-
|
|
18
|
-
/* Strictness & Safety */
|
|
19
|
-
"strict": true /* Ensures high-quality, type-safe code */,
|
|
20
|
-
"noImplicitAny": true,
|
|
21
|
-
"esModuleInterop": true /* Fixes compatibility with some older JS packages */,
|
|
22
|
-
"skipLibCheck": true,
|
|
23
|
-
"forceConsistentCasingInFileNames": true,
|
|
24
|
-
|
|
25
|
-
/* Path Mapping (Optional) */
|
|
26
|
-
"baseUrl": ".",
|
|
27
|
-
"paths": {
|
|
28
|
-
"*": ["node_modules/*"]
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"include": ["src/**/*"] /* Only compile files in the src folder */,
|
|
32
|
-
"exclude": ["node_modules", "dist"]
|
|
33
|
-
}
|