@jay-framework/dev-server 0.8.0 → 0.10.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/dist/index.d.ts +79 -9
- package/dist/index.js +1585 -57
- package/package.json +13 -12
package/dist/index.js
CHANGED
|
@@ -6,17 +6,1223 @@ var __publicField = (obj, key, value) => {
|
|
|
6
6
|
};
|
|
7
7
|
import { createServer } from "vite";
|
|
8
8
|
import { scanRoutes, routeToExpressRoute } from "@jay-framework/stack-route-scanner";
|
|
9
|
-
import { runInitCallbacks, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, DevSlowlyChangingPhase, loadPageParts, renderFastChangingData, generateClientScript } from "@jay-framework/stack-server-runtime";
|
|
9
|
+
import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, actionRegistry, discoverAndRegisterActions, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, DevSlowlyChangingPhase, preparePluginClientInits, loadPageParts, renderFastChangingData, getClientInitData, generateClientScript } from "@jay-framework/stack-server-runtime";
|
|
10
10
|
import { jayRuntime } from "@jay-framework/vite-plugin";
|
|
11
|
+
import { createRequire } from "module";
|
|
12
|
+
import "@jay-framework/compiler-shared";
|
|
11
13
|
import * as path from "node:path";
|
|
12
14
|
import path__default from "node:path";
|
|
15
|
+
import "@jay-framework/compiler-jay-html";
|
|
13
16
|
import * as fs from "node:fs";
|
|
14
17
|
import { pathToFileURL } from "node:url";
|
|
18
|
+
const s$1 = createRequire(import.meta.url), e$1 = s$1("typescript"), c$1 = new Proxy(e$1, {
|
|
19
|
+
get(t, r) {
|
|
20
|
+
return t[r];
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
var __defProp2 = Object.defineProperty;
|
|
24
|
+
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
25
|
+
var __publicField2 = (obj, key, value) => {
|
|
26
|
+
__defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
27
|
+
return value;
|
|
28
|
+
};
|
|
29
|
+
const s = createRequire(import.meta.url), e = s("typescript"), c = new Proxy(e, {
|
|
30
|
+
get(t, r) {
|
|
31
|
+
return t[r];
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const {
|
|
35
|
+
visitEachChild: visitEachChild$5,
|
|
36
|
+
isArrowFunction: isArrowFunction$4,
|
|
37
|
+
isFunctionExpression: isFunctionExpression$1,
|
|
38
|
+
createSourceFile: createSourceFile$1,
|
|
39
|
+
ScriptTarget: ScriptTarget$1,
|
|
40
|
+
isFunctionDeclaration: isFunctionDeclaration$3,
|
|
41
|
+
isMethodDeclaration,
|
|
42
|
+
isConstructorDeclaration,
|
|
43
|
+
isGetAccessorDeclaration,
|
|
44
|
+
isSetAccessorDeclaration,
|
|
45
|
+
createPrinter: createPrinter$1,
|
|
46
|
+
NewLineKind,
|
|
47
|
+
EmitHint,
|
|
48
|
+
setTextRange
|
|
49
|
+
} = c;
|
|
50
|
+
createPrinter$1({
|
|
51
|
+
newLine: NewLineKind.LineFeed
|
|
52
|
+
});
|
|
53
|
+
function isFunctionLikeDeclarationBase(node) {
|
|
54
|
+
return isFunctionExpression$1(node) || isArrowFunction$4(node) || isFunctionDeclaration$3(node) || isMethodDeclaration(node) || isConstructorDeclaration(node) || isGetAccessorDeclaration(node) || isSetAccessorDeclaration(node);
|
|
55
|
+
}
|
|
56
|
+
function mkTransformer(fileTransformer, config) {
|
|
57
|
+
return (context) => {
|
|
58
|
+
const { factory } = context;
|
|
59
|
+
return (sourceFile) => {
|
|
60
|
+
return fileTransformer({ factory, context, sourceFile, ...config || {} });
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const {
|
|
65
|
+
isIdentifier: isIdentifier$9,
|
|
66
|
+
isStatement: isStatement$3,
|
|
67
|
+
isObjectBindingPattern,
|
|
68
|
+
isArrayBindingPattern,
|
|
69
|
+
isBindingElement,
|
|
70
|
+
isPropertyAccessExpression: isPropertyAccessExpression$5,
|
|
71
|
+
isElementAccessExpression: isElementAccessExpression$1,
|
|
72
|
+
isStringLiteral: isStringLiteral$8,
|
|
73
|
+
isParenthesizedExpression,
|
|
74
|
+
isAsExpression,
|
|
75
|
+
isObjectLiteralExpression,
|
|
76
|
+
isPropertyAssignment: isPropertyAssignment$1,
|
|
77
|
+
isShorthandPropertyAssignment,
|
|
78
|
+
isNumericLiteral,
|
|
79
|
+
isToken,
|
|
80
|
+
isNamespaceImport,
|
|
81
|
+
isNamedImports: isNamedImports$1,
|
|
82
|
+
isArrowFunction: isArrowFunction$2,
|
|
83
|
+
isFunctionExpression,
|
|
84
|
+
isCallExpression: isCallExpression$6,
|
|
85
|
+
NodeFlags,
|
|
86
|
+
SyntaxKind: SyntaxKind$5
|
|
87
|
+
} = c;
|
|
88
|
+
var VariableRootType = /* @__PURE__ */ ((VariableRootType2) => {
|
|
89
|
+
VariableRootType2[VariableRootType2["FunctionParameter"] = 0] = "FunctionParameter";
|
|
90
|
+
VariableRootType2[VariableRootType2["FunctionDefinition"] = 1] = "FunctionDefinition";
|
|
91
|
+
VariableRootType2[VariableRootType2["Literal"] = 2] = "Literal";
|
|
92
|
+
VariableRootType2[VariableRootType2["ImportModule"] = 3] = "ImportModule";
|
|
93
|
+
VariableRootType2[VariableRootType2["FunctionCall"] = 4] = "FunctionCall";
|
|
94
|
+
VariableRootType2[VariableRootType2["Global"] = 5] = "Global";
|
|
95
|
+
VariableRootType2[VariableRootType2["Other"] = 6] = "Other";
|
|
96
|
+
return VariableRootType2;
|
|
97
|
+
})(VariableRootType || {});
|
|
98
|
+
function mkParameterVariableRoot(param, paramIndex) {
|
|
99
|
+
return { kind: 0, param, paramIndex };
|
|
100
|
+
}
|
|
101
|
+
function mkFunctionVariableRoot(func) {
|
|
102
|
+
return { kind: 1, func };
|
|
103
|
+
}
|
|
104
|
+
function mkLiteralVariableRoot(literal) {
|
|
105
|
+
return { kind: 2, literal };
|
|
106
|
+
}
|
|
107
|
+
function mkImportModuleVariableRoot(module, importType) {
|
|
108
|
+
return { kind: 3, module, importType };
|
|
109
|
+
}
|
|
110
|
+
function mkFunctionCallVariableRoot(node) {
|
|
111
|
+
return { kind: 4, node };
|
|
112
|
+
}
|
|
113
|
+
function mkGlobalVariableRoot(name) {
|
|
114
|
+
return { kind: 5, name };
|
|
115
|
+
}
|
|
116
|
+
function mkOtherVariableRoot(node) {
|
|
117
|
+
return { kind: 6, node };
|
|
118
|
+
}
|
|
119
|
+
function isImportModuleVariableRoot(vr) {
|
|
120
|
+
return vr.kind === 3;
|
|
121
|
+
}
|
|
122
|
+
function mkVariable(members) {
|
|
123
|
+
return Object.fromEntries(Object.entries(members).filter(([, value]) => value !== void 0));
|
|
124
|
+
}
|
|
125
|
+
const UNKNOWN_VARIABLE = {};
|
|
126
|
+
const getAccessedByProperty = (binding, accessedFrom, propertyName) => {
|
|
127
|
+
return accessedFrom ? propertyName ? isIdentifier$9(propertyName) ? propertyName.text : void 0 : binding.text : void 0;
|
|
128
|
+
};
|
|
129
|
+
function findDeclaringStatement(node) {
|
|
130
|
+
if (!node)
|
|
131
|
+
return void 0;
|
|
132
|
+
else if (isStatement$3(node))
|
|
133
|
+
return node;
|
|
134
|
+
else
|
|
135
|
+
return findDeclaringStatement(node.parent);
|
|
136
|
+
}
|
|
137
|
+
function tsBindingNameToVariable(binding, accessedFrom, assignedFrom, propertyName, root) {
|
|
138
|
+
if (isIdentifier$9(binding)) {
|
|
139
|
+
return [
|
|
140
|
+
mkVariable({
|
|
141
|
+
name: binding.text,
|
|
142
|
+
accessedFrom,
|
|
143
|
+
accessedByProperty: getAccessedByProperty(binding, accessedFrom, propertyName),
|
|
144
|
+
assignedFrom,
|
|
145
|
+
root,
|
|
146
|
+
definingStatement: findDeclaringStatement(binding)
|
|
147
|
+
})
|
|
148
|
+
];
|
|
149
|
+
} else if (isObjectBindingPattern(binding)) {
|
|
150
|
+
let variable = mkVariable({
|
|
151
|
+
accessedFrom,
|
|
152
|
+
accessedByProperty: propertyName ? isIdentifier$9(propertyName) ? propertyName.text : void 0 : void 0,
|
|
153
|
+
assignedFrom,
|
|
154
|
+
root,
|
|
155
|
+
definingStatement: findDeclaringStatement(binding)
|
|
156
|
+
});
|
|
157
|
+
return binding.elements.flatMap((element) => {
|
|
158
|
+
return tsBindingNameToVariable(element.name, variable, void 0, element.propertyName);
|
|
159
|
+
});
|
|
160
|
+
} else if (isArrayBindingPattern(binding)) {
|
|
161
|
+
let variable = mkVariable({
|
|
162
|
+
accessedFrom,
|
|
163
|
+
accessedByProperty: propertyName ? isIdentifier$9(propertyName) ? propertyName.text : void 0 : void 0,
|
|
164
|
+
assignedFrom,
|
|
165
|
+
root,
|
|
166
|
+
definingStatement: findDeclaringStatement(binding)
|
|
167
|
+
});
|
|
168
|
+
return binding.elements.flatMap((element, index) => {
|
|
169
|
+
return isBindingElement(element) && tsBindingNameToVariable(element.name, variable, void 0, {
|
|
170
|
+
kind: 80,
|
|
171
|
+
text: "" + index
|
|
172
|
+
});
|
|
173
|
+
}).filter((variable2) => !!variable2);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
class NameBindingResolver {
|
|
177
|
+
constructor(parentNameResolver) {
|
|
178
|
+
__publicField2(this, "variables", /* @__PURE__ */ new Map());
|
|
179
|
+
this.parentNameResolver = parentNameResolver;
|
|
180
|
+
}
|
|
181
|
+
addVariable(name, variable) {
|
|
182
|
+
this.variables.set(name, variable);
|
|
183
|
+
}
|
|
184
|
+
addFunctionParams(functionDeclaration) {
|
|
185
|
+
functionDeclaration.parameters.map((param, paramIndex) => {
|
|
186
|
+
let paramVariables = tsBindingNameToVariable(
|
|
187
|
+
param.name,
|
|
188
|
+
void 0,
|
|
189
|
+
void 0,
|
|
190
|
+
void 0,
|
|
191
|
+
mkParameterVariableRoot(param, paramIndex)
|
|
192
|
+
);
|
|
193
|
+
paramVariables.forEach((variable) => {
|
|
194
|
+
if (variable.name)
|
|
195
|
+
this.variables.set(variable.name, variable);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
addFunctionDeclaration(statement) {
|
|
200
|
+
if (statement.name) {
|
|
201
|
+
let functionVariable = mkVariable({
|
|
202
|
+
name: statement.name.text,
|
|
203
|
+
root: mkFunctionVariableRoot(statement),
|
|
204
|
+
definingStatement: statement
|
|
205
|
+
});
|
|
206
|
+
this.variables.set(statement.name.text, functionVariable);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
addVariableDeclarationList(declarationList) {
|
|
210
|
+
const letOrConst = declarationList.flags === NodeFlags.Const ? 1 : 0;
|
|
211
|
+
declarationList.declarations.forEach((declaration) => {
|
|
212
|
+
let rightSide = declaration.initializer ? this.resolvePropertyAccessChain(declaration.initializer) : void 0;
|
|
213
|
+
let declaredVariable = tsBindingNameToVariable(
|
|
214
|
+
declaration.name,
|
|
215
|
+
void 0,
|
|
216
|
+
rightSide,
|
|
217
|
+
void 0
|
|
218
|
+
);
|
|
219
|
+
declaredVariable.forEach(
|
|
220
|
+
(variable) => this.variables.set(variable.name, { ...variable, letOrConst })
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
addVariableStatement(variableStatement) {
|
|
225
|
+
this.addVariableDeclarationList(variableStatement.declarationList);
|
|
226
|
+
}
|
|
227
|
+
getVariable(name) {
|
|
228
|
+
return this.variables.get(name) || UNKNOWN_VARIABLE;
|
|
229
|
+
}
|
|
230
|
+
resolvePropertyAccessChain(expression) {
|
|
231
|
+
if (isPropertyAccessExpression$5(expression)) {
|
|
232
|
+
const name = expression.name.text;
|
|
233
|
+
const identifiersFromObject = this.resolvePropertyAccessChain(expression.expression);
|
|
234
|
+
return { accessedFrom: identifiersFromObject, accessedByProperty: name };
|
|
235
|
+
} else if (isElementAccessExpression$1(expression) && isStringLiteral$8(expression.argumentExpression)) {
|
|
236
|
+
const name = expression.argumentExpression.text;
|
|
237
|
+
const identifiersFromObject = this.resolvePropertyAccessChain(expression.expression);
|
|
238
|
+
return { accessedFrom: identifiersFromObject, accessedByProperty: name };
|
|
239
|
+
} else if (isIdentifier$9(expression)) {
|
|
240
|
+
return this.resolveIdentifier(expression);
|
|
241
|
+
} else if (isParenthesizedExpression(expression)) {
|
|
242
|
+
return this.resolvePropertyAccessChain(expression.expression);
|
|
243
|
+
} else if (isAsExpression(expression)) {
|
|
244
|
+
return this.resolvePropertyAccessChain(expression.expression);
|
|
245
|
+
} else if (isObjectLiteralExpression(expression)) {
|
|
246
|
+
return {
|
|
247
|
+
properties: expression.properties.map((property) => {
|
|
248
|
+
if (isPropertyAssignment$1(property) && (isStringLiteral$8(property.name) || isIdentifier$9(property.name))) {
|
|
249
|
+
if (isIdentifier$9(property.initializer))
|
|
250
|
+
return {
|
|
251
|
+
name: property.name.text,
|
|
252
|
+
assignedFrom: this.resolveIdentifier(property.initializer)
|
|
253
|
+
};
|
|
254
|
+
else if (isObjectLiteralExpression(property.initializer)) {
|
|
255
|
+
let nestedProperty = this.resolvePropertyAccessChain(
|
|
256
|
+
property.initializer
|
|
257
|
+
);
|
|
258
|
+
nestedProperty.name = property.name.text;
|
|
259
|
+
return nestedProperty;
|
|
260
|
+
} else if (isArrowFunction$2(property.initializer) || isFunctionExpression(property.initializer)) {
|
|
261
|
+
return {
|
|
262
|
+
name: property.name.text,
|
|
263
|
+
root: mkFunctionVariableRoot(property.initializer)
|
|
264
|
+
};
|
|
265
|
+
} else
|
|
266
|
+
return {
|
|
267
|
+
name: property.name.text,
|
|
268
|
+
root: mkLiteralVariableRoot(property.initializer)
|
|
269
|
+
};
|
|
270
|
+
} else if (isShorthandPropertyAssignment(property))
|
|
271
|
+
return {
|
|
272
|
+
name: property.name.text,
|
|
273
|
+
assignedFrom: this.resolveIdentifier(property.name)
|
|
274
|
+
};
|
|
275
|
+
})
|
|
276
|
+
};
|
|
277
|
+
} else if (isArrowFunction$2(expression) || isFunctionExpression(expression)) {
|
|
278
|
+
return { root: mkFunctionVariableRoot(expression) };
|
|
279
|
+
} else if (isCallExpression$6(expression)) {
|
|
280
|
+
return { root: mkFunctionCallVariableRoot(expression) };
|
|
281
|
+
} else if (isStringLiteral$8(expression) || isNumericLiteral(expression) || isToken(expression) && expression.kind === SyntaxKind$5.TrueKeyword || isToken(expression) && expression.kind === SyntaxKind$5.FalseKeyword) {
|
|
282
|
+
return { root: mkLiteralVariableRoot(expression) };
|
|
283
|
+
} else {
|
|
284
|
+
return { root: mkOtherVariableRoot(expression) };
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
resolvePropertyAccess(expression) {
|
|
288
|
+
return this.resolvePropertyAccessChain(expression);
|
|
289
|
+
}
|
|
290
|
+
resolveIdentifier(expression) {
|
|
291
|
+
let variableName = expression.text;
|
|
292
|
+
let nameResolver = this;
|
|
293
|
+
let resolved;
|
|
294
|
+
while ((resolved = nameResolver.getVariable(variableName)) === UNKNOWN_VARIABLE && nameResolver.parentNameResolver)
|
|
295
|
+
nameResolver = nameResolver.parentNameResolver;
|
|
296
|
+
if (resolved === UNKNOWN_VARIABLE)
|
|
297
|
+
return { root: mkGlobalVariableRoot(variableName) };
|
|
298
|
+
return resolved;
|
|
299
|
+
}
|
|
300
|
+
addImportDeclaration(node) {
|
|
301
|
+
if (node.importClause?.name) {
|
|
302
|
+
let root = mkImportModuleVariableRoot(
|
|
303
|
+
node.moduleSpecifier,
|
|
304
|
+
0
|
|
305
|
+
/* defaultImport */
|
|
306
|
+
);
|
|
307
|
+
let variable = mkVariable({
|
|
308
|
+
name: node.importClause.name.text,
|
|
309
|
+
definingStatement: node,
|
|
310
|
+
root
|
|
311
|
+
});
|
|
312
|
+
this.variables.set(node.importClause.name.text, variable);
|
|
313
|
+
}
|
|
314
|
+
if (node.importClause?.namedBindings) {
|
|
315
|
+
let root = mkImportModuleVariableRoot(
|
|
316
|
+
node.moduleSpecifier,
|
|
317
|
+
1
|
|
318
|
+
/* namedImport */
|
|
319
|
+
);
|
|
320
|
+
let namedBindings = node.importClause.namedBindings;
|
|
321
|
+
if (isNamespaceImport(namedBindings)) {
|
|
322
|
+
let variable = mkVariable({
|
|
323
|
+
name: namedBindings.name.text,
|
|
324
|
+
definingStatement: node,
|
|
325
|
+
root
|
|
326
|
+
});
|
|
327
|
+
this.variables.set(namedBindings.name.text, variable);
|
|
328
|
+
} else if (isNamedImports$1(namedBindings)) {
|
|
329
|
+
namedBindings.elements.forEach((importSpecifier) => {
|
|
330
|
+
if (!importSpecifier.isTypeOnly) {
|
|
331
|
+
let variable = mkVariable({
|
|
332
|
+
name: importSpecifier.name.text,
|
|
333
|
+
accessedByProperty: (importSpecifier.propertyName || importSpecifier.name).text,
|
|
334
|
+
accessedFrom: {
|
|
335
|
+
definingStatement: node,
|
|
336
|
+
root
|
|
337
|
+
},
|
|
338
|
+
definingStatement: node
|
|
339
|
+
});
|
|
340
|
+
this.variables.set(importSpecifier.name.text, variable);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function flattenVariable(variable, path2 = []) {
|
|
348
|
+
if (variable.assignedFrom)
|
|
349
|
+
return flattenVariable(variable.assignedFrom, path2);
|
|
350
|
+
else if (variable.accessedFrom) {
|
|
351
|
+
return flattenVariable(variable.accessedFrom, [variable.accessedByProperty, ...path2]);
|
|
352
|
+
} else if (variable.properties && !!variable.properties.find((_) => _.name === path2[0])) {
|
|
353
|
+
return flattenVariable(
|
|
354
|
+
variable.properties.find((_) => _.name === path2[0]),
|
|
355
|
+
path2.slice(1)
|
|
356
|
+
);
|
|
357
|
+
} else
|
|
358
|
+
return { path: path2, root: variable.root };
|
|
359
|
+
}
|
|
360
|
+
function byAnd() {
|
|
361
|
+
return (agg, value) => agg && value;
|
|
362
|
+
}
|
|
363
|
+
const {
|
|
364
|
+
isIdentifier: isIdentifier$6,
|
|
365
|
+
SyntaxKind: SyntaxKind$4,
|
|
366
|
+
isStringLiteral: isStringLiteral$7,
|
|
367
|
+
visitNode: visitNode$4,
|
|
368
|
+
isFunctionDeclaration: isFunctionDeclaration$1,
|
|
369
|
+
isVariableStatement: isVariableStatement$2,
|
|
370
|
+
isImportDeclaration: isImportDeclaration$3,
|
|
371
|
+
isBlock: isBlock$2,
|
|
372
|
+
isForStatement: isForStatement$1,
|
|
373
|
+
isVariableDeclarationList,
|
|
374
|
+
isForInStatement: isForInStatement$1,
|
|
375
|
+
isForOfStatement: isForOfStatement$1,
|
|
376
|
+
isTypeReferenceNode: isTypeReferenceNode$1,
|
|
377
|
+
isArrayTypeNode,
|
|
378
|
+
isFunctionTypeNode,
|
|
379
|
+
isUnionTypeNode
|
|
380
|
+
} = c;
|
|
381
|
+
const BUILT_IN_TYPES = ["RegExp", "Date"];
|
|
382
|
+
function builtInType(text) {
|
|
383
|
+
return BUILT_IN_TYPES.findIndex((_) => _ === text) > -1;
|
|
384
|
+
}
|
|
385
|
+
class BuiltInResolvedType {
|
|
386
|
+
constructor(name) {
|
|
387
|
+
this.name = name;
|
|
388
|
+
}
|
|
389
|
+
canBeAssignedFrom(rightSide) {
|
|
390
|
+
return rightSide instanceof BuiltInResolvedType && this.name === rightSide.name;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
class ImportFromModuleResolvedType {
|
|
394
|
+
constructor(module, path2) {
|
|
395
|
+
this.module = module;
|
|
396
|
+
this.path = path2;
|
|
397
|
+
}
|
|
398
|
+
canBeAssignedFrom(rightSide) {
|
|
399
|
+
if (rightSide instanceof ImportFromModuleResolvedType) {
|
|
400
|
+
let pathEqual = this.path.length === rightSide.path.length;
|
|
401
|
+
if (pathEqual) {
|
|
402
|
+
pathEqual = this.path.map((value, index) => value === rightSide.path[index]).reduce(byAnd(), true);
|
|
403
|
+
}
|
|
404
|
+
return pathEqual && this.module === rightSide.module;
|
|
405
|
+
}
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
class ArrayResolvedType {
|
|
410
|
+
constructor(itemType) {
|
|
411
|
+
this.itemType = itemType;
|
|
412
|
+
}
|
|
413
|
+
canBeAssignedFrom(rightSide) {
|
|
414
|
+
return rightSide instanceof ArrayResolvedType && this.itemType === rightSide.itemType;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
class FunctionResolvedType {
|
|
418
|
+
constructor(params, returns) {
|
|
419
|
+
this.params = params;
|
|
420
|
+
this.returns = returns;
|
|
421
|
+
}
|
|
422
|
+
canBeAssignedFrom(rightSide) {
|
|
423
|
+
return rightSide instanceof FunctionResolvedType && this.returns.canBeAssignedFrom(rightSide.returns);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
class UnionResolvedType {
|
|
427
|
+
constructor(types) {
|
|
428
|
+
this.types = types;
|
|
429
|
+
}
|
|
430
|
+
canBeAssignedFrom(rightSide) {
|
|
431
|
+
if (rightSide instanceof UnionResolvedType) {
|
|
432
|
+
for (const item1 of this.types)
|
|
433
|
+
for (const item2 of rightSide.types)
|
|
434
|
+
if (item1.canBeAssignedFrom(item2))
|
|
435
|
+
return true;
|
|
436
|
+
} else
|
|
437
|
+
for (const item1 of this.types)
|
|
438
|
+
if (item1.canBeAssignedFrom(rightSide))
|
|
439
|
+
return true;
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
class GlobalResolvedType {
|
|
444
|
+
constructor(name) {
|
|
445
|
+
this.name = name;
|
|
446
|
+
}
|
|
447
|
+
canBeAssignedFrom(rightSide) {
|
|
448
|
+
return rightSide instanceof GlobalResolvedType && this.name === rightSide.name;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
class SourceFileBindingResolver {
|
|
452
|
+
constructor(sourceFile) {
|
|
453
|
+
__publicField2(this, "nameBindingResolvers", /* @__PURE__ */ new Map());
|
|
454
|
+
this.nameBindingResolvers.set(sourceFile, new NameBindingResolver());
|
|
455
|
+
const nbResolversQueue = [
|
|
456
|
+
this.nameBindingResolvers.get(sourceFile)
|
|
457
|
+
];
|
|
458
|
+
const doWithChildBindingResolver = (node, callback) => {
|
|
459
|
+
nbResolversQueue.unshift(new NameBindingResolver(nbResolversQueue[0]));
|
|
460
|
+
this.nameBindingResolvers.set(node, nbResolversQueue[0]);
|
|
461
|
+
callback();
|
|
462
|
+
node.getChildren().forEach((child) => visitNode$4(child, visitor));
|
|
463
|
+
nbResolversQueue.shift();
|
|
464
|
+
return node;
|
|
465
|
+
};
|
|
466
|
+
const visitor = (node) => {
|
|
467
|
+
if (isFunctionDeclaration$1(node))
|
|
468
|
+
nbResolversQueue[0].addFunctionDeclaration(node);
|
|
469
|
+
if (isVariableStatement$2(node))
|
|
470
|
+
nbResolversQueue[0].addVariableStatement(node);
|
|
471
|
+
else if (isImportDeclaration$3(node))
|
|
472
|
+
nbResolversQueue[0].addImportDeclaration(node);
|
|
473
|
+
else if (isBlock$2(node))
|
|
474
|
+
return doWithChildBindingResolver(node, () => {
|
|
475
|
+
});
|
|
476
|
+
else if (isFunctionLikeDeclarationBase(node)) {
|
|
477
|
+
return doWithChildBindingResolver(
|
|
478
|
+
node,
|
|
479
|
+
() => nbResolversQueue[0].addFunctionParams(node)
|
|
480
|
+
);
|
|
481
|
+
} else if (isForStatement$1(node) && isVariableDeclarationList(node.initializer)) {
|
|
482
|
+
return doWithChildBindingResolver(
|
|
483
|
+
node,
|
|
484
|
+
() => nbResolversQueue[0].addVariableDeclarationList(
|
|
485
|
+
node.initializer
|
|
486
|
+
)
|
|
487
|
+
);
|
|
488
|
+
} else if ((isForInStatement$1(node) || isForOfStatement$1(node)) && isVariableDeclarationList(node.initializer) && node.initializer.declarations.length === 1 && isIdentifier$6(node.initializer.declarations[0].name)) {
|
|
489
|
+
return doWithChildBindingResolver(node, () => {
|
|
490
|
+
let name = node.initializer.declarations[0].name.text;
|
|
491
|
+
nbResolversQueue[0].addVariable(
|
|
492
|
+
name,
|
|
493
|
+
mkVariable({
|
|
494
|
+
name,
|
|
495
|
+
root: mkOtherVariableRoot(node),
|
|
496
|
+
definingStatement: node
|
|
497
|
+
})
|
|
498
|
+
);
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
node.getChildren().forEach((child) => visitNode$4(child, visitor));
|
|
502
|
+
return node;
|
|
503
|
+
};
|
|
504
|
+
visitNode$4(sourceFile, visitor);
|
|
505
|
+
}
|
|
506
|
+
findBindingResolver(node) {
|
|
507
|
+
let found;
|
|
508
|
+
while (!(found = this.nameBindingResolvers.get(node)) && node.parent)
|
|
509
|
+
node = node.parent;
|
|
510
|
+
return found;
|
|
511
|
+
}
|
|
512
|
+
explain(identifier) {
|
|
513
|
+
return this.findBindingResolver(identifier).resolvePropertyAccessChain(identifier);
|
|
514
|
+
}
|
|
515
|
+
explainFlattenedVariableType(flattened) {
|
|
516
|
+
if (!!flattened.root) {
|
|
517
|
+
if (isImportModuleVariableRoot(flattened.root) && isStringLiteral$7(flattened.root.module)) {
|
|
518
|
+
return new ImportFromModuleResolvedType(flattened.root.module.text, flattened.path);
|
|
519
|
+
}
|
|
520
|
+
} else
|
|
521
|
+
return void 0;
|
|
522
|
+
}
|
|
523
|
+
explainType(type) {
|
|
524
|
+
if (type) {
|
|
525
|
+
if (isTypeReferenceNode$1(type)) {
|
|
526
|
+
let typeName = type.typeName;
|
|
527
|
+
if (isIdentifier$6(typeName)) {
|
|
528
|
+
let resolved = this.findBindingResolver(typeName).resolveIdentifier(typeName);
|
|
529
|
+
let flattened = flattenVariable(resolved);
|
|
530
|
+
let typeFromFlattened = this.explainFlattenedVariableType(flattened);
|
|
531
|
+
if (typeFromFlattened)
|
|
532
|
+
return typeFromFlattened;
|
|
533
|
+
if (builtInType(typeName.text))
|
|
534
|
+
return new BuiltInResolvedType(typeName.text);
|
|
535
|
+
}
|
|
536
|
+
} else if (type.kind === SyntaxKind$4.StringKeyword)
|
|
537
|
+
return new BuiltInResolvedType("string");
|
|
538
|
+
else if (type.kind === SyntaxKind$4.NumberKeyword)
|
|
539
|
+
return new BuiltInResolvedType("number");
|
|
540
|
+
else if (type.kind === SyntaxKind$4.BooleanKeyword)
|
|
541
|
+
return new BuiltInResolvedType("boolean");
|
|
542
|
+
else if (type.kind === SyntaxKind$4.AnyKeyword)
|
|
543
|
+
return new BuiltInResolvedType("any");
|
|
544
|
+
else if (type.kind === SyntaxKind$4.VoidKeyword)
|
|
545
|
+
return new BuiltInResolvedType("void");
|
|
546
|
+
else if (isArrayTypeNode(type))
|
|
547
|
+
return new ArrayResolvedType(this.explainType(type.elementType));
|
|
548
|
+
else if (isFunctionTypeNode(type)) {
|
|
549
|
+
const params = type.parameters.map((param) => this.explainType(param.type));
|
|
550
|
+
const ret = this.explainType(type.type);
|
|
551
|
+
return new FunctionResolvedType(params, ret);
|
|
552
|
+
} else if (isUnionTypeNode(type))
|
|
553
|
+
return new UnionResolvedType(type.types.map((aType) => this.explainType(aType)));
|
|
554
|
+
}
|
|
555
|
+
return new BuiltInResolvedType("void");
|
|
556
|
+
}
|
|
557
|
+
globalType(globalVariableRoot) {
|
|
558
|
+
return new GlobalResolvedType(globalVariableRoot.name);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const { isStringLiteral: isStringLiteral$1 } = c;
|
|
562
|
+
function areFlattenedAccessChainsEqual(chain1, chain2) {
|
|
563
|
+
if (chain1.path.length !== chain2.path.length) {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
const pathsEqual = chain1.path.every((value, index) => value === chain2.path[index]);
|
|
567
|
+
if (!pathsEqual) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
return areVariableRootsEqual(chain1.root, chain2.root);
|
|
571
|
+
}
|
|
572
|
+
function areVariableRootsEqual(root1, root2) {
|
|
573
|
+
if (!root1 && !root2) {
|
|
574
|
+
return true;
|
|
575
|
+
}
|
|
576
|
+
if (!root1 || !root2) {
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
if (root1.kind !== root2.kind) {
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
switch (root1.kind) {
|
|
583
|
+
case VariableRootType.ImportModule:
|
|
584
|
+
if (isImportModuleVariableRoot(root1) && isImportModuleVariableRoot(root2)) {
|
|
585
|
+
const module1 = isStringLiteral$1(root1.module) ? root1.module.text : String(root1.module);
|
|
586
|
+
const module2 = isStringLiteral$1(root2.module) ? root2.module.text : String(root2.module);
|
|
587
|
+
return module1 === module2 && root1.importType === root2.importType;
|
|
588
|
+
}
|
|
589
|
+
return false;
|
|
590
|
+
case VariableRootType.FunctionParameter:
|
|
591
|
+
case VariableRootType.FunctionDefinition:
|
|
592
|
+
case VariableRootType.Literal:
|
|
593
|
+
case VariableRootType.FunctionCall:
|
|
594
|
+
return true;
|
|
595
|
+
case VariableRootType.Global:
|
|
596
|
+
case VariableRootType.Other:
|
|
597
|
+
return true;
|
|
598
|
+
default:
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
const COMPONENT_SERVER_METHODS = /* @__PURE__ */ new Set([
|
|
603
|
+
"withServices",
|
|
604
|
+
"withLoadParams",
|
|
605
|
+
"withSlowlyRender",
|
|
606
|
+
"withFastRender"
|
|
607
|
+
]);
|
|
608
|
+
const COMPONENT_CLIENT_METHODS = /* @__PURE__ */ new Set(["withInteractive", "withContexts"]);
|
|
609
|
+
const INIT_SERVER_METHODS = /* @__PURE__ */ new Set(["withServer"]);
|
|
610
|
+
const INIT_CLIENT_METHODS = /* @__PURE__ */ new Set(["withClient"]);
|
|
611
|
+
function shouldRemoveMethod(methodName, environment) {
|
|
612
|
+
if (environment === "client" && COMPONENT_SERVER_METHODS.has(methodName))
|
|
613
|
+
return true;
|
|
614
|
+
if (environment === "server" && COMPONENT_CLIENT_METHODS.has(methodName))
|
|
615
|
+
return true;
|
|
616
|
+
if (environment === "client" && INIT_SERVER_METHODS.has(methodName))
|
|
617
|
+
return true;
|
|
618
|
+
if (environment === "server" && INIT_CLIENT_METHODS.has(methodName))
|
|
619
|
+
return true;
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
const { isCallExpression: isCallExpression$1, isPropertyAccessExpression: isPropertyAccessExpression$1, isIdentifier: isIdentifier$2, isStringLiteral } = c$1;
|
|
623
|
+
function findBuilderMethodsToRemove(sourceFile, bindingResolver, environment) {
|
|
624
|
+
const callsToRemove = [];
|
|
625
|
+
const removedVariables = /* @__PURE__ */ new Set();
|
|
626
|
+
const visit = (node) => {
|
|
627
|
+
if (isCallExpression$1(node) && isPropertyAccessExpression$1(node.expression) && isPartOfJayStackChain(node, bindingResolver)) {
|
|
628
|
+
const methodName = node.expression.name.text;
|
|
629
|
+
if (shouldRemoveMethod(methodName, environment)) {
|
|
630
|
+
const variable = bindingResolver.explain(node.expression);
|
|
631
|
+
const flattened = flattenVariable(variable);
|
|
632
|
+
callsToRemove.push(flattened);
|
|
633
|
+
collectVariablesFromArguments(node.arguments, bindingResolver, removedVariables);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
node.forEachChild(visit);
|
|
637
|
+
};
|
|
638
|
+
sourceFile.forEachChild(visit);
|
|
639
|
+
return { callsToRemove, removedVariables };
|
|
640
|
+
}
|
|
641
|
+
const JAY_BUILDER_FUNCTIONS = /* @__PURE__ */ new Set(["makeJayStackComponent", "makeJayInit"]);
|
|
642
|
+
function isPartOfJayStackChain(callExpr, bindingResolver) {
|
|
643
|
+
let current = callExpr.expression;
|
|
644
|
+
while (true) {
|
|
645
|
+
if (isPropertyAccessExpression$1(current)) {
|
|
646
|
+
current = current.expression;
|
|
647
|
+
} else if (isCallExpression$1(current)) {
|
|
648
|
+
if (isIdentifier$2(current.expression)) {
|
|
649
|
+
const variable = bindingResolver.explain(current.expression);
|
|
650
|
+
const flattened = flattenVariable(variable);
|
|
651
|
+
if (flattened.path.length === 1 && JAY_BUILDER_FUNCTIONS.has(flattened.path[0]) && isImportModuleVariableRoot(flattened.root) && isStringLiteral(flattened.root.module) && flattened.root.module.text === "@jay-framework/fullstack-component")
|
|
652
|
+
return true;
|
|
653
|
+
}
|
|
654
|
+
if (isPropertyAccessExpression$1(current.expression)) {
|
|
655
|
+
current = current.expression.expression;
|
|
656
|
+
continue;
|
|
657
|
+
} else {
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
} else {
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
function collectVariablesFromArguments(args, bindingResolver, variables) {
|
|
667
|
+
const visitor = (node) => {
|
|
668
|
+
if (isIdentifier$2(node)) {
|
|
669
|
+
const variable = bindingResolver.explain(node);
|
|
670
|
+
if (variable && (variable.name || variable.root)) {
|
|
671
|
+
variables.add(variable);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
node.forEachChild(visitor);
|
|
675
|
+
};
|
|
676
|
+
args.forEach((arg) => visitor(arg));
|
|
677
|
+
}
|
|
678
|
+
const {
|
|
679
|
+
isIdentifier: isIdentifier$1,
|
|
680
|
+
isImportDeclaration: isImportDeclaration$1,
|
|
681
|
+
isFunctionDeclaration,
|
|
682
|
+
isVariableStatement,
|
|
683
|
+
isInterfaceDeclaration,
|
|
684
|
+
isTypeAliasDeclaration,
|
|
685
|
+
isClassDeclaration,
|
|
686
|
+
isEnumDeclaration,
|
|
687
|
+
SyntaxKind
|
|
688
|
+
} = c$1;
|
|
689
|
+
function analyzeUnusedStatements(sourceFile) {
|
|
690
|
+
const statementsToRemove = /* @__PURE__ */ new Set();
|
|
691
|
+
const collectUsedIdentifiers = () => {
|
|
692
|
+
const used = /* @__PURE__ */ new Set();
|
|
693
|
+
for (const statement of sourceFile.statements) {
|
|
694
|
+
if (isImportDeclaration$1(statement) || statementsToRemove.has(statement)) {
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
const definedName = getStatementDefinedName(statement);
|
|
698
|
+
const visitor = (node, parent) => {
|
|
699
|
+
if (isIdentifier$1(node)) {
|
|
700
|
+
if (node.text !== definedName) {
|
|
701
|
+
used.add(node.text);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
node.forEachChild((child) => visitor(child));
|
|
705
|
+
};
|
|
706
|
+
statement.forEachChild((child) => visitor(child));
|
|
707
|
+
}
|
|
708
|
+
return used;
|
|
709
|
+
};
|
|
710
|
+
let changed = true;
|
|
711
|
+
while (changed) {
|
|
712
|
+
changed = false;
|
|
713
|
+
const stillUsedIdentifiers = collectUsedIdentifiers();
|
|
714
|
+
for (const statement of sourceFile.statements) {
|
|
715
|
+
if (statementsToRemove.has(statement) || isImportDeclaration$1(statement) || isExportStatement(statement)) {
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
const definedName = getStatementDefinedName(statement);
|
|
719
|
+
if (definedName && !stillUsedIdentifiers.has(definedName)) {
|
|
720
|
+
statementsToRemove.add(statement);
|
|
721
|
+
changed = true;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
const finalUsedIdentifiers = collectUsedIdentifiers();
|
|
726
|
+
const unusedImports = /* @__PURE__ */ new Set();
|
|
727
|
+
for (const statement of sourceFile.statements) {
|
|
728
|
+
if (isImportDeclaration$1(statement) && statement.importClause?.namedBindings) {
|
|
729
|
+
const namedBindings = statement.importClause.namedBindings;
|
|
730
|
+
if ("elements" in namedBindings) {
|
|
731
|
+
for (const element of namedBindings.elements) {
|
|
732
|
+
const importName = element.name.text;
|
|
733
|
+
if (!finalUsedIdentifiers.has(importName)) {
|
|
734
|
+
unusedImports.add(importName);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
return { statementsToRemove, unusedImports };
|
|
741
|
+
}
|
|
742
|
+
function isExportStatement(statement) {
|
|
743
|
+
const modifiers = "modifiers" in statement ? statement.modifiers : void 0;
|
|
744
|
+
if (modifiers) {
|
|
745
|
+
return modifiers.some((mod) => mod.kind === SyntaxKind.ExportKeyword);
|
|
746
|
+
}
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
function getStatementDefinedName(statement) {
|
|
750
|
+
if (isFunctionDeclaration(statement) && statement.name) {
|
|
751
|
+
return statement.name.text;
|
|
752
|
+
}
|
|
753
|
+
if (isVariableStatement(statement)) {
|
|
754
|
+
const firstDecl = statement.declarationList.declarations[0];
|
|
755
|
+
if (firstDecl && isIdentifier$1(firstDecl.name)) {
|
|
756
|
+
return firstDecl.name.text;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
if (isInterfaceDeclaration(statement) && statement.name) {
|
|
760
|
+
return statement.name.text;
|
|
761
|
+
}
|
|
762
|
+
if (isTypeAliasDeclaration(statement) && statement.name) {
|
|
763
|
+
return statement.name.text;
|
|
764
|
+
}
|
|
765
|
+
if (isClassDeclaration(statement) && statement.name) {
|
|
766
|
+
return statement.name.text;
|
|
767
|
+
}
|
|
768
|
+
if (isEnumDeclaration(statement) && statement.name) {
|
|
769
|
+
return statement.name.text;
|
|
770
|
+
}
|
|
771
|
+
return void 0;
|
|
772
|
+
}
|
|
773
|
+
const {
|
|
774
|
+
createPrinter,
|
|
775
|
+
createSourceFile,
|
|
776
|
+
ScriptTarget,
|
|
777
|
+
visitEachChild,
|
|
778
|
+
isCallExpression,
|
|
779
|
+
isPropertyAccessExpression,
|
|
780
|
+
isImportDeclaration,
|
|
781
|
+
isNamedImports,
|
|
782
|
+
isIdentifier
|
|
783
|
+
} = c$1;
|
|
784
|
+
function transformJayStackBuilder(code, filePath, environment) {
|
|
785
|
+
const sourceFile = createSourceFile(filePath, code, ScriptTarget.Latest, true);
|
|
786
|
+
const transformers = [mkTransformer(mkJayStackCodeSplitTransformer, { environment })];
|
|
787
|
+
const printer = createPrinter();
|
|
788
|
+
const result = c$1.transform(sourceFile, transformers);
|
|
789
|
+
const transformedFile = result.transformed[0];
|
|
790
|
+
const transformedCode = printer.printFile(transformedFile);
|
|
791
|
+
result.dispose();
|
|
792
|
+
return {
|
|
793
|
+
code: transformedCode
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
function isCallToRemove(flattened, callsToRemove) {
|
|
797
|
+
return callsToRemove.some((call) => areFlattenedAccessChainsEqual(flattened, call));
|
|
798
|
+
}
|
|
799
|
+
function mkJayStackCodeSplitTransformer({
|
|
800
|
+
factory,
|
|
801
|
+
sourceFile,
|
|
802
|
+
context,
|
|
803
|
+
environment
|
|
804
|
+
}) {
|
|
805
|
+
const bindingResolver = new SourceFileBindingResolver(sourceFile);
|
|
806
|
+
const { callsToRemove } = findBuilderMethodsToRemove(sourceFile, bindingResolver, environment);
|
|
807
|
+
const transformVisitor = (node) => {
|
|
808
|
+
if (isCallExpression(node) && isPropertyAccessExpression(node.expression)) {
|
|
809
|
+
const variable = bindingResolver.explain(node.expression);
|
|
810
|
+
const flattened = flattenVariable(variable);
|
|
811
|
+
if (isCallToRemove(flattened, callsToRemove)) {
|
|
812
|
+
const receiver = node.expression.expression;
|
|
813
|
+
return transformVisitor(receiver);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return visitEachChild(node, transformVisitor, context);
|
|
817
|
+
};
|
|
818
|
+
let transformedSourceFile = visitEachChild(
|
|
819
|
+
sourceFile,
|
|
820
|
+
transformVisitor,
|
|
821
|
+
context
|
|
822
|
+
);
|
|
823
|
+
const { statementsToRemove, unusedImports } = analyzeUnusedStatements(transformedSourceFile);
|
|
824
|
+
const transformedStatements = transformedSourceFile.statements.map((statement) => {
|
|
825
|
+
if (statementsToRemove.has(statement)) {
|
|
826
|
+
return void 0;
|
|
827
|
+
}
|
|
828
|
+
if (isImportDeclaration(statement)) {
|
|
829
|
+
return filterImportDeclaration(statement, unusedImports, factory);
|
|
830
|
+
}
|
|
831
|
+
return statement;
|
|
832
|
+
}).filter((s2) => s2 !== void 0);
|
|
833
|
+
return factory.updateSourceFile(transformedSourceFile, transformedStatements);
|
|
834
|
+
}
|
|
835
|
+
function filterImportDeclaration(statement, unusedImports, factory) {
|
|
836
|
+
const importClause = statement.importClause;
|
|
837
|
+
if (!importClause?.namedBindings || !isNamedImports(importClause.namedBindings)) {
|
|
838
|
+
return statement;
|
|
839
|
+
}
|
|
840
|
+
const usedElements = importClause.namedBindings.elements.filter(
|
|
841
|
+
(element) => !unusedImports.has(element.name.text)
|
|
842
|
+
);
|
|
843
|
+
if (usedElements.length === 0) {
|
|
844
|
+
return void 0;
|
|
845
|
+
}
|
|
846
|
+
return factory.updateImportDeclaration(
|
|
847
|
+
statement,
|
|
848
|
+
statement.modifiers,
|
|
849
|
+
factory.updateImportClause(
|
|
850
|
+
importClause,
|
|
851
|
+
importClause.isTypeOnly,
|
|
852
|
+
importClause.name,
|
|
853
|
+
factory.updateNamedImports(importClause.namedBindings, usedElements)
|
|
854
|
+
),
|
|
855
|
+
statement.moduleSpecifier,
|
|
856
|
+
statement.assertClause
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
const actionMetadataCache = /* @__PURE__ */ new Map();
|
|
860
|
+
function clearActionMetadataCache() {
|
|
861
|
+
actionMetadataCache.clear();
|
|
862
|
+
}
|
|
863
|
+
function isActionImport(importSource) {
|
|
864
|
+
return importSource.includes(".actions") || importSource.includes("-actions") || importSource.includes("/actions/") || importSource.endsWith("/actions");
|
|
865
|
+
}
|
|
866
|
+
function extractActionsFromSource(sourceCode, filePath) {
|
|
867
|
+
const cached = actionMetadataCache.get(filePath);
|
|
868
|
+
if (cached) {
|
|
869
|
+
return cached;
|
|
870
|
+
}
|
|
871
|
+
const actions = [];
|
|
872
|
+
const sourceFile = c$1.createSourceFile(
|
|
873
|
+
filePath,
|
|
874
|
+
sourceCode,
|
|
875
|
+
c$1.ScriptTarget.Latest,
|
|
876
|
+
true
|
|
877
|
+
);
|
|
878
|
+
function visit(node) {
|
|
879
|
+
if (c$1.isVariableStatement(node)) {
|
|
880
|
+
const hasExport = node.modifiers?.some(
|
|
881
|
+
(m) => m.kind === c$1.SyntaxKind.ExportKeyword
|
|
882
|
+
);
|
|
883
|
+
if (!hasExport) {
|
|
884
|
+
c$1.forEachChild(node, visit);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
for (const decl of node.declarationList.declarations) {
|
|
888
|
+
if (!c$1.isIdentifier(decl.name) || !decl.initializer) {
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
const exportName = decl.name.text;
|
|
892
|
+
const actionMeta = extractActionFromExpression(decl.initializer);
|
|
893
|
+
if (actionMeta) {
|
|
894
|
+
actions.push({
|
|
895
|
+
...actionMeta,
|
|
896
|
+
exportName
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
c$1.forEachChild(node, visit);
|
|
902
|
+
}
|
|
903
|
+
visit(sourceFile);
|
|
904
|
+
actionMetadataCache.set(filePath, actions);
|
|
905
|
+
return actions;
|
|
906
|
+
}
|
|
907
|
+
function extractActionFromExpression(node) {
|
|
908
|
+
let current = node;
|
|
909
|
+
let method = "POST";
|
|
910
|
+
let explicitMethod = null;
|
|
911
|
+
while (c$1.isCallExpression(current)) {
|
|
912
|
+
const expr = current.expression;
|
|
913
|
+
if (c$1.isPropertyAccessExpression(expr) && expr.name.text === "withMethod") {
|
|
914
|
+
const arg = current.arguments[0];
|
|
915
|
+
if (arg && c$1.isStringLiteral(arg)) {
|
|
916
|
+
explicitMethod = arg.text;
|
|
917
|
+
}
|
|
918
|
+
current = expr.expression;
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
if (c$1.isPropertyAccessExpression(expr) && ["withServices", "withCaching", "withHandler", "withTimeout"].includes(expr.name.text)) {
|
|
922
|
+
current = expr.expression;
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
if (c$1.isIdentifier(expr)) {
|
|
926
|
+
const funcName = expr.text;
|
|
927
|
+
if (funcName === "makeJayAction" || funcName === "makeJayQuery") {
|
|
928
|
+
const nameArg = current.arguments[0];
|
|
929
|
+
if (nameArg && c$1.isStringLiteral(nameArg)) {
|
|
930
|
+
method = funcName === "makeJayQuery" ? "GET" : "POST";
|
|
931
|
+
if (explicitMethod) {
|
|
932
|
+
method = explicitMethod;
|
|
933
|
+
}
|
|
934
|
+
return {
|
|
935
|
+
actionName: nameArg.text,
|
|
936
|
+
method
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
break;
|
|
942
|
+
}
|
|
943
|
+
return null;
|
|
944
|
+
}
|
|
945
|
+
const SERVER_ONLY_MODULES = /* @__PURE__ */ new Set([
|
|
946
|
+
"module",
|
|
947
|
+
// createRequire
|
|
948
|
+
"fs",
|
|
949
|
+
"path",
|
|
950
|
+
"node:fs",
|
|
951
|
+
"node:path",
|
|
952
|
+
"node:module",
|
|
953
|
+
"child_process",
|
|
954
|
+
"node:child_process",
|
|
955
|
+
"crypto",
|
|
956
|
+
"node:crypto"
|
|
957
|
+
]);
|
|
958
|
+
const SERVER_ONLY_PACKAGE_PATTERNS = [
|
|
959
|
+
"@jay-framework/compiler-shared",
|
|
960
|
+
"@jay-framework/stack-server-runtime",
|
|
961
|
+
"yaml"
|
|
962
|
+
// Often used in server config
|
|
963
|
+
];
|
|
964
|
+
function createImportChainTracker(options = {}) {
|
|
965
|
+
const {
|
|
966
|
+
verbose = false,
|
|
967
|
+
additionalServerModules = [],
|
|
968
|
+
additionalServerPatterns = []
|
|
969
|
+
} = options;
|
|
970
|
+
const importChain = /* @__PURE__ */ new Map();
|
|
971
|
+
const detectedServerModules = /* @__PURE__ */ new Set();
|
|
972
|
+
const serverOnlyModules = /* @__PURE__ */ new Set([...SERVER_ONLY_MODULES, ...additionalServerModules]);
|
|
973
|
+
const serverOnlyPatterns = [...SERVER_ONLY_PACKAGE_PATTERNS, ...additionalServerPatterns];
|
|
974
|
+
function isServerOnlyModule(id) {
|
|
975
|
+
if (serverOnlyModules.has(id)) {
|
|
976
|
+
return true;
|
|
977
|
+
}
|
|
978
|
+
for (const pattern of serverOnlyPatterns) {
|
|
979
|
+
if (id.includes(pattern)) {
|
|
980
|
+
return true;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
function buildImportChain(moduleId) {
|
|
986
|
+
const chain = [moduleId];
|
|
987
|
+
let current = moduleId;
|
|
988
|
+
for (let i = 0; i < 100; i++) {
|
|
989
|
+
const importer = importChain.get(current);
|
|
990
|
+
if (!importer)
|
|
991
|
+
break;
|
|
992
|
+
chain.push(importer);
|
|
993
|
+
current = importer;
|
|
994
|
+
}
|
|
995
|
+
return chain.reverse();
|
|
996
|
+
}
|
|
997
|
+
function formatChain(chain) {
|
|
998
|
+
return chain.map((id, idx) => {
|
|
999
|
+
const indent = " ".repeat(idx);
|
|
1000
|
+
const shortId = shortenPath(id);
|
|
1001
|
+
return `${indent}${idx === 0 ? "" : "↳ "}${shortId}`;
|
|
1002
|
+
}).join("\n");
|
|
1003
|
+
}
|
|
1004
|
+
function shortenPath(id) {
|
|
1005
|
+
if (id.includes("node_modules")) {
|
|
1006
|
+
const parts = id.split("node_modules/");
|
|
1007
|
+
return parts[parts.length - 1];
|
|
1008
|
+
}
|
|
1009
|
+
const cwd = process.cwd();
|
|
1010
|
+
if (id.startsWith(cwd)) {
|
|
1011
|
+
return id.slice(cwd.length + 1);
|
|
1012
|
+
}
|
|
1013
|
+
return id;
|
|
1014
|
+
}
|
|
1015
|
+
return {
|
|
1016
|
+
name: "jay-stack:import-chain-tracker",
|
|
1017
|
+
enforce: "pre",
|
|
1018
|
+
buildStart() {
|
|
1019
|
+
importChain.clear();
|
|
1020
|
+
detectedServerModules.clear();
|
|
1021
|
+
if (verbose) {
|
|
1022
|
+
console.log("[import-chain-tracker] Build started, tracking imports...");
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1025
|
+
resolveId(source, importer, options2) {
|
|
1026
|
+
if (options2?.ssr) {
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
if (source.startsWith("\0")) {
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
if (importer) {
|
|
1033
|
+
if (verbose) {
|
|
1034
|
+
console.log(
|
|
1035
|
+
`[import-chain-tracker] ${shortenPath(importer)} imports ${source}`
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return null;
|
|
1040
|
+
},
|
|
1041
|
+
load(id) {
|
|
1042
|
+
return null;
|
|
1043
|
+
},
|
|
1044
|
+
transform(code, id, options2) {
|
|
1045
|
+
if (options2?.ssr) {
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
if (isServerOnlyModule(id)) {
|
|
1049
|
+
detectedServerModules.add(id);
|
|
1050
|
+
const chain = buildImportChain(id);
|
|
1051
|
+
console.error(
|
|
1052
|
+
`
|
|
1053
|
+
[import-chain-tracker] ⚠️ Server-only module detected in client build!`
|
|
1054
|
+
);
|
|
1055
|
+
console.error(`Module: ${shortenPath(id)}`);
|
|
1056
|
+
console.error(`Import chain:`);
|
|
1057
|
+
console.error(formatChain(chain));
|
|
1058
|
+
console.error("");
|
|
1059
|
+
}
|
|
1060
|
+
const importRegex = /import\s+(?:(?:\{[^}]*\}|[^{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
1061
|
+
let match;
|
|
1062
|
+
while ((match = importRegex.exec(code)) !== null) {
|
|
1063
|
+
const importedModule = match[1];
|
|
1064
|
+
importChain.set(importedModule, id);
|
|
1065
|
+
if (isServerOnlyModule(importedModule)) {
|
|
1066
|
+
if (!detectedServerModules.has(importedModule)) {
|
|
1067
|
+
detectedServerModules.add(importedModule);
|
|
1068
|
+
console.error(
|
|
1069
|
+
`
|
|
1070
|
+
[import-chain-tracker] ⚠️ Server-only import detected in client build!`
|
|
1071
|
+
);
|
|
1072
|
+
console.error(`Module "${importedModule}" imported by: ${shortenPath(id)}`);
|
|
1073
|
+
const chain = buildImportChain(id);
|
|
1074
|
+
chain.push(importedModule);
|
|
1075
|
+
console.error(`Import chain:`);
|
|
1076
|
+
console.error(formatChain(chain));
|
|
1077
|
+
console.error("");
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
return null;
|
|
1082
|
+
},
|
|
1083
|
+
buildEnd() {
|
|
1084
|
+
if (detectedServerModules.size > 0) {
|
|
1085
|
+
console.warn(
|
|
1086
|
+
`
|
|
1087
|
+
[import-chain-tracker] ⚠️ ${detectedServerModules.size} server-only module(s) detected during transform:`
|
|
1088
|
+
);
|
|
1089
|
+
for (const mod of detectedServerModules) {
|
|
1090
|
+
console.warn(` - ${mod}`);
|
|
1091
|
+
}
|
|
1092
|
+
console.warn(
|
|
1093
|
+
"\nNote: These may be stripped by the code-split transform if only used in .withServer()."
|
|
1094
|
+
);
|
|
1095
|
+
console.warn(
|
|
1096
|
+
'If build fails with "not exported" errors, check the import chains above.\n'
|
|
1097
|
+
);
|
|
1098
|
+
} else if (verbose) {
|
|
1099
|
+
console.log(
|
|
1100
|
+
"[import-chain-tracker] ✅ No server-only modules detected in client build"
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
function jayStackCompiler(options = {}) {
|
|
1107
|
+
const { trackImports, ...jayOptions } = options;
|
|
1108
|
+
const moduleCache = /* @__PURE__ */ new Map();
|
|
1109
|
+
const shouldTrackImports = trackImports || process.env.DEBUG_IMPORTS === "1";
|
|
1110
|
+
const trackerOptions = typeof trackImports === "object" ? trackImports : { verbose: process.env.DEBUG_IMPORTS === "1" };
|
|
1111
|
+
const plugins = [];
|
|
1112
|
+
if (shouldTrackImports) {
|
|
1113
|
+
plugins.push(createImportChainTracker(trackerOptions));
|
|
1114
|
+
}
|
|
1115
|
+
plugins.push(
|
|
1116
|
+
// First: Jay Stack code splitting transformation
|
|
1117
|
+
{
|
|
1118
|
+
name: "jay-stack:code-split",
|
|
1119
|
+
enforce: "pre",
|
|
1120
|
+
// Run before jay:runtime
|
|
1121
|
+
transform(code, id, options2) {
|
|
1122
|
+
if (!id.endsWith(".ts") && !id.includes(".ts?")) {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
const hasComponent = code.includes("makeJayStackComponent");
|
|
1126
|
+
const hasInit = code.includes("makeJayInit");
|
|
1127
|
+
if (!hasComponent && !hasInit) {
|
|
1128
|
+
return null;
|
|
1129
|
+
}
|
|
1130
|
+
const environment = options2?.ssr ? "server" : "client";
|
|
1131
|
+
try {
|
|
1132
|
+
return transformJayStackBuilder(code, id, environment);
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
console.error(`[jay-stack:code-split] Error transforming ${id}:`, error);
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
},
|
|
1139
|
+
// Second: Action import transformation (client builds only)
|
|
1140
|
+
// Uses resolveId + load to replace action modules with virtual modules
|
|
1141
|
+
// containing createActionCaller calls BEFORE bundling happens.
|
|
1142
|
+
(() => {
|
|
1143
|
+
let isSSRBuild = false;
|
|
1144
|
+
return {
|
|
1145
|
+
name: "jay-stack:action-transform",
|
|
1146
|
+
enforce: "pre",
|
|
1147
|
+
// Track SSR mode from config
|
|
1148
|
+
configResolved(config) {
|
|
1149
|
+
isSSRBuild = config.build?.ssr ?? false;
|
|
1150
|
+
},
|
|
1151
|
+
buildStart() {
|
|
1152
|
+
clearActionMetadataCache();
|
|
1153
|
+
moduleCache.clear();
|
|
1154
|
+
},
|
|
1155
|
+
async resolveId(source, importer, options2) {
|
|
1156
|
+
if (options2?.ssr || isSSRBuild) {
|
|
1157
|
+
return null;
|
|
1158
|
+
}
|
|
1159
|
+
if (!isActionImport(source)) {
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1162
|
+
if (!source.startsWith(".") || !importer) {
|
|
1163
|
+
return null;
|
|
1164
|
+
}
|
|
1165
|
+
const importerDir = path.dirname(importer);
|
|
1166
|
+
let resolvedPath = path.resolve(importerDir, source);
|
|
1167
|
+
if (!resolvedPath.endsWith(".ts") && !resolvedPath.endsWith(".js")) {
|
|
1168
|
+
if (fs.existsSync(resolvedPath + ".ts")) {
|
|
1169
|
+
resolvedPath += ".ts";
|
|
1170
|
+
} else if (fs.existsSync(resolvedPath + ".js")) {
|
|
1171
|
+
resolvedPath += ".js";
|
|
1172
|
+
} else {
|
|
1173
|
+
return null;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
return `\0jay-action:${resolvedPath}`;
|
|
1177
|
+
},
|
|
1178
|
+
async load(id) {
|
|
1179
|
+
if (!id.startsWith("\0jay-action:")) {
|
|
1180
|
+
return null;
|
|
1181
|
+
}
|
|
1182
|
+
const actualPath = id.slice("\0jay-action:".length);
|
|
1183
|
+
let code;
|
|
1184
|
+
try {
|
|
1185
|
+
code = await fs.promises.readFile(actualPath, "utf-8");
|
|
1186
|
+
} catch (err) {
|
|
1187
|
+
console.error(`[action-transform] Could not read ${actualPath}:`, err);
|
|
1188
|
+
return null;
|
|
1189
|
+
}
|
|
1190
|
+
const actions = extractActionsFromSource(code, actualPath);
|
|
1191
|
+
if (actions.length === 0) {
|
|
1192
|
+
console.warn(`[action-transform] No actions found in ${actualPath}`);
|
|
1193
|
+
return null;
|
|
1194
|
+
}
|
|
1195
|
+
const lines = [
|
|
1196
|
+
`import { createActionCaller } from '@jay-framework/stack-client-runtime';`,
|
|
1197
|
+
""
|
|
1198
|
+
];
|
|
1199
|
+
for (const action of actions) {
|
|
1200
|
+
lines.push(
|
|
1201
|
+
`export const ${action.exportName} = createActionCaller('${action.actionName}', '${action.method}');`
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
if (code.includes("ActionError")) {
|
|
1205
|
+
lines.push(
|
|
1206
|
+
`export { ActionError } from '@jay-framework/stack-client-runtime';`
|
|
1207
|
+
);
|
|
1208
|
+
}
|
|
1209
|
+
const result = lines.join("\n");
|
|
1210
|
+
return result;
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
})(),
|
|
1214
|
+
// Third: Jay runtime compilation (existing plugin)
|
|
1215
|
+
jayRuntime(jayOptions)
|
|
1216
|
+
);
|
|
1217
|
+
return plugins;
|
|
1218
|
+
}
|
|
15
1219
|
class ServiceLifecycleManager {
|
|
16
1220
|
constructor(projectRoot, sourceBase = "src") {
|
|
17
|
-
|
|
1221
|
+
/** Path to project's lib/init.ts (makeJayInit pattern) */
|
|
1222
|
+
__publicField(this, "projectInitFilePath", null);
|
|
18
1223
|
__publicField(this, "isInitialized", false);
|
|
19
1224
|
__publicField(this, "viteServer", null);
|
|
1225
|
+
__publicField(this, "pluginsWithInit", []);
|
|
20
1226
|
this.projectRoot = projectRoot;
|
|
21
1227
|
this.sourceBase = sourceBase;
|
|
22
1228
|
}
|
|
@@ -27,14 +1233,13 @@ class ServiceLifecycleManager {
|
|
|
27
1233
|
this.viteServer = viteServer;
|
|
28
1234
|
}
|
|
29
1235
|
/**
|
|
30
|
-
* Finds the
|
|
31
|
-
* Looks in: {projectRoot}/{sourceBase}/
|
|
1236
|
+
* Finds the project init file using makeJayInit pattern.
|
|
1237
|
+
* Looks in: {projectRoot}/{sourceBase}/init.{ts,js}
|
|
32
1238
|
*/
|
|
33
|
-
|
|
34
|
-
const extensions = [".ts", ".js"
|
|
35
|
-
const baseFilename = "jay.init";
|
|
1239
|
+
findProjectInitFile() {
|
|
1240
|
+
const extensions = [".ts", ".js"];
|
|
36
1241
|
for (const ext of extensions) {
|
|
37
|
-
const filePath = path.join(this.projectRoot, this.sourceBase,
|
|
1242
|
+
const filePath = path.join(this.projectRoot, this.sourceBase, "init" + ext);
|
|
38
1243
|
if (fs.existsSync(filePath)) {
|
|
39
1244
|
return filePath;
|
|
40
1245
|
}
|
|
@@ -42,32 +1247,88 @@ class ServiceLifecycleManager {
|
|
|
42
1247
|
return null;
|
|
43
1248
|
}
|
|
44
1249
|
/**
|
|
45
|
-
* Initializes services by
|
|
1250
|
+
* Initializes services by:
|
|
1251
|
+
* 1. Discovering and executing plugin server inits (in dependency order)
|
|
1252
|
+
* 2. Loading and executing project lib/init.ts
|
|
1253
|
+
* 3. Running all registered onInit callbacks
|
|
1254
|
+
* 4. Auto-discovering and registering actions
|
|
46
1255
|
*/
|
|
47
1256
|
async initialize() {
|
|
48
1257
|
if (this.isInitialized) {
|
|
49
1258
|
console.warn("[Services] Already initialized, skipping...");
|
|
50
1259
|
return;
|
|
51
1260
|
}
|
|
52
|
-
this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1261
|
+
this.projectInitFilePath = this.findProjectInitFile();
|
|
1262
|
+
const discoveredPlugins = await discoverPluginsWithInit({
|
|
1263
|
+
projectRoot: this.projectRoot,
|
|
1264
|
+
verbose: true
|
|
1265
|
+
});
|
|
1266
|
+
this.pluginsWithInit = sortPluginsByDependencies(discoveredPlugins);
|
|
1267
|
+
if (this.pluginsWithInit.length > 0) {
|
|
1268
|
+
console.log(
|
|
1269
|
+
`[Services] Found ${this.pluginsWithInit.length} plugin(s) with init: ${this.pluginsWithInit.map((p) => p.name).join(", ")}`
|
|
1270
|
+
);
|
|
56
1271
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
1272
|
+
await executePluginServerInits(this.pluginsWithInit, this.viteServer ?? void 0, true);
|
|
1273
|
+
if (this.projectInitFilePath) {
|
|
1274
|
+
console.log("[DevServer] Loading project init: src/init.ts");
|
|
1275
|
+
try {
|
|
1276
|
+
if (this.viteServer) {
|
|
1277
|
+
const module = await this.viteServer.ssrLoadModule(this.projectInitFilePath);
|
|
1278
|
+
if (module.init?._serverInit) {
|
|
1279
|
+
console.log("[DevServer] Running server init: project");
|
|
1280
|
+
const { setClientInitData } = await import("@jay-framework/stack-server-runtime");
|
|
1281
|
+
const clientData = await module.init._serverInit();
|
|
1282
|
+
if (clientData !== void 0 && clientData !== null) {
|
|
1283
|
+
setClientInitData("project", clientData);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
} else {
|
|
1287
|
+
const fileUrl = pathToFileURL(this.projectInitFilePath).href;
|
|
1288
|
+
await import(fileUrl);
|
|
1289
|
+
}
|
|
1290
|
+
} catch (error) {
|
|
1291
|
+
console.error("[Services] Failed to load project init:", error);
|
|
1292
|
+
throw error;
|
|
64
1293
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
1294
|
+
} else {
|
|
1295
|
+
console.log("[Services] No init.ts found, skipping project initialization");
|
|
1296
|
+
}
|
|
1297
|
+
await runInitCallbacks();
|
|
1298
|
+
console.log("[Services] Initialization complete");
|
|
1299
|
+
await this.discoverActions();
|
|
1300
|
+
this.isInitialized = true;
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Auto-discovers and registers actions from project and plugins.
|
|
1304
|
+
*/
|
|
1305
|
+
async discoverActions() {
|
|
1306
|
+
let totalActions = 0;
|
|
1307
|
+
try {
|
|
1308
|
+
const result = await discoverAndRegisterActions({
|
|
1309
|
+
projectRoot: this.projectRoot,
|
|
1310
|
+
actionsDir: path.join(this.sourceBase, "actions"),
|
|
1311
|
+
registry: actionRegistry,
|
|
1312
|
+
verbose: true,
|
|
1313
|
+
viteServer: this.viteServer ?? void 0
|
|
1314
|
+
});
|
|
1315
|
+
totalActions += result.actionCount;
|
|
68
1316
|
} catch (error) {
|
|
69
|
-
console.error("[
|
|
70
|
-
|
|
1317
|
+
console.error("[Actions] Failed to auto-discover project actions:", error);
|
|
1318
|
+
}
|
|
1319
|
+
try {
|
|
1320
|
+
const pluginActions = await discoverAllPluginActions({
|
|
1321
|
+
projectRoot: this.projectRoot,
|
|
1322
|
+
registry: actionRegistry,
|
|
1323
|
+
verbose: true,
|
|
1324
|
+
viteServer: this.viteServer ?? void 0
|
|
1325
|
+
});
|
|
1326
|
+
totalActions += pluginActions.length;
|
|
1327
|
+
} catch (error) {
|
|
1328
|
+
console.error("[Actions] Failed to auto-discover plugin actions:", error);
|
|
1329
|
+
}
|
|
1330
|
+
if (totalActions > 0) {
|
|
1331
|
+
console.log(`[Actions] Auto-registered ${totalActions} action(s) total`);
|
|
71
1332
|
}
|
|
72
1333
|
}
|
|
73
1334
|
/**
|
|
@@ -100,31 +1361,48 @@ class ServiceLifecycleManager {
|
|
|
100
1361
|
* Hot reload: shutdown, clear caches, re-import, and re-initialize
|
|
101
1362
|
*/
|
|
102
1363
|
async reload() {
|
|
103
|
-
if (!this.initFilePath) {
|
|
104
|
-
console.log("[Services] No init file to reload");
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
1364
|
console.log("[Services] Reloading services...");
|
|
108
1365
|
await this.shutdown();
|
|
109
1366
|
clearLifecycleCallbacks();
|
|
110
1367
|
clearServiceRegistry();
|
|
111
|
-
|
|
112
|
-
|
|
1368
|
+
clearClientInitData();
|
|
1369
|
+
actionRegistry.clear();
|
|
1370
|
+
if (this.projectInitFilePath && this.viteServer) {
|
|
1371
|
+
const moduleNode = this.viteServer.moduleGraph.getModuleById(this.projectInitFilePath);
|
|
113
1372
|
if (moduleNode) {
|
|
114
1373
|
await this.viteServer.moduleGraph.invalidateModule(moduleNode);
|
|
115
1374
|
}
|
|
116
|
-
} else {
|
|
117
|
-
delete require.cache[require.resolve(this.
|
|
1375
|
+
} else if (this.projectInitFilePath) {
|
|
1376
|
+
delete require.cache[require.resolve(this.projectInitFilePath)];
|
|
118
1377
|
}
|
|
119
1378
|
this.isInitialized = false;
|
|
120
1379
|
await this.initialize();
|
|
121
1380
|
console.log("[Services] Reload complete");
|
|
122
1381
|
}
|
|
123
1382
|
/**
|
|
124
|
-
* Returns the path to the init file if found
|
|
1383
|
+
* Returns the path to the init file if found.
|
|
125
1384
|
*/
|
|
126
1385
|
getInitFilePath() {
|
|
127
|
-
return this.
|
|
1386
|
+
return this.projectInitFilePath;
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Returns project init info for client-side embedding.
|
|
1390
|
+
*/
|
|
1391
|
+
getProjectInit() {
|
|
1392
|
+
if (!this.projectInitFilePath) {
|
|
1393
|
+
return null;
|
|
1394
|
+
}
|
|
1395
|
+
return {
|
|
1396
|
+
importPath: this.projectInitFilePath,
|
|
1397
|
+
initExport: "init"
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Returns the discovered plugins with init configurations.
|
|
1402
|
+
* Sorted by dependencies (plugins with no deps first).
|
|
1403
|
+
*/
|
|
1404
|
+
getPluginsWithInit() {
|
|
1405
|
+
return this.pluginsWithInit;
|
|
128
1406
|
}
|
|
129
1407
|
/**
|
|
130
1408
|
* Checks if services are initialized
|
|
@@ -133,6 +1411,212 @@ class ServiceLifecycleManager {
|
|
|
133
1411
|
return this.isInitialized;
|
|
134
1412
|
}
|
|
135
1413
|
}
|
|
1414
|
+
function deepMergeViewStates(base, overlay, trackByMap, path2 = "") {
|
|
1415
|
+
if (!base && !overlay)
|
|
1416
|
+
return {};
|
|
1417
|
+
if (!base)
|
|
1418
|
+
return overlay || {};
|
|
1419
|
+
if (!overlay)
|
|
1420
|
+
return base || {};
|
|
1421
|
+
const result = {};
|
|
1422
|
+
const allKeys = /* @__PURE__ */ new Set([...Object.keys(base), ...Object.keys(overlay)]);
|
|
1423
|
+
for (const key of allKeys) {
|
|
1424
|
+
const baseValue = base[key];
|
|
1425
|
+
const overlayValue = overlay[key];
|
|
1426
|
+
const currentPath = path2 ? `${path2}.${key}` : key;
|
|
1427
|
+
if (overlayValue === void 0) {
|
|
1428
|
+
result[key] = baseValue;
|
|
1429
|
+
} else if (baseValue === void 0) {
|
|
1430
|
+
result[key] = overlayValue;
|
|
1431
|
+
} else if (Array.isArray(baseValue) && Array.isArray(overlayValue)) {
|
|
1432
|
+
const trackByField = trackByMap[currentPath];
|
|
1433
|
+
if (trackByField) {
|
|
1434
|
+
result[key] = mergeArraysByTrackBy(
|
|
1435
|
+
baseValue,
|
|
1436
|
+
overlayValue,
|
|
1437
|
+
trackByField,
|
|
1438
|
+
trackByMap,
|
|
1439
|
+
currentPath
|
|
1440
|
+
);
|
|
1441
|
+
} else {
|
|
1442
|
+
result[key] = overlayValue;
|
|
1443
|
+
}
|
|
1444
|
+
} else if (typeof baseValue === "object" && baseValue !== null && typeof overlayValue === "object" && overlayValue !== null && !Array.isArray(baseValue) && !Array.isArray(overlayValue)) {
|
|
1445
|
+
result[key] = deepMergeViewStates(baseValue, overlayValue, trackByMap, currentPath);
|
|
1446
|
+
} else {
|
|
1447
|
+
result[key] = overlayValue;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
return result;
|
|
1451
|
+
}
|
|
1452
|
+
function mergeArraysByTrackBy(baseArray, overlayArray, trackByField, trackByMap, arrayPath) {
|
|
1453
|
+
const baseByKey = /* @__PURE__ */ new Map();
|
|
1454
|
+
for (const item of baseArray) {
|
|
1455
|
+
const key = item[trackByField];
|
|
1456
|
+
if (key !== void 0 && key !== null) {
|
|
1457
|
+
if (baseByKey.has(key)) {
|
|
1458
|
+
console.warn(
|
|
1459
|
+
`Duplicate trackBy key [${key}] in base array at path [${arrayPath}]. This may cause incorrect merging.`
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
baseByKey.set(key, item);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
const overlayByKey = /* @__PURE__ */ new Map();
|
|
1466
|
+
for (const item of overlayArray) {
|
|
1467
|
+
const key = item[trackByField];
|
|
1468
|
+
if (key !== void 0 && key !== null) {
|
|
1469
|
+
overlayByKey.set(key, item);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return baseArray.map((baseItem) => {
|
|
1473
|
+
const key = baseItem[trackByField];
|
|
1474
|
+
if (key === void 0 || key === null) {
|
|
1475
|
+
return baseItem;
|
|
1476
|
+
}
|
|
1477
|
+
const overlayItem = overlayByKey.get(key);
|
|
1478
|
+
if (overlayItem) {
|
|
1479
|
+
return deepMergeViewStates(baseItem, overlayItem, trackByMap, arrayPath);
|
|
1480
|
+
} else {
|
|
1481
|
+
return baseItem;
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
const ACTION_ENDPOINT_BASE = "/_jay/actions";
|
|
1486
|
+
function createActionRouter(options) {
|
|
1487
|
+
const registry = options?.registry ?? actionRegistry;
|
|
1488
|
+
return async (req, res) => {
|
|
1489
|
+
const actionName = req.path.slice(1);
|
|
1490
|
+
if (!actionName) {
|
|
1491
|
+
res.status(400).json({
|
|
1492
|
+
success: false,
|
|
1493
|
+
error: {
|
|
1494
|
+
code: "MISSING_ACTION_NAME",
|
|
1495
|
+
message: "Action name is required",
|
|
1496
|
+
isActionError: false
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
const action = registry.get(actionName);
|
|
1502
|
+
if (!action) {
|
|
1503
|
+
res.status(404).json({
|
|
1504
|
+
success: false,
|
|
1505
|
+
error: {
|
|
1506
|
+
code: "ACTION_NOT_FOUND",
|
|
1507
|
+
message: `Action '${actionName}' is not registered`,
|
|
1508
|
+
isActionError: false
|
|
1509
|
+
}
|
|
1510
|
+
});
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
const requestMethod = req.method.toUpperCase();
|
|
1514
|
+
if (requestMethod !== action.method) {
|
|
1515
|
+
res.status(405).json({
|
|
1516
|
+
success: false,
|
|
1517
|
+
error: {
|
|
1518
|
+
code: "METHOD_NOT_ALLOWED",
|
|
1519
|
+
message: `Action '${actionName}' expects ${action.method}, got ${requestMethod}`,
|
|
1520
|
+
isActionError: false
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
let input;
|
|
1526
|
+
try {
|
|
1527
|
+
if (requestMethod === "GET") {
|
|
1528
|
+
if (req.query._input) {
|
|
1529
|
+
input = JSON.parse(req.query._input);
|
|
1530
|
+
} else {
|
|
1531
|
+
input = { ...req.query };
|
|
1532
|
+
delete input._input;
|
|
1533
|
+
}
|
|
1534
|
+
} else {
|
|
1535
|
+
input = req.body;
|
|
1536
|
+
}
|
|
1537
|
+
} catch (parseError) {
|
|
1538
|
+
res.status(400).json({
|
|
1539
|
+
success: false,
|
|
1540
|
+
error: {
|
|
1541
|
+
code: "INVALID_INPUT",
|
|
1542
|
+
message: "Failed to parse request input",
|
|
1543
|
+
isActionError: false
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
const result = await registry.execute(actionName, input);
|
|
1549
|
+
if (requestMethod === "GET" && result.success) {
|
|
1550
|
+
const cacheHeaders = registry.getCacheHeaders(actionName);
|
|
1551
|
+
if (cacheHeaders) {
|
|
1552
|
+
res.set("Cache-Control", cacheHeaders);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
if (result.success) {
|
|
1556
|
+
res.status(200).json({
|
|
1557
|
+
success: true,
|
|
1558
|
+
data: result.data
|
|
1559
|
+
});
|
|
1560
|
+
} else {
|
|
1561
|
+
const statusCode = getStatusCodeForError(result.error.code, result.error.isActionError);
|
|
1562
|
+
res.status(statusCode).json({
|
|
1563
|
+
success: false,
|
|
1564
|
+
error: result.error
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
function getStatusCodeForError(code, isActionError) {
|
|
1570
|
+
if (isActionError) {
|
|
1571
|
+
return 422;
|
|
1572
|
+
}
|
|
1573
|
+
switch (code) {
|
|
1574
|
+
case "ACTION_NOT_FOUND":
|
|
1575
|
+
return 404;
|
|
1576
|
+
case "INVALID_INPUT":
|
|
1577
|
+
case "VALIDATION_ERROR":
|
|
1578
|
+
return 400;
|
|
1579
|
+
case "UNAUTHORIZED":
|
|
1580
|
+
return 401;
|
|
1581
|
+
case "FORBIDDEN":
|
|
1582
|
+
return 403;
|
|
1583
|
+
case "INTERNAL_ERROR":
|
|
1584
|
+
default:
|
|
1585
|
+
return 500;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
function actionBodyParser() {
|
|
1589
|
+
return (req, res, next) => {
|
|
1590
|
+
if (!req.path.startsWith(ACTION_ENDPOINT_BASE)) {
|
|
1591
|
+
next();
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
if (req.method === "GET") {
|
|
1595
|
+
next();
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
let body = "";
|
|
1599
|
+
req.setEncoding("utf8");
|
|
1600
|
+
req.on("data", (chunk) => {
|
|
1601
|
+
body += chunk;
|
|
1602
|
+
});
|
|
1603
|
+
req.on("end", () => {
|
|
1604
|
+
try {
|
|
1605
|
+
req.body = body ? JSON.parse(body) : {};
|
|
1606
|
+
next();
|
|
1607
|
+
} catch (e2) {
|
|
1608
|
+
res.status(400).json({
|
|
1609
|
+
success: false,
|
|
1610
|
+
error: {
|
|
1611
|
+
code: "INVALID_JSON",
|
|
1612
|
+
message: "Invalid JSON in request body",
|
|
1613
|
+
isActionError: false
|
|
1614
|
+
}
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
});
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
136
1620
|
async function initRoutes(pagesBaseFolder) {
|
|
137
1621
|
return await scanRoutes(pagesBaseFolder, {
|
|
138
1622
|
jayHtmlFilename: "page.jay-html",
|
|
@@ -142,7 +1626,10 @@ async function initRoutes(pagesBaseFolder) {
|
|
|
142
1626
|
function defaults(options) {
|
|
143
1627
|
const publicBaseUrlPath = options.publicBaseUrlPath || process.env.BASE || "/";
|
|
144
1628
|
const projectRootFolder = options.projectRootFolder || ".";
|
|
145
|
-
const pagesRootFolder = path__default.resolve(
|
|
1629
|
+
const pagesRootFolder = path__default.resolve(
|
|
1630
|
+
projectRootFolder,
|
|
1631
|
+
options.pagesRootFolder || "./src/pages"
|
|
1632
|
+
);
|
|
146
1633
|
const tsConfigFilePath = options.jayRollupConfig.tsConfigFilePath || path__default.resolve(projectRootFolder, "./tsconfig.json");
|
|
147
1634
|
return {
|
|
148
1635
|
publicBaseUrlPath,
|
|
@@ -163,7 +1650,7 @@ function handleOtherResponseCodes(res, renderedResult) {
|
|
|
163
1650
|
else
|
|
164
1651
|
res.status(renderedResult.status).end("redirect to " + renderedResult.location);
|
|
165
1652
|
}
|
|
166
|
-
function mkRoute(route, vite, slowlyPhase, options) {
|
|
1653
|
+
function mkRoute(route, vite, slowlyPhase, options, projectInit, allPluginsWithInit = [], allPluginClientInits = []) {
|
|
167
1654
|
const path2 = routeToExpressRoute(route);
|
|
168
1655
|
const handler = async (req, res) => {
|
|
169
1656
|
try {
|
|
@@ -174,33 +1661,56 @@ function mkRoute(route, vite, slowlyPhase, options) {
|
|
|
174
1661
|
url
|
|
175
1662
|
};
|
|
176
1663
|
let viewState, carryForward;
|
|
177
|
-
const
|
|
1664
|
+
const pagePartsResult = await loadPageParts(
|
|
178
1665
|
vite,
|
|
179
1666
|
route,
|
|
180
1667
|
options.pagesRootFolder,
|
|
1668
|
+
options.projectRootFolder,
|
|
181
1669
|
options.jayRollupConfig
|
|
182
1670
|
);
|
|
183
|
-
if (
|
|
1671
|
+
if (pagePartsResult.val) {
|
|
1672
|
+
const {
|
|
1673
|
+
parts: pageParts,
|
|
1674
|
+
serverTrackByMap,
|
|
1675
|
+
clientTrackByMap,
|
|
1676
|
+
usedPackages
|
|
1677
|
+
} = pagePartsResult.val;
|
|
1678
|
+
const pluginsForPage = allPluginClientInits.filter((plugin) => {
|
|
1679
|
+
const pluginInfo = allPluginsWithInit.find((p) => p.name === plugin.name);
|
|
1680
|
+
return pluginInfo && usedPackages.has(pluginInfo.packageName);
|
|
1681
|
+
});
|
|
184
1682
|
const renderedSlowly = await slowlyPhase.runSlowlyForPage(
|
|
185
1683
|
pageParams,
|
|
186
1684
|
pageProps,
|
|
187
|
-
pageParts
|
|
1685
|
+
pageParts
|
|
188
1686
|
);
|
|
189
|
-
if (renderedSlowly.kind === "
|
|
1687
|
+
if (renderedSlowly.kind === "PhaseOutput") {
|
|
190
1688
|
const renderedFast = await renderFastChangingData(
|
|
191
1689
|
pageParams,
|
|
192
1690
|
pageProps,
|
|
193
1691
|
renderedSlowly.carryForward,
|
|
194
|
-
pageParts
|
|
1692
|
+
pageParts
|
|
195
1693
|
);
|
|
196
|
-
if (renderedFast.kind === "
|
|
197
|
-
|
|
1694
|
+
if (renderedFast.kind === "PhaseOutput") {
|
|
1695
|
+
if (serverTrackByMap && Object.keys(serverTrackByMap).length > 0) {
|
|
1696
|
+
viewState = deepMergeViewStates(
|
|
1697
|
+
renderedSlowly.rendered,
|
|
1698
|
+
renderedFast.rendered,
|
|
1699
|
+
serverTrackByMap
|
|
1700
|
+
);
|
|
1701
|
+
} else {
|
|
1702
|
+
viewState = { ...renderedSlowly.rendered, ...renderedFast.rendered };
|
|
1703
|
+
}
|
|
198
1704
|
carryForward = renderedFast.carryForward;
|
|
199
1705
|
const pageHtml = generateClientScript(
|
|
200
1706
|
viewState,
|
|
201
1707
|
carryForward,
|
|
202
|
-
pageParts
|
|
203
|
-
route.jayHtmlPath
|
|
1708
|
+
pageParts,
|
|
1709
|
+
route.jayHtmlPath,
|
|
1710
|
+
clientTrackByMap,
|
|
1711
|
+
getClientInitData(),
|
|
1712
|
+
projectInit,
|
|
1713
|
+
pluginsForPage
|
|
204
1714
|
);
|
|
205
1715
|
const compiledPageHtml = await vite.transformIndexHtml(
|
|
206
1716
|
!!url ? url : "/",
|
|
@@ -214,40 +1724,50 @@ function mkRoute(route, vite, slowlyPhase, options) {
|
|
|
214
1724
|
handleOtherResponseCodes(res, renderedSlowly);
|
|
215
1725
|
}
|
|
216
1726
|
} else {
|
|
217
|
-
console.log(
|
|
218
|
-
res.status(500).end(
|
|
1727
|
+
console.log(pagePartsResult.validations.join("\n"));
|
|
1728
|
+
res.status(500).end(pagePartsResult.validations.join("\n"));
|
|
219
1729
|
}
|
|
220
|
-
} catch (
|
|
221
|
-
vite?.ssrFixStacktrace(
|
|
222
|
-
console.log(
|
|
223
|
-
res.status(500).end(
|
|
1730
|
+
} catch (e2) {
|
|
1731
|
+
vite?.ssrFixStacktrace(e2);
|
|
1732
|
+
console.log(e2.stack);
|
|
1733
|
+
res.status(500).end(e2.stack);
|
|
224
1734
|
}
|
|
225
1735
|
};
|
|
226
1736
|
return { path: path2, handler, fsRoute: route };
|
|
227
1737
|
}
|
|
228
1738
|
async function mkDevServer(options) {
|
|
229
|
-
const {
|
|
1739
|
+
const {
|
|
1740
|
+
publicBaseUrlPath,
|
|
1741
|
+
pagesRootFolder,
|
|
1742
|
+
projectRootFolder,
|
|
1743
|
+
jayRollupConfig,
|
|
1744
|
+
dontCacheSlowly
|
|
1745
|
+
} = defaults(options);
|
|
230
1746
|
const lifecycleManager = new ServiceLifecycleManager(projectRootFolder);
|
|
231
1747
|
setupGracefulShutdown(lifecycleManager);
|
|
232
1748
|
const vite = await createServer({
|
|
233
1749
|
server: { middlewareMode: true },
|
|
234
|
-
plugins: [
|
|
1750
|
+
plugins: [...jayStackCompiler(jayRollupConfig)],
|
|
235
1751
|
appType: "custom",
|
|
236
1752
|
base: publicBaseUrlPath,
|
|
237
1753
|
root: pagesRootFolder,
|
|
238
1754
|
ssr: {
|
|
239
1755
|
// Mark stack-server-runtime as external so Vite uses Node's require
|
|
240
|
-
// This ensures
|
|
1756
|
+
// This ensures lib/init.ts and dev-server share the same module instance
|
|
241
1757
|
external: ["@jay-framework/stack-server-runtime"]
|
|
242
1758
|
}
|
|
243
1759
|
});
|
|
244
1760
|
lifecycleManager.setViteServer(vite);
|
|
245
1761
|
await lifecycleManager.initialize();
|
|
246
1762
|
setupServiceHotReload(vite, lifecycleManager);
|
|
1763
|
+
setupActionRouter(vite);
|
|
247
1764
|
const routes = await initRoutes(pagesRootFolder);
|
|
248
1765
|
const slowlyPhase = new DevSlowlyChangingPhase(dontCacheSlowly);
|
|
1766
|
+
const projectInit = lifecycleManager.getProjectInit() ?? void 0;
|
|
1767
|
+
const pluginsWithInit = lifecycleManager.getPluginsWithInit();
|
|
1768
|
+
const pluginClientInits = preparePluginClientInits(pluginsWithInit);
|
|
249
1769
|
const devServerRoutes = routes.map(
|
|
250
|
-
(route) => mkRoute(route, vite, slowlyPhase, options)
|
|
1770
|
+
(route) => mkRoute(route, vite, slowlyPhase, options, projectInit, pluginsWithInit, pluginClientInits)
|
|
251
1771
|
);
|
|
252
1772
|
return {
|
|
253
1773
|
server: vite.middlewares,
|
|
@@ -274,7 +1794,7 @@ function setupServiceHotReload(vite, lifecycleManager) {
|
|
|
274
1794
|
vite.watcher.add(initFilePath);
|
|
275
1795
|
vite.watcher.on("change", async (changedPath) => {
|
|
276
1796
|
if (changedPath === initFilePath) {
|
|
277
|
-
console.log("[Services]
|
|
1797
|
+
console.log("[Services] lib/init.ts changed, reloading services...");
|
|
278
1798
|
try {
|
|
279
1799
|
await lifecycleManager.reload();
|
|
280
1800
|
vite.ws.send({
|
|
@@ -287,6 +1807,14 @@ function setupServiceHotReload(vite, lifecycleManager) {
|
|
|
287
1807
|
}
|
|
288
1808
|
});
|
|
289
1809
|
}
|
|
1810
|
+
function setupActionRouter(vite) {
|
|
1811
|
+
vite.middlewares.use(actionBodyParser());
|
|
1812
|
+
vite.middlewares.use(ACTION_ENDPOINT_BASE, createActionRouter());
|
|
1813
|
+
console.log(`[Actions] Action router mounted at ${ACTION_ENDPOINT_BASE}`);
|
|
1814
|
+
}
|
|
290
1815
|
export {
|
|
1816
|
+
ACTION_ENDPOINT_BASE,
|
|
1817
|
+
actionBodyParser,
|
|
1818
|
+
createActionRouter,
|
|
291
1819
|
mkDevServer
|
|
292
1820
|
};
|