klei-cli 1.0.1 → 1.0.5

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.
Files changed (3) hide show
  1. package/README.md +13 -27
  2. package/bin/cli.js +366 -37
  3. package/package.json +11 -6
package/README.md CHANGED
@@ -16,46 +16,32 @@ pnpm install -g klei-cli
16
16
 
17
17
  Para usar la CLI, puedes ejecutar los siguientes comandos:
18
18
 
19
- ### Mostrar Ayuda
19
+ ### create
20
+
21
+ Este comando crea un nuevo proyecto.
20
22
 
21
23
  ```bash
22
- klei ayuda
24
+ # klei create <nombre> [opciones]
25
+ # klei create mi-proyecto
26
+ # klei create --t npmjs
27
+ # klei create --type npmjs
28
+ klei create mi-proyecto --type npmjs
23
29
  ```
24
30
 
25
- Este comando muestra la ayuda y los comandos disponibles.
31
+ ### help
26
32
 
27
- ### Saludar
33
+ Este comando muestra la ayuda y los comandos disponibles.
28
34
 
29
35
  ```bash
30
- klei saludar <nombre> [opciones]
36
+ klei help
31
37
  ```
32
38
 
33
- Este comando saluda al usuario especificado.
34
-
35
- #### Opciones
36
-
37
- - `-e, --exclamar`: Agrega una exclamación al saludo.
38
-
39
39
  ## Comandos Disponibles
40
40
 
41
- - `saludar <nombre>`: Saluda al usuario.
42
- - `-e, --exclamar`: Agrega una exclamación al saludo.
41
+ - `create [nombre]`: Crea un nuevo proyecto.
42
+ - `--t, --type <type>`: Especifica el tipo de proyecto.
43
43
  - `help`: Muestra la ayuda y los comandos disponibles.
44
44
 
45
- ## Ejemplos
46
-
47
- ```bash
48
- klei saludar Juan -e
49
- ```
50
-
51
- Este comando saluda a Juan con una exclamación.
52
-
53
- ```bash
54
- klei ayuda
55
- ```
56
-
57
- Este comando muestra la ayuda.
58
-
59
45
  ## Contribuir
60
46
 
61
47
  Si deseas contribuir a este proyecto, por favor sigue los siguientes pasos:
package/bin/cli.js CHANGED
@@ -1,59 +1,388 @@
1
1
  #!/usr/bin/env node
2
- // klei-cli
2
+ // $ klei
3
3
 
4
4
  // src/index.ts
5
5
  import chalk4 from "chalk";
6
6
  import { program } from "commander";
7
+ import fs3 from "fs";
7
8
 
8
- // src/commands/help.ts
9
+ // src/utils/banner.ts
9
10
  import chalk from "chalk";
