Skip to content

Commit 68706d6

Browse files
committed
main 🧊 rework tocase
1 parent 2842ccc commit 68706d6

6 files changed

Lines changed: 205 additions & 151 deletions

File tree

β€Žpackages/cli/package.jsonβ€Ž

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@
3939
"pretty": "yarn type && yarn lint && yarn format"
4040
},
4141
"dependencies": {
42-
"@antfu/ni": "^25.0.0",
43-
"@siberiacancode/fetches": "1.11.0",
44-
"chalk": "5.6.0",
42+
"@antfu/ni": "^26.1.0",
43+
"@siberiacancode/fetches": "^1.13.1",
44+
"chalk": "5.6.2",
4545
"cosmiconfig": "^9.0.0",
4646
"execa": "9.6.0",
47-
"ora": "8.2.0",
47+
"ora": "9.0.0",
4848
"prompts": "^2.4.2",
4949
"tsconfig-paths": "^4.2.0",
5050
"yargs": "^18.0.0",
51-
"zod": "^4.0.17"
51+
"zod": "^4.1.12"
5252
},
5353
"devDependencies": {
5454
"@types/prompts": "^2.4.9",

β€Žpackages/cli/src/add.tsβ€Ž

Lines changed: 113 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
1-
import type { Argv } from 'yargs';
1+
import type { Argv } from "yargs";
22

3-
import fetches from '@siberiacancode/fetches';
4-
import chalk from 'chalk';
5-
import { execa } from 'execa';
6-
import fs from 'node:fs';
7-
import path from 'node:path';
8-
import ora from 'ora';
9-
import prompts from 'prompts';
10-
import { createMatchPath, loadConfig } from 'tsconfig-paths';
3+
import fetches from "@siberiacancode/fetches";
4+
import chalk from "chalk";
5+
import { execa } from "execa";
6+
import fs from "node:fs";
7+
import path from "node:path";
8+
import ora from "ora";
9+
import prompts from "prompts";
10+
import { createMatchPath, loadConfig } from "tsconfig-paths";
1111

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

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

18-
type FileType = 'hook' | 'package' | 'util';
18+
type FileType = "hook" | "package" | "util";
1919
interface FileItem {
2020
name: string;
2121
parent: string;
2222
type: FileType;
2323
}
2424

25-
const resolveDependencies = (registry: Registry, hooks: string[]): Map<string, FileItem> => {
25+
const resolveDependencies = (
26+
registry: Registry,
27+
hooks: string[]
28+
): Map<string, FileItem> => {
2629
const files = new Map<string, FileItem>();
2730

2831
const addFile = (name: string, type: FileType, parent: string) =>
@@ -33,10 +36,10 @@ const resolveDependencies = (registry: Registry, hooks: string[]): Map<string, F
3336

3437
const item = registry[hook]!;
3538

36-
addFile(hook, 'hook', item.name);
39+
addFile(hook, "hook", item.name);
3740

38-
item.utils.forEach((util) => addFile(util, 'util', item.name));
39-
item.packages.forEach((pkg) => addFile(pkg, 'package', item.name));
41+
item.utils.forEach((util) => addFile(util, "util", item.name));
42+
item.packages.forEach((pkg) => addFile(pkg, "package", item.name));
4043
item.hooks.forEach(resolveDependency);
4144
};
4245

@@ -51,18 +54,19 @@ interface UpdateImportsRules {
5154
}
5255

5356
const updateImports = async (filePath: string, config: ConfigSchema) => {
54-
const fileContent = fs.readFileSync(filePath, 'utf-8');
57+
const fileContent = fs.readFileSync(filePath, "utf-8");
5558

5659
const rules: UpdateImportsRules[] = [
5760
{
5861
regex: /import\s+\{([^}]+)\}\s+from\s+['"](@\/utils[^'"]*)['"]/g,
59-
replacer: (_, imports) => `import {${imports}} from '${config.aliases.utils}'`
62+
replacer: (_, imports) =>
63+
`import { ${imports} } from '${config.aliases.utils}'`,
6064
},
6165
{
6266
regex: /import\s+(?:type\s+)?\{([^}]+)\}\s+from\s+['"](\.[^'"]*)['"]/g,
6367
replacer: (_, imports, internalPath) =>
64-
`import {${imports}} from '${toCase(internalPath, config.case)}'`
65-
}
68+
`import { ${imports} } from '${toCase(internalPath, config.case)}'`,
69+
},
6670
];
6771

