proteum 1.0.2 → 2.0.0

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 (185) hide show
  1. package/AGENTS.md +101 -0
  2. package/agents/codex/AGENTS.md +95 -0
  3. package/agents/codex/CODING_STYLE.md +71 -0
  4. package/agents/codex/agents.md.zip +0 -0
  5. package/agents/codex/client/AGENTS.md +102 -0
  6. package/agents/codex/client/pages/AGENTS.md +35 -0
  7. package/agents/codex/server/routes/AGENTS.md +12 -0
  8. package/agents/codex/server/services/AGENTS.md +137 -0
  9. package/agents/codex/tests/AGENTS.md +8 -0
  10. package/cli/app/config.ts +13 -11
  11. package/cli/app/index.ts +74 -82
  12. package/cli/bin.js +1 -1
  13. package/cli/commands/build.ts +51 -14
  14. package/cli/commands/check.ts +19 -0
  15. package/cli/commands/deploy/app.ts +4 -8
  16. package/cli/commands/deploy/web.ts +16 -20
  17. package/cli/commands/dev.ts +189 -64
  18. package/cli/commands/devEvents.ts +106 -0
  19. package/cli/commands/init.ts +63 -57
  20. package/cli/commands/lint.ts +21 -0
  21. package/cli/commands/refresh.ts +18 -0
  22. package/cli/commands/typecheck.ts +18 -0
  23. package/cli/compiler/client/identite.ts +80 -53
  24. package/cli/compiler/client/index.ts +139 -213
  25. package/cli/compiler/common/bundleAnalysis.ts +94 -0
  26. package/cli/compiler/common/clientManifest.ts +67 -0
  27. package/cli/compiler/common/controllers.ts +288 -0
  28. package/cli/compiler/common/files/autres.ts +7 -18
  29. package/cli/compiler/common/files/images.ts +40 -37
  30. package/cli/compiler/common/files/style.ts +11 -22
  31. package/cli/compiler/common/generatedRouteModules.ts +368 -0
  32. package/cli/compiler/common/index.ts +31 -65
  33. package/cli/compiler/common/loaders/forbid-ssr-import.js +13 -0
  34. package/cli/compiler/common/rspackAliases.ts +13 -0
  35. package/cli/compiler/common/scripts.ts +37 -0
  36. package/cli/compiler/index.ts +781 -230
  37. package/cli/compiler/server/index.ts +59 -75
  38. package/cli/compiler/writeIfChanged.ts +21 -0
  39. package/cli/index.ts +71 -72
  40. package/cli/paths.ts +51 -57
  41. package/cli/print.ts +17 -11
  42. package/cli/tsconfig.json +5 -4
  43. package/cli/utils/agents.ts +100 -0
  44. package/cli/utils/check.ts +71 -0
  45. package/cli/utils/index.ts +1 -3
  46. package/cli/utils/keyboard.ts +8 -25
  47. package/cli/utils/runProcess.ts +30 -0
  48. package/client/app/component.tsx +29 -29
  49. package/client/app/index.ts +36 -57
  50. package/client/app/service.ts +7 -12
  51. package/client/app.tsconfig.json +2 -2
  52. package/client/components/Dialog/Manager.ssr.tsx +40 -0
  53. package/client/components/Dialog/Manager.tsx +119 -150
  54. package/client/components/Dialog/status.tsx +3 -3
  55. package/client/components/index.ts +1 -1
  56. package/client/components/types.d.ts +1 -3
  57. package/client/dev/hmr.ts +65 -0
  58. package/client/global.d.ts +2 -2
  59. package/client/hooks.ts +6 -9
  60. package/client/index.ts +2 -1
  61. package/client/islands/index.ts +7 -0
  62. package/client/islands/useDeferredModule.ts +199 -0
  63. package/client/pages/_layout/index.tsx +4 -12
  64. package/client/pages/useHeader.tsx +14 -21
  65. package/client/router.ts +27 -0
  66. package/client/services/router/components/Link.tsx +34 -27
  67. package/client/services/router/components/Page.tsx +6 -14
  68. package/client/services/router/components/router.ssr.tsx +36 -0
  69. package/client/services/router/components/router.tsx +63 -83
  70. package/client/services/router/index.tsx +185 -220
  71. package/client/services/router/request/api.ts +97 -119
  72. package/client/services/router/request/history.ts +2 -2
  73. package/client/services/router/request/index.ts +13 -12
  74. package/client/services/router/request/multipart.ts +72 -62
  75. package/client/services/router/response/index.tsx +68 -61
  76. package/client/services/router/response/page.ts +28 -32
  77. package/client/utils/dom.ts +17 -33
  78. package/common/app/index.ts +3 -3
  79. package/common/data/chaines/index.ts +22 -23
  80. package/common/data/dates.ts +35 -70
  81. package/common/data/markdown.ts +42 -39
  82. package/common/dev/serverHotReload.ts +26 -0
  83. package/common/errors/index.tsx +110 -142
  84. package/common/router/contracts.ts +29 -0
  85. package/common/router/index.ts +89 -108
  86. package/common/router/layouts.ts +34 -47
  87. package/common/router/pageSetup.ts +50 -0
  88. package/common/router/register.ts +53 -24
  89. package/common/router/request/api.ts +30 -36
  90. package/common/router/request/index.ts +2 -8
  91. package/common/router/response/index.ts +8 -15
  92. package/common/router/response/page.ts +70 -58
  93. package/common/utils.ts +1 -1
  94. package/doc/TODO.md +1 -1
  95. package/eslint.js +62 -0
  96. package/package.json +12 -47
  97. package/prettier.config.cjs +9 -0
  98. package/scripts/cleanup-generated-controllers.ts +62 -0
  99. package/scripts/fix-reference-app-typing.ts +490 -0
  100. package/scripts/refactor-client-app-imports.ts +244 -0
  101. package/scripts/refactor-client-pages.ts +587 -0
  102. package/scripts/refactor-server-controllers.ts +470 -0
  103. package/scripts/refactor-server-runtime-aliases.ts +360 -0
  104. package/scripts/restore-client-app-import-files.ts +41 -0
  105. package/scripts/restore-files-from-git-head.ts +20 -0
  106. package/scripts/update-codex-agents.ts +35 -0
  107. package/server/app/commands.ts +35 -64
  108. package/server/app/container/config.ts +48 -59
  109. package/server/app/container/console/index.ts +202 -248
  110. package/server/app/container/index.ts +33 -71
  111. package/server/app/controller/index.ts +61 -0
  112. package/server/app/index.ts +39 -105
  113. package/server/app/service/container.ts +41 -42
  114. package/server/app/service/index.ts +120 -147
  115. package/server/context.ts +1 -1
  116. package/server/index.ts +25 -1
  117. package/server/services/auth/index.ts +75 -115
  118. package/server/services/auth/router/index.ts +31 -32
  119. package/server/services/auth/router/request.ts +14 -16
  120. package/server/services/cron/CronTask.ts +13 -26
  121. package/server/services/cron/index.ts +14 -36
  122. package/server/services/disks/driver.ts +40 -58
  123. package/server/services/disks/drivers/local/index.ts +79 -90
  124. package/server/services/disks/drivers/s3/index.ts +116 -163
  125. package/server/services/disks/index.ts +23 -38
  126. package/server/services/email/index.ts +45 -104
  127. package/server/services/email/utils.ts +14 -27
  128. package/server/services/fetch/index.ts +53 -85
  129. package/server/services/prisma/Facet.ts +39 -91
  130. package/server/services/prisma/index.ts +74 -110
  131. package/server/services/router/generatedRuntime.ts +29 -0
  132. package/server/services/router/http/index.ts +78 -73
  133. package/server/services/router/http/multipart.ts +19 -42
  134. package/server/services/router/index.ts +378 -365
  135. package/server/services/router/request/api.ts +26 -25
  136. package/server/services/router/request/index.ts +44 -51
  137. package/server/services/router/request/service.ts +7 -11
  138. package/server/services/router/request/validation/zod.ts +111 -148
  139. package/server/services/router/response/index.ts +110 -125
  140. package/server/services/router/response/mask/Filter.ts +31 -72
  141. package/server/services/router/response/mask/index.ts +8 -15
  142. package/server/services/router/response/mask/selecteurs.ts +11 -25
  143. package/server/services/router/response/page/clientManifest.ts +25 -0
  144. package/server/services/router/response/page/document.tsx +199 -127
  145. package/server/services/router/response/page/index.tsx +89 -94
  146. package/server/services/router/service.ts +13 -15
  147. package/server/services/schema/index.ts +17 -26
  148. package/server/services/schema/request.ts +19 -33
  149. package/server/services/schema/router/index.ts +8 -11
  150. package/server/services/security/encrypt/aes/index.ts +15 -35
  151. package/server/utils/slug.ts +29 -35
  152. package/skills/clean-project-code/SKILL.md +63 -0
  153. package/skills/clean-project-code/agents/openai.yaml +4 -0
  154. package/tsconfig.common.json +4 -3
  155. package/tsconfig.json +4 -1
  156. package/types/aliases.d.ts +17 -21
  157. package/types/controller-input.test.ts +48 -0
  158. package/types/express-extra.d.ts +6 -0
  159. package/types/global/constants.d.ts +13 -0
  160. package/types/global/express-extra.d.ts +6 -0
  161. package/types/global/modules.d.ts +13 -16
  162. package/types/global/utils.d.ts +17 -49
  163. package/types/global/vendors.d.ts +62 -0
  164. package/types/icons.d.ts +65 -1
  165. package/types/uuid.d.ts +3 -0
  166. package/types/vendors.d.ts +62 -0
  167. package/cli/compiler/common/babel/index.ts +0 -170
  168. package/cli/compiler/common/babel/plugins/index.ts +0 -0
  169. package/cli/compiler/common/babel/plugins/services.ts +0 -586
  170. package/cli/compiler/common/babel/routes/imports.ts +0 -127
  171. package/cli/compiler/common/babel/routes/routes.ts +0 -1130
  172. package/client/services/captcha/index.ts +0 -67
  173. package/client/services/socket/index.ts +0 -147
  174. package/common/data/rte/nodes.ts +0 -83
  175. package/common/data/stats.ts +0 -90
  176. package/common/utils/rte.ts +0 -183
  177. package/server/services/auth/old.ts +0 -277
  178. package/server/services/cache/commands.ts +0 -41
  179. package/server/services/cache/index.ts +0 -297
  180. package/server/services/cache/service.json +0 -6
  181. package/server/services/socket/index.ts +0 -162
  182. package/server/services/socket/scope.ts +0 -226
  183. package/server/services/socket/service.json +0 -6
  184. package/server/services_old/SocketClient.ts +0 -92
  185. package/server/services_old/Token.old.ts +0 -97
