hightjs 0.3.2 → 0.3.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.
Files changed (42) hide show
  1. package/dist/adapters/factory.js +8 -8
  2. package/dist/adapters/native.js +3 -3
  3. package/dist/auth/client.js +5 -5
  4. package/dist/auth/components.js +2 -2
  5. package/dist/auth/core.js +2 -2
  6. package/dist/auth/react.js +4 -4
  7. package/dist/auth/routes.js +1 -1
  8. package/dist/bin/hightjs.js +29 -328
  9. package/dist/builder.js +47 -21
  10. package/dist/client/DefaultNotFound.js +1 -1
  11. package/dist/client/entry.client.js +3 -3
  12. package/dist/helpers.d.ts +1 -0
  13. package/dist/helpers.js +90 -28
  14. package/dist/hotReload.d.ts +3 -1
  15. package/dist/hotReload.js +43 -51
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +16 -30
  18. package/dist/router.js +133 -62
  19. package/dist/types.d.ts +42 -0
  20. package/docs/config.md +201 -0
  21. package/example/hightjs.config.ts +81 -0
  22. package/example/package-lock.json +633 -3054
  23. package/example/package.json +1 -1
  24. package/package.json +1 -1
  25. package/src/adapters/factory.ts +8 -8
  26. package/src/adapters/native.ts +3 -3
  27. package/src/auth/client.ts +5 -5
  28. package/src/auth/components.tsx +2 -2
  29. package/src/auth/core.ts +2 -2
  30. package/src/auth/react.tsx +4 -4
  31. package/src/auth/routes.ts +1 -1
  32. package/src/bin/hightjs.js +30 -391
  33. package/src/builder.js +47 -22
  34. package/src/client/DefaultNotFound.tsx +1 -1
  35. package/src/client/entry.client.tsx +3 -3
  36. package/src/helpers.ts +105 -29
  37. package/src/hotReload.ts +45 -55
  38. package/src/index.ts +20 -33
  39. package/src/router.ts +140 -63
  40. package/src/types.ts +52 -0
  41. package/example/.hweb/entry.client.js +0 -24
  42. package/example/hweb-dist/main-5KKAYNUU.js +0 -1137
@@ -50,40 +50,40 @@ class FrameworkAdapterFactory {
50
50
  if (this.adapter) {
51
51
  return this.adapter;
52
52
  }
53
- const msg = console_1.default.dynamicLine(` ${console_1.Colors.FgYellow}● ${console_1.Colors.Reset}Detectando framework web...`);
53
+ const msg = console_1.default.dynamicLine(` ${console_1.Colors.FgYellow}● ${console_1.Colors.Reset}Detecting web framework...`);
54
54
  // Detecta Express
55
55
  if (req.app && req.route && res.locals !== undefined) {
56
- msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detectado: Express`);
56
+ msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detected: Express`);
57
57
  this.adapter = new express_1.ExpressAdapter();
58
58
  return this.adapter;
59
59
  }
60
60
  // Detecta Fastify
61
61
  if (req.server && req.routerPath !== undefined && res.request) {
62
- msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detectado: Fastify`);
62
+ msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detected: Fastify`);
63
63
  this.adapter = new fastify_1.FastifyAdapter();
64
64
  return this.adapter;
65
65
  }
66
66
  // Detecta HTTP nativo do Node.js
67
67
  if (req.method !== undefined && req.url !== undefined && req.headers !== undefined &&
68
68
  res.statusCode !== undefined && res.setHeader !== undefined && res.end !== undefined) {
69
- msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detectado: HightJS Native (HTTP)`);
69
+ msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detected: HightJS Native (HTTP)`);
70
70
  this.adapter = new native_1.NativeAdapter();
71
71
  return this.adapter;
72
72
  }
73
73
  // Fallback mais específico para Express
74
74
  if (res.status && res.send && res.json && res.cookie) {
75
- msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detectado: Express (fallback)`);
75
+ msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detected: Express (fallback)`);
76
76
  this.adapter = new express_1.ExpressAdapter();
77
77
  return this.adapter;
78
78
  }
79
79
  // Fallback mais específico para Fastify
80
80
  if (res.code && res.send && res.type && res.setCookie) {
81
- msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detectado: Fastify (fallback)`);
81
+ msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Framework detected: Fastify (fallback)`);
82
82
  this.adapter = new fastify_1.FastifyAdapter();
83
83
  return this.adapter;
84
84
  }
85
85
  // Default para HightJS Native se não conseguir detectar
