tumemo 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 +11 -11
  2. package/index.js +61 -93
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
- # Tumemo CLI 🚀
1
+ # 🚀 Tumemo CLI
2
2
 
3
- Um CLI robusto para automatizar o setup de projetos **React + TypeScript + Vite**, focado em produtividade e limpeza de boilerplate.
3
+ O jeito mais rápido de iniciar seus projetos React com TypeScript, Axios e as melhores ferramentas de estilo.
4
4
 
5
5
  ## 🛠️ O que ele faz?
6
-
7
- - **Setup Instantâneo:** Cria a base com Vite + React + TS no diretório atual.
8
- - **Limpeza Radical:** Remove automaticamente `assets/`, `App.css` e `index.css` do Vite.
9
- - **Configuração de Estilos:** Cria uma pasta `src/shared/tailwind.css` (opcional).
10
- - **Integração Shadcn UI:** Configura Aliases (`@/`) no Vite e TS, além de rodar o init do Shadcn.
11
- - **Pronto para API:** instala o **Axios** por padrão.
12
- - **Organização Sênior:** Cria pastas `components`, `pages`, `hooks` e `lib`.
6
+ - Gera um projeto **Vite (React + TS)** limpo.
7
+ - Remove arquivos desnecessários (`App.css`, `index.css`, ativos de exemplo).
8
+ - Instala automaticamente: **Axios**, **React Router Dom**, **Tailwind Merge** e **Clsx**.
9
+ - Configura Aliases de caminho (`@/` aponta para `src/`).
10
+ - entrega as pastas `src/components`, `src/pages` e `src/shared` criadas.
11
+ - **Inicia o servidor automaticamente** após o setup.
13
12
 
14
13
  ## 🚀 Como usar
15
14
 