@@ -0,0 +1,94 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import type { RspackPluginInstance } from '@rspack/core';
4
+
5
+ import cli from '../..';
6
+ import type { App } from '../../app';
7
+
8
+ const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
9
+
10
+ export type TBundleAnalysisReportPaths = { reportPath: string; statsPath: string };
11
+
12
+ export const isBundleAnalysisEnabled = () => cli.args.analyze === true;
13
+
14
+ export const getClientBundleAnalysisReportPaths = (
15
+ app: App,
16
+ outputTarget: 'dev' | 'bin',
17
+ ): TBundleAnalysisReportPaths => {
18
+ const reportDir = path.join(app.outputPath(outputTarget), 'bundle-analysis');
19
+
20
+ return { reportPath: path.join(reportDir, 'client.html'), statsPath: path.join(reportDir, 'client-stats.json') };
21
+ };
22
+
23
+ export const createClientBundleAnalysisPlugins = (app: App, outputTarget: 'dev' | 'bin'): RspackPluginInstance[] => {
24
+ if (!isBundleAnalysisEnabled()) return [];
25
+
26
+ const { reportPath, statsPath } = getClientBundleAnalysisReportPaths(app, outputTarget);
27
+
28
+ fs.ensureDirSync(path.dirname(reportPath));
29
+
30
+ return [
31
+ new BundleAnalyzerPlugin({
32
+ analyzerMode: 'static',
33
+ openAnalyzer: false,
34
+ defaultSizes: 'parsed',
35
+ reportFilename: reportPath,
36
+ generateStatsFile: true,
37
+ statsFilename: statsPath,
38
+ logLevel: 'info',
39
+ }),
40
+ ];
41
+ };
42
+
43
+ const sleep = (delayMs: number) => new Promise((resolve) => setTimeout(resolve, delayMs));
44
+
45
+ const isJsonFileComplete = (filepath: string) => {
46
+ const fd = fs.openSync(filepath, 'r');
47
+
48
+ try {
49
+ const { size } = fs.fstatSync(fd);
50
+ if (size === 0) return false;
51
+
52
+ const readLength = Math.min(512, size);
53
+ const buffer = Buffer.alloc(readLength);
54
+ fs.readSync(fd, buffer, 0, readLength, size - readLength);
55
+
56
+ const tail = buffer.toString('utf8').trimEnd();
57
+ if (!tail.endsWith('}')) return false;
58
+
59
+ JSON.parse(fs.readFileSync(filepath, 'utf8'));
60
+ return true;
61
+ } catch {
62
+ return false;
63
+ } finally {
64
+ fs.closeSync(fd);
65
+ }
66
+ };
67
+
68
+ export const waitForClientBundleAnalysisArtifacts = async (
69
+ app: App,
70
+ outputTarget: 'dev' | 'bin',
71
+ timeoutMs: number = 30000,
72
+ ) => {
73
+ const startedAt = Date.now();
74
+ const { reportPath, statsPath } = getClientBundleAnalysisReportPaths(app, outputTarget);
75
+ let previousStatsSize = -1;
76
+
77
+ while (Date.now() - startedAt < timeoutMs) {
78
+ const reportExists = fs.existsSync(reportPath);
79
+ const statsExists = fs.existsSync(statsPath);
80
+
81
+ if (reportExists && statsExists) {
82
+ const { size } = fs.statSync(statsPath);
83
+ const sizeStable = size > 0 && size === previousStatsSize;
84
+
85
+ if (sizeStable && isJsonFileComplete(statsPath)) return;
86
+
87
+ previousStatsSize = size;
88
+ }
89
+
90
+ await sleep(250);
91
+ }
92
+
93
+ throw new Error(`Timed out waiting for bundle analysis artifacts to complete: ${reportPath}, ${statsPath}`);
94
+ };
@@ -0,0 +1,67 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import type { Stats } from '@rspack/core';
4
+
5
+ export type TClientManifestChunkAssets = { assets: string[]; css: string[]; js: string[] };
6
+
7
+ export type TClientBuildManifest = {
8
+ publicPath: string;
9
+ entries: Record<string, TClientManifestChunkAssets>;
10
+ chunks: Record<string, TClientManifestChunkAssets>;
11
+ };
12
+
13
+ const filterAsset = (asset: string) => !asset.endsWith('.map');
14
+
15
+ const classifyAssets = (assets: string[]): TClientManifestChunkAssets => {
16
+ const filtered = assets.filter(filterAsset);
17
+
18
+ return {
19
+ assets: filtered,
20
+ css: filtered.filter((asset) => asset.endsWith('.css')),
21
+ js: filtered.filter((asset) => asset.endsWith('.js')),
22
+ };
23
+ };
24
+
25
+ const normalizePublicPath = (publicPath?: string) => {
26
+ if (!publicPath || publicPath === 'auto') return '/public/';
27
+
28
+ return publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
29
+ };
30
+
31
+ export const getClientManifestPath = (outputPath: string) => path.join(outputPath, 'client-manifest.json');
32
+
33
+ export const writeClientManifest = (stats: Stats, outputPath: string) => {
34
+ const statsJson = stats.toJson({
35
+ assets: true,
36
+ assetsByChunkName: true,
37
+ entrypoints: true,
38
+ namedChunkGroups: true,
39
+ publicPath: true,
40
+ });
41
+ const publicPath = normalizePublicPath(statsJson.publicPath);
42
+
43
+ const buildChunkAssets = (chunkGroup: { assets?: Array<string | { name?: string | null }> } | undefined) => {
44
+ const assets = (chunkGroup?.assets || [])
45
+ .map((asset) => (typeof asset === 'string' ? asset : asset.name || ''))
46
+ .filter(Boolean);
47
+
48
+ return classifyAssets(assets);
49
+ };
50
+
51
+ const entries = Object.fromEntries(
52
+ Object.entries(statsJson.entrypoints || {}).map(([name, chunkGroup]) => [name, buildChunkAssets(chunkGroup)]),
53
+ );
54
+
55
+ const chunks = Object.fromEntries(
56
+ Object.entries(statsJson.namedChunkGroups || {}).map(([name, chunkGroup]) => [
57
+ name,
58
+ buildChunkAssets(chunkGroup),
59
+ ]),
60
+ );
61
+
62
+ const manifest: TClientBuildManifest = { publicPath, entries, chunks };
63
+
64
+ fs.writeJsonSync(getClientManifestPath(outputPath), manifest, { spaces: 2 });
65
+
66
+ return manifest;
67
+ };
@@ -0,0 +1,288 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import fs from 'fs-extra';
7
+ import path from 'path';
8
+ import ts from 'typescript';
9
+
10
+ /*----------------------------------
11
+ - TYPES
12
+ ----------------------------------*/
13
+
14
+ export type TControllerMethodMeta = { name: string; inputCallsCount: number; routePath: string };
15
+
16
+ export type TControllerFileMeta = {
17
+ importPath: string;
18
+ filepath: string;
19
+ className: string;
20
+ routeBasePath: string;
21
+ methods: TControllerMethodMeta[];
22
+ };
23
+
24
+ export type TControllerServiceRoot = { alias: string; dir: string };
25
+
26
+ type TControllerSearchDir = { importPrefix: string; root: string; serviceRoots?: TControllerServiceRoot[] };
27
+
28
+ /*----------------------------------
29
+ - HELPERS
30
+ ----------------------------------*/
31
+
32
+ const getControllerSegments = (relativePath: string) => {
33
+ const segments = relativePath
34
+ .replace(/\.controller\.ts$/, '')
35
+ .split('/')
36
+ .filter(Boolean);
37
+
38
+ if (segments.length > 1 && segments[segments.length - 1] === segments[segments.length - 2]) {
39
+ segments.pop();
40
+ }
41
+
42
+ return segments;
43
+ };
44
+
45
+ const getControllerBasePathFromFilepath = (filepath: string, root: string, serviceRoots: TControllerServiceRoot[] = []) => {
46
+ const normalizedFilepath = filepath.replace(/\\/g, '/');
47
+ const serviceRoot = serviceRoots
48
+ .filter((candidate) => normalizedFilepath.startsWith(candidate.dir.replace(/\\/g, '/') + '/'))
49
+ .sort((a, b) => b.dir.length - a.dir.length)[0];
50
+
51
+ if (!serviceRoot) {
52
+ return getControllerSegments(path.relative(root, filepath).replace(/\\/g, '/')).join('/');
53
+ }
54
+
55
+ const segments = getControllerSegments(path.relative(serviceRoot.dir, filepath).replace(/\\/g, '/'));
56
+
57
+ if (segments[0]?.toLowerCase() === serviceRoot.alias.toLowerCase()) {
58
+ segments.shift();
59
+ }
60
+
61
+ return [serviceRoot.alias, ...segments].filter(Boolean).join('/');
62
+ };
63
+
64
+ const getGeneratedClassName = (filepath: string) => {
65
+ const filename = path.basename(filepath, '.ts').replace(/[^A-Za-z0-9_$]+/g, '_');
66
+ const normalized = filename.length ? filename : 'Controller';
67
+
68
+ return normalized[0].toUpperCase() + normalized.substring(1);
69
+ };
70
+
71
+ const buildImportPath = (searchDir: TControllerSearchDir, filepath: string) =>
72
+ searchDir.importPrefix + path.relative(searchDir.root, filepath).replace(/\\/g, '/').replace(/\.ts$/, '');
73
+
74
+ const findControllerFiles = (dir: string): string[] => {
75
+ if (!fs.existsSync(dir)) return [];
76
+
77
+ const files: string[] = [];
78
+
79
+ for (const dirent of fs.readdirSync(dir, { withFileTypes: true })) {
80
+ const filepath = path.join(dir, dirent.name);
81
+
82
+ if (dirent.isDirectory()) {
83
+ files.push(...findControllerFiles(filepath));
84
+ continue;
85
+ }
86
+
87
+ if (!dirent.isFile()) continue;
88
+ if (!dirent.name.endsWith('.controller.ts')) continue;
89
+
90
+ files.push(filepath);
91
+ }
92
+
93
+ return files;
94
+ };
95
+
96
+ const parseSourceFile = (filepath: string, code: string) =>
97
+ ts.createSourceFile(
98
+ filepath,
99
+ code,
100
+ ts.ScriptTarget.Latest,
101
+ true,
102
+ filepath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
103
+ );
104
+
105
+ const hasModifier = (node: ts.Node, kind: ts.SyntaxKind) =>
106
+ !!node.modifiers?.some((modifier) => modifier.kind === kind);
107
+
108
+ const getDefaultExportClass = (sourceFile: ts.SourceFile) => {
109
+ const classes = new Map<string, ts.ClassDeclaration>();
110
+
111
+ for (const statement of sourceFile.statements) {
112
+ if (ts.isClassDeclaration(statement) && statement.name) {
113
+ classes.set(statement.name.text, statement);
114
+
115
+ if (hasModifier(statement, ts.SyntaxKind.DefaultKeyword)) {
116
+ return statement;
117
+ }
118
+ }
119
+ }
120
+
121
+ for (const statement of sourceFile.statements) {
122
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals) continue;
123
+
124
+ if (ts.isIdentifier(statement.expression)) {
125
+ return classes.get(statement.expression.text);
126
+ }
127
+ }
128
+
129
+ return undefined;
130
+ };
131
+
132
+ const getExportedString = (sourceFile: ts.SourceFile, exportName: string) => {
133
+ for (const statement of sourceFile.statements) {
134
+ if (!ts.isVariableStatement(statement)) continue;
135
+ if (!hasModifier(statement, ts.SyntaxKind.ExportKeyword)) continue;
136
+
137
+ for (const declaration of statement.declarationList.declarations) {
138
+ if (!ts.isIdentifier(declaration.name)) continue;
139
+ if (declaration.name.text !== exportName) continue;
140
+ if (!declaration.initializer || !ts.isStringLiteral(declaration.initializer)) continue;
141
+
142
+ return declaration.initializer.text;
143
+ }
144
+ }
145
+
146
+ return undefined;
147
+ };
148
+
149
+ const countInputCalls = (method: ts.MethodDeclaration) => {
150
+ let inputCallsCount = 0;
151
+
152
+ const visit = (node: ts.Node) => {
153
+ if (
154
+ ts.isCallExpression(node) &&
155
+ ts.isPropertyAccessExpression(node.expression) &&
156
+ node.expression.expression.kind === ts.SyntaxKind.ThisKeyword &&
157
+ node.expression.name.text === 'input'
158
+ ) {
159
+ inputCallsCount++;
160
+ }
161
+
162
+ ts.forEachChild(node, visit);
163
+ };
164
+
165
+ if (method.body) ts.forEachChild(method.body, visit);
166
+
167
+ return inputCallsCount;
168
+ };
169
+
170
+ /*----------------------------------
171
+ - EXPORTS
172
+ ----------------------------------*/
173
+
174
+ export const indexControllers = (searchDirs: TControllerSearchDir[]) => {
175
+ const controllers: TControllerFileMeta[] = [];
176
+
177
+ for (const searchDir of searchDirs) {
178
+ const controllerFiles = findControllerFiles(searchDir.root);
179
+
180
+ for (const filepath of controllerFiles.sort((a, b) => a.localeCompare(b))) {
181
+ const code = fs.readFileSync(filepath, 'utf8');
182
+ const sourceFile = parseSourceFile(filepath, code);
183
+
184
+ const controllerPathOverride = getExportedString(sourceFile, 'controllerPath');
185
+ const defaultClass = getDefaultExportClass(sourceFile);
186
+
187
+ if (!defaultClass) continue;
188
+
189
+ const className = defaultClass.name?.text || getGeneratedClassName(filepath);
190
+ const routeBasePath =
191
+ controllerPathOverride ||
192
+ getControllerBasePathFromFilepath(filepath, searchDir.root, searchDir.serviceRoots || []);
193
+ const methods: TControllerMethodMeta[] = [];
194
+
195
+ for (const member of defaultClass.members) {
196
+ if (!ts.isMethodDeclaration(member)) continue;
197
+ if (!member.body) continue;
198
+ if (!member.name || !ts.isIdentifier(member.name)) continue;
199
+
200
+ const methodName = member.name.text;
201
+ const inputCallsCount = countInputCalls(member);
202
+
203
+ if (inputCallsCount > 1) {
204
+ throw new Error(`${filepath}#${methodName} uses this.input() more than once.`);
205
+ }
206
+
207
+ methods.push({
208
+ name: methodName,
209
+ inputCallsCount,
210
+ routePath: [routeBasePath, methodName].filter(Boolean).join('/'),
211
+ });
212
+ }
213
+
214
+ if (!methods.length) continue;
215
+
216
+ controllers.push({
217
+ filepath,
218
+ importPath: buildImportPath(searchDir, filepath),
219
+ className,
220
+ routeBasePath,
221
+ methods,
222
+ });
223
+ }
224
+ }
225
+
226
+ return controllers.sort((a, b) => a.filepath.localeCompare(b.filepath));
227
+ };
228
+
229
+ export const generateControllerClientTree = (controllers: TControllerFileMeta[]) => {
230
+ const root: Record<string, any> = {};
231
+
232
+ const insert = (segments: string[], valueFactory: () => string) => {
233
+ let cursor = root;
234
+
235
+ for (let i = 0; i < segments.length; i++) {
236
+ const segment = segments[i];
237
+ const isLeaf = i === segments.length - 1;
238
+
239
+ if (isLeaf) {
240
+ cursor[segment] = valueFactory();
241
+ return;
242
+ }
243
+
244
+ cursor[segment] = cursor[segment] || {};
245
+ cursor = cursor[segment];
246
+ }
247
+ };
248
+
249
+ for (const controller of controllers) {
250
+ for (const method of controller.methods) {
251
+ insert(method.routePath.split('/'), () =>
252
+ JSON.stringify({
253
+ importPath: controller.importPath,
254
+ className: controller.className,
255
+ methodName: method.name,
256
+ routePath: '/api/' + method.routePath,
257
+ hasInput: method.inputCallsCount > 0,
258
+ }),
259
+ );
260
+ }
261
+ }
262
+
263
+ return root;
264
+ };
265
+
266
+ export const printControllerTree = (
267
+ tree: Record<string, any>,
268
+ renderLeaf: (leaf: string) => string,
269
+ indentLevel: number = 1,
270
+ ) => {
271
+ const indent = ' '.repeat(indentLevel);
272
+ const lines: string[] = ['{'];
273
+
274
+ for (const key of Object.keys(tree).sort((a, b) => a.localeCompare(b))) {
275
+ const value = tree[key];
276
+
277
+ if (typeof value === 'string') {
278
+ lines.push(`${indent}${JSON.stringify(key)}: ${renderLeaf(value)},`);
279
+ continue;
280
+ }
281
+
282
+ lines.push(`${indent}${JSON.stringify(key)}: ${printControllerTree(value, renderLeaf, indentLevel + 1)},`);
283
+ }
284
+
285
+ lines.push(`${' '.repeat(indentLevel - 1)}}`);
286
+
287
+ return lines.join('\n');
288
+ };
@@ -2,38 +2,27 @@ import { staticAssetName } from '../../../paths';
2
2
 