86
- msg.end(` ${console_1.Colors.FgYellow}● ${console_1.Colors.Reset}Não foi possível detectar o framework. Usando HightJS Native como padrão.`);
86
+ msg.end(` ${console_1.Colors.FgYellow}● ${console_1.Colors.Reset}Unable to detect framework. Using HightJS Native as default.`);
87
87
  this.adapter = new native_1.NativeAdapter();
88
88
  return this.adapter;
89
89
  }
@@ -102,7 +102,7 @@ class FrameworkAdapterFactory {
102
102
  this.adapter = new native_1.NativeAdapter();
103
103
  break;
104
104
  default:
105
- throw new Error(`Framework não suportado: ${framework}`);
105
+ throw new Error(`Unsupported framework: ${framework}`);
106
106
  }
107
107
  }
108
108
  /**
@@ -59,7 +59,7 @@ class NativeAdapter {
59
59
  }
60
60
  catch (e) {
61
61
  // Prevenção de crash: Ignora cookies com valores malformados (e.g., URI inválida).
62
- console.error(`Aviso: Cookie malformado com nome "${name}" foi ignorado.`);
62
+ console.error(`Warning: Malformed cookie with name "${name}" was ignored.`);
63
63
  }
64
64
  }
65
65
  });
@@ -88,7 +88,7 @@ class NativeResponseWrapper {
88
88
  const sanitizedName = sanitizeHeaderValue(name);
89
89
  const sanitizedValue = sanitizeHeaderValue(value);
90
90
  if (name !== sanitizedName || String(value) !== sanitizedValue) {
91
- console.warn(`Aviso: Tentativa potencial de HTTP Header Injection foi detectada e sanitizada. Header original: "${name}"`);
91
+ console.warn(`Warning: Potential HTTP Header Injection attempt detected and sanitized. Original header: "${name}"`);
92
92
  }
93
93
  this.headers[sanitizedName] = sanitizedValue;
94
94
  return this;
@@ -96,7 +96,7 @@ class NativeResponseWrapper {
96
96
  cookie(name, value, options) {
97
97
  // Medida de segurança: Valida o nome do cookie.
98
98
  if (!isValidCookieName(name)) {
99
- console.error(`Erro: Nome de cookie inválido "${name}". O cookie não será definido.`);
99
+ console.error(`Error: Invalid cookie name "${name}". The cookie will not be set.`);
100
100
  return this;
101
101
  }
102
102
  let cookieString = `${name}=${encodeURIComponent(value)}`;
@@ -26,7 +26,7 @@ async function getSession() {
26
26
  return data.session || null;
27
27
  }
28
28
  catch (error) {
29
- console.error('[hweb-auth] Erro ao buscar sessão:', error);
29
+ console.error('[hweb-auth] Error fetching session:', error);
30
30
  return null;
31
31
  }
32
32
  }
@@ -45,7 +45,7 @@ async function getCsrfToken() {
45
45
  return data.csrfToken || null;
46
46
  }
47
47
  catch (error) {
48
- console.error('[hweb-auth] Erro ao buscar CSRF token:', error);
48
+ console.error('[hweb-auth] Error fetching CSRF token:', error);
49
49
  return null;
50
50
  }
51
51
  }
@@ -64,7 +64,7 @@ async function getProviders() {
64
64
  return data.providers || [];
65
65
  }
66
66
  catch (error) {
67
- console.error('[hweb-auth] Erro ao buscar providers:', error);
67
+ console.error('[hweb-auth] Error searching for providers:', error);
68
68
  return null;
69
69
  }
70
70
  }
@@ -119,7 +119,7 @@ async function signIn(provider = 'credentials', options = {}) {
119
119
  }
120
120
  }
121
121
  catch (error) {
122
- console.error('[hweb-auth] Erro no signIn:', error);
122
+ console.error('[hweb-auth] Error on signIn:', error);
123
123
  return {
124
124
  error: 'Network error',
125
125
  status: 500,
@@ -141,6 +141,6 @@ async function signOut(options = {}) {
141
141
  }
142
142
  }
143
143
  catch (error) {
144
- console.error('[hweb-auth] Erro no signOut:', error);
144
+ console.error('[hweb-auth] Error on signOut:', error);
145
145
  }
146
146
  }
@@ -34,7 +34,7 @@ function ProtectedRoute({ children, fallback, redirectTo = '/auth/signin', requi
34
34
  const { isAuthenticated, isLoading } = (0, react_2.useAuth)();
35
35
  // Ainda carregando
36
36
  if (isLoading) {
37
- return fallback || (0, jsx_runtime_1.jsx)("div", { children: "Carregando..." });
37
+ return fallback || (0, jsx_runtime_1.jsx)("div", { children: "Loading..." });
38
38
  }
39
39
  // Requer auth mas não está autenticado
40
40
  if (requireAuth && !isAuthenticated) {
@@ -42,7 +42,7 @@ function ProtectedRoute({ children, fallback, redirectTo = '/auth/signin', requi
42
42
  window.location.href = redirectTo;
43
43
  return null;
44
44
  }
45
- return fallback || (0, jsx_runtime_1.jsx)("div", { children: "N\u00E3o autorizado" });
45
+ return fallback || (0, jsx_runtime_1.jsx)("div", { children: "Unauthorized" });
46
46
  }
47
47
  // Não requer auth mas está autenticado (ex: página de login)
48
48
  if (!requireAuth && isAuthenticated && redirectTo) {
package/dist/auth/core.js CHANGED
@@ -76,7 +76,7 @@ class HWebAuth {
76
76
  return sessionResult;
77
77
  }
78
78
  catch (error) {
79
- console.error(`[hweb-auth] Erro no signIn com provider ${providerId}:`, error);
79
+ console.error(`[hweb-auth] Error signing in with provider ${providerId}:`, error);
80
80
  return null;
81
81
  }
82
82
  }
@@ -93,7 +93,7 @@ class HWebAuth {
93
93
  await provider.handleSignOut();
94
94
  }
95
95
  catch (error) {
96
- console.error(`[hweb-auth] Erro no signOut do provider ${provider.id}:`, error);
96
+ console.error(`[hweb-auth] Signout error on provider ${provider.id}:`, error);
97
97
  }
98
98
  }
99
99
  }
@@ -50,7 +50,7 @@ function SessionProvider({ children, basePath = '/api/auth', refetchInterval = 0
50
50
  }
51
51
  }
52
52
  catch (error) {
53
- console.error('[hweb-auth] Erro ao buscar sessão:', error);
53
+ console.error('[hweb-auth] Error fetching session:', error);
54
54
  setSession(null);
55
55
  setStatus('unauthenticated');
56
56
  return null;
@@ -106,7 +106,7 @@ function SessionProvider({ children, basePath = '/api/auth', refetchInterval = 0
106
106
  }
107
107
  }
108
108
  catch (error) {
109
- console.error('[hweb-auth] Erro no signIn:', error);
109
+ console.error('[hweb-auth] Error on signIn:', error);
110
110
  return {
111
111
  error: 'Network error',
112
112
  status: 500,
@@ -133,7 +133,7 @@ function SessionProvider({ children, basePath = '/api/auth', refetchInterval = 0
133
133
  }
134
134
  }
135
135
  catch (error) {
136
- console.error('[hweb-auth] Erro no signOut:', error);
136
+ console.error('[hweb-auth] Error on signOut:', error);
137
137
  }
138
138
  }, [basePath]);
139
139
  // Update session
@@ -182,7 +182,7 @@ function SessionProvider({ children, basePath = '/api/auth', refetchInterval = 0
182
182
  function useSession() {
183
183
  const context = (0, react_1.useContext)(SessionContext);
184
184
  if (context === undefined) {
185
- throw new Error('useSession deve ser usado dentro de um SessionProvider');
185
+ throw new Error('useSession must be used inside a SessionProvider');
186
186
  }
187
187
  return context;
188
188
  }
@@ -140,7 +140,7 @@ async function handleSignIn(req, auth) {
140
140
  });
141
141
  }
142
142
  catch (error) {
143
- console.error('[hweb-auth] Erro no handleSignIn:', error);
143
+ console.error('[hweb-auth] Error on handleSignIn:', error);
144
144
  return http_1.HightJSResponse.json({ error: 'Authentication failed' }, { status: 500 });
145
145
  }
146
146
  }
@@ -8,7 +8,7 @@
8
8
  * you may not use this file except in compliance with the License.
9
9
  * You may obtain a copy of the License at
10
10
  *
11
- * http://www.apache.org/licenses/LICENSE-2.0
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
12
  *
13
13
  * Unless required by applicable law or agreed to in writing, software
14
14
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,7 +21,7 @@ require('ts-node').register();
21
21
  const { program } = require('commander');
22
22
  program
23
23
  .version('1.0.0')
24
- .description('CLI para gerenciar a aplicação.');
24
+ .description('CLI to manage the application.');
25
25
  // --- Comando DEV ---
26
26
  const fs = require('fs');
27
27
  const path = require('path');
@@ -59,7 +59,7 @@ function initializeApp(options, isDev) {
59
59
  appOptions.ssl.redirectPort = options.httpRedirectPort || 80;
60
60
  }
61
61
  else {
62
- Console.logWithout(Levels.ERROR, null, `Certifique-se que './certs/key.pem' e './certs/cert.pem' existem.`, `Flag --ssl foi usada, mas os arquivos não foram encontrados.`);
62
+ Console.logWithout(Levels.ERROR, null, `Ensure that './certs/key.pem' and './certs/cert.pem' exist.`, `--ssl flag was used, but the files were not found.`);
63
63
  process.exit(1); // Encerra o processo com erro
64
64
  }
65
65
  }
@@ -71,64 +71,64 @@ function initializeApp(options, isDev) {
71
71
  // --- Comando DEV ---
72
72
  program
73
73
  .command('dev')
74
- .description('Inicia a aplicação em modo de desenvolvimento.')
75
- .option('-p, --port <number>', 'Especifica a porta para rodar', '3000')
76
- .option('-H, --hostname <string>', 'Especifica o hostname para rodar', '0.0.0.0')
77
- .option('--ssl', 'Ativa o modo HTTPS/SSL (requer ./ssl/key.pem e ./ssl/cert.pem)')
78
- .option('--http-redirect-port <number>', 'Porta para redirecionamento HTTP->HTTPS', '80')
74
+ .description('Starts the application in development mode.')
75
+ .option('-p, --port <number>', 'Specifies the port to run on', '3000')
76
+ .option('-H, --hostname <string>', 'Specifies the hostname to run on', '0.0.0.0')
77
+ .option('--ssl', 'Activates HTTPS/SSL mode (requires ./ssl/key.pem and ./ssl/cert.pem)')
78
+ .option('--http-redirect-port <number>', 'Port for HTTP->HTTPS redirection', '80')
79
79
  .action((options) => {
80
80
  initializeApp(options, true); // Chama a função com dev: true
81
81
  });
82
82
  // --- Comando START (Produção) ---
83
83
  program
84
84
  .command('start')
85
- .description('Inicia a aplicação em modo produção.')
86
- .option('-p, --port <number>', 'Especifica a porta para rodar', '3000')
87
- .option('-H, --hostname <string>', 'Especifica o hostname para rodar', '0.0.0.0')
88
- .option('--ssl', 'Ativa o modo HTTPS/SSL (requer ./ssl/key.pem e ./ssl/cert.pem)')
89
- .option('--http-redirect-port <number>', 'Porta para redirecionamento HTTP->HTTPS', '80')
85
+ .description('Starts the application in production mode.')
86
+ .option('-p, --port <number>', 'Specifies the port to run on', '3000')
87
+ .option('-H, --hostname <string>', 'Specifies the hostname to run on', '0.0.0.0')
88
+ .option('--ssl', 'Activates HTTPS/SSL mode (requires ./ssl/key.pem and ./ssl/cert.pem)')
89
+ .option('--http-redirect-port <number>', 'Port for HTTP->HTTPS redirection', '80')
90
90
  .action((options) => {
91
91
  initializeApp(options, false); // Chama a função com dev: false
92
92
  });
93
93
  // --- Comando EXPORT ---
94
94
  program
95
95
  .command('export')
96
- .description('Exporta a aplicação como HTML estático na pasta "exported".')
97
- .option('-o, --output <path>', 'Especifica o diretório de saída', 'exported')
96
+ .description('Exports the application as static HTML to the "exported" folder.')
97
+ .option('-o, --output <path>', 'Specifies the output directory', 'exported')
98
98
  .action(async (options) => {
99
99
  const projectDir = process.cwd();
100
100
  const exportDir = path.join(projectDir, options.output);
101
- console.log('🚀 Iniciando exportação...\n');
101
+ console.log('🚀 Starting export...\n');
102
102
  try {
103
103
  // 1. Cria a pasta exported (limpa se já existir)
104
104
  if (fs.existsSync(exportDir)) {
105
- console.log('🗑️ Limpando pasta de exportação existente...');
105
+ console.log('🗑️ Cleaning existing export folder...');
106
106
  fs.rmSync(exportDir, { recursive: true, force: true });
107
107
  }
108
108
  fs.mkdirSync(exportDir, { recursive: true });
109
- console.log('✅ Pasta de exportação criada\n');
109
+ console.log('✅ Export folder created\n');
110
110
  // 2. Inicializa e prepara o build
111
- console.log('🔨 Buildando aplicação...');
111
+ console.log('🔨 Building application...');
112
112
  const teste = require("../helpers");
113
113
  const app = teste.default({ dev: false, port: 3000, hostname: '0.0.0.0', framework: 'native' });
114
114
  await app.prepare();
115
- console.log('✅ Build concluído\n');
115
+ console.log('✅ Build complete\n');
116
116
  // 3. Copia a pasta hweb-dist para exported
117
117
  const distDir = path.join(projectDir, 'hweb-dist');
118
118
  if (fs.existsSync(distDir)) {
119
- console.log('📦 Copiando arquivos JavaScript...');
119
+ console.log('📦 Copying JavaScript files...');
120
120
  const exportDistDir = path.join(exportDir, 'hweb-dist');
121
121
  fs.mkdirSync(exportDistDir, { recursive: true });
122
122
  const files = fs.readdirSync(distDir);
123
123
  files.forEach(file => {
124
124
  fs.copyFileSync(path.join(distDir, file), path.join(exportDistDir, file));
125
125
  });
126
- console.log('✅ Arquivos JavaScript copiados\n');
126
+ console.log('✅ JavaScript files copied\n');
127
127
  }
128
128
  // 4. Copia a pasta public se existir
129
129
  const publicDir = path.join(projectDir, 'public');
130
130
  if (fs.existsSync(publicDir)) {
131
- console.log('📁 Copiando arquivos públicos...');
131
+ console.log('📁 Copying public files...');
132
132
  const exportPublicDir = path.join(exportDir, 'public');
133
133
  function copyRecursive(src, dest) {
134
134
  if (fs.statSync(src).isDirectory()) {
@@ -142,10 +142,10 @@ program
142
142
  }
143
143
  }
144
144
  copyRecursive(publicDir, exportPublicDir);
145
- console.log('✅ Arquivos públicos copiados\n');
145
+ console.log('✅ Public files copied\n');
146
146
  }
147
147
  // 5. Gera o index.html
148
- console.log('📝 Gerando index.html...');
148
+ console.log('📝 Generating index.html...');
149
149
  const { render } = require('../renderer');
150
150
  const { loadRoutes, loadLayout, loadNotFound } = require('../router');
151
151
  // Carrega as rotas para gerar o HTML
@@ -172,314 +172,15 @@ program
172
172
  });
173
173
  const indexPath = path.join(exportDir, 'index.html');
174
174
  fs.writeFileSync(indexPath, html, 'utf8');
175
- console.log('✅ index.html gerado\n');
175
+ console.log('✅ index.html generated\n');
176
176
  }
177
- console.log('🎉 Exportação concluída com sucesso!');
178
- console.log(`📂 Arquivos exportados em: ${exportDir}\n`);
177
+ console.log('🎉 Export completed successfully!');
178
+ console.log(`📂 Files exported to: ${exportDir}\n`);
179
179
  }
180
180
  catch (error) {
181
- console.error('❌ Erro durante a exportação:', error.message);
181
+ console.error('❌ Error during export:', error.message);
182
182
  process.exit(1);
183
183
  }
184
184
  });
185
- // --- Comando MIGRATE FROM NEXTJS ---
186
- program
187
- .command('migrate-from-nextjs')
188
- .description('Migra um projeto Next.js para HightJS.')
189
- .option('-s, --source <path>', 'Caminho do projeto Next.js', process.cwd())
190
- .option('-o, --output <path>', 'Diretório de saída para o projeto HightJS', './hightjs-project')
191
- .action(async (options) => {
192
- const sourcePath = path.resolve(options.source);
193
- const outputPath = path.resolve(options.output);
194
- console.log('🚀 Iniciando migração de Next.js para HightJS...\n');
195
- console.log(`📂 Origem: ${sourcePath}`);
196
- console.log(`📂 Destino: ${outputPath}\n`);
197
- try {
198
- // Verifica se o diretório de origem existe
199
- if (!fs.existsSync(sourcePath)) {
200
- throw new Error(`Diretório de origem não encontrado: ${sourcePath}`);
201
- }
202
- // Verifica se é um projeto Next.js
203
- const nextConfigPath = path.join(sourcePath, 'next.config.js');
204
- const nextConfigMjsPath = path.join(sourcePath, 'next.config.mjs');
205
- const packageJsonPath = path.join(sourcePath, 'package.json');
206
- if (!fs.existsSync(nextConfigPath) && !fs.existsSync(nextConfigMjsPath) && !fs.existsSync(packageJsonPath)) {
207
- throw new Error('Não foi encontrado um projeto Next.js válido no diretório especificado.');
208
- }
209
- // Cria o diretório de saída
210
- if (fs.existsSync(outputPath)) {
211
- console.log('⚠️ Diretório de destino já existe. Limpando...');
212
- fs.rmSync(outputPath, { recursive: true, force: true });
213
- }
214
- fs.mkdirSync(outputPath, { recursive: true });
215
- // 1. Cria estrutura básica do HightJS
216
- console.log('📁 Criando estrutura de diretórios...');
217
- const srcDir = path.join(outputPath, 'src');
218
- const webDir = path.join(srcDir, 'web');
219
- const routesDir = path.join(webDir, 'routes');
220
- const publicDir = path.join(outputPath, 'public');
221
- fs.mkdirSync(srcDir, { recursive: true });
222
- fs.mkdirSync(webDir, { recursive: true });
223
- fs.mkdirSync(routesDir, { recursive: true });
224
- fs.mkdirSync(publicDir, { recursive: true });
225
- // 2. Copia arquivos públicos
226
- console.log('📦 Copiando arquivos públicos...');
227
- const nextPublicDir = path.join(sourcePath, 'public');
228
- if (fs.existsSync(nextPublicDir)) {
229
- copyDirectory(nextPublicDir, publicDir);
230
- }
231
- // 3. Migra páginas do Next.js para rotas do HightJS
232
- console.log('🔄 Migrando páginas para rotas...');
233
- const nextPagesDir = path.join(sourcePath, 'pages');
234
- const nextAppDir = path.join(sourcePath, 'app');
235
- const nextSrcPagesDir = path.join(sourcePath, 'src', 'pages');
236
- const nextSrcAppDir = path.join(sourcePath, 'src', 'app');
237
- let pagesDir = null;
238
- let isAppRouter = false;
239
- if (fs.existsSync(nextAppDir)) {
240
- pagesDir = nextAppDir;
241
- isAppRouter = true;
242
- console.log('✅ Detectado Next.js App Router');
243
- }
244
- else if (fs.existsSync(nextSrcAppDir)) {
245
- pagesDir = nextSrcAppDir;
246
- isAppRouter = true;
247
- console.log('✅ Detectado Next.js App Router (em src/)');
248
- }
249
- else if (fs.existsSync(nextPagesDir)) {
250
- pagesDir = nextPagesDir;
251
- console.log('✅ Detectado Next.js Pages Router');
252
- }
253
- else if (fs.existsSync(nextSrcPagesDir)) {
254
- pagesDir = nextSrcPagesDir;
255
- console.log('✅ Detectado Next.js Pages Router (em src/)');
256
- }
257
- if (pagesDir) {
258
- if (isAppRouter) {
259
- migrateAppRouter(pagesDir, routesDir);
260
- }
261
- else {
262
- migratePagesRouter(pagesDir, routesDir);
263
- }
264
- }
265
- // 5. Cria package.json
266
- console.log('📄 Criando package.json...');
267
- let originalPackageJson = {};
268
- if (fs.existsSync(packageJsonPath)) {
269
- originalPackageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
270
- }
271
- const newPackageJson = {
272
- name: originalPackageJson.name || 'hightjs-app',
273
- version: '1.0.0',
274
- description: originalPackageJson.description || 'HightJS application migrated from Next.js',
275
- scripts: {
276
- dev: 'hight dev',
277
- start: 'hight start',
278
- build: 'hight export',
279
- ...originalPackageJson.scripts
280
- },
281
- dependencies: {
282
- hightjs: 'latest',
283
- react: originalPackageJson.dependencies?.react || '^18.2.0',
284
- 'react-dom': originalPackageJson.dependencies?.['react-dom'] || '^18.2.0',
285
- ...filterDependencies(originalPackageJson.dependencies)
286
- },
287
- devDependencies: {
288
- '@types/node': '^20.11.24',
289
- '@types/react': '^18.2.0',
290
- '@types/react-dom': '^18.2.0',
291
- typescript: '^5.3.3',
292
- ...filterDependencies(originalPackageJson.devDependencies)
293
- }
294
- };
295
- fs.writeFileSync(path.join(outputPath, 'package.json'), JSON.stringify(newPackageJson, null, 2), 'utf8');
296
- // 6. Cria tsconfig.json
297
- console.log('⚙️ Criando tsconfig.json...');
298
- const tsConfig = {
299
- compilerOptions: {
300
- target: 'ES2020',
301
- lib: ['ES2020', 'DOM', 'DOM.Iterable'],
302
- jsx: 'react-jsx',
303
- module: 'commonjs',
304
- moduleResolution: 'node',
305
- esModuleInterop: true,
306
- strict: true,
307
- skipLibCheck: true,
308
- forceConsistentCasingInFileNames: true,
309
- resolveJsonModule: true,
310
- allowSyntheticDefaultImports: true
311
- },
312
- include: ['src/**/*'],
313
- exclude: ['node_modules']
314
- };
315
- fs.writeFileSync(path.join(outputPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2), 'utf8');
316
- // 7. Cria README
317
- console.log('📖 Criando README...');
318
- const readmeContent = `# ${originalPackageJson.name || 'HightJS App'}
319
-
320
- Este projeto foi migrado de Next.js para HightJS.
321
-
322
- ## Comandos Disponíveis
323
-
324
- - \`npm run dev\` - Inicia o servidor de desenvolvimento
325
- - \`npm run start\` - Inicia o servidor em modo produção
326
- - \`npm run build\` - Exporta a aplicação como HTML estático
327
-
328
- ## Próximos Passos
329
-
330
- 1. Instale as dependências: \`npm install\`
331
- 2. Revise os arquivos migrados em \`src/web/routes/\`
332
- 3. Ajuste manualmente qualquer código que precise de adaptação
333
- 4. Execute \`npm run dev\` para testar
334
-
335
- ## Notas de Migração
336
-
337
- - Rotas dinâmicas do Next.js foram convertidas para o formato HightJS
338
- - API Routes precisam ser migradas manualmente para HightJS API routes
339
- - Server Components foram convertidos para componentes React padrão
340
- - Revise imports e configurações específicas do Next.js
341
-
342
- Para mais informações sobre HightJS, visite a documentação.
343
- `;
344
- fs.writeFileSync(path.join(outputPath, 'README.md'), readmeContent, 'utf8');
345
- console.log('\n✅ Migração concluída com sucesso!');
346
- console.log(`\n📂 Projeto criado em: ${outputPath}`);
347
- console.log('\n📋 Próximos passos:');
348
- console.log(` 1. cd ${path.relative(process.cwd(), outputPath)}`);
349
- console.log(' 2. npm install');
350
- console.log(' 3. npm run dev');
351
- console.log('\n⚠️ IMPORTANTE: Revise os arquivos migrados e ajuste conforme necessário.\n');
352
- }
353
- catch (error) {
354
- console.error('❌ Erro durante a migração:', error.message);
355
- console.error(error.stack);
356
- process.exit(1);
357
- }
358
- });
359
- // Funções auxiliares para migração
360
- function copyDirectory(src, dest) {
361
- if (!fs.existsSync(src))
362
- return;
363
- fs.mkdirSync(dest, { recursive: true });
364
- const entries = fs.readdirSync(src, { withFileTypes: true });
365
- for (const entry of entries) {
366
- const srcPath = path.join(src, entry.name);
367
- const destPath = path.join(dest, entry.name);
368
- if (entry.isDirectory()) {
369
- copyDirectory(srcPath, destPath);
370
- }
371
- else {
372
- fs.copyFileSync(srcPath, destPath);
373
- }
374
- }
375
- }
376
- function migratePagesRouter(pagesDir, routesDir) {
377
- function processDirectory(dir, baseRoute = '') {
378
- const entries = fs.readdirSync(dir, { withFileTypes: true });
379
- for (const entry of entries) {
380
- const fullPath = path.join(dir, entry.name);
381
- if (entry.isDirectory()) {
382
- // Processa subdiretórios (rotas aninhadas)
383
- const newBaseRoute = path.join(baseRoute, entry.name);
384
- processDirectory(fullPath, newBaseRoute);
385
- }
386
- else if (entry.name.match(/\.(tsx?|jsx?)$/)) {
387
- // Ignora arquivos especiais do Next.js
388
- if (['_app', '_document', '_error', 'api'].some(special => entry.name.startsWith(special))) {
389
- continue;
390
- }
391
- // Converte nome do arquivo para rota HightJS
392
- let fileName = entry.name.replace(/\.(tsx?|jsx?)$/, '');
393
- let routePath = baseRoute;
394
- if (fileName === 'index') {
395
- // index.tsx -> route vazia ou baseRoute
396
- routePath = baseRoute || '/';
397
- }
398
- else {
399
- // [id].tsx -> $id.tsx
400
- fileName = fileName.replace(/\[([^\]]+)\]/g, '$$$1');
401
- routePath = path.join(baseRoute, fileName);
402
- }
403
- // Lê o conteúdo original
404
- const originalContent = fs.readFileSync(fullPath, 'utf8');
405
- // Transforma o conteúdo
406
- const transformedContent = transformNextJsPage(originalContent);
407
- // Cria estrutura de diretórios se necessário
408
- const targetDir = path.join(routesDir, baseRoute);
409
- fs.mkdirSync(targetDir, { recursive: true });
410
- // Salva o arquivo transformado
411
- const targetFileName = fileName === 'index' ? 'route.tsx' : `${fileName}.route.tsx`;
412
- const targetPath = path.join(targetDir, targetFileName);
413
- fs.writeFileSync(targetPath, transformedContent, 'utf8');
414
- console.log(` ✓ ${path.relative(pagesDir, fullPath)} -> ${path.relative(routesDir, targetPath)}`);
415
- }
416
- }
417
- }
418
- processDirectory(pagesDir);
419
- }
420
- function migrateAppRouter(appDir, routesDir) {
421
- function processDirectory(dir, baseRoute = '') {
422
- const entries = fs.readdirSync(dir, { withFileTypes: true });
423
- let hasPage = false;
424
- for (const entry of entries) {
425
- const fullPath = path.join(dir, entry.name);
426
- if (entry.isDirectory()) {
427
- // Suporta rotas dinâmicas como [id]
428
- let dirName = entry.name;
429
- if (dirName.startsWith('[') && dirName.endsWith(']')) {
430
- dirName = '$' + dirName.slice(1, -1);
431
- }
432
- const newBaseRoute = path.join(baseRoute, dirName);
433
- processDirectory(fullPath, newBaseRoute);
434
- }
435
- else if (entry.name === 'page.tsx' || entry.name === 'page.jsx' || entry.name === 'page.ts' || entry.name === 'page.js') {
436
- hasPage = true;
437
- // Lê o conteúdo original
438
- const originalContent = fs.readFileSync(fullPath, 'utf8');
439
- // Transforma o conteúdo
440
- const transformedContent = transformNextJsPage(originalContent);
441
- // Cria estrutura de diretórios
442
- const targetDir = path.join(routesDir, baseRoute);
443
- fs.mkdirSync(targetDir, { recursive: true });
444
- // Salva como route.tsx
445
- const targetPath = path.join(targetDir, 'route.tsx');
446
- fs.writeFileSync(targetPath, transformedContent, 'utf8');
447
- console.log(` ✓ ${path.relative(appDir, fullPath)} -> ${path.relative(routesDir, targetPath)}`);
448
- }
449
- }
450
- }
451
- processDirectory(appDir);
452
- }
453
- function transformNextJsPage(content) {
454
- // Remove 'use client' e 'use server'
455
- content = content.replace(/['"]use (client|server)['"]\s*;\s*/g, '');
456
- // Remove imports específicos do Next.js
457
- content = content.replace(/import\s+.*?from\s+['"]next\/.*?['"];?\s*/g, '');
458
- // Substitui Link do Next.js por Link do HightJS
459
- if (content.includes('Link')) {
460
- content = `import { Link } from 'hightjs/client';\n` + content;
461
- }
462
- // Substitui useRouter do Next.js
463
- content = content.replace(/import\s*\{\s*useRouter\s*\}\s*from\s*['"]next\/router['"]/g, "import { useRouter } from 'hightjs/client'");
464
- // Substitui Image do Next.js por img normal (com comentário para revisão)
465
- content = content.replace(/<Image\s+/g, '<img /* TODO: Migrado de Next.js Image - revisar otimizações */ ');
466
- // Remove getServerSideProps, getStaticProps, getStaticPaths
467
- content = content.replace(/export\s+(async\s+)?function\s+get(ServerSideProps|StaticProps|StaticPaths)\s*\([^)]*\)\s*\{[\s\S]*?\n\}/g, '');
468
- // Adiciona comentário sobre metadata se houver
469
- if (content.includes('export const metadata')) {
470
- content = '// TODO: Migrar metadata do Next.js para HightJS\n' + content;
471
- }
472
- return content.trim();
473
- }
474
- function filterDependencies(deps) {
475
- if (!deps)
476
- return {};
477
- const filtered = { ...deps };
478
- // Remove dependências específicas do Next.js
479
- delete filtered.next;
480
- delete filtered['@next/font'];
481
- delete filtered['next-auth'];
482
- return filtered;
483
- }
484
185
  // Faz o "parse" dos argumentos passados na linha de comando
485
186
  program.parse(process.argv);