16
- ### Via NPX (Sem instalação)
15
+ Acesse a pasta onde deseja criar o projeto e rode:
16
+
17
17
  ```bash
18
- npx tumemo-cli -s
18
+ npx tumemo@latest
package/index.js CHANGED
@@ -6,7 +6,6 @@ import { execa } from 'execa';
6
6
  import fs from 'fs-extra';
7
7
  import path from 'path';
8
8
 
9
- // Força o Chalk a usar cores mesmo em sub-processos
10
9
  process.env.FORCE_COLOR = "1";
11
10
 
12
11
  const log = {
@@ -18,132 +17,101 @@ const log = {
18
17
 
19
18
  async function runCommand(command, args, options = {}) {
20
19
  try {
21
- // Adicionado env para forçar cores nos comandos do NPM/Vite
22
20
  await execa(command, args, {
23
21
  stdio: 'inherit',
24
- env: { ...process.env, FORCE_COLOR: "1" },
22
+ shell: true,
23
+ env: { ...process.env, FORCE_COLOR: "1" },
25
24
  ...options
26
25
  });
27
26
  } catch (error) {
28
- log.error(`Erro ao executar: ${command} ${args.join(' ')}`);
27
+ log.error(`Erro: ${error.message}`);
29
28
  process.exit(1);
30
29
  }
31
30
  }
32
31
 
33
32
  program
34
33
  .name('Tumemo')
35
- .description('Setup automatizado React + TS + Axios')
36
- .version('1.0.2')
37
- .option('-t, --tailwind', 'Instalar Tailwind CSS')
38
- .option('-s, --shadcn', 'Instalar Tailwind + Shadcn UI')
34
+ .description('O setup mais rápido para React + TS')
35
+ .version('1.1.1')
36
+ .option('-t, --tailwind', 'Instalar Tailwind v4')
37
+ .option('-s, --shadcn', 'Instalar Shadcn')
39
38
  .action(async (options) => {
40
39
  const root = process.cwd();
40
+ const projectName = path.basename(root);
41
41
 
42
42
  try {
43
43
  log.step(`Iniciando Setup Tumemo em: ${root}`);
44
44
 
45
- // 1. Vite Base (Adicionado --yes para evitar menus interativos)
46
- log.info('Criando base Vite...');
47
- await runCommand('npm', ['create', 'vite@latest', '.', '--yes', '--', '--template', 'react-ts']);
45
+ log.info('Baixando template React + TS...');
46
+ await runCommand('npx', ['--yes', 'degit', 'vitejs/vite/packages/create-vite/template-react-ts', '.']);
48
47
 
49
- // 2. Instalação (npm install puro primeiro)
50
- log.info('Baixando dependências base...');
48
+ const oldGit = path.join(root, '_gitignore');
49
+ if (fs.existsSync(oldGit)) fs.renameSync(oldGit, path.join(root, '.gitignore'));
50
+
51
+ const pkgPath = path.join(root, 'package.json');
52
+ const pkg = await fs.readJson(pkgPath);
53
+ pkg.name = projectName;
54
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
55
+
56
+ log.info('Instalando dependências base...');
51
57
  await runCommand('npm', ['install']);
52
-
53
- log.info('Instalando bibliotecas auxiliares (Axios, Router, etc)...');
54
- await runCommand('npm', ['install', 'axios', 'react-router-dom', 'tailwind-merge', 'clsx']);
55
- await runCommand('npm', ['install', '-D', '@types/node']);
56
58
 
57
- // 3. Limpeza Radical
58
59
  log.info('Limpando boilerplate...');
59
- const toDelete = ['src/assets', 'src/App.css', 'src/index.css'];
60
- for (const item of toDelete) {
61
- const fullPath = path.join(root, item);
62
- if (await fs.pathExists(fullPath)) {
63
- await fs.remove(fullPath);
64
- }
65
- }
60
+ ['src/assets', 'src/App.css', 'src/index.css', 'public/vite.svg'].forEach(item => {
61
+ const fullPath = path.resolve(root, item);
62
+ if (fs.existsSync(fullPath)) fs.removeSync(fullPath);
63
+ });
64
+
65
+ const htmlPath = path.join(root, 'index.html');
66
+ let htmlContent = fs.readFileSync(htmlPath, 'utf8');
67
+ htmlContent = htmlContent.replace('</head>', ' <style>body { margin: 0; padding: 0; box-sizing: border-box; }</style>\n </head>');
68
+ fs.writeFileSync(htmlPath, htmlContent);
69
+
70
+ await runCommand('npm', ['install', 'axios', 'react-router-dom', 'tailwind-merge', 'clsx']);
71
+ await runCommand('npm', ['install', '-D', '@types/node']);
66
72
 
67
73
  const useTailwind = options.tailwind || options.shadcn;
74
+ const useShadcn = options.shadcn;
68
75
 
69
- // 4. Configuração Tailwind
70
76
  if (useTailwind) {
71
- log.info('Configurando estrutura Tailwind...');
72
- await runCommand('npm', ['install', '-D', 'tailwindcss', 'postcss', 'autoprefixer']);
73
- await runCommand('npx', ['tailwindcss', 'init', '-p']);
74
-
75
- const tailwindContent = `@tailwind base;\n@tailwind components;\n@tailwind utilities;`;
76
- await fs.ensureDir(path.join(root, 'src/shared'));
77
- await fs.writeFile(path.join(root, 'src/shared/tailwind.css'), tailwindContent);
77
+ log.info('Configurando Tailwind v4...');
78
+ await runCommand('npm', ['install', 'tailwindcss', '@tailwindcss/vite']);
79
+ fs.ensureDirSync(path.join(root, 'src/shared'));
80
+ fs.writeFileSync(path.join(root, 'src/shared/tailwind.css'), `@import "tailwindcss";`);
78
81
  }
79
82
 
80
- // 5. Shadcn Integration
81
- if (options.shadcn) {
83
+ if (useShadcn) {
82
84
  log.info('Configurando Shadcn UI...');
83
- await runCommand('npm', ['install', 'lucide-react', 'class-variance-authority']);
84
- await runCommand('npx', ['shadcn-ui@latest', 'init', '-y']);
85
+ await runCommand('npx', ['--yes', 'shadcn@latest', 'init', '-y']);
85
86
  }
86
87
 
87
- // 6. Config de Paths (@/)
88
- const viteConfig = `
89
- import path from "path"
90
- import react from "@vitejs/plugin-react"
91
- import { defineConfig } from "vite"
92
-
93
- export default defineConfig({
94
- plugins: [react()],
95
- resolve: {
96
- alias: {
97
- "@": path.resolve(__dirname, "./src"),
98
- },
99
- },
100
- })`;
101
- await fs.writeFile(path.join(root, 'vite.config.ts'), viteConfig.trim());
102
-
103
- const tsConfigPath = path.join(root, 'tsconfig.app.json');
104
- if (await fs.pathExists(tsConfigPath)) {
105
- const tsConfig = await fs.readJson(tsConfigPath);
106
- tsConfig.compilerOptions.baseUrl = ".";
107
- tsConfig.compilerOptions.paths = { "@/*": ["./src/*"] };
108
- await fs.writeJson(tsConfigPath, tsConfig, { spaces: 2 });
109
- }
88
+ const viteConfig = `import path from "path"\nimport react from "@vitejs/plugin-react"\nimport { defineConfig } from "vite"\n${useTailwind ? 'import tailwindcss from "@tailwindcss/vite"' : ''}\n\nexport default defineConfig({\n plugins: [react(), ${useTailwind ? 'tailwindcss()' : ''}],\n resolve: { alias: { "@": path.resolve(__dirname, "./src") } },\n})`;
89
+ fs.writeFileSync(path.join(root, 'vite.config.ts'), viteConfig.trim());
110
90
 
111
- // 7. main.tsx (Ajustado para importar o CSS apenas se usar Tailwind)
112
- const mainContent = `
113
- import React from 'react'
114
- import ReactDOM from 'react-dom/client'
115
- import App from './App.tsx'
116
- ${useTailwind ? "import '@/shared/tailwind.css'" : ""}
117
-
118
- ReactDOM.createRoot(document.getElementById('root')!).render(
119
- <React.StrictMode>
120
- <App />
121
- </React.StrictMode>,
122
- )`;
123
- await fs.writeFile(path.join(root, 'src/main.tsx'), mainContent.trim());
124
-
125
- // 8. App.tsx
126
- const appContent = `
127
- export default function App() {
128
- return (
129
- <div style={{ padding: '2rem', fontFamily: 'sans-serif' }}>
130
- <h1>Setup Tumemo</h1>
131
- <p>Projeto pronto. React + TS + Axios configurados.</p>
132
- </div>
133
- )
134
- }
135
- `;
136
- await fs.writeFile(path.join(root, 'src/App.tsx'), appContent.trim());
91
+ const tsAppPath = path.join(root, 'tsconfig.app.json');
92
+ const fallbackTs = { compilerOptions: { target: "ESNext", lib: ["DOM", "DOM.Iterable", "ESNext"], module: "ESNext", skipLibCheck: true, moduleResolution: "Node", resolveJsonModule: true, isolatedModules: true, noEmit: true, jsx: "react-jsx", strict: true, baseUrl: ".", paths: { "@/*": ["./src/*"] } } };
93
+ fs.writeJsonSync(tsAppPath, fallbackTs, { spaces: 2 });
137
94
 
138
- // 9. Pastas Selecionadas
139
- const dirs = ['src/components', 'src/pages'];
140
- for (const dir of dirs) {
141
- await fs.ensureDir(path.join(root, dir));
142
- }
95
+ let techStack = "React + TS";
96
+ if (useShadcn) techStack += " + Shadcn UI";
97
+ else if (useTailwind) techStack += " + Tailwind v4";
98
+
99
+ const appContent = `export default function App() {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', width: '100%', fontFamily: 'system-ui, sans-serif', backgroundColor: '#0f172a', color: '#f8fafc', margin: 0 }}>\n <h1 style={{ fontSize: '3.5rem', marginBottom: '0.5rem' }}>Tumemo CLI</h1>\n <p style={{ fontSize: '1.25rem', color: '#94a3b8' }}>Projeto: <strong style={{ color: '#38bdf8' }}>${projectName}</strong></p>\n <div style={{ marginTop: '2.5rem', padding: '1.5rem 3rem', borderRadius: '12px', backgroundColor: '#1e293b', border: '1px solid #334155' }}>\n <p>Stack: <strong>${techStack}</strong></p>\n </div>\n </div>\n )\n}`;
100
+ fs.writeFileSync(path.join(root, 'src/App.tsx'), appContent.trim());
101
+
102
+ const mainContent = `import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App.tsx'\n${useTailwind ? "import '@/shared/tailwind.css'\n" : ""}ReactDOM.createRoot(document.getElementById('root')!).render(<App />)`;
103
+ fs.writeFileSync(path.join(root, 'src/main.tsx'), mainContent);
104
+
105
+ ['src/components', 'src/pages'].forEach(dir => fs.ensureDirSync(path.join(root, dir)));
106
+
107
+ log.success(`\nTumemo v1.0.5 finalizado!`);
108
+ log.info('Iniciando servidor de desenvolvimento...\n');
109
+
110
+ // COMANDO PARA RODAR O SERVIDOR AUTOMATICAMENTE
111
+ await runCommand('npm', ['run', 'dev']);
143
112
 
144
- log.success('Setup Tumemo finalizado! Bom trabalho.');
145
113
  } catch (err) {
146
- log.error(`Erro crítico: ${err.message}`);
114
+ log.error(`Falha: ${err.message}`);
147
115
  }
148
116
  });
149
117
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tumemo",
3
- "version": "1.0.1",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "CLI para automação de projetos React",
6
6
  "main": "index.js",