3
3
  import type App from '../../../app';
4
4
 
5
- module.exports = (app: App, dev: boolean, client: boolean) => ([
6
-
5
+ module.exports = (app: App, dev: boolean, client: boolean) => [
7
6
  // Allow to use ?raw at the end of the module path to iport the raw content only
8
7
  // Example: import VisualParserSource from './Parsers/visual.js?raw';
9
- {
10
- resourceQuery: /raw/,
11
- type: 'asset/source',
12
- },
8
+ { resourceQuery: /raw/, type: 'asset/source' },
13
9
 
14
10
  // Client uniquement: Retourne le fichier correspondant au fichier dans le dossier public
15
11
  {
16
12
  test: /\.(xml|ico|wav|mp3)$/,
17
13
  //loader: 'file-loader',
18
14
  type: 'asset/resource',
19
- generator: {
20
- filename: staticAssetName
21
- }
15
+ generator: { filename: staticAssetName },
22
16
  },
23
17
 
24
18
  // Texte brut
25
- {
26
- type: 'asset/source',
27
- test: /\.(md|hbs|sql|txt|csv|html)$/,
28
- },
19
+ { type: 'asset/source', test: /\.(md|hbs|sql|txt|csv|html)$/ },
29
20
 
30
21
  // Polices dans un fichier distinc dans le dossier dédié
31
22
  {
32
23
  test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
33
24
  //loader: 'file-loader',
34
25
  type: 'asset/resource',
35
- generator: {
36
- filename: 'fonts/[name].[ext]'
37
- }
38
- }
39
- ])
26
+ generator: { filename: 'fonts/[name].[ext]' },
27
+ },
28
+ ];
@@ -1,42 +1,45 @@
1
1
  import { staticAssetName } from '../../../paths';