6872
const updatedContent = rules.reduce(
@@ -74,39 +78,40 @@ const updateImports = async (filePath: string, config: ConfigSchema) => {
7478
};
7579

7680
export const add = {
77-
command: 'add [hooks...]',
78-
describe: 'Add a hook to your project',
81+
command: "add [hooks...]",
82+
describe: "Add a hook to your project",
7983
builder: (yargs: Argv) =>
8084
yargs
81-
.positional('hooks', {
82-
describe: 'List of hooks to add',
83-
type: 'string',
85+
.positional("hooks", {
86+
describe: "List of hooks to add",
87+
type: "string",
8488
demandOption: true,
8589
array: true,
86-
default: []
90+
default: [],
8791
})
88-
.option('all', {
89-
alias: 'a',
90-
type: 'boolean',
92+
.option("all", {
93+
alias: "a",
94+
type: "boolean",
9195
default: false,
92-
description: 'add all available hooks'
96+
description: "add all available hooks",
9397
})
94-
.option('cwd', {
95-
type: 'string',
96-
description: 'the working directory. defaults to the current directory.',
97-
default: APP_PATH
98+
.option("cwd", {
99+
type: "string",
100+
description:
101+
"the working directory. defaults to the current directory.",
102+
default: APP_PATH,
98103
})
99-
.option('overwrite', {
100-
alias: 'o',
101-
type: 'boolean',
104+
.option("overwrite", {
105+
alias: "o",
106+
type: "boolean",
102107
default: false,
103-
description: 'overwrite existing files'
108+
description: "overwrite existing files",
104109
})
105-
.option('registry', {
106-
type: 'string',
107-
description: 'url of the registry to use',
110+
.option("registry", {
111+
type: "string",
112+
description: "url of the registry to use",
108113
demandOption: true,
109-
default: 'https://siberiacancode.github.io/reactuse/registry.json'
114+
default: "https://siberiacancode.github.io/reactuse/registry.json",
110115
}),
111116

112117
handler: async (argv: AddOptionsSchema) => {
@@ -115,30 +120,30 @@ export const add = {
115120
all: argv.all,
116121
registry: argv.registry,
117122
overwrite: argv.overwrite,
118-
cwd: argv.cwd
123+
cwd: argv.cwd,
119124
});
120125

121126
const registryResponse = await fetches.get<Registry>(options.registry);
122127
const registry = registryResponse.data;
123128

124129
if (!registry) {
125-
console.log('Registry is missing. Please check the url.');
130+
console.log("Registry is missing. Please check the url.");
126131
process.exit(1);
127132
}
128133

129134
let selectedHooks = options.all ? Object.keys(registry) : options.hooks;
130135
if (!selectedHooks.length) {
131136
const { hooks } = await prompts({
132-
type: 'multiselect',
133-
name: 'hooks',
134-
message: `Which ${chalk.cyan('hooks')} would you like to add?`,
135-
hint: 'Space to select. A to toggle all. Enter to submit.',
137+
type: "multiselect",
138+
name: "hooks",
139+
message: `Which ${chalk.cyan("hooks")} would you like to add?`,
140+
hint: "Space to select. A to toggle all. Enter to submit.",
136141
instructions: false,
137142
choices: Object.values(registry).map((hook) => ({
138143
title: hook.name,
139144
value: hook.name,
140-
selected: false
141-
}))
145+
selected: false,
146+
})),
142147
});
143148
if (hooks) selectedHooks = hooks;
144149
}
@@ -153,35 +158,51 @@ export const add = {
153158
}
154159

155160
if (!selectedHooks.length) {
156-
console.log('No hooks selected.');
161+
console.log("No hooks selected.");
157162
process.exit(0);
158163
}
159164

160165
const config = await getConfig(options.cwd);
161-
const language = config?.ts ? 'ts' : 'js';
166+
const language = config?.ts ? "ts" : "js";
162167

163168
const projectConfig = loadConfig(options.cwd);
164-
if (projectConfig.resultType === 'failed') {
169+
if (projectConfig.resultType === "failed") {
165170
throw new Error(
166-
`Failed to load ${language}config.json. ${projectConfig.message ?? ''}`.trim()
171+
`Failed to load ${language}config.json. ${
172+
projectConfig.message ?? ""
173+
}`.trim()
167174
);
168175
}
169176

170-
const matchPath = createMatchPath(projectConfig.absoluteBaseUrl, projectConfig.paths);
171-
const pathToLoadHooks = matchPath(config.aliases.hooks, undefined, () => true);
172-
const pathToLoadUtils = matchPath(config.aliases.utils, undefined, () => true);
177+
const matchPath = createMatchPath(
178+
projectConfig.absoluteBaseUrl,
179+
projectConfig.paths
180+
);
181+
const pathToLoadHooks = matchPath(
182+
config.aliases.hooks,
183+
undefined,
184+
() => true
185+
);
186+
const pathToLoadUtils = matchPath(
187+
config.aliases.utils,
188+
undefined,
189+
() => true
190+
);
173191

174192
if (!pathToLoadHooks || !pathToLoadUtils) {
175-
console.log('Failed to load paths.');
193+
console.log("Failed to load paths.");
176194
process.exit(1);
177195
}
178196

179197
const dependencies = resolveDependencies(registry, selectedHooks);
180198
const packages: string[] = [];
181199
const files = Array.from(dependencies.values())
182200
.map((dependency) => {
183-
if (dependency.type === 'hook') {
184-
const filePath = toCase(`${dependency.name}/${dependency.name}`, config.case);
201+
if (dependency.type === "hook") {
202+
const filePath = toCase(
203+
`${dependency.name}/${dependency.name}`,
204+
config.case
205+
);
185206
const directoryPath = `${pathToLoadHooks}/${filePath}.${language}`;
186207
const registryPath = `${
187208
REPO_URLS[language.toUpperCase() as keyof typeof REPO_URLS]
@@ -193,11 +214,11 @@ export const add = {
193214
registryPath,
194215
type: dependency.type,
195216
indexPath,
196-
filePath
217+
filePath,
197218
};
198219
}
199220

200-
if (dependency.type === 'util') {
221+
if (dependency.type === "util") {
201222
const filePath = toCase(`${dependency.name}`, config.case);
202223
const directoryPath = `${pathToLoadUtils}/${filePath}.${language}`;
203224
const registryPath = `${
@@ -210,11 +231,11 @@ export const add = {
210231
registryPath,
211232
type: dependency.type,
212233
indexPath,
213-
filePath
234+
filePath,
214235
};
215236
}
216237

217-
if (dependency.type === 'package') {
238+
if (dependency.type === "package") {
218239
packages.push(dependency.name);
219240
return undefined;
220241
}
@@ -223,25 +244,28 @@ export const add = {
223244
})
224245
.filter(Boolean);
225246

226-
const spinner = ora('Installing files...').start();
247+
const spinner = ora("Installing files...").start();
227248
for (const file of files) {
228-
const { directoryPath, registryPath, indexPath, filePath, name, type } = file!;
249+
const { directoryPath, registryPath, indexPath, filePath, name, type } =
250+
file!;
229251
spinner.text = `Installing ${name}...`;
230252
const directory = path.dirname(directoryPath);
231253

232254
const isExists = fs.existsSync(directory);
233255
if (isExists && !options.overwrite) {
234256
spinner.stop();
235257
const { overwrite } = await prompts({
236-
type: 'confirm',
237-
name: 'overwrite',
258+
type: "confirm",
259+
name: "overwrite",
238260
message: `File ${name} already exists. Would you like to overwrite?`,
239-
initial: false
261+
initial: false,
240262
});
241263

242264
if (!overwrite) {
243265
console.log(
244-
`Skipped ${name}. To overwrite, run with the ${chalk.green('--overwrite')} flag.`
266+
`Skipped ${name}. To overwrite, run with the ${chalk.green(
267+
"--overwrite"
268+
)} flag.`
245269
);
246270
continue;
247271
}
@@ -257,30 +281,34 @@ export const add = {
257281

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

260-
if (!fs.existsSync(indexPath)) fs.writeFileSync(indexPath, '');
261-
const indexFileContent = fs.readFileSync(indexPath, 'utf-8');
284+
if (!fs.existsSync(indexPath)) fs.writeFileSync(indexPath, "");
285+
const indexFileContent = fs.readFileSync(indexPath, "utf-8");
262286
if (!indexFileContent.includes(exportStatement))
263-
fs.appendFileSync(indexPath, exportStatement, 'utf-8');
287+
fs.appendFileSync(indexPath, exportStatement, "utf-8");
264288
}
265289

266290
const packageManager = await getPackageManager(options.cwd);
267291

268-
spinner.text = `Installing packages ${chalk.bold(packages.join(', '))} with ${chalk.cyan(
269-
packageManager
270-
)}`;
292+
spinner.text = `Installing packages ${chalk.bold(
293+
packages.join(", ")
294+
)} with ${chalk.cyan(packageManager)}`;
271295
if (packages.length) {
272-
await execa(packageManager, [packageManager === 'npm' ? 'install' : 'add', ...packages], {
273-
cwd: options.cwd
274-
});
296+
await execa(
297+
packageManager,
298+
[packageManager === "npm" ? "install" : "add", ...packages],
299+
{
300+
cwd: options.cwd,
301+
}
302+
);
275303
}
276304

277305
spinner.stop();
278306

279307
const installedHooks = files
280-
.filter((file) => file!.type === 'hook')
308+
.filter((file) => file!.type === "hook")
281309
.map((file) => chalk.green(file!.name))
282-
.join(', ');
310+
.join(", ");
283311
console.log(`\nInstalled hooks: ${installedHooks}`);
284-
console.log(chalk.bold('\nπŸŽ‰ Hooks added successfully! πŸŽ‰'));
285-
}
312+
console.log(chalk.bold("\nπŸŽ‰ Hooks added successfully! πŸŽ‰"));
313+
},
286314
};
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export * from "./getConfig";
22
export * from "./getPackageManager";
3-
export * from "./toKebabCase";
43
export * from "./toCase";
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { toKebabCase } from "./toKebabCase";
1+
export const toCase = (string: string, mode: "camel" | "kebab" = "camel") => {
2+
if (mode === "camel") return string;
23

3-
export const toCase = (string: string, mode: "camel" | "kebab" = "camel") =>
4-
mode === "camel" ? string : toKebabCase(string);
4+
return string.replace(
5+
/[A-Z]+(?![a-z])|[A-Z]/g,
6+
(match, offset) => (offset ? "-" : "") + match.toLowerCase()
7+
);
8+
};

0 commit comments

Comments
Β (0)