proteum 1.0.2 → 2.0.0-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.
- package/AGENTS.md +101 -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 +13 -11
- package/cli/app/index.ts +74 -82
- package/cli/bin.js +1 -1
- package/cli/commands/build.ts +51 -14
- 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 +189 -64
- 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 +18 -0
- package/cli/commands/typecheck.ts +18 -0
- package/cli/compiler/client/identite.ts +80 -53
- package/cli/compiler/client/index.ts +139 -213
- 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 +11 -22
- package/cli/compiler/common/generatedRouteModules.ts +368 -0
- package/cli/compiler/common/index.ts +31 -65
- 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 +781 -230
- package/cli/compiler/server/index.ts +59 -75
- package/cli/compiler/writeIfChanged.ts +21 -0
- package/cli/index.ts +71 -72
- 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/doc/TODO.md +1 -1
- package/eslint.js +62 -0
- package/package.json +14 -49
- 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 +48 -59
- 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 +78 -73
- 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 -35
- 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 +13 -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 -170
- 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 -1130
- 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,32 +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'
|
|
33
|
+
export type TCompileMode = 'dev' | 'prod';
|
|
34
|
+
export type TCompileOutputTarget = 'dev' | 'bin';
|
|
37
35
|
|
|
38
36
|
/*----------------------------------
|
|
39
37
|
- BASE CONFIG
|
|
40
38
|
----------------------------------*/
|
|
41
39
|
|
|
42
|
-
export default function createCommonConfig(
|
|
43
|
-
app: App,
|
|
44
|
-
side: TAppSide,
|
|
40
|
+
export default function createCommonConfig(
|
|
41
|
+
app: App,
|
|
42
|
+
side: TAppSide,
|
|
45
43
|
mode: TCompileMode,
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
outputTarget: TCompileOutputTarget = mode === 'dev' ? 'dev' : 'bin',
|
|
45
|
+
): Configuration {
|
|
48
46
|
const dev = mode === 'dev';
|
|
49
|
-
const
|
|
50
|
-
|
|
47
|
+
const enableFilesystemCache = dev ? cli.args.cache !== false : cli.args.cache === true;
|
|
48
|
+
const config: Configuration = {
|
|
51
49
|
// Project root
|
|
52
50
|
context: app.paths.root,
|
|
53
51
|
|
|
@@ -66,16 +64,13 @@ export default function createCommonConfig(
|
|
|
66
64
|
},
|
|
67
65
|
|
|
68
66
|
plugins: [
|
|
69
|
-
|
|
70
|
-
// https://webpack.js.org/plugins/define-plugin/
|
|
71
|
-
new webpack.DefinePlugin({
|
|
72
|
-
|
|
67
|
+
new rspack.DefinePlugin({
|
|
73
68
|
// Flags
|
|
74
69
|
__DEV__: dev,
|
|
75
70
|
SERVER: side === 'server',
|
|
76
71
|
|
|
77
72
|
// Core
|
|
78
|
-
CORE_VERSION: JSON.stringify(
|
|
73
|
+
CORE_VERSION: JSON.stringify(cli.packageJson.version),
|
|
79
74
|
CORE_PATH: JSON.stringify(cli.paths.core.root),
|
|
80
75
|
|
|
81
76
|
// Application
|
|
@@ -83,29 +78,15 @@ export default function createCommonConfig(
|
|
|
83
78
|
BUILD_ID: JSON.stringify(app.buildId),
|
|
84
79
|
APP_PATH: JSON.stringify(app.paths.root),
|
|
85
80
|
APP_NAME: JSON.stringify(app.identity.web.title),
|
|
86
|
-
|
|
81
|
+
APP_OUTPUT_DIR: JSON.stringify(path.basename(app.outputPath(outputTarget))),
|
|
82
|
+
PROTEUM_DEV_EVENT_PORT: JSON.stringify(dev ? (app.devEventPort ?? null) : null),
|
|
83
|
+
PROTEUM_ROUTER_PORT_OVERRIDE: JSON.stringify(app.routerPortOverride ?? null),
|
|
87
84
|
}),
|
|
88
85
|
|
|
89
|
-
...(
|
|
90
|
-
|
|
91
|
-
new BundleAnalyzerPlugin({
|
|
92
|
-
defaultSizes: 'stat',
|
|
93
|
-
openAnalyzer: false
|
|
94
|
-
}),
|
|
95
|
-
|
|
96
|
-
] : []),
|
|
97
|
-
|
|
98
|
-
...(dev ? [
|
|
99
|
-
|
|
100
|
-
// HMR
|
|
101
|
-
//new webpack.HotModuleReplacementPlugin()
|
|
102
|
-
|
|
103
|
-
] : []),
|
|
104
|
-
|
|
86
|
+
...(dev ? [] : []),
|
|
105
87
|
],
|
|
106
88
|
|
|
107
89
|
resolve: {
|
|
108
|
-
|
|
109
90
|
// Empêche le remplatcement des chemins vers les liens symboliques par leur vrai chemin
|
|
110
91
|
// Permet de conserver le chemin des packages enregistrés via npm link
|
|
111
92
|
// Equivalent tsconfig: preserveSymlinks: true
|
|
@@ -121,40 +102,25 @@ export default function createCommonConfig(
|
|
|
121
102
|
// our own hints via the FileSizeReporter
|
|
122
103
|
performance: false,
|
|
123
104
|
|
|
124
|
-
//
|
|
105
|
+
// Smoke builds should fail immediately on the first compilation error.
|
|
125
106
|
bail: !dev,
|
|
126
107
|
|
|
127
|
-
// Persistent cache speeds up
|
|
128
|
-
cache:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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,
|
|
136
117
|
|
|
137
118
|
// Increase compilation performance
|
|
138
119
|
profile: false,
|
|
139
120
|
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
cached: dev,
|
|
144
|
-
cachedAssets: dev,
|
|
145
|
-
chunks: dev,
|
|
146
|
-
chunkModules: dev,
|
|
147
|
-
colors: true,
|
|
148
|
-
hash: dev,
|
|
149
|
-
modules: dev,
|
|
150
|
-
reasons: dev,
|
|
151
|
-
timings: true,
|
|
152
|
-
version: dev,
|
|
153
|
-
errorDetails: true
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
}
|
|
121
|
+
// Keep output compact while preserving timing and error context.
|
|
122
|
+
stats: { colors: true, errors: true, errorDetails: true, timings: true, warnings: true },
|
|
123
|
+
};
|
|
157
124
|
|
|
158
125
|
return config;
|
|
159
|
-
|
|
160
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
|
+
};
|