2
- import type webpack from 'webpack';
2
+ import type { RuleSetRule } from '@rspack/core';
3
+ import type App from '../../../app';
3
4
 
4
- module.exports = (app: App, dev: boolean, client: boolean): webpack.RuleSetRule[] => {
5
+ module.exports = (app: App, dev: boolean, client: boolean): RuleSetRule[] => {
6
+ return [
7
+ {
8
+ test: /\.(bmp|gif|png|jpe?g|ico|svg|webp)$/i,
9
+ type: 'asset',
10
+ parser: {
11
+ dataUrlCondition: {
12
+ // < 4kb = importation inline
13
+ // > 4kb = référence à l'url
14
+ maxSize: 4 * 1024, // 4kb
15
+ },
16
+ },
17
+ },
5
18
 
6
- return [{
7
- test: /\.(bmp|gif|png|jpe?g|ico|svg|webp)$/i,
8
- type: 'asset',
9
- parser: {
10
- dataUrlCondition: {
11
- // https://webpack.js.org/guides/asset-modules/#general-asset-type
12
- // < 4kb = importation inline
13
- // > 4kb = référence à l'url
14
- maxSize: 4 * 1024 // 4kb
15
- }
16
- }
19
+ ...(dev
20
+ ? []
21
+ : [
22
+ {
23
+ test: /\.(jpg|jpeg|png)$/i,
24
+ type: 'javascript/auto',
25
+ use: [
26
+ {
27
+ loader: 'responsive-loader',
28
+ options: {
29
+ sizes: [320, 480, 640, 768, 1024, 1300],
30
+ placeholder: true,
31
+ placeholderSize: 20,
32
+ quality: 100,
33
+ publicPath: '/public',
17
34
 
18
- },
35
+ // Triggers error
36
+ // cacheDirectory: true,
37
+ },
38
+ },
39
+ ],
40
+ },
41
+ ]),
19
42
 
20
- ...(dev ? [] : [{
21
- test: /\.(jpg|jpeg|png)$/i,
22
- type: "javascript/auto",
23
- use: [{
24
- loader: "responsive-loader",
25
- options: {
26
- sizes: [320, 480, 640, 768, 1024, 1300],
27
- placeholder: true,
28
- placeholderSize: 20,
29
- quality: 100,
30
- publicPath: '/public',
31
-
32
- // Triggers error
33
- // cacheDirectory: true,
34
- }
35
- }],
36
- }]),
37
-
38
- {
39
- test: /\.(webm|mp4|avi|mpk|mov|mkv)$/,
40
- type: 'asset/resource',
41
- },]
42
- }
43
+ { test: /\.(webm|mp4|avi|mpk|mov|mkv)$/, type: 'asset/resource' },
44
+ ];
45
+ };
@@ -1,36 +1,26 @@
1
1
  // Plugons