10
- function helpCommand() {
11
- console.log(chalk.blue("-".repeat(48)));
12
- console.log(chalk.bold.green("klei CLI - Ayuda"));
13
- console.log(chalk.yellow(`
14
- Comandos disponibles:
11
+ import figlet from "figlet";
12
+ var printBanner = () => {
13
+ console.log(
14
+ chalk.blue(
15
+ figlet.textSync("KLEI", { horizontalLayout: "full" })
16
+ )
17
+ );
18
+ };
15
19
 
16
- saludar <nombre> Saluda al usuario.
20
+ // src/commands/create.ts
21
+ import inquirer from "inquirer";
22
+ import chalk3 from "chalk";
23
+ import ora from "ora";
17
24
 
18
- help Muestra la ayuda y los comandos disponibles.
25
+ // src/utils/project.ts
26
+ import chalk2 from "chalk";
27
+ import fs2 from "fs";
28
+ import path2 from "path";
19
29
 
20
- Uso:
21
- klei <comando>
30
+ // src/templates/npmjs.ts
31
+ var npmjs = [
32
+ {
33
+ content: "# Proyecto generado por Klei CLI.",
34
+ pathFileName: "README.md"
35
+ },
36
+ {
37
+ content: JSON.stringify({
38
+ name: "my-project",
39
+ version: "1.0.0",
40
+ description: "",
41
+ type: "module",
42
+ main: "./dist/index.cjs",
43
+ module: "./dist/index.js",
44
+ types: "./dist/index.d.ts",
45
+ files: [
46
+ "dist/**"
47
+ ],
48
+ scripts: {
49
+ start: "tsx src/index.ts",
50
+ xtart: "npx -y tsx src/index.ts",
51
+ watch: 'tsup --entry.index src/index.ts --format esm --clean --watch --onSuccess "node dist/index.js"',
52
+ build: "tsup --entry.index src/index.ts --format esm,cjs --dts --clean",
53
+ "test:esm": 'tsup --entry.test src/index.ts --format esm --clean --onSuccess "node dist/test.js"',
54
+ "test:spec": 'tsup test/test.spec.ts --format esm --clean --onSuccess "cross-env NODE_ENV=test node --test dist/test.spec.js"'
55
+ },
56
+ keywords: [],
57
+ author: "",
58
+ license: "ISC",
59
+ dependencies: {},
60
+ devDependencies: {
61
+ "@eslint/js": "latest",
62
+ // "@types/assert": 'latest',
63
+ "@types/node": "latest",
64
+ "cross-env": "latest",
65
+ eslint: "latest",
66
+ nodemon: "latest",
67
+ "ts-node": "latest",
68
+ tsup: "latest",
69
+ tsx: "latest",
70
+ typescript: "latest",
71
+ "typescript-eslint": "latest"
72
+ }
73
+ }, null, 2),
74
+ pathFileName: "package.json"
75
+ },
76
+ {
77
+ content: `import { defineConfig } from 'tsup'
78
+ export default defineConfig(${JSON.stringify({
79
+ entry: {
80
+ index: "src/index.ts"
81
+ },
82
+ format: ["esm", "cjs"],
83
+ dts: true,
84
+ clean: true
85
+ }, null, 2)})`,
86
+ pathFileName: "tsup.config.ts"
87
+ },
88
+ {
89
+ content: JSON.stringify({
90
+ $schema: "https://json.schemastore.org/tsconfig",
91
+ display: "Default",
92
+ compilerOptions: {
93
+ target: "ES2024",
94
+ module: "ES2022",
95
+ // outDir: './dist',
96
+ // rootDir: './src',
97
+ strict: true,
98
+ esModuleInterop: true,
99
+ skipLibCheck: true,
100
+ forceConsistentCasingInFileNames: true,
101
+ declaration: true,
102
+ moduleResolution: "node",
103
+ resolveJsonModule: true,
104
+ noUnusedLocals: false,
105
+ noImplicitThis: false,
106
+ noUnusedParameters: false,
107
+ baseUrl: ".",
108
+ paths: {
109
+ "@/*": [
110
+ "./src/*"
111
+ ]
112
+ }
113
+ },
114
+ include: ["."],
115
+ exclude: ["node_modules", "dist", "build", "docs"]
116
+ }, null, 2),
117
+ pathFileName: "tsconfig.json"
118
+ },
119
+ {
120
+ content: `// Example TypeScript code with types and interfaces
22
121
 
23
- Ejemplos:
24
- klei saludar <nombre> - Saluda al usuario.
25
- klei help - Muestra la ayuda.
26
- `));
27
- console.log(chalk.blue("-".repeat(48)));
122
+ // Define an interface for a User
123
+ interface User {
124
+ id: number;
125
+ name: string;
126
+ email: string;
127
+ isActive: boolean;
28
128
  }
29
- var help_default = helpCommand;
30
129
 
31
- // src/commands/saludar.ts
32
- import chalk2 from "chalk";
33
- var saludar_default = (program2) => {
34
- program2.command("saludar <nombre>").description("Saluda al usuario").option("-e, --exclamar", "Agrega una exclamaci\xF3n").action((nombre, options) => {
35
- let mensaje = `Hola ${chalk2.green(nombre)}!`;
36
- if (options.exclamar) mensaje += " \u{1F44B}";
37
- console.log(mensaje);
38
- });
130
+ // Define a type for a function that takes a User and returns a string
131
+ type GreetUser = (user: User) => string;
132
+
133
+ // Example implementation of the GreetUser function
134
+ export const greetUser: GreetUser = (user) => {
135
+ return \`Hello, \${user.name}! Your email is \${user.email}.\`;
39
136
  };
40
137
 
41
- // src/utils/banner.ts
42
- import chalk3 from "chalk";
43
- import figlet from "figlet";
44
- var printBanner = () => {
45
- console.log(
46
- chalk3.blue(
47
- figlet.textSync("KLEI", { horizontalLayout: "full" })
48
- )
49
- );
138
+ // Example usage
139
+ export const exampleUser: User = {
140
+ id: 1,
141
+ name: 'John Doe',
142
+ email: 'john.doe@example.com',
143
+ isActive: true
50
144
  };
51
145
 
146
+ console.log(greetUser(exampleUser));
147
+ `,
148
+ pathFileName: "src/index.ts"
149
+ },
150
+ {
151
+ content: `// @ts-check
152
+
153
+ import eslint from '@eslint/js'
154
+ import tseslint from 'typescript-eslint'
155
+
156
+ export default tseslint.config(
157
+ { ignores: ['node_modules', 'dist/', 'bin/'] },
158
+ eslint.configs.recommended,
159
+ tseslint.configs.strict,
160
+ tseslint.configs.stylistic,
161
+ {
162
+ rules: {
163
+ quotes: [2, 'single', { avoidEscape: true }],
164
+ 'prefer-const': ['error', { ignoreReadBeforeAssign: true }],
165
+ 'space-before-function-paren': ['off'],
166
+ '@typescript-eslint/no-explicit-any': 'off',
167
+ 'no-useless-escape': 'off',
168
+ 'eol-last': ['error', 'always'],
169
+ semi: ['error', 'never'],
170
+ 'quote-props': ['error', 'as-needed'],
171
+ 'spaced-comment': ['error', 'always', { markers: ['/'] }],
172
+ 'comma-dangle': ['error', 'never'],
173
+ 'no-multiple-empty-lines': ['error', { max: 1 }],
174
+ 'no-async-promise-executor': 'off'
175
+ }
176
+ }
177
+ )`,
178
+ pathFileName: "eslint.config.mjs"
179
+ },
180
+ {
181
+ content: `// \u2501\u2501 IMPORT MODULES \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
182
+ // \xBB IMPORT NATIVE NODE MODULES
183
+
184
+ import { describe, it } from 'node:test'
185
+
186
+ import assert from 'node:assert'
187
+
188
+ // \xBB IMPORT MODULES
189
+ import { greetUser, exampleUser } from '@/index'
190
+
191
+ // \u2501\u2501 TEST \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
192
+
193
+ describe('greetUser', () => {
194
+ it('should return a greeting message with the provided name', () => {
195
+ const result = greetUser(exampleUser)
196
+ assert.strictEqual(result, 'Hello, John Doe! Your email is john.doe@example.com.')
197
+ })
198
+ })`,
199
+ pathFileName: "test/test.spec.ts"
200
+ }
201
+ ];
202
+
203
+ // src/lib/utils/npm-utils.js
204
+ import fs from "node:fs";
205
+ import spawn from "cross-spawn";
206
+ import path from "node:path";
207
+ import process2 from "node:process";
208
+ import console2 from "node:console";
209
+ function findPackageJson(startDir) {
210
+ let dir = path.resolve(startDir || process2.cwd());
211
+ do {
212
+ const pkgFile = path.join(dir, "package.json");
213
+ if (!fs.existsSync(pkgFile) || !fs.statSync(pkgFile).isFile()) {
214
+ dir = path.join(dir, "..");
215
+ continue;
216
+ }
217
+ return pkgFile;
218
+ } while (dir !== path.resolve(dir, ".."));
219
+ return null;
220
+ }
221
+ function installSyncSaveDev(packages, packageManager = "npm", cwd, installFlags = ["-D"]) {
222
+ const packageList = Array.isArray(packages) ? packages : [packages];
223
+ const installCmd = packageManager === "yarn" ? "add" : "install";
224
+ const installProcess = spawn.sync(packageManager, [installCmd, ...installFlags].concat(packageList), { stdio: "inherit", cwd });
225
+ const error = installProcess.error;
226
+ if (error && error.code === "ENOENT") {
227
+ const pluralS = packageList.length > 1 ? "s" : "";
228
+ console2.error(`Could not execute ${packageManager}. Please install the following package${pluralS} with a package manager of your choice: ${packageList.join(", ")}`);
229
+ }
230
+ }
231
+ function parsePackageName(packageName) {
232
+ const atIndex = packageName.lastIndexOf("@");
233
+ if (atIndex > 0) {
234
+ const name = packageName.slice(0, atIndex);
235
+ const version2 = packageName.slice(atIndex + 1) || "latest";
236
+ return { name, version: version2 };
237
+ }
238
+ return { name: packageName, version: "latest" };
239
+ }
240
+ function getPkgs(path3) {
241
+ return JSON.parse(fs.readFileSync(path3, "utf-8"));
242
+ }
243
+
244
+ // src/utils/project.ts
245
+ var createProjectStructure = async (answers, spinner) => {
246
+ return new Promise((resolve, reject) => {
247
+ const projects = {
248
+ npmjs,
249
+ monorepo: []
250
+ };
251
+ const projectStr = projects[answers.projectType];
252
+ if (!projectStr) {
253
+ return reject(new Error("Tipo de proyecto no v\xE1lido. --t ".concat(Object.keys(projects).join(", "))));
254
+ }
255
+ const projectDir = path2.join(process.cwd(), answers.projectName);
256
+ if (fs2.existsSync(projectDir) && answers.projectName !== ".") {
257
+ return reject(new Error(`El directorio ${projectDir} ya existe. Elige otro nombre.`));
258
+ }
259
+ for (const file of projectStr) {
260
+ const { content, pathFileName } = file;
261
+ const filePath = path2.join(projectDir, pathFileName);
262
+ if (answers.projectName === "." && fs2.existsSync(filePath)) {
263
+ spinner.warn(`El archivo ${chalk2.yellow(filePath)} ya existe. Se omitir\xE1 su creaci\xF3n.`);
264
+ continue;
265
+ }
266
+ spinner.info(`Creando ${chalk2.yellow(filePath)}`);
267
+ const dirPath = path2.dirname(filePath);
268
+ fs2.mkdirSync(dirPath, { recursive: true });
269
+ fs2.writeFileSync(filePath, content);
270
+ }
271
+ if (answers.projectInstall) {
272
+ spinner.info(`Instalando dependencias con ${chalk2.yellow(answers.projectPackageManager)}`);
273
+ const packageJsonPath = findPackageJson(projectDir);
274
+ const packageJson = getPkgs(packageJsonPath);
275
+ const pkgs = Object.keys(packageJson.devDependencies).map((pkgName) => parsePackageName(pkgName)).map((pkg) => pkg.name);
276
+ spinner.info(`Instalando dependencias: ${chalk2.yellow(pkgs.join(" "))}`);
277
+ installSyncSaveDev(pkgs, answers.projectPackageManager, projectDir);
278
+ spinner.info(chalk2.green("Dependencias instaladas exitosamente"));
279
+ }
280
+ spinner.succeed(`${chalk2.green(` Proyecto ${chalk2.bold(projectDir)} creado exitosamente`)}`);
281
+ resolve(true);
282
+ });
283
+ };
284
+
285
+ // src/commands/create.ts
286
+ var logo = `
287
+ ${chalk3.dim("Creaci\xF3n r\xE1pida de proyectos")}
288
+ `;
289
+ var questionsMain = [
290
+ {
291
+ type: "list",
292
+ name: "projectType",
293
+ message: " \xBFQu\xE9 tipo de proyecto quieres crear?",
294
+ choices: [
295
+ { name: "npmjs package (Node.js)", value: "npmjs" }
296
+ // { name: 'Aplicación Monorepo (Node.js)', value: 'monorepo' }
297
+ // { name: 'Aplicación CLI (Node.js)', value: 'cli' }
298
+ ]
299
+ },
300
+ {
301
+ type: "input",
302
+ name: "projectName",
303
+ message: " \xBFCu\xE1l es el nombre del proyecto?",
304
+ validate: (input) => {
305
+ if (input.trim() === "") {
306
+ return "El nombre del proyecto no puede estar vac\xEDo.";
307
+ }
308
+ return true;
309
+ }
310
+ },
311
+ {
312
+ type: "list",
313
+ name: "projectInstall",
314
+ message: " \xBFQuieres instalar dependencias?",
315
+ choices: [
316
+ { name: "No", value: false },
317
+ { name: "S\xED", value: true }
318
+ ]
319
+ },
320
+ {
321
+ type: "list",
322
+ name: "projectPackageManager",
323
+ message: " \xBFQu\xE9 gestor de paquetes quieres usar?",
324
+ choices: [
325
+ { name: "npm", value: "npm" },
326
+ { name: "yarn", value: "yarn" },
327
+ { name: "pnpm", value: "pnpm" },
328
+ { name: "bun", value: "bun" }
329
+ ],
330
+ when: (answers) => answers.projectInstall
331
+ }
332
+ ];
333
+ async function createCommand({ name, options }) {
334
+ console.log(logo);
335
+ console.log(chalk3.blue("------------------------------------------------\n"));
336
+ const questions = [];
337
+ if (typeof options?.type === "undefined") questions.push(questionsMain[0]);
338
+ if (typeof name === "undefined") questions.push(questionsMain[1]);
339
+ let answers;
340
+ if (questions.length === 0) {
341
+ answers = {
342
+ projectType: options?.type,
343
+ projectName: name,
344
+ projectInstall: false,
345
+ projectPackageManager: "npm" /* npm */
346
+ };
347
+ } else {
348
+ questions.push(questionsMain[2]);
349
+ questions.push(questionsMain[3]);
350
+ answers = await inquirer.prompt(questions);
351
+ if (typeof name !== "undefined") {
352
+ answers.projectName = name;
353
+ }
354
+ if (typeof options?.type !== "undefined") {
355
+ answers.projectType = options.type;
356
+ }
357
+ }
358
+ const spinner = ora("Creando proyecto...\n\n").start();
359
+ try {
360
+ await createProjectStructure(answers, spinner);
361
+ } catch (error) {
362
+ spinner.fail(chalk3.red("Error al crear el proyecto."));
363
+ showError(error);
364
+ } finally {
365
+ spinner.stop();
366
+ }
367
+ }
368
+ var create_default = createCommand;
369
+ function showError(error) {
370
+ if (error instanceof Error) {
371
+ console.error(chalk3.red(error.message));
372
+ } else {
373
+ console.error(chalk3.red("Error desconocido".concat(JSON.stringify(error))));
374
+ }
375
+ }
376
+
52
377
  // src/index.ts
378
+ var { version } = JSON.parse(
379
+ fs3.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
380
+ );
53
381
  printBanner();
54
- program.name("klei").version("1.0.0").description("CLI profesional con m\xFAltiples caracter\xEDsticas");
55
- program.command("help").description("Muestra ayuda en espa\xF1ol").action(help_default);
56
- saludar_default(program);
382
+ program.name("klei").version(version, "-v, --version", "Muestra la versi\xF3n actual").description("CLI con m\xFAltiples caracter\xEDsticas");
383
+ program.command("create [name]").alias("c").option("--t, --type <type>", "Tipo de proyecto").description("Crea un nuevo proyecto").action((name, options) => {
384
+ create_default({ name, options });
385
+ });
57
386
  program.configureOutput({
58
387
  outputError: (err) => {
59
388
  console.error(chalk4.red(`Error: ${err}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klei-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.5",
4
4
  "description": "cli for creating and managing packages",
5
5
  "type": "module",
6
6
  "funding": {
@@ -48,14 +48,15 @@
48
48
  "devDependencies": {
49
49
  "@eslint/js": "^9.21.0",
50
50
  "@types/assert": "^1.5.11",
51
+ "@types/cross-spawn": "^6.0.6",
51
52
  "@types/figlet": "^1.7.0",
52
53
  "@types/node": "^22.13.5",
53
54
  "eslint": "^9.21.0",
54
- "tsup": "^8.3.6",
55
- "typescript": "^5.7.3",
55
+ "tsup": "^8.4.0",
56
+ "typescript": "^5.8.3",
56
57
  "typescript-eslint": "^8.25.0"
57
58
  },
58
- "packageManager": "pnpm@10.4.1+sha512.c753b6c3ad7afa13af388fa6d808035a008e30ea9993f58c6663e2bc5ff21679aa834db094987129aa4d488b86df57f7b634981b2f827cdcacc698cc0cfb88af",
59
+ "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39",
59
60
  "pnpm": {
60
61
  "onlyBuiltDependencies": [
61
62
  "esbuild"
@@ -64,6 +65,10 @@
64
65
  "dependencies": {
65
66
  "chalk": "^5.4.1",
66
67
  "commander": "^13.1.0",
67
- "figlet": "^1.8.0"
68
+ "cross-spawn": "^7.0.6",
69
+ "figlet": "^1.8.0",
70
+ "inquirer": "^12.4.2",
71
+ "ora": "^8.2.0",
72
+ "simple-git": "^3.27.0"
68
73
  }
69
- }
74
+ }