proteum 1.0.3 → 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.
- package/AGENTS.md +92 -0
- package/agents/codex/AGENTS.md +95 -0
- package/agents/codex/CODING_STYLE.md +71 -0
- package/agents/codex/agents.md.zip +0 -0
- package/agents/codex/client/AGENTS.md +102 -0
- package/agents/codex/client/pages/AGENTS.md +35 -0
- package/agents/codex/server/routes/AGENTS.md +12 -0
- package/agents/codex/server/services/AGENTS.md +137 -0
- package/agents/codex/tests/AGENTS.md +8 -0
- package/cli/app/config.ts +12 -17
- package/cli/app/index.ts +59 -99
- package/cli/bin.js +1 -1
- package/cli/commands/build.ts +23 -12
- package/cli/commands/check.ts +19 -0
- package/cli/commands/deploy/app.ts +4 -8
- package/cli/commands/deploy/web.ts +16 -20
- package/cli/commands/dev.ts +185 -75
- package/cli/commands/devEvents.ts +106 -0
- package/cli/commands/init.ts +63 -57
- package/cli/commands/lint.ts +21 -0
- package/cli/commands/refresh.ts +6 -6
- package/cli/commands/typecheck.ts +18 -0
- package/cli/compiler/client/identite.ts +79 -49
- package/cli/compiler/client/index.ts +132 -214
- package/cli/compiler/common/bundleAnalysis.ts +94 -0
- package/cli/compiler/common/clientManifest.ts +67 -0
- package/cli/compiler/common/controllers.ts +288 -0
- package/cli/compiler/common/files/autres.ts +7 -18
- package/cli/compiler/common/files/images.ts +40 -37
- package/cli/compiler/common/files/style.ts +12 -25
- package/cli/compiler/common/generatedRouteModules.ts +368 -0
- package/cli/compiler/common/index.ts +29 -68
- package/cli/compiler/common/loaders/forbid-ssr-import.js +13 -0
- package/cli/compiler/common/rspackAliases.ts +13 -0
- package/cli/compiler/common/scripts.ts +37 -0
- package/cli/compiler/index.ts +764 -234
- package/cli/compiler/server/index.ts +52 -77
- package/cli/compiler/writeIfChanged.ts +21 -0
- package/cli/index.ts +65 -90
- package/cli/paths.ts +51 -57
- package/cli/print.ts +17 -11
- package/cli/tsconfig.json +5 -4
- package/cli/utils/agents.ts +100 -0
- package/cli/utils/check.ts +71 -0
- package/cli/utils/index.ts +1 -3
- package/cli/utils/keyboard.ts +8 -25
- package/cli/utils/runProcess.ts +30 -0
- package/client/app/component.tsx +29 -29
- package/client/app/index.ts +36 -57
- package/client/app/service.ts +7 -12
- package/client/app.tsconfig.json +2 -2
- package/client/components/Dialog/Manager.ssr.tsx +40 -0
- package/client/components/Dialog/Manager.tsx +119 -150
- package/client/components/Dialog/status.tsx +3 -3
- package/client/components/index.ts +1 -1
- package/client/components/types.d.ts +1 -3
- package/client/dev/hmr.ts +65 -0
- package/client/global.d.ts +2 -2
- package/client/hooks.ts +6 -9
- package/client/index.ts +2 -1
- package/client/islands/index.ts +7 -0
- package/client/islands/useDeferredModule.ts +199 -0
- package/client/pages/_layout/index.tsx +4 -12
- package/client/pages/useHeader.tsx +14 -21
- package/client/router.ts +27 -0
- package/client/services/router/components/Link.tsx +34 -27
- package/client/services/router/components/Page.tsx +6 -14
- package/client/services/router/components/router.ssr.tsx +36 -0
- package/client/services/router/components/router.tsx +63 -83
- package/client/services/router/index.tsx +185 -220
- package/client/services/router/request/api.ts +97 -119
- package/client/services/router/request/history.ts +2 -2
- package/client/services/router/request/index.ts +13 -12
- package/client/services/router/request/multipart.ts +72 -62
- package/client/services/router/response/index.tsx +68 -61
- package/client/services/router/response/page.ts +28 -32
- package/client/utils/dom.ts +17 -33
- package/common/app/index.ts +3 -3
- package/common/data/chaines/index.ts +22 -23
- package/common/data/dates.ts +35 -70
- package/common/data/markdown.ts +42 -39
- package/common/dev/serverHotReload.ts +26 -0
- package/common/errors/index.tsx +110 -142
- package/common/router/contracts.ts +29 -0
- package/common/router/index.ts +89 -108
- package/common/router/layouts.ts +34 -47
- package/common/router/pageSetup.ts +50 -0
- package/common/router/register.ts +53 -24
- package/common/router/request/api.ts +30 -36
- package/common/router/request/index.ts +2 -8
- package/common/router/response/index.ts +8 -15
- package/common/router/response/page.ts +70 -58
- package/common/utils.ts +1 -1
- package/eslint.js +62 -0
- package/package.json +12 -45
- package/prettier.config.cjs +9 -0
- package/scripts/cleanup-generated-controllers.ts +62 -0
- package/scripts/fix-reference-app-typing.ts +490 -0
- package/scripts/refactor-client-app-imports.ts +244 -0
- package/scripts/refactor-client-pages.ts +587 -0
- package/scripts/refactor-server-controllers.ts +470 -0
- package/scripts/refactor-server-runtime-aliases.ts +360 -0
- package/scripts/restore-client-app-import-files.ts +41 -0
- package/scripts/restore-files-from-git-head.ts +20 -0
- package/scripts/update-codex-agents.ts +35 -0
- package/server/app/commands.ts +35 -64
- package/server/app/container/config.ts +39 -69
- package/server/app/container/console/index.ts +202 -248
- package/server/app/container/index.ts +33 -71
- package/server/app/controller/index.ts +61 -0
- package/server/app/index.ts +39 -105
- package/server/app/service/container.ts +41 -42
- package/server/app/service/index.ts +120 -147
- package/server/context.ts +1 -1
- package/server/index.ts +25 -1
- package/server/services/auth/index.ts +75 -115
- package/server/services/auth/router/index.ts +31 -32
- package/server/services/auth/router/request.ts +14 -16
- package/server/services/cron/CronTask.ts +13 -26
- package/server/services/cron/index.ts +14 -36
- package/server/services/disks/driver.ts +40 -58
- package/server/services/disks/drivers/local/index.ts +79 -90
- package/server/services/disks/drivers/s3/index.ts +116 -163
- package/server/services/disks/index.ts +23 -38
- package/server/services/email/index.ts +45 -104
- package/server/services/email/utils.ts +14 -27
- package/server/services/fetch/index.ts +53 -85
- package/server/services/prisma/Facet.ts +39 -91
- package/server/services/prisma/index.ts +74 -110
- package/server/services/router/generatedRuntime.ts +29 -0
- package/server/services/router/http/index.ts +77 -72
- package/server/services/router/http/multipart.ts +19 -42
- package/server/services/router/index.ts +378 -365
- package/server/services/router/request/api.ts +26 -25
- package/server/services/router/request/index.ts +44 -51
- package/server/services/router/request/service.ts +7 -11
- package/server/services/router/request/validation/zod.ts +111 -148
- package/server/services/router/response/index.ts +110 -125
- package/server/services/router/response/mask/Filter.ts +31 -72
- package/server/services/router/response/mask/index.ts +8 -15
- package/server/services/router/response/mask/selecteurs.ts +11 -25
- package/server/services/router/response/page/clientManifest.ts +25 -0
- package/server/services/router/response/page/document.tsx +199 -127
- package/server/services/router/response/page/index.tsx +89 -94
- package/server/services/router/service.ts +13 -15
- package/server/services/schema/index.ts +17 -26
- package/server/services/schema/request.ts +19 -33
- package/server/services/schema/router/index.ts +8 -11
- package/server/services/security/encrypt/aes/index.ts +15 -35
- package/server/utils/slug.ts +29 -32
- package/skills/clean-project-code/SKILL.md +63 -0
- package/skills/clean-project-code/agents/openai.yaml +4 -0
- package/tsconfig.common.json +4 -3
- package/tsconfig.json +4 -1
- package/types/aliases.d.ts +17 -21
- package/types/controller-input.test.ts +48 -0
- package/types/express-extra.d.ts +6 -0
- package/types/global/constants.d.ts +1 -0
- package/types/global/express-extra.d.ts +6 -0
- package/types/global/modules.d.ts +13 -16
- package/types/global/utils.d.ts +17 -49
- package/types/global/vendors.d.ts +62 -0
- package/types/icons.d.ts +65 -1
- package/types/uuid.d.ts +3 -0
- package/types/vendors.d.ts +62 -0
- package/cli/compiler/common/babel/index.ts +0 -173
- package/cli/compiler/common/babel/plugins/index.ts +0 -0
- package/cli/compiler/common/babel/plugins/services.ts +0 -586
- package/cli/compiler/common/babel/routes/imports.ts +0 -127
- package/cli/compiler/common/babel/routes/routes.ts +0 -1170
- package/client/services/captcha/index.ts +0 -67
- package/client/services/socket/index.ts +0 -147
- package/common/data/rte/nodes.ts +0 -83
- package/common/data/stats.ts +0 -90
- package/common/utils/rte.ts +0 -183
- package/server/services/auth/old.ts +0 -277
- package/server/services/cache/commands.ts +0 -41
- package/server/services/cache/index.ts +0 -297
- package/server/services/cache/service.json +0 -6
- package/server/services/socket/index.ts +0 -162
- package/server/services/socket/scope.ts +0 -226
- package/server/services/socket/service.json +0 -6
- package/server/services_old/SocketClient.ts +0 -92
- package/server/services_old/Token.old.ts +0 -97
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
|
|
5
|
+
import writeIfChanged from '../writeIfChanged';
|
|
6
|
+
|
|
7
|
+
type TRouteSide = 'client' | 'server';
|
|
8
|
+
type TRouteRuntime = 'client' | 'server';
|
|
9
|
+
|
|
10
|
+
type TImportedService = { importedName: string; localName: string };
|
|
11
|
+
|
|
12
|
+
type TRouteDefinition = { args: ts.NodeArray<ts.Expression>; methodName: string; serviceLocalName: string };
|
|
13
|
+
|
|
14
|
+
type TGeneratedClientRouteModuleOptions = { chunkId: string; filepath: string };
|
|
15
|
+
|
|
16
|
+
type TWriteGeneratedRouteModuleOptions = {
|
|
17
|
+
outputFilepath: string;
|
|
18
|
+
runtime: TRouteRuntime;
|
|
19
|
+
side: TRouteSide;
|
|
20
|
+
sourceFilepath: string;
|
|
21
|
+
clientRoute?: TGeneratedClientRouteModuleOptions;
|
|
22
|
+
routeSourceFilepaths?: Set<string>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const clientRouterImportSources = new Set(['@client/router', '@/client/router']);
|
|
26
|
+
const routerMethods = new Set(['page', 'error', 'get', 'post', 'put', 'delete', 'patch']);
|
|
27
|
+
|
|
28
|
+
const parseSourceFile = (filepath: string, code: string) =>
|
|
29
|
+
ts.createSourceFile(
|
|
30
|
+
filepath,
|
|
31
|
+
code,
|
|
32
|
+
ts.ScriptTarget.Latest,
|
|
33
|
+
true,
|
|
34
|
+
filepath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const normalizeFilepath = (value: string) => path.resolve(value).replace(/\\/g, '/');
|
|
38
|
+
|
|
39
|
+
const getNodeText = (sourceFile: ts.SourceFile, node: ts.Node) =>
|
|
40
|
+
sourceFile.text.slice(node.getStart(sourceFile), node.getEnd());
|
|
41
|
+
|
|
42
|
+
const routeModuleExtensions = ['.ts', '.tsx', '.js', '.jsx'];
|
|
43
|
+
|
|
44
|
+
const resolveRouteImport = (sourceFilepath: string, moduleSpecifier: string, routeSourceFilepaths?: Set<string>) => {
|
|
45
|
+
if (!routeSourceFilepaths || !moduleSpecifier.startsWith('.')) return undefined;
|
|
46
|
+
|
|
47
|
+
const absoluteBasePath = path.resolve(path.dirname(sourceFilepath), moduleSpecifier);
|
|
48
|
+
const candidates = [
|
|
49
|
+
absoluteBasePath,
|
|
50
|
+
...routeModuleExtensions.map((extension) => absoluteBasePath + extension),
|
|
51
|
+
...routeModuleExtensions.map((extension) => path.join(absoluteBasePath, `index${extension}`)),
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
return candidates.find((candidate) => routeSourceFilepaths.has(normalizeFilepath(candidate)));
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const addImportedService = (importedServices: TImportedService[], importedName: string, localName: string) => {
|
|
58
|
+
if (
|
|
59
|
+
importedServices.some(
|
|
60
|
+
(importedService) =>
|
|
61
|
+
importedService.importedName === importedName && importedService.localName === localName,
|
|
62
|
+
)
|
|
63
|
+
) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
importedServices.push({ importedName, localName });
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const collectImportedServices = (
|
|
71
|
+
sourceFile: ts.SourceFile,
|
|
72
|
+
side: TRouteSide,
|
|
73
|
+
stripRanges: Array<{ start: number; end: number }>,
|
|
74
|
+
) => {
|
|
75
|
+
const importedServices: TImportedService[] = [];
|
|
76
|
+
|
|
77
|
+
for (const statement of sourceFile.statements) {
|
|
78
|
+
if (!ts.isImportDeclaration(statement)) continue;
|
|
79
|
+
if (!statement.importClause) continue;
|
|
80
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
81
|
+
|
|
82
|
+
const source = statement.moduleSpecifier.text;
|
|
83
|
+
const isClientRouterImport = side === 'client' && clientRouterImportSources.has(source);
|
|
84
|
+
|
|
85
|
+
if (source !== '@app' && !isClientRouterImport) continue;
|
|
86
|
+
|
|
87
|
+
if (isClientRouterImport && statement.importClause.name) {
|
|
88
|
+
addImportedService(importedServices, 'Router', statement.importClause.name.text);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const specifier of statement.importClause.namedBindings
|
|
92
|
+
? ts.isNamedImports(statement.importClause.namedBindings)
|
|
93
|
+
? statement.importClause.namedBindings.elements
|
|
94
|
+
: []
|
|
95
|
+
: []) {
|
|
96
|
+
addImportedService(
|
|
97
|
+
importedServices,
|
|
98
|
+
specifier.propertyName?.text || specifier.name.text,
|
|
99
|
+
specifier.name.text,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
stripRanges.push({ start: statement.getStart(sourceFile), end: statement.getEnd() });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return importedServices;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const collectNestedRouteImports = (
|
|
110
|
+
sourceFile: ts.SourceFile,
|
|
111
|
+
sourceFilepath: string,
|
|
112
|
+
routeSourceFilepaths: Set<string> | undefined,
|
|
113
|
+
stripRanges: Array<{ start: number; end: number }>,
|
|
114
|
+
) => {
|
|
115
|
+
for (const statement of sourceFile.statements) {
|
|
116
|
+
if (!ts.isImportDeclaration(statement)) continue;
|
|
117
|
+
if (statement.importClause) continue;
|
|
118
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
119
|
+
|
|
120
|
+
const routeImportPath = resolveRouteImport(
|
|
121
|
+
sourceFilepath,
|
|
122
|
+
statement.moduleSpecifier.text,
|
|
123
|
+
routeSourceFilepaths,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
if (!routeImportPath) continue;
|
|
127
|
+
|
|
128
|
+
stripRanges.push({ start: statement.getStart(sourceFile), end: statement.getEnd() });
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const collectRouteDefinitions = (
|
|
133
|
+
sourceFile: ts.SourceFile,
|
|
134
|
+
importedServices: TImportedService[],
|
|
135
|
+
stripRanges: Array<{ start: number; end: number }>,
|
|
136
|
+
) => {
|
|
137
|
+
const importedServiceNames = new Set(importedServices.map((importedService) => importedService.localName));
|
|
138
|
+
const definitions: TRouteDefinition[] = [];
|
|
139
|
+
|
|
140
|
+
for (const statement of sourceFile.statements) {
|
|
141
|
+
if (!ts.isExpressionStatement(statement)) continue;
|
|
142
|
+
if (!ts.isCallExpression(statement.expression)) continue;
|
|
143
|
+
if (!ts.isPropertyAccessExpression(statement.expression.expression)) continue;
|
|
144
|
+
|
|
145
|
+
const callee = statement.expression.expression;
|
|
146
|
+
if (!ts.isIdentifier(callee.expression)) continue;
|
|
147
|
+
if (!routerMethods.has(callee.name.text)) continue;
|
|
148
|
+
if (!importedServiceNames.has(callee.expression.text)) continue;
|
|
149
|
+
|
|
150
|
+
definitions.push({
|
|
151
|
+
args: statement.expression.arguments,
|
|
152
|
+
methodName: callee.name.text,
|
|
153
|
+
serviceLocalName: callee.expression.text,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
stripRanges.push({ start: statement.getStart(sourceFile), end: statement.getEnd() });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return definitions;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const buildRemainingSource = (sourceFile: ts.SourceFile, stripRanges: Array<{ start: number; end: number }>) => {
|
|
163
|
+
const sortedRanges = stripRanges.sort((a, b) => a.start - b.start);
|
|
164
|
+
const chunks: string[] = [];
|
|
165
|
+
let cursor = 0;
|
|
166
|
+
|
|
167
|
+
for (const range of sortedRanges) {
|
|
168
|
+
if (cursor < range.start) chunks.push(sourceFile.text.slice(cursor, range.start));
|
|
169
|
+
cursor = Math.max(cursor, range.end);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (cursor < sourceFile.text.length) {
|
|
173
|
+
chunks.push(sourceFile.text.slice(cursor));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return chunks.join('').trim();
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const normalizeRelativeImportPath = (value: string) => (value.startsWith('.') ? value : `./${value}`);
|
|
180
|
+
|
|
181
|
+
const rebaseRelativeModuleSpecifiers = (code: string, outputFilepath: string, sourceFilepath: string) => {
|
|
182
|
+
const outputDir = path.dirname(outputFilepath);
|
|
183
|
+
const sourceDir = path.dirname(sourceFilepath);
|
|
184
|
+
const sourceFile = parseSourceFile(outputFilepath, code);
|
|
185
|
+
const replacements: Array<{ start: number; end: number; value: string }> = [];
|
|
186
|
+
|
|
187
|
+
const addReplacement = (literal: ts.StringLiteralLike) => {
|
|
188
|
+
if (!literal.text.startsWith('.')) return;
|
|
189
|
+
|
|
190
|
+
const absoluteTarget = path.resolve(sourceDir, literal.text);
|
|
191
|
+
const nextRelativePath = normalizeRelativeImportPath(
|
|
192
|
+
path.relative(outputDir, absoluteTarget).replace(/\\/g, '/'),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
replacements.push({
|
|
196
|
+
start: literal.getStart(sourceFile),
|
|
197
|
+
end: literal.getEnd(),
|
|
198
|
+
value: JSON.stringify(nextRelativePath),
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const visit = (node: ts.Node) => {
|
|
203
|
+
if (
|
|
204
|
+
(ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
|
|
205
|
+
node.moduleSpecifier &&
|
|
206
|
+
ts.isStringLiteral(node.moduleSpecifier)
|
|
207
|
+
) {
|
|
208
|
+
addReplacement(node.moduleSpecifier);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (
|
|
212
|
+
ts.isCallExpression(node) &&
|
|
213
|
+
node.arguments.length > 0 &&
|
|
214
|
+
ts.isStringLiteral(node.arguments[0]) &&
|
|
215
|
+
(node.expression.kind === ts.SyntaxKind.ImportKeyword ||
|
|
216
|
+
(ts.isIdentifier(node.expression) && node.expression.text === 'require'))
|
|
217
|
+
) {
|
|
218
|
+
addReplacement(node.arguments[0]);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (
|
|
222
|
+
ts.isImportTypeNode(node) &&
|
|
223
|
+
ts.isLiteralTypeNode(node.argument) &&
|
|
224
|
+
ts.isStringLiteral(node.argument.literal)
|
|
225
|
+
) {
|
|
226
|
+
addReplacement(node.argument.literal);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
ts.forEachChild(node, visit);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
ts.forEachChild(sourceFile, visit);
|
|
233
|
+
|
|
234
|
+
return replacements
|
|
235
|
+
.sort((a, b) => b.start - a.start)
|
|
236
|
+
.reduce(
|
|
237
|
+
(currentCode, replacement) =>
|
|
238
|
+
currentCode.slice(0, replacement.start) + replacement.value + currentCode.slice(replacement.end),
|
|
239
|
+
code,
|
|
240
|
+
);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const buildDestructuring = (importedServices: TImportedService[]) => {
|
|
244
|
+
const parts = importedServices.map(({ importedName, localName }) =>
|
|
245
|
+
importedName === localName ? importedName : `${importedName}: ${localName}`,
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
return `const { ${parts.join(', ')} } = app;`;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const buildClientRegisterArgs = (
|
|
252
|
+
sourceFile: ts.SourceFile,
|
|
253
|
+
definition: TRouteDefinition,
|
|
254
|
+
clientRoute: TGeneratedClientRouteModuleOptions,
|
|
255
|
+
) => {
|
|
256
|
+
const [, ...routeArgs] = [...definition.args];
|
|
257
|
+
const injectedOptions = `{ id: ${JSON.stringify(clientRoute.chunkId)}, filepath: ${JSON.stringify(clientRoute.filepath)} }`;
|
|
258
|
+
|
|
259
|
+
if (routeArgs.length === 1) {
|
|
260
|
+
return [injectedOptions, getNodeText(sourceFile, routeArgs[0])];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (routeArgs.length === 2) {
|
|
264
|
+
if (ts.isObjectLiteralExpression(routeArgs[0])) {
|
|
265
|
+
return [
|
|
266
|
+
`{ ...(${getNodeText(sourceFile, routeArgs[0])}), id: ${JSON.stringify(clientRoute.chunkId)}, filepath: ${JSON.stringify(clientRoute.filepath)} }`,
|
|
267
|
+
getNodeText(sourceFile, routeArgs[1]),
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return [injectedOptions, getNodeText(sourceFile, routeArgs[0]), getNodeText(sourceFile, routeArgs[1])];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (routeArgs.length === 3 && ts.isObjectLiteralExpression(routeArgs[0])) {
|
|
275
|
+
return [
|
|
276
|
+
`{ ...(${getNodeText(sourceFile, routeArgs[0])}), id: ${JSON.stringify(clientRoute.chunkId)}, filepath: ${JSON.stringify(clientRoute.filepath)} }`,
|
|
277
|
+
getNodeText(sourceFile, routeArgs[1]),
|
|
278
|
+
getNodeText(sourceFile, routeArgs[2]),
|
|
279
|
+
];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
throw new Error(
|
|
283
|
+
`Unsupported client route signature in ${sourceFile.fileName}. Expected Router.page/error with 2-4 arguments.`,
|
|
284
|
+
);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const buildRegisterStatements = (
|
|
288
|
+
sourceFile: ts.SourceFile,
|
|
289
|
+
side: TRouteSide,
|
|
290
|
+
definitions: TRouteDefinition[],
|
|
291
|
+
clientRoute?: TGeneratedClientRouteModuleOptions,
|
|
292
|
+
) => {
|
|
293
|
+
if (side === 'client') {
|
|
294
|
+
if (!clientRoute) {
|
|
295
|
+
throw new Error(`Missing client route metadata for ${sourceFile.fileName}.`);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (definitions.length !== 1) {
|
|
299
|
+
throw new Error(
|
|
300
|
+
`Frontend route definition files can contain only one route definition. ${definitions.length} were found in ${sourceFile.fileName}.`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const definition = definitions[0];
|
|
305
|
+
const [routePath, ...routeArgs] = [...definition.args];
|
|
306
|
+
const finalArgs = [
|
|
307
|
+
getNodeText(sourceFile, routePath),
|
|
308
|
+
...buildClientRegisterArgs(sourceFile, definition, clientRoute),
|
|
309
|
+
];
|
|
310
|
+
|
|
311
|
+
return [`return ${definition.serviceLocalName}.${definition.methodName}(${finalArgs.join(', ')});`];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return definitions.map((definition) => {
|
|
315
|
+
const args = [...definition.args].map((arg) => getNodeText(sourceFile, arg));
|
|
316
|
+
|
|
317
|
+
return `${definition.serviceLocalName}.${definition.methodName}(${args.join(', ')});`;
|
|
318
|
+
});
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
export const getGeneratedRouteModuleFilepath = (generatedRoot: string, sourceRoot: string, sourceFilepath: string) =>
|
|
322
|
+
path.join(generatedRoot, 'route-modules', path.relative(sourceRoot, sourceFilepath));
|
|
323
|
+
|
|
324
|
+
export const writeGeneratedRouteModule = ({
|
|
325
|
+
outputFilepath,
|
|
326
|
+
runtime,
|
|
327
|
+
side,
|
|
328
|
+
sourceFilepath,
|
|
329
|
+
clientRoute,
|
|
330
|
+
routeSourceFilepaths,
|
|
331
|
+
}: TWriteGeneratedRouteModuleOptions) => {
|
|
332
|
+
const code = fs.readFileSync(sourceFilepath, 'utf8');
|
|
333
|
+
const sourceFile = parseSourceFile(sourceFilepath, code);
|
|
334
|
+
const stripRanges: Array<{ start: number; end: number }> = [];
|
|
335
|
+
const importedServices = collectImportedServices(sourceFile, side, stripRanges);
|
|
336
|
+
collectNestedRouteImports(sourceFile, sourceFilepath, routeSourceFilepaths, stripRanges);
|
|
337
|
+
const definitions = collectRouteDefinitions(sourceFile, importedServices, stripRanges);
|
|
338
|
+
|
|
339
|
+
if (definitions.length === 0) {
|
|
340
|
+
throw new Error(`No route definitions were found in ${sourceFilepath}.`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const remainingSource = rebaseRelativeModuleSpecifiers(
|
|
344
|
+
buildRemainingSource(sourceFile, stripRanges),
|
|
345
|
+
outputFilepath,
|
|
346
|
+
sourceFilepath,
|
|
347
|
+
);
|
|
348
|
+
const registerStatements = buildRegisterStatements(sourceFile, side, definitions, clientRoute);
|
|
349
|
+
const runtimeAppImportPath = runtime === 'client' ? '@/client/index' : '@/server/.generated/app';
|
|
350
|
+
|
|
351
|
+
const content = `/*----------------------------------
|
|
352
|
+
- GENERATED FILE
|
|
353
|
+
----------------------------------*/
|
|
354
|
+
|
|
355
|
+
// This file is generated by Proteum from ${path.relative(process.cwd(), sourceFilepath).replace(/\\/g, '/')}.
|
|
356
|
+
// Do not edit it manually.
|
|
357
|
+
|
|
358
|
+
import type __GeneratedRouteApp from ${JSON.stringify(runtimeAppImportPath)};
|
|
359
|
+
|
|
360
|
+
${remainingSource}
|
|
361
|
+
${remainingSource ? '\n' : ''}export const __register = (app: __GeneratedRouteApp) => {
|
|
362
|
+
${buildDestructuring(importedServices)}
|
|
363
|
+
${registerStatements.join('\n ')}
|
|
364
|
+
};
|
|
365
|
+
`;
|
|
366
|
+
|
|
367
|
+
return writeIfChanged(outputFilepath, content);
|
|
368
|
+
};
|
|
@@ -3,12 +3,9 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// npm
|
|
6
|
-
import webpack from 'webpack';
|
|
7
6
|
import dayjs from 'dayjs';
|
|
8
7
|
import path from 'path';
|
|
9
|
-
|
|
10
|
-
// Plugins
|
|
11
|
-
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
8
|
+
import { rspack, type Configuration } from '@rspack/core';
|
|
12
9
|
|
|
13
10
|
// Core
|
|
14
11
|
import cli from '../..';
|
|
@@ -22,35 +19,33 @@ import type { TAppSide } from '../../app';
|
|
|
22
19
|
----------------------------------*/
|
|
23
20
|
|
|
24
21
|
export const regex = {
|
|
25
|
-
scripts: /\.(ts|tsx)$/,
|
|
22
|
+
scripts: /\.(ts|tsx|js|jsx)$/,
|
|
26
23
|
style: /\.(css|less|scss)$/,
|
|
27
24
|
images: /\.(bmp|gif|jpg|jpeg|png|ico|svg)$/, // SVG gérés par SVGR
|
|
28
25
|
fonts: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
|
|
29
26
|
staticAssetName: /*isDebug ? '[name].[ext].[hash:8]' :*/ '[hash:8][ext]',
|
|
30
|
-
}
|
|
27
|
+
};
|
|
31
28
|
|
|
32
29
|
/*----------------------------------
|
|
33
30
|
- TYPES
|
|
34
31
|
----------------------------------*/
|
|
35
32
|
|
|
36
|
-
export type TCompileMode = 'dev' | 'prod'
|
|
37
|
-
export type TCompileOutputTarget = 'dev' | 'bin'
|
|
33
|
+
export type TCompileMode = 'dev' | 'prod';
|
|
34
|
+
export type TCompileOutputTarget = 'dev' | 'bin';
|
|
38
35
|
|
|
39
36
|
/*----------------------------------
|
|
40
37
|
- BASE CONFIG
|
|
41
38
|
----------------------------------*/
|
|
42
39
|
|
|
43
|
-
export default function createCommonConfig(
|
|
44
|
-
app: App,
|
|
45
|
-
side: TAppSide,
|
|
40
|
+
export default function createCommonConfig(
|
|
41
|
+
app: App,
|
|
42
|
+
side: TAppSide,
|
|
46
43
|
mode: TCompileMode,
|
|
47
44
|
outputTarget: TCompileOutputTarget = mode === 'dev' ? 'dev' : 'bin',
|
|
48
|
-
):
|
|
49
|
-
|
|
45
|
+
): Configuration {
|
|
50
46
|
const dev = mode === 'dev';
|
|
51
|
-
const
|
|
52
|
-
const config:
|
|
53
|
-
|
|
47
|
+
const enableFilesystemCache = dev ? cli.args.cache !== false : cli.args.cache === true;
|
|
48
|
+
const config: Configuration = {
|
|
54
49
|
// Project root
|
|
55
50
|
context: app.paths.root,
|
|
56
51
|
|
|
@@ -69,16 +64,13 @@ export default function createCommonConfig(
|
|
|
69
64
|
},
|
|
70
65
|
|
|
71
66
|
plugins: [
|
|
72
|
-
|
|
73
|
-
// https://webpack.js.org/plugins/define-plugin/
|
|
74
|
-
new webpack.DefinePlugin({
|
|
75
|
-
|
|
67
|
+
new rspack.DefinePlugin({
|
|
76
68
|
// Flags
|
|
77
69
|
__DEV__: dev,
|
|
78
70
|
SERVER: side === 'server',
|
|
79
71
|
|
|
80
72
|
// Core
|
|
81
|
-
CORE_VERSION: JSON.stringify(
|
|
73
|
+
CORE_VERSION: JSON.stringify(cli.packageJson.version),
|
|
82
74
|
CORE_PATH: JSON.stringify(cli.paths.core.root),
|
|
83
75
|
|
|
84
76
|
// Application
|
|
@@ -87,30 +79,14 @@ export default function createCommonConfig(
|
|
|
87
79
|
APP_PATH: JSON.stringify(app.paths.root),
|
|
88
80
|
APP_NAME: JSON.stringify(app.identity.web.title),
|
|
89
81
|
APP_OUTPUT_DIR: JSON.stringify(path.basename(app.outputPath(outputTarget))),
|
|
82
|
+
PROTEUM_DEV_EVENT_PORT: JSON.stringify(dev ? (app.devEventPort ?? null) : null),
|
|
90
83
|
PROTEUM_ROUTER_PORT_OVERRIDE: JSON.stringify(app.routerPortOverride ?? null),
|
|
91
|
-
|
|
92
84
|
}),
|
|
93
85
|
|
|
94
|
-
...(
|
|
95
|
-
|
|
96
|
-
new BundleAnalyzerPlugin({
|
|
97
|
-
defaultSizes: 'stat',
|
|
98
|
-
openAnalyzer: false
|
|
99
|
-
}),
|
|
100
|
-
|
|
101
|
-
] : []),
|
|
102
|
-
|
|
103
|
-
...(dev ? [
|
|
104
|
-
|
|
105
|
-
// HMR
|
|
106
|
-
//new webpack.HotModuleReplacementPlugin()
|
|
107
|
-
|
|
108
|
-
] : []),
|
|
109
|
-
|
|
86
|
+
...(dev ? [] : []),
|
|
110
87
|
],
|
|
111
88
|
|
|
112
89
|
resolve: {
|
|
113
|
-
|
|
114
90
|
// Empêche le remplatcement des chemins vers les liens symboliques par leur vrai chemin
|
|
115
91
|
// Permet de conserver le chemin des packages enregistrés via npm link
|
|
116
92
|
// Equivalent tsconfig: preserveSymlinks: true
|
|
@@ -127,39 +103,24 @@ export default function createCommonConfig(
|
|
|
127
103
|
performance: false,
|
|
128
104
|
|
|
129
105
|
// Smoke builds should fail immediately on the first compilation error.
|
|
130
|
-
bail:
|
|
131
|
-
|
|
132
|
-
// Persistent cache speeds up repeated local
|
|
133
|
-
cache:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
106
|
+
bail: !dev,
|
|
107
|
+
|
|
108
|
+
// Persistent cache speeds up repeated local dev and prod build invocations.
|
|
109
|
+
cache: enableFilesystemCache
|
|
110
|
+
? {
|
|
111
|
+
type: 'filesystem',
|
|
112
|
+
cacheDirectory: path.join(app.paths.cache, 'rspack', side, mode),
|
|
113
|
+
compression: false,
|
|
114
|
+
buildDependencies: { config: [__filename] },
|
|
115
|
+
}
|
|
116
|
+
: false,
|
|
141
117
|
|
|
142
118
|
// Increase compilation performance
|
|
143
119
|
profile: false,
|
|
144
120
|
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
cached: dev,
|
|
149
|
-
cachedAssets: dev,
|
|
150
|
-
chunks: dev,
|
|
151
|
-
chunkModules: dev,
|
|
152
|
-
colors: true,
|
|
153
|
-
hash: dev,
|
|
154
|
-
modules: dev,
|
|
155
|
-
reasons: dev,
|
|
156
|
-
timings: true,
|
|
157
|
-
version: dev,
|
|
158
|
-
errorDetails: true
|
|
159
|
-
},
|
|
160
|
-
|
|
161
|
-
}
|
|
121
|
+
// Keep output compact while preserving timing and error context.
|
|
122
|
+
stats: { colors: true, errors: true, errorDetails: true, timings: true, warnings: true },
|
|
123
|
+
};
|
|
162
124
|
|
|
163
125
|
return config;
|
|
164
|
-
|
|
165
126
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = function forbidSsrImportLoader() {
|
|
4
|
+
const resourcePath = this.resourcePath || this.request || '<unknown>';
|
|
5
|
+
|
|
6
|
+
throw new Error(
|
|
7
|
+
[
|
|
8
|
+
'SSR-only module imported into the client bundle:',
|
|
9
|
+
resourcePath,
|
|
10
|
+
'Provide the browser implementation without the ".ssr" suffix and keep SSR-specific logic in "*.ssr.tsx" files.',
|
|
11
|
+
].join('\n'),
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
|
|
3
|
+
type TWebpackAliases = Record<string, string | string[]>;
|
|
4
|
+
|
|
5
|
+
export const toRspackAliases = (aliases: TWebpackAliases) =>
|
|
6
|
+
Object.fromEntries(
|
|
7
|
+
Object.entries(aliases).map(([alias, value]) => {
|
|
8
|
+
const candidates = Array.isArray(value) ? value : [value];
|
|
9
|
+
const selectedCandidate = candidates.find((candidate) => fs.existsSync(candidate)) || candidates[0];
|
|
10
|
+
|
|
11
|
+
return [alias, selectedCandidate];
|
|
12
|
+
}),
|
|
13
|
+
);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { App, TAppSide } from '@cli/app';
|
|
2
|
+
import type { RuleSetRule } from '@rspack/core';
|
|
3
|
+
|
|
4
|
+
type TScriptRuleOptions = { app: App; side: TAppSide; dev: boolean };
|
|
5
|
+
|
|
6
|
+
const shouldExcludeNodeModule = (filePath: string) => {
|
|
7
|
+
if (!filePath.includes('node_modules')) return false;
|
|
8
|
+
|
|
9
|
+
if (filePath.includes('node_modules/proteum') && !filePath.includes('node_modules/proteum/node_modules')) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const getSwcTarget = (side: TAppSide) => (side === 'client' ? 'es2022' : 'es2021');
|
|
17
|
+
|
|
18
|
+
module.exports = ({ side, dev }: TScriptRuleOptions): RuleSetRule[] => {
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
loader: 'builtin:swc-loader',
|
|
22
|
+
type: 'javascript/auto',
|
|
23
|
+
exclude: shouldExcludeNodeModule,
|
|
24
|
+
options: {
|
|
25
|
+
sourceMaps: true,
|
|
26
|
+
jsc: {
|
|
27
|
+
target: getSwcTarget(side),
|
|
28
|
+
loose: true,
|
|
29
|
+
parser: { syntax: 'typescript', tsx: true, decorators: false, dynamicImport: true },
|
|
30
|
+
transform: {
|
|
31
|
+
react: { runtime: 'automatic', importSource: 'preact', development: dev, refresh: false },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
};
|