2
- import MiniCssExtractPlugin from "mini-css-extract-plugin";
2
+ import { rspack } from '@rspack/core';
3
3
 
4
4
  import type { App } from '../../../app';
5
5
 
6
- module.exports = (app: App, dev: Boolean, client: boolean) => {
7
-
8
- console.log('app.paths.root', app.paths.root)
6
+ module.exports = (app: App, dev: boolean, client: boolean) => {
7
+ const enableSourceMaps = dev;
8
+ const useStyleLoader = client && dev;
9
9
 
10
10
  return [
11
-
12
11
  // Apply PostCSS plugins including autoprefixer
13
- {
14
- loader: MiniCssExtractPlugin.loader
15
- },
12
+ useStyleLoader ? { loader: 'style-loader' } : { loader: rspack.CssExtractRspackPlugin.loader },
16
13
 
17
14
  // Process external/third-party styles
18
- {
19
- exclude: [app.paths.root],
20
- loader: 'css-loader',
21
- options: {
22
- sourceMap: dev
23
- },
24
- },
15
+ { exclude: [app.paths.root], loader: 'css-loader', options: { sourceMap: enableSourceMaps } },
25
16
 
26
17
  // Process internal/project styles (from root folder)
27
18
  {
28
19
  include: [app.paths.root],
29
20
  loader: 'css-loader',
30
21
  options: {
31
- // CSS Loader https://github.com/webpack/css-loader
32
22
  importLoaders: 1, // let postcss run on @imports
33
- sourceMap: dev
23
+ sourceMap: enableSourceMaps,
34
24
  },
35
25
  },
36
26
 
@@ -40,7 +30,7 @@ module.exports = (app: App, dev: Boolean, client: boolean) => {
40
30
  options: {
41
31
  postcssOptions: {
42
32
  plugins: [
43
- /* Tailwind V4 */require('@tailwindcss/postcss')({
33
+ /* Tailwind V4 */ require('@tailwindcss/postcss')({
44
34
  // Ensure Tailwind scans the application sources even if the build
45
35
  // process is launched from another working directory (e.g. Docker).
46
36
  base: app.paths.root,
@@ -68,13 +58,12 @@ module.exports = (app: App, dev: Boolean, client: boolean) => {
68
58
  // https://lesscss.org/usage/#less-options-math
69
59
  math: 'always',
70
60
  },
71
- }
61
+ },
72
62
  },
73
63
 
74
64
  /*{
75
65
  test: /\.scss/,
76
66
  loader: process.env.framework + '/node_modules/sass-loader',
77
67
  }*/
78
- ]
79
-
80
- }
68
+ ];
69
+ };