hightjs 0.1.1

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 (131) hide show
  1. package/.idea/HightJS.iml +9 -0
  2. package/.idea/copilot.data.migration.agent.xml +6 -0
  3. package/.idea/copilot.data.migration.ask.xml +6 -0
  4. package/.idea/copilot.data.migration.ask2agent.xml +6 -0
  5. package/.idea/copilot.data.migration.edit.xml +6 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +13 -0
  7. package/.idea/libraries/test_package.xml +9 -0
  8. package/.idea/libraries/ts_commonjs_default_export.xml +9 -0
  9. package/.idea/misc.xml +7 -0
  10. package/.idea/modules.xml +8 -0
  11. package/.idea/vcs.xml +6 -0
  12. package/LICENSE +13 -0
  13. package/README.md +508 -0
  14. package/dist/adapters/express.d.ts +7 -0
  15. package/dist/adapters/express.js +63 -0
  16. package/dist/adapters/factory.d.ts +23 -0
  17. package/dist/adapters/factory.js +122 -0
  18. package/dist/adapters/fastify.d.ts +25 -0
  19. package/dist/adapters/fastify.js +61 -0
  20. package/dist/adapters/native.d.ts +8 -0
  21. package/dist/adapters/native.js +203 -0
  22. package/dist/adapters/starters/express.d.ts +0 -0
  23. package/dist/adapters/starters/express.js +1 -0
  24. package/dist/adapters/starters/factory.d.ts +0 -0
  25. package/dist/adapters/starters/factory.js +1 -0
  26. package/dist/adapters/starters/fastify.d.ts +0 -0
  27. package/dist/adapters/starters/fastify.js +1 -0
  28. package/dist/adapters/starters/index.d.ts +0 -0
  29. package/dist/adapters/starters/index.js +1 -0
  30. package/dist/adapters/starters/native.d.ts +0 -0
  31. package/dist/adapters/starters/native.js +1 -0
  32. package/dist/api/console.d.ts +92 -0
  33. package/dist/api/console.js +276 -0
  34. package/dist/api/http.d.ts +180 -0
  35. package/dist/api/http.js +467 -0
  36. package/dist/auth/client.d.ts +14 -0
  37. package/dist/auth/client.js +68 -0
  38. package/dist/auth/components.d.ts +29 -0
  39. package/dist/auth/components.js +84 -0
  40. package/dist/auth/core.d.ts +38 -0
  41. package/dist/auth/core.js +124 -0
  42. package/dist/auth/index.d.ts +7 -0
  43. package/dist/auth/index.js +27 -0
  44. package/dist/auth/jwt.d.ts +41 -0
  45. package/dist/auth/jwt.js +169 -0
  46. package/dist/auth/providers.d.ts +5 -0
  47. package/dist/auth/providers.js +14 -0
  48. package/dist/auth/react/index.d.ts +6 -0
  49. package/dist/auth/react/index.js +32 -0
  50. package/dist/auth/react.d.ts +22 -0
  51. package/dist/auth/react.js +175 -0
  52. package/dist/auth/routes.d.ts +16 -0
  53. package/dist/auth/routes.js +104 -0
  54. package/dist/auth/types.d.ts +62 -0
  55. package/dist/auth/types.js +2 -0
  56. package/dist/bin/hightjs.d.ts +2 -0
  57. package/dist/bin/hightjs.js +35 -0
  58. package/dist/builder.d.ts +32 -0
  59. package/dist/builder.js +341 -0
  60. package/dist/client/DefaultNotFound.d.ts +1 -0
  61. package/dist/client/DefaultNotFound.js +53 -0
  62. package/dist/client/ErrorBoundary.d.ts +16 -0
  63. package/dist/client/ErrorBoundary.js +181 -0
  64. package/dist/client/clientRouter.d.ts +58 -0
  65. package/dist/client/clientRouter.js +116 -0
  66. package/dist/client/entry.client.d.ts +1 -0
  67. package/dist/client/entry.client.js +271 -0
  68. package/dist/client/routerContext.d.ts +26 -0
  69. package/dist/client/routerContext.js +62 -0
  70. package/dist/client.d.ts +3 -0
  71. package/dist/client.js +8 -0
  72. package/dist/components/Link.d.ts +7 -0
  73. package/dist/components/Link.js +13 -0
  74. package/dist/eslint/index.d.ts +32 -0
  75. package/dist/eslint/index.js +15 -0
  76. package/dist/eslint/use-client-rule.d.ts +19 -0
  77. package/dist/eslint/use-client-rule.js +99 -0
  78. package/dist/eslintSetup.d.ts +0 -0
  79. package/dist/eslintSetup.js +1 -0
  80. package/dist/example/src/web/routes/index.d.ts +3 -0
  81. package/dist/example/src/web/routes/index.js +15 -0
  82. package/dist/helpers.d.ts +18 -0
  83. package/dist/helpers.js +318 -0
  84. package/dist/hotReload.d.ts +23 -0
  85. package/dist/hotReload.js +292 -0
  86. package/dist/index.d.ts +17 -0
  87. package/dist/index.js +480 -0
  88. package/dist/renderer.d.ts +14 -0
  89. package/dist/renderer.js +106 -0
  90. package/dist/router.d.ts +78 -0
  91. package/dist/router.js +359 -0
  92. package/dist/types/framework.d.ts +37 -0
  93. package/dist/types/framework.js +2 -0
  94. package/dist/types.d.ts +43 -0
  95. package/dist/types.js +2 -0
  96. package/dist/typescript/use-client-plugin.d.ts +5 -0
  97. package/dist/typescript/use-client-plugin.js +113 -0
  98. package/dist/validation.d.ts +0 -0
  99. package/dist/validation.js +1 -0
  100. package/package.json +72 -0
  101. package/src/adapters/express.ts +70 -0
  102. package/src/adapters/factory.ts +96 -0
  103. package/src/adapters/fastify.ts +88 -0
  104. package/src/adapters/native.ts +223 -0
  105. package/src/api/console.ts +285 -0
  106. package/src/api/http.ts +515 -0
  107. package/src/auth/client.ts +74 -0
  108. package/src/auth/components.tsx +109 -0
  109. package/src/auth/core.ts +143 -0
  110. package/src/auth/index.ts +9 -0
  111. package/src/auth/jwt.ts +194 -0
  112. package/src/auth/providers.ts +13 -0
  113. package/src/auth/react/index.ts +9 -0
  114. package/src/auth/react.tsx +209 -0
  115. package/src/auth/routes.ts +133 -0
  116. package/src/auth/types.ts +73 -0
  117. package/src/bin/hightjs.js +40 -0
  118. package/src/builder.js +362 -0
  119. package/src/client/DefaultNotFound.tsx +68 -0
  120. package/src/client/clientRouter.ts +137 -0
  121. package/src/client/entry.client.tsx +302 -0
  122. package/src/client.ts +8 -0
  123. package/src/components/Link.tsx +22 -0
  124. package/src/helpers.ts +316 -0
  125. package/src/hotReload.ts +289 -0
  126. package/src/index.ts +514 -0
  127. package/src/renderer.tsx +122 -0
  128. package/src/router.ts +400 -0
  129. package/src/types/framework.ts +42 -0
  130. package/src/types.ts +54 -0
  131. package/tsconfig.json +17 -0
