Skip to content

Commit 997dae0

Browse files
authored
Merge pull request #412 from str0yka/cli-case
cli-case 🧊 add case setting in cli
2 parents 2e89012 + 433526d commit 997dae0

File tree

7 files changed

+69
-21
lines changed

7 files changed

+69
-21
lines changed

packages/cli/src/add.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import ora from 'ora';
99
import prompts from 'prompts';
1010
import { createMatchPath, loadConfig } from 'tsconfig-paths';
1111

12-
import type { AddOptionsSchema, Registry } from '@/utils/types';
12+
import type { AddOptionsSchema, ConfigSchema, Registry } from '@/utils/types';
1313

1414
import { APP_PATH, REPO_URLS } from '@/utils/constants';
15-
import { getConfig, getPackageManager } from '@/utils/helpers';
15+
import { getConfig, getPackageManager, toCase } from '@/utils/helpers';
1616
import { addOptionsSchema } from '@/utils/types';
1717

1818
type FileType = 'hook' | 'package' | 'util';
@@ -45,13 +45,29 @@ const resolveDependencies = (registry: Registry, hooks: string[]): Map<string, F
4545
return files;
4646
};
4747

48-
const updateImports = async (filePath: string, utilsPath: string) => {
49-
const fileContent = await fs.readFileSync(filePath, 'utf-8');
50-
const utilsImportRegex = /import\s+\{([^}]+)\}\s+from\s+['"](@\/utils[^'"]*)['"]/g;
48+
interface UpdateImportsRules {
49+
regex: RegExp;
50+
replacer: (...args: string[]) => string;
51+
}
52+
53+
const updateImports = async (filePath: string, config: ConfigSchema) => {
54+
const fileContent = fs.readFileSync(filePath, 'utf-8');
55+
56+
const rules: UpdateImportsRules[] = [
57+
{
58+
regex: /import\s+\{([^}]+)\}\s+from\s+['"](@\/utils[^'"]*)['"]/g,
59+
replacer: (_, imports) => `import {${imports}} from '${config.aliases.utils}'`
60+
},
61+
{
62+
regex: /import\s+(?:type\s+)?\{([^}]+)\}\s+from\s+['"](\.[^'"]*)['"]/g,
63+
replacer: (_, imports, internalPath) =>
64+
`import {${imports}} from '${toCase(internalPath, config.case)}'`
65+
}
66+
];
5167

52-
const updatedContent = fileContent.replace(
53-
utilsImportRegex,
54-
(_, imports) => `import {${imports}} from '${utilsPath}'`
68+
const updatedContent = rules.reduce(
69+
(acc, { regex, replacer }) => acc.replace(regex, replacer),
70+
fileContent
5571
);
5672

5773
fs.writeFileSync(filePath, updatedContent);
@@ -165,9 +181,11 @@ export const add = {
165181
const files = Array.from(dependencies.values())
166182
.map((dependency) => {
167183
if (dependency.type === 'hook') {
168-
const filePath = `${dependency.name}/${dependency.name}`;
184+
const filePath = toCase(`${dependency.name}/${dependency.name}`, config.case);
169185
const directoryPath = `${pathToLoadHooks}/${filePath}.${language}`;
170-
const registryPath = `${REPO_URLS[language.toUpperCase() as keyof typeof REPO_URLS]}/hooks/${filePath}.${language}`;
186+
const registryPath = `${
187+
REPO_URLS[language.toUpperCase() as keyof typeof REPO_URLS]
188+
}/hooks/${dependency.name}/${dependency.name}.${language}`;
171189
const indexPath = `${pathToLoadHooks}/index.${language}`;
172190
return {
173191
name: dependency.name,
@@ -180,9 +198,11 @@ export const add = {
180198
}
181199

182200
if (dependency.type === 'util') {
183-
const filePath = `${dependency.name}`;
201+
const filePath = toCase(`${dependency.name}`, config.case);
184202
const directoryPath = `${pathToLoadUtils}/${filePath}.${language}`;
185-
const registryPath = `${REPO_URLS[language.toUpperCase() as keyof typeof REPO_URLS]}/utils/helpers/${filePath}.${language}`;
203+
const registryPath = `${
204+
REPO_URLS[language.toUpperCase() as keyof typeof REPO_URLS]
205+
}/utils/helpers/${dependency.name}.${language}`;
186206
const indexPath = `${pathToLoadUtils}/index.${language}`;
187207
return {
188208
name: dependency.name,
@@ -233,9 +253,7 @@ export const add = {
233253

234254
const fileResponse = await fetches.get<Buffer>(registryPath);
235255
await fs.writeFileSync(directoryPath, fileResponse.data);
236-
if (type === 'hook') {
237-
await updateImports(directoryPath, config.aliases.utils);
238-
}
256+
await updateImports(directoryPath, config);
239257

240258
const exportStatement = `export * from './${filePath}';\n`;
241259

@@ -247,7 +265,9 @@ export const add = {
247265

248266
const packageManager = await getPackageManager(options.cwd);
249267

250-
spinner.text = `Installing packages ${chalk.bold(packages.join(', '))} with ${chalk.cyan(packageManager)}`;
268+
spinner.text = `Installing packages ${chalk.bold(packages.join(', '))} with ${chalk.cyan(
269+
packageManager
270+
)}`;
251271
if (packages.length) {
252272
await execa(packageManager, [packageManager === 'npm' ? 'install' : 'add', ...packages], {
253273
cwd: options.cwd

packages/cli/src/init.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ export const init = async () => {
4343
aliases: {
4444
hooks: '@/shared/hooks',
4545
utils: '@/utils/lib'
46-
}
46+
},
47+
case: 'camel'
4748
};
4849
await fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
4950
console.log(JSON.stringify(config, null, 2));
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
export * from './getConfig';
2-
export * from './getPackageManager';
1+
export * from "./getConfig";
2+
export * from "./getPackageManager";
3+
export * from "./toKebabCase";
4+
export * from "./toCase";
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { toKebabCase } from "./toKebabCase";
2+
3+
export const toCase = (string: string, mode: "camel" | "kebab" = "camel") =>
4+
mode === "camel" ? string : toKebabCase(string);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const toKebabCase = (string: string) =>
2+
string.replace(
3+
/[A-Z]+(?![a-z])|[A-Z]/g,
4+
(match, offset) => (offset ? "-" : "") + match.toLowerCase()
5+
);

packages/cli/src/utils/types/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export const configSchema = z
2727
aliases: z.object({
2828
hooks: z.string(),
2929
utils: z.string()
30-
})
30+
}),
31+
case: z.literal(['camel', 'kebab']).optional()
3132
})
3233
.strict();
3334

packages/docs/app/reactuse-json.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Setting this option to `false` allows hooks to be added as JavaScript with the `
2828

2929
```json title="reactuse.json"
3030
{
31-
"ts": "true | false"
31+
"ts": true | false
3232
}
3333
```
3434

@@ -66,3 +66,18 @@ Import alias for your hooks.
6666
}
6767
}
6868
```
69+
70+
## case
71+
72+
Controls the naming convention for generated files.
73+
74+
There are two options:
75+
76+
- `camel`: All files will be generated in `camelCase` (e.g., `useClickOutside.ts`).
77+
- `kebab`: All files will be generated in `kebab-case` (e.g., `use-click-outside.ts`).
78+
79+
```json title="reactuse.json"
80+
{
81+
"case": "camel" | "kebab"
82+
}
83+
```

0 commit comments

Comments
 (0)