@@ -0,0 +1,78 @@
1
+ import { RouteConfig, BackendRouteConfig } from './types';
2
+ /**
3
+ * Limpa todo o cache de rotas carregadas
4
+ */
5
+ export declare function clearAllRouteCache(): void;
6
+ /**
7
+ * Limpa o cache de um arquivo específico e recarrega as rotas se necessário
8
+ * @param changedFilePath Caminho do arquivo que foi alterado
9
+ */
10
+ export declare function clearFileCache(changedFilePath: string): void;
11
+ /**
12
+ * Carrega o layout.tsx se existir no diretório web
13
+ * @param webDir O diretório web onde procurar o layout
14
+ * @returns O layout carregado ou null se não existir
15
+ */
16
+ export declare function loadLayout(webDir: string): {
17
+ componentPath: string;
18
+ metadata?: any;
19
+ } | null;
20
+ /**
21
+ * Retorna o layout atual se carregado
22
+ */
23
+ export declare function getLayout(): {
24
+ componentPath: string;
25
+ metadata?: any;
26
+ } | null;
27
+ /**
28
+ * Carrega dinamicamente todas as rotas de frontend do diretório do usuário.
29
+ * @param routesDir O diretório onde as rotas de página estão localizadas.
30
+ * @returns A lista de rotas de página que foram carregadas.
31
+ */
32
+ export declare function loadRoutes(routesDir: string): (RouteConfig & {
33
+ componentPath: string;
34
+ })[];
35
+ /**
36
+ * Encontra a rota de página correspondente para uma URL.
37
+ * @param pathname O caminho da URL (ex: "/users/123").
38
+ * @returns Um objeto com a rota e os parâmetros, ou null se não encontrar.
39
+ */
40
+ export declare function findMatchingRoute(pathname: string): {
41
+ route: RouteConfig & {
42
+ componentPath: string;
43
+ };
44
+ params: {
45
+ [key: string]: string;
46
+ };
47
+ } | null;
48
+ /**
49
+ * Carrega dinamicamente todas as rotas de API do diretório de backend.
50
+ * @param backendRoutesDir O diretório onde as rotas de API estão localizadas.
51
+ */
52
+ export declare function loadBackendRoutes(backendRoutesDir: string): void;
53
+ /**
54
+ * Encontra a rota de API correspondente para uma URL e método HTTP.
55
+ * @param pathname O caminho da URL (ex: "/api/users/123").
56
+ * @param method O método HTTP da requisição (GET, POST, etc.).
57
+ * @returns Um objeto com a rota e os parâmetros, ou null se não encontrar.
58
+ */
59
+ export declare function findMatchingBackendRoute(pathname: string, method: string): {
60
+ route: BackendRouteConfig;
61
+ params: {
62
+ [key: string]: string;
63
+ };
64
+ } | null;
65
+ /**
66
+ * Carrega o notFound.tsx se existir no diretório web
67
+ * @param webDir O diretório web onde procurar o notFound
68
+ * @returns O notFound carregado ou null se não existir
69
+ */
70
+ export declare function loadNotFound(webDir: string): {
71
+ componentPath: string;
72
+ } | null;
73
+ /**
74
+ * Retorna o componente 404 atual se carregado
75
+ */
76
+ export declare function getNotFound(): {
77
+ componentPath: string;
78
+ } | null;
package/dist/router.js ADDED
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.clearAllRouteCache = clearAllRouteCache;
7
+ exports.clearFileCache = clearFileCache;
8
+ exports.loadLayout = loadLayout;
9
+ exports.getLayout = getLayout;
10
+ exports.loadRoutes = loadRoutes;
11
+ exports.findMatchingRoute = findMatchingRoute;
12
+ exports.loadBackendRoutes = loadBackendRoutes;
13
+ exports.findMatchingBackendRoute = findMatchingBackendRoute;
14
+ exports.loadNotFound = loadNotFound;
15
+ exports.getNotFound = getNotFound;
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const console_1 = __importDefault(require("./api/console"));
19
+ // --- Roteamento do Frontend ---
20
+ // Guarda todas as rotas de PÁGINA (React) encontradas
21
+ // A rota agora também armazena o caminho do arquivo para ser usado como um ID único no cliente
22
+ let allRoutes = [];
23
+ // Guarda o layout se existir
24
+ let layoutComponent = null;
25
+ // Guarda o componente 404 personalizado se existir
26
+ let notFoundComponent = null;
27
+ // Cache de arquivos carregados para limpeza
28
+ let loadedRouteFiles = new Set();
29
+ let loadedLayoutFiles = new Set();
30
+ let loadedNotFoundFiles = new Set();
31
+ /**
32
+ * Limpa o cache do require para um arquivo específico
33
+ * @param filePath Caminho do arquivo para limpar
34
+ */
35
+ function clearRequireCache(filePath) {
36
+ try {
37
+ const resolvedPath = require.resolve(filePath);
38
+ delete require.cache[resolvedPath];
39
+ // Também limpa arquivos temporários relacionados
40
+ const tempFile = filePath.replace(/\.(tsx|ts)$/, '.temp.$1');
41
+ try {
42
+ const tempResolvedPath = require.resolve(tempFile);
43
+ delete require.cache[tempResolvedPath];
44
+ }
45
+ catch {
46
+ // Arquivo temporário pode não existir
47
+ }
48
+ }
49
+ catch (error) {
50
+ // Arquivo pode não estar no cache
51
+ }
52
+ }
53
+ /**
54
+ * Limpa todo o cache de rotas carregadas
55
+ */
56
+ function clearAllRouteCache() {
57
+ // Limpa cache das rotas
58
+ loadedRouteFiles.forEach(filePath => {
59
+ clearRequireCache(filePath);
60
+ });
61
+ loadedRouteFiles.clear();
62
+ // Limpa cache do layout
63
+ loadedLayoutFiles.forEach(filePath => {
64
+ clearRequireCache(filePath);
65
+ });
66
+ loadedLayoutFiles.clear();
67
+ // Limpa cache do notFound
68
+ loadedNotFoundFiles.forEach(filePath => {
69
+ clearRequireCache(filePath);
70
+ });
71
+ loadedNotFoundFiles.clear();
72
+ }
73
+ /**
74
+ * Limpa o cache de um arquivo específico e recarrega as rotas se necessário
75
+ * @param changedFilePath Caminho do arquivo que foi alterado
76
+ */
77
+ function clearFileCache(changedFilePath) {
78
+ const absolutePath = path_1.default.isAbsolute(changedFilePath) ? changedFilePath : path_1.default.resolve(changedFilePath);
79
+ // Limpa o cache do arquivo específico
80
+ clearRequireCache(absolutePath);
81
+ // Remove das listas de arquivos carregados
82
+ loadedRouteFiles.delete(absolutePath);
83
+ loadedLayoutFiles.delete(absolutePath);
84
+ loadedNotFoundFiles.delete(absolutePath);
85
+ }
86
+ /**
87
+ * Carrega o layout.tsx se existir no diretório web
88
+ * @param webDir O diretório web onde procurar o layout
89
+ * @returns O layout carregado ou null se não existir
90
+ */
91
+ function loadLayout(webDir) {
92
+ const layoutPath = path_1.default.join(webDir, 'layout.tsx');
93
+ const layoutPathJs = path_1.default.join(webDir, 'layout.ts');
94
+ const layoutFile = fs_1.default.existsSync(layoutPath) ? layoutPath :
95
+ fs_1.default.existsSync(layoutPathJs) ? layoutPathJs : null;
96
+ if (layoutFile) {
97
+ const componentPath = path_1.default.relative(process.cwd(), layoutFile).replace(/\\/g, '/');
98
+ const absolutePath = path_1.default.resolve(layoutFile);
99
+ try {
100
+ // Limpa o cache antes de recarregar
101
+ clearRequireCache(absolutePath);
102
+ // HACK: Cria uma versão temporária do layout SEM imports de CSS para carregar no servidor
103
+ const layoutContent = fs_1.default.readFileSync(layoutFile, 'utf8');
104
+ const tempContent = layoutContent
105
+ .replace(/import\s+['"][^'"]*\.css['"];?/g, '// CSS import removido para servidor')
106
+ .replace(/import\s+['"][^'"]*\.scss['"];?/g, '// SCSS import removido para servidor')
107
+ .replace(/import\s+['"][^'"]*\.sass['"];?/g, '// SASS import removido para servidor');
108
+ const tempFile = layoutFile.replace(/\.(tsx|ts)$/, '.temp.$1');
109
+ fs_1.default.writeFileSync(tempFile, tempContent);
110
+ // Carrega o arquivo temporário sem CSS
111
+ delete require.cache[require.resolve(tempFile)];
112
+ const layoutModule = require(tempFile);
113
+ // Remove o arquivo temporário
114
+ fs_1.default.unlinkSync(tempFile);
115
+ const metadata = layoutModule.metadata || null;
116
+ // Registra o arquivo como carregado
117
+ loadedLayoutFiles.add(absolutePath);
118
+ layoutComponent = { componentPath, metadata };
119
+ return layoutComponent;
120
+ }
121
+ catch (error) {
122
+ console_1.default.error(`Erro ao carregar layout ${layoutFile}:`, error);
123
+ layoutComponent = { componentPath };
124
+ return layoutComponent;
125
+ }
126
+ }
127
+ layoutComponent = null;
128
+ return null;
129
+ }
130
+ /**
131
+ * Retorna o layout atual se carregado
132
+ */
133
+ function getLayout() {
134
+ return layoutComponent;
135
+ }
136
+ /**
137
+ * Carrega dinamicamente todas as rotas de frontend do diretório do usuário.
138
+ * @param routesDir O diretório onde as rotas de página estão localizadas.
139
+ * @returns A lista de rotas de página que foram carregadas.
140
+ */
141
+ function loadRoutes(routesDir) {
142
+ if (!fs_1.default.existsSync(routesDir)) {
143
+ console_1.default.warn(`Diretório de rotas de frontend não encontrado em ${routesDir}. Nenhuma página será carregada.`);
144
+ allRoutes = [];
145
+ return allRoutes;
146
+ }
147
+ const files = fs_1.default.readdirSync(routesDir, { recursive: true, encoding: 'utf-8' });
148
+ // Corrigindo o filtro para excluir corretamente o diretório backend
149
+ const routeFiles = files.filter(file => {
150
+ const isTypeScriptFile = file.endsWith('.ts') || file.endsWith('.tsx');
151
+ const isNotBackend = !file.includes('backend' + path_1.default.sep) && !file.includes('backend/');
152
+ return isTypeScriptFile && isNotBackend;
153
+ });
154
+ const loaded = [];
155
+ for (const file of routeFiles) {
156
+ const filePath = path_1.default.join(routesDir, file);
157
+ const absolutePath = path_1.default.resolve(filePath);
158
+ // Usamos um caminho relativo ao CWD como um ID estável para o componente.
159
+ const componentPath = path_1.default.relative(process.cwd(), filePath).replace(/\\/g, '/');
160
+ try {
161
+ // Limpa o cache antes de recarregar para pegar alterações nos metadados
162
+ clearRequireCache(absolutePath);
163
+ const routeModule = require(filePath);
164
+ if (routeModule.default && routeModule.default.pattern && routeModule.default.component) {
165
+ loaded.push({ ...routeModule.default, componentPath });
166
+ // Registra o arquivo como carregado
167
+ loadedRouteFiles.add(absolutePath);
168
+ }
169
+ }
170
+ catch (error) {
171
+ console_1.default.error(`Erro ao carregar a rota de página ${filePath}:`, error);
172
+ }
173
+ }
174
+ allRoutes = loaded;
175
+ return allRoutes;
176
+ }
177
+ /**
178
+ * Encontra a rota de página correspondente para uma URL.
179
+ * @param pathname O caminho da URL (ex: "/users/123").
180
+ * @returns Um objeto com a rota e os parâmetros, ou null se não encontrar.
181
+ */
182
+ function findMatchingRoute(pathname) {
183
+ for (const route of allRoutes) {
184
+ if (!route.pattern)
185
+ continue;
186
+ // Converte o padrão da rota (ex: /users/[id]) em uma RegExp
187
+ const regexPattern = route.pattern.replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
188
+ const regex = new RegExp(`^${regexPattern}/?$`);
189
+ const match = pathname.match(regex);
190
+ if (match) {
191
+ return {
192
+ route,
193
+ params: match.groups || {}
194
+ };
195
+ }
196
+ }
197
+ return null;
198
+ }
199
+ // --- Roteamento do Backend ---
200
+ // Guarda todas as rotas de API encontradas
201
+ let allBackendRoutes = [];
202
+ // Cache de middlewares carregados por diretório
203
+ let loadedMiddlewares = new Map();
204
+ /**
205
+ * Carrega middlewares de um diretório específico
206
+ * @param dir O diretório onde procurar por middleware.ts
207
+ * @returns Array de middlewares encontrados
208
+ */
209
+ function loadMiddlewareFromDirectory(dir) {
210
+ const middlewares = [];
211
+ // Procura por middleware.ts ou middleware.tsx
212
+ const middlewarePath = path_1.default.join(dir, 'middleware.ts');
213
+ const middlewarePathTsx = path_1.default.join(dir, 'middleware.tsx');
214
+ const middlewareFile = fs_1.default.existsSync(middlewarePath) ? middlewarePath :
215
+ fs_1.default.existsSync(middlewarePathTsx) ? middlewarePathTsx : null;
216
+ if (middlewareFile) {
217
+ try {
218
+ const absolutePath = path_1.default.resolve(middlewareFile);
219
+ clearRequireCache(absolutePath);
220
+ const middlewareModule = require(middlewareFile);
221
+ // Suporte para export default (função única) ou export { middleware1, middleware2 }
222
+ if (typeof middlewareModule.default === 'function') {
223
+ middlewares.push(middlewareModule.default);
224
+ }
225
+ else if (middlewareModule.default && Array.isArray(middlewareModule.default)) {
226
+ middlewares.push(...middlewareModule.default);
227
+ }
228
+ else {
229
+ // Procura por exports nomeados que sejam funções
230
+ Object.keys(middlewareModule).forEach(key => {
231
+ if (key !== 'default' && typeof middlewareModule[key] === 'function') {
232
+ middlewares.push(middlewareModule[key]);
233
+ }
234
+ });
235
+ }
236
+ }
237
+ catch (error) {
238
+ console_1.default.error(`Erro ao carregar middleware ${middlewareFile}:`, error);
239
+ }
240
+ }
241
+ return middlewares;
242
+ }
243
+ /**
244
+ * Coleta middlewares do diretório específico da rota (não herda dos pais)
245
+ * @param routeFilePath Caminho completo do arquivo de rota
246
+ * @param backendRoutesDir Diretório raiz das rotas de backend
247
+ * @returns Array com middlewares apenas do diretório da rota
248
+ */
249
+ function collectMiddlewaresForRoute(routeFilePath, backendRoutesDir) {
250
+ const relativePath = path_1.default.relative(backendRoutesDir, routeFilePath);
251
+ const routeDir = path_1.default.dirname(path_1.default.join(backendRoutesDir, relativePath));
252
+ // Carrega middlewares APENAS do diretório específico da rota (não herda dos pais)
253
+ if (!loadedMiddlewares.has(routeDir)) {
254
+ const middlewares = loadMiddlewareFromDirectory(routeDir);
255
+ loadedMiddlewares.set(routeDir, middlewares);
256
+ }
257
+ return loadedMiddlewares.get(routeDir) || [];
258
+ }
259
+ /**
260
+ * Carrega dinamicamente todas as rotas de API do diretório de backend.
261
+ * @param backendRoutesDir O diretório onde as rotas de API estão localizadas.
262
+ */
263
+ function loadBackendRoutes(backendRoutesDir) {
264
+ if (!fs_1.default.existsSync(backendRoutesDir)) {
265
+ // É opcional ter uma API, então não mostramos um aviso se a pasta não existir.
266
+ allBackendRoutes = [];
267
+ return;
268
+ }
269
+ // Limpa cache de middlewares para recarregar
270
+ loadedMiddlewares.clear();
271
+ const files = fs_1.default.readdirSync(backendRoutesDir, { recursive: true, encoding: 'utf-8' });
272
+ const routeFiles = files.filter(file => {
273
+ const isTypeScript = file.endsWith('.ts') || file.endsWith('.tsx');
274
+ const isNotMiddleware = !path_1.default.basename(file).startsWith('middleware');
275
+ return isTypeScript && isNotMiddleware;
276
+ });
277
+ const loaded = [];
278
+ for (const file of routeFiles) {
279
+ const filePath = path_1.default.join(backendRoutesDir, file);
280
+ try {
281
+ const routeModule = require(filePath);
282
+ if (routeModule.default && routeModule.default.pattern) {
283
+ const routeConfig = { ...routeModule.default };
284
+ // Se a rota NÃO tem a propriedade middleware definida, carrega os da pasta
285
+ if (!routeConfig.hasOwnProperty('middleware')) {
286
+ const folderMiddlewares = collectMiddlewaresForRoute(filePath, backendRoutesDir);
287
+ if (folderMiddlewares.length > 0) {
288
+ routeConfig.middleware = folderMiddlewares;
289
+ }
290
+ }
291
+ // Se tem middleware definido (mesmo que seja []), usa só esses (não adiciona os da pasta)
292
+ loaded.push(routeConfig);
293
+ }
294
+ }
295
+ catch (error) {
296
+ console_1.default.error(`Erro ao carregar a rota de API ${filePath}:`, error);
297
+ }
298
+ }
299
+ allBackendRoutes = loaded;
300
+ }
301
+ /**
302
+ * Encontra a rota de API correspondente para uma URL e método HTTP.
303
+ * @param pathname O caminho da URL (ex: "/api/users/123").
304
+ * @param method O método HTTP da requisição (GET, POST, etc.).
305
+ * @returns Um objeto com a rota e os parâmetros, ou null se não encontrar.
306
+ */
307
+ function findMatchingBackendRoute(pathname, method) {
308
+ for (const route of allBackendRoutes) {
309
+ // Verifica se a rota tem um handler para o método HTTP atual
310
+ if (!route.pattern || !route[method.toUpperCase()])
311
+ continue;
312
+ const regexPattern = route.pattern.replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
313
+ const regex = new RegExp(`^${regexPattern}/?$`);
314
+ const match = pathname.match(regex);
315
+ if (match) {
316
+ return {
317
+ route,
318
+ params: match.groups || {}
319
+ };
320
+ }
321
+ }
322
+ return null;
323
+ }
324
+ /**
325
+ * Carrega o notFound.tsx se existir no diretório web
326
+ * @param webDir O diretório web onde procurar o notFound
327
+ * @returns O notFound carregado ou null se não existir
328
+ */
329
+ function loadNotFound(webDir) {
330
+ const notFoundPath = path_1.default.join(webDir, 'notFound.tsx');
331
+ const notFoundPathJs = path_1.default.join(webDir, 'notFound.ts');
332
+ const notFoundFile = fs_1.default.existsSync(notFoundPath) ? notFoundPath :
333
+ fs_1.default.existsSync(notFoundPathJs) ? notFoundPathJs : null;
334
+ if (notFoundFile) {
335
+ const componentPath = path_1.default.relative(process.cwd(), notFoundFile).replace(/\\/g, '/');
336
+ const absolutePath = path_1.default.resolve(notFoundFile);
337
+ try {
338
+ // Limpa o cache antes de recarregar
339
+ clearRequireCache(absolutePath);
340
+ // Registra o arquivo como carregado
341
+ loadedNotFoundFiles.add(absolutePath);
342
+ notFoundComponent = { componentPath };
343
+ return notFoundComponent;
344
+ }
345
+ catch (error) {
346
+ console_1.default.error(`Erro ao carregar notFound ${notFoundFile}:`, error);
347
+ notFoundComponent = { componentPath };
348
+ return notFoundComponent;
349
+ }
350
+ }
351
+ notFoundComponent = null;
352
+ return null;
353
+ }
354
+ /**
355
+ * Retorna o componente 404 atual se carregado
356
+ */
357
+ function getNotFound() {
358
+ return notFoundComponent;
359
+ }
@@ -0,0 +1,37 @@
1
+ export interface GenericRequest {
2
+ method: string;
3
+ url: string;
4
+ headers: Record<string, string | string[]>;
5
+ body?: any;
6
+ query?: Record<string, any>;
7
+ params?: Record<string, string>;
8
+ cookies?: Record<string, string>;
9
+ raw?: any;
10
+ }
11
+ export interface GenericResponse {
12
+ status(code: number): GenericResponse;
13
+ header(name: string, value: string): GenericResponse;
14
+ cookie(name: string, value: string, options?: CookieOptions): GenericResponse;
15
+ clearCookie(name: string, options?: CookieOptions): GenericResponse;
16
+ json(data: any): void;
17
+ text(data: string): void;
18
+ send(data: any): void;
19
+ redirect(url: string): void;
20
+ raw?: any;
21
+ }
22
+ export interface CookieOptions {
23
+ domain?: string;
24
+ expires?: Date;
25
+ httpOnly?: boolean;
26
+ maxAge?: number;
27
+ path?: string;
28
+ secure?: boolean;
29
+ signed?: boolean;
30
+ sameSite?: boolean | 'lax' | 'strict' | 'none';
31
+ }
32
+ export type FrameworkType = 'express' | 'fastify' | 'native';
33
+ export interface FrameworkAdapter {
34
+ type: FrameworkType;
35
+ parseRequest(req: any): GenericRequest;
36
+ createResponse(res: any): GenericResponse;
37
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,43 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { GenericRequest } from './types/framework';
3
+ import { HightJSRequest, HightJSResponse } from "./api/http";
4
+ export interface HightJSOptions {
5
+ dev?: boolean;
6
+ hostname?: string;
7
+ port?: number;
8
+ dir?: string;
9
+ framework?: 'express' | 'fastify' | 'native';
10
+ }
11
+ export interface Metadata {
12
+ title?: string;
13
+ description?: string;
14
+ favicon?: string;
15
+ }
16
+ export interface RouteConfig {
17
+ pattern: string;
18
+ component: ComponentType<any>;
19
+ generateMetadata?: (params: any, req: GenericRequest) => Promise<Metadata> | Metadata;
20
+ }
21
+ export type RequestHandler = (req: any, res: any) => Promise<void>;
22
+ /**
23
+ * Define o formato de uma função que manipula uma rota da API.
24
+ */
25
+ export type BackendHandler = (request: HightJSRequest, // HWebRequest será importado onde necessário
26
+ params: {
27
+ [key: string]: string;
28
+ }) => Promise<HightJSResponse> | HightJSResponse;
29
+ export type HightMiddleware = (request: HightJSRequest, // HWebRequest será importado onde necessário
30
+ params: {
31
+ [key: string]: string;
32
+ }, next: () => Promise<HightJSResponse>) => Promise<HightJSResponse> | HightJSResponse;
33
+ /**
34
+ * Define a estrutura de cada rota da API, com suporte para métodos HTTP.
35
+ */
36
+ export interface BackendRouteConfig {
37
+ pattern: string;
38
+ GET?: BackendHandler;
39
+ POST?: BackendHandler;
40
+ PUT?: BackendHandler;
41
+ DELETE?: BackendHandler;
42
+ middleware?: HightMiddleware[];
43
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * TypeScript Plugin: require-use-client
3
+ * Integra a validação "use client" diretamente no TypeScript
4
+ */
5
+ export default function createPlugin(info: any): any;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ /**
3
+ * TypeScript Plugin: require-use-client
4
+ * Integra a validação "use client" diretamente no TypeScript
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.default = createPlugin;
8
+ const defaultConfig = {
9
+ enabled: true,
10
+ severity: 'error'
11
+ };
12
+ function isReactImport(node) {
13
+ if (!node.moduleSpecifier || node.moduleSpecifier.kind !== 10) { // StringLiteral = 10
14
+ return false;
15
+ }
16
+ const moduleName = node.moduleSpecifier.text;
17
+ return moduleName === 'react' || moduleName === 'react/jsx-runtime';
18
+ }
19
+ function hasReactHooks(node) {
20
+ if (!isReactImport(node) || !node.importClause) {
21
+ return false;
22
+ }
23
+ const reactHooks = [
24
+ 'useState', 'useEffect', 'useContext', 'useReducer',
25
+ 'useCallback', 'useMemo', 'useRef', 'useImperativeHandle',
26
+ 'useLayoutEffect', 'useDebugValue', 'useDeferredValue',
27
+ 'useTransition', 'useId', 'useSyncExternalStore',
28
+ 'useInsertionEffect'
29
+ ];
30
+ if (node.importClause.namedBindings && node.importClause.namedBindings.kind === 271) { // NamedImports = 271
31
+ return node.importClause.namedBindings.elements.some((element) => reactHooks.includes(element.name.text));
32
+ }
33
+ return false;
34
+ }
35
+ function hasUseClientDirective(sourceFile) {
36
+ // Verifica se a primeira statement é uma expressão "use client"
37
+ if (sourceFile.statements.length === 0)
38
+ return false;
39
+ const firstStatement = sourceFile.statements[0];
40
+ if (firstStatement.kind === 233 && // ExpressionStatement = 233
41
+ firstStatement.expression.kind === 10) { // StringLiteral = 10
42
+ const value = firstStatement.expression.text;
43
+ return value === 'use client';
44
+ }
45
+ return false;
46
+ }
47
+ function isBackendFile(fileName) {
48
+ // Verifica se o arquivo está no diretório backend
49
+ return fileName.includes('/backend/') || fileName.includes('\\backend\\');
50
+ }
51
+ function isFrontendFile(fileName) {
52
+ // Verifica se é um arquivo frontend (não backend e dentro de src/web)
53
+ const isInWebDir = fileName.includes('/src/web/') || fileName.includes('\\src\\web\\');
54
+ const isNotBackend = !isBackendFile(fileName);
55
+ const isReactFile = fileName.endsWith('.tsx') || fileName.endsWith('.jsx');
56
+ return isInWebDir && isNotBackend && isReactFile;
57
+ }
58
+ function createDiagnostic(sourceFile, severity, start = 0, length = 1) {
59
+ const category = severity === 'error' ? 1 : 0; // Error = 1, Warning = 0
60
+ return {
61
+ file: sourceFile,
62
+ start,
63
+ length,
64
+ messageText: 'Arquivos que importam React ou hooks devem começar com "use client"',
65
+ category,
66
+ code: 9001, // Código customizado para o plugin HightJS
67
+ source: 'hightjs'
68
+ };
69
+ }
70
+ function createPlugin(info) {
71
+ const config = { ...defaultConfig, ...info.config };
72
+ if (!config.enabled) {
73
+ return info.languageService;
74
+ }
75
+ const proxy = Object.create(null);
76
+ // Proxy todas as funções do language service
77
+ for (let k of Object.keys(info.languageService)) {
78
+ const x = info.languageService[k];
79
+ proxy[k] = (...args) => x.apply(info.languageService, args);
80
+ }
81
+ // Sobrescreve getSemanticDiagnostics para adicionar nossa validação
82
+ proxy.getSemanticDiagnostics = (fileName) => {
83
+ const originalDiagnostics = info.languageService.getSemanticDiagnostics(fileName);
84
+ // Só valida arquivos frontend
85
+ if (!isFrontendFile(fileName)) {
86
+ return originalDiagnostics;
87
+ }
88
+ const sourceFile = info.languageService.getProgram()?.getSourceFile(fileName);
89
+ if (!sourceFile) {
90
+ return originalDiagnostics;
91
+ }
92
+ let hasReactImportOrHooks = false;
93
+ // Verifica se há imports do React ou hooks
94
+ function visitNode(node) {
95
+ if (node.kind === 270) { // ImportDeclaration = 270
96
+ if (isReactImport(node) || hasReactHooks(node)) {
97
+ hasReactImportOrHooks = true;
98
+ }
99
+ }
100
+ node.forEachChild?.(visitNode);
101
+ }
102
+ visitNode(sourceFile);
103
+ // Se usa React mas não tem "use client", adiciona diagnóstico
104
+ if (hasReactImportOrHooks && !hasUseClientDirective(sourceFile)) {
105
+ const diagnostic = createDiagnostic(sourceFile, config.severity, 0, 1);
106
+ return [...originalDiagnostics, diagnostic];
107
+ }
108
+ return originalDiagnostics;
109
+ };
110
+ return proxy;
111
+ }
112
+ // Para compatibilidade com diferentes versões do TypeScript
113
+ module.exports = createPlugin;
File without changes
@@ -0,0 +1 @@
1
+ "use strict";