@constela/server 17.0.1 → 18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -24
- package/dist/index.js +59 -1143
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import { CompiledProgram } from '@constela/compiler';
|
|
2
|
-
import { StreamingRenderOptions } from '@constela/core';
|
|
2
|
+
import { StylePreset, StreamingRenderOptions } from '@constela/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* SSR Renderer
|
|
6
6
|
*
|
|
7
7
|
* Renders CompiledProgram to HTML string for Server-Side Rendering.
|
|
8
|
+
* Uses the unified evaluate module from @constela/core.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
|
-
/**
|
|
11
|
-
* Style preset definition for SSR
|
|
12
|
-
*/
|
|
13
|
-
interface StylePreset$1 {
|
|
14
|
-
base: string;
|
|
15
|
-
variants?: Record<string, Record<string, string>>;
|
|
16
|
-
defaultVariants?: Record<string, string>;
|
|
17
|
-
compoundVariants?: Array<Record<string, string> & {
|
|
18
|
-
class: string;
|
|
19
|
-
}>;
|
|
20
|
-
}
|
|
21
11
|
/**
|
|
22
12
|
* Options for renderToString
|
|
23
13
|
*/
|
|
@@ -28,7 +18,7 @@ interface RenderOptions {
|
|
|
28
18
|
path?: string;
|
|
29
19
|
};
|
|
30
20
|
imports?: Record<string, unknown>;
|
|
31
|
-
styles?: Record<string, StylePreset
|
|
21
|
+
styles?: Record<string, StylePreset>;
|
|
32
22
|
stateOverrides?: Record<string, unknown>;
|
|
33
23
|
cookies?: Record<string, string>;
|
|
34
24
|
}
|
|
@@ -46,6 +36,7 @@ declare function renderToString(program: CompiledProgram, options?: RenderOption
|
|
|
46
36
|
*
|
|
47
37
|
* Renders CompiledProgram to a ReadableStream for Server-Side Rendering.
|
|
48
38
|
* Uses Web Streams API for Edge Runtime compatibility.
|
|
39
|
+
* Uses the unified evaluate module from @constela/core.
|
|
49
40
|
*
|
|
50
41
|
* Features:
|
|
51
42
|
* - Three flush strategies: immediate, batched, manual
|
|
@@ -54,17 +45,6 @@ declare function renderToString(program: CompiledProgram, options?: RenderOption
|
|
|
54
45
|
* - Suspense boundary support for async content
|
|
55
46
|
*/
|
|
56
47
|
|
|
57
|
-
/**
|
|
58
|
-
* Style preset definition for SSR
|
|
59
|
-
*/
|
|
60
|
-
interface StylePreset {
|
|
61
|
-
base: string;
|
|
62
|
-
variants?: Record<string, Record<string, string>>;
|
|
63
|
-
defaultVariants?: Record<string, string>;
|
|
64
|
-
compoundVariants?: Array<Record<string, string> & {
|
|
65
|
-
class: string;
|
|
66
|
-
}>;
|
|
67
|
-
}
|
|
68
48
|
/**
|
|
69
49
|
* Extended options for streaming render
|
|
70
50
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/renderer.ts
|
|
2
|
-
import { isCookieInitialExpr,
|
|
2
|
+
import { isCookieInitialExpr, evaluate as coreEvaluate } from "@constela/core";
|
|
3
3
|
|
|
4
4
|
// src/markdown.ts
|
|
5
5
|
import { marked } from "marked";
|
|
@@ -108,7 +108,37 @@ async function parseMarkdownSSRAsync(content) {
|
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
// src/
|
|
111
|
+
// src/shared.ts
|
|
112
|
+
import { GLOBAL_FUNCTIONS } from "@constela/core";
|
|
113
|
+
var ssrAdapter = {
|
|
114
|
+
resolveRef: () => null,
|
|
115
|
+
resolveValidity: () => false,
|
|
116
|
+
resolveGlobal(name) {
|
|
117
|
+
const safeGlobals = {
|
|
118
|
+
JSON,
|
|
119
|
+
Math,
|
|
120
|
+
Date,
|
|
121
|
+
Object,
|
|
122
|
+
Array,
|
|
123
|
+
String,
|
|
124
|
+
Number,
|
|
125
|
+
Boolean,
|
|
126
|
+
console,
|
|
127
|
+
...GLOBAL_FUNCTIONS
|
|
128
|
+
};
|
|
129
|
+
return safeGlobals[name];
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
function toCoreContext(ctx) {
|
|
133
|
+
return {
|
|
134
|
+
state: ctx.state,
|
|
135
|
+
locals: ctx.locals,
|
|
136
|
+
route: ctx.route,
|
|
137
|
+
imports: ctx.imports,
|
|
138
|
+
styles: ctx.styles,
|
|
139
|
+
env: ssrAdapter
|
|
140
|
+
};
|
|
141
|
+
}
|
|
112
142
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
113
143
|
"area",
|
|
114
144
|
"base",
|
|
@@ -125,557 +155,6 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
125
155
|
"track",
|
|
126
156
|
"wbr"
|
|
127
157
|
]);
|
|
128
|
-
var SAFE_ARRAY_METHODS = /* @__PURE__ */ new Set([
|
|
129
|
-
"length",
|
|
130
|
-
"at",
|
|
131
|
-
"includes",
|
|
132
|
-
"slice",
|
|
133
|
-
"indexOf",
|
|
134
|
-
"join",
|
|
135
|
-
"filter",
|
|
136
|
-
"map",
|
|
137
|
-
"find",
|
|
138
|
-
"findIndex",
|
|
139
|
-
"some",
|
|
140
|
-
"every"
|
|
141
|
-
]);
|
|
142
|
-
var SAFE_STRING_METHODS = /* @__PURE__ */ new Set([
|
|
143
|
-
"length",
|
|
144
|
-
"charAt",
|
|
145
|
-
"substring",
|
|
146
|
-
"slice",
|
|
147
|
-
"split",
|
|
148
|
-
"trim",
|
|
149
|
-
"toUpperCase",
|
|
150
|
-
"toLowerCase",
|
|
151
|
-
"replace",
|
|
152
|
-
"includes",
|
|
153
|
-
"startsWith",
|
|
154
|
-
"endsWith",
|
|
155
|
-
"indexOf"
|
|
156
|
-
]);
|
|
157
|
-
var SAFE_MATH_METHODS = /* @__PURE__ */ new Set([
|
|
158
|
-
"min",
|
|
159
|
-
"max",
|
|
160
|
-
"round",
|
|
161
|
-
"floor",
|
|
162
|
-
"ceil",
|
|
163
|
-
"abs",
|
|
164
|
-
"sqrt",
|
|
165
|
-
"pow",
|
|
166
|
-
"random",
|
|
167
|
-
"sin",
|
|
168
|
-
"cos",
|
|
169
|
-
"tan"
|
|
170
|
-
]);
|
|
171
|
-
var SAFE_DATE_STATIC_METHODS = /* @__PURE__ */ new Set(["now", "parse"]);
|
|
172
|
-
var SAFE_DATE_INSTANCE_METHODS = /* @__PURE__ */ new Set([
|
|
173
|
-
"toISOString",
|
|
174
|
-
"toDateString",
|
|
175
|
-
"toTimeString",
|
|
176
|
-
"getTime",
|
|
177
|
-
"getFullYear",
|
|
178
|
-
"getMonth",
|
|
179
|
-
"getDate",
|
|
180
|
-
"getHours",
|
|
181
|
-
"getMinutes",
|
|
182
|
-
"getSeconds",
|
|
183
|
-
"getMilliseconds"
|
|
184
|
-
]);
|
|
185
|
-
function isEventHandler(value) {
|
|
186
|
-
return typeof value === "object" && value !== null && "event" in value && "action" in value;
|
|
187
|
-
}
|
|
188
|
-
function createLambdaFunction(lambda, ctx) {
|
|
189
|
-
return (item, index) => {
|
|
190
|
-
const lambdaLocals = {
|
|
191
|
-
...ctx.locals,
|
|
192
|
-
[lambda.param]: item
|
|
193
|
-
};
|
|
194
|
-
if (lambda.index !== void 0) {
|
|
195
|
-
lambdaLocals[lambda.index] = index;
|
|
196
|
-
}
|
|
197
|
-
return evaluate(lambda.body, { ...ctx, locals: lambdaLocals });
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
function callArrayMethod(target, method, args, ctx, rawArgs) {
|
|
201
|
-
if (!SAFE_ARRAY_METHODS.has(method)) return void 0;
|
|
202
|
-
switch (method) {
|
|
203
|
-
case "length":
|
|
204
|
-
return target.length;
|
|
205
|
-
case "at": {
|
|
206
|
-
const index = typeof args[0] === "number" ? args[0] : 0;
|
|
207
|
-
return target.at(index);
|
|
208
|
-
}
|
|
209
|
-
case "includes": {
|
|
210
|
-
const searchElement = args[0];
|
|
211
|
-
const fromIndex = typeof args[1] === "number" ? args[1] : void 0;
|
|
212
|
-
return target.includes(searchElement, fromIndex);
|
|
213
|
-
}
|
|
214
|
-
case "slice": {
|
|
215
|
-
const start = typeof args[0] === "number" ? args[0] : void 0;
|
|
216
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
217
|
-
return target.slice(start, end);
|
|
218
|
-
}
|
|
219
|
-
case "indexOf": {
|
|
220
|
-
const searchElement = args[0];
|
|
221
|
-
const fromIndex = typeof args[1] === "number" ? args[1] : void 0;
|
|
222
|
-
return target.indexOf(searchElement, fromIndex);
|
|
223
|
-
}
|
|
224
|
-
case "join": {
|
|
225
|
-
const separator = typeof args[0] === "string" ? args[0] : ",";
|
|
226
|
-
return target.join(separator);
|
|
227
|
-
}
|
|
228
|
-
case "filter": {
|
|
229
|
-
const lambdaExpr = rawArgs?.[0];
|
|
230
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
231
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
232
|
-
return target.filter((item, index) => !!fn(item, index));
|
|
233
|
-
}
|
|
234
|
-
case "map": {
|
|
235
|
-
const lambdaExpr = rawArgs?.[0];
|
|
236
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
237
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
238
|
-
return target.map((item, index) => fn(item, index));
|
|
239
|
-
}
|
|
240
|
-
case "find": {
|
|
241
|
-
const lambdaExpr = rawArgs?.[0];
|
|
242
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
243
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
244
|
-
return target.find((item, index) => !!fn(item, index));
|
|
245
|
-
}
|
|
246
|
-
case "findIndex": {
|
|
247
|
-
const lambdaExpr = rawArgs?.[0];
|
|
248
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
249
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
250
|
-
return target.findIndex((item, index) => !!fn(item, index));
|
|
251
|
-
}
|
|
252
|
-
case "some": {
|
|
253
|
-
const lambdaExpr = rawArgs?.[0];
|
|
254
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
255
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
256
|
-
return target.some((item, index) => !!fn(item, index));
|
|
257
|
-
}
|
|
258
|
-
case "every": {
|
|
259
|
-
const lambdaExpr = rawArgs?.[0];
|
|
260
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
261
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
262
|
-
return target.every((item, index) => !!fn(item, index));
|
|
263
|
-
}
|
|
264
|
-
default:
|
|
265
|
-
return void 0;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
function callStringMethod(target, method, args) {
|
|
269
|
-
if (!SAFE_STRING_METHODS.has(method)) return void 0;
|
|
270
|
-
switch (method) {
|
|
271
|
-
case "length":
|
|
272
|
-
return target.length;
|
|
273
|
-
case "charAt": {
|
|
274
|
-
const index = typeof args[0] === "number" ? args[0] : 0;
|
|
275
|
-
return target.charAt(index);
|
|
276
|
-
}
|
|
277
|
-
case "substring": {
|
|
278
|
-
const start = typeof args[0] === "number" ? args[0] : 0;
|
|
279
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
280
|
-
return target.substring(start, end);
|
|
281
|
-
}
|
|
282
|
-
case "slice": {
|
|
283
|
-
const start = typeof args[0] === "number" ? args[0] : void 0;
|
|
284
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
285
|
-
return target.slice(start, end);
|
|
286
|
-
}
|
|
287
|
-
case "split": {
|
|
288
|
-
const separator = typeof args[0] === "string" ? args[0] : "";
|
|
289
|
-
return target.split(separator);
|
|
290
|
-
}
|
|
291
|
-
case "trim":
|
|
292
|
-
return target.trim();
|
|
293
|
-
case "toUpperCase":
|
|
294
|
-
return target.toUpperCase();
|
|
295
|
-
case "toLowerCase":
|
|
296
|
-
return target.toLowerCase();
|
|
297
|
-
case "replace": {
|
|
298
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
299
|
-
const replace = typeof args[1] === "string" ? args[1] : "";
|
|
300
|
-
return target.replace(search, replace);
|
|
301
|
-
}
|
|
302
|
-
case "includes": {
|
|
303
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
304
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
305
|
-
return target.includes(search, position);
|
|
306
|
-
}
|
|
307
|
-
case "startsWith": {
|
|
308
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
309
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
310
|
-
return target.startsWith(search, position);
|
|
311
|
-
}
|
|
312
|
-
case "endsWith": {
|
|
313
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
314
|
-
const length = typeof args[1] === "number" ? args[1] : void 0;
|
|
315
|
-
return target.endsWith(search, length);
|
|
316
|
-
}
|
|
317
|
-
case "indexOf": {
|
|
318
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
319
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
320
|
-
return target.indexOf(search, position);
|
|
321
|
-
}
|
|
322
|
-
default:
|
|
323
|
-
return void 0;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
function callMathMethod(method, args) {
|
|
327
|
-
if (!SAFE_MATH_METHODS.has(method)) return void 0;
|
|
328
|
-
const numbers = args.filter((a) => typeof a === "number");
|
|
329
|
-
switch (method) {
|
|
330
|
-
case "min":
|
|
331
|
-
return numbers.length > 0 ? Math.min(...numbers) : void 0;
|
|
332
|
-
case "max":
|
|
333
|
-
return numbers.length > 0 ? Math.max(...numbers) : void 0;
|
|
334
|
-
case "round":
|
|
335
|
-
return numbers[0] !== void 0 ? Math.round(numbers[0]) : void 0;
|
|
336
|
-
case "floor":
|
|
337
|
-
return numbers[0] !== void 0 ? Math.floor(numbers[0]) : void 0;
|
|
338
|
-
case "ceil":
|
|
339
|
-
return numbers[0] !== void 0 ? Math.ceil(numbers[0]) : void 0;
|
|
340
|
-
case "abs":
|
|
341
|
-
return numbers[0] !== void 0 ? Math.abs(numbers[0]) : void 0;
|
|
342
|
-
case "sqrt":
|
|
343
|
-
return numbers[0] !== void 0 ? Math.sqrt(numbers[0]) : void 0;
|
|
344
|
-
case "pow":
|
|
345
|
-
return numbers[0] !== void 0 && numbers[1] !== void 0 ? Math.pow(numbers[0], numbers[1]) : void 0;
|
|
346
|
-
case "random":
|
|
347
|
-
return Math.random();
|
|
348
|
-
case "sin":
|
|
349
|
-
return numbers[0] !== void 0 ? Math.sin(numbers[0]) : void 0;
|
|
350
|
-
case "cos":
|
|
351
|
-
return numbers[0] !== void 0 ? Math.cos(numbers[0]) : void 0;
|
|
352
|
-
case "tan":
|
|
353
|
-
return numbers[0] !== void 0 ? Math.tan(numbers[0]) : void 0;
|
|
354
|
-
default:
|
|
355
|
-
return void 0;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
function callDateStaticMethod(method, args) {
|
|
359
|
-
if (!SAFE_DATE_STATIC_METHODS.has(method)) return void 0;
|
|
360
|
-
switch (method) {
|
|
361
|
-
case "now":
|
|
362
|
-
return Date.now();
|
|
363
|
-
case "parse": {
|
|
364
|
-
const dateString = args[0];
|
|
365
|
-
return typeof dateString === "string" ? Date.parse(dateString) : void 0;
|
|
366
|
-
}
|
|
367
|
-
default:
|
|
368
|
-
return void 0;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
function callDateInstanceMethod(target, method) {
|
|
372
|
-
if (!SAFE_DATE_INSTANCE_METHODS.has(method)) return void 0;
|
|
373
|
-
switch (method) {
|
|
374
|
-
case "toISOString":
|
|
375
|
-
return target.toISOString();
|
|
376
|
-
case "toDateString":
|
|
377
|
-
return target.toDateString();
|
|
378
|
-
case "toTimeString":
|
|
379
|
-
return target.toTimeString();
|
|
380
|
-
case "getTime":
|
|
381
|
-
return target.getTime();
|
|
382
|
-
case "getFullYear":
|
|
383
|
-
return target.getFullYear();
|
|
384
|
-
case "getMonth":
|
|
385
|
-
return target.getMonth();
|
|
386
|
-
case "getDate":
|
|
387
|
-
return target.getDate();
|
|
388
|
-
case "getHours":
|
|
389
|
-
return target.getHours();
|
|
390
|
-
case "getMinutes":
|
|
391
|
-
return target.getMinutes();
|
|
392
|
-
case "getSeconds":
|
|
393
|
-
return target.getSeconds();
|
|
394
|
-
case "getMilliseconds":
|
|
395
|
-
return target.getMilliseconds();
|
|
396
|
-
default:
|
|
397
|
-
return void 0;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
function evaluate(expr, ctx) {
|
|
401
|
-
switch (expr.expr) {
|
|
402
|
-
case "lit":
|
|
403
|
-
return expr.value;
|
|
404
|
-
case "state":
|
|
405
|
-
return ctx.state.get(expr.name);
|
|
406
|
-
case "local":
|
|
407
|
-
return ctx.locals[expr.name];
|
|
408
|
-
case "var": {
|
|
409
|
-
let varName = expr.name;
|
|
410
|
-
let pathParts = [];
|
|
411
|
-
if (varName.includes(".")) {
|
|
412
|
-
const parts = varName.split(".");
|
|
413
|
-
varName = parts[0];
|
|
414
|
-
pathParts = parts.slice(1);
|
|
415
|
-
}
|
|
416
|
-
if (expr.path) {
|
|
417
|
-
pathParts = pathParts.concat(expr.path.split("."));
|
|
418
|
-
}
|
|
419
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
420
|
-
for (const part of pathParts) {
|
|
421
|
-
if (forbiddenKeys.has(part)) {
|
|
422
|
-
return void 0;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
let value = ctx.locals[varName];
|
|
426
|
-
for (const part of pathParts) {
|
|
427
|
-
if (value == null) break;
|
|
428
|
-
value = value[part];
|
|
429
|
-
}
|
|
430
|
-
return value;
|
|
431
|
-
}
|
|
432
|
-
case "bin":
|
|
433
|
-
return evaluateBinary(expr.op, expr.left, expr.right, ctx);
|
|
434
|
-
case "not":
|
|
435
|
-
return !evaluate(expr.operand, ctx);
|
|
436
|
-
case "cond":
|
|
437
|
-
return evaluate(expr.if, ctx) ? evaluate(expr.then, ctx) : evaluate(expr.else, ctx);
|
|
438
|
-
case "get": {
|
|
439
|
-
const baseValue = evaluate(expr.base, ctx);
|
|
440
|
-
if (baseValue == null) return void 0;
|
|
441
|
-
const pathParts = expr.path.split(".");
|
|
442
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
443
|
-
let value = baseValue;
|
|
444
|
-
for (const part of pathParts) {
|
|
445
|
-
if (forbiddenKeys.has(part)) return void 0;
|
|
446
|
-
if (value == null) return void 0;
|
|
447
|
-
value = value[part];
|
|
448
|
-
}
|
|
449
|
-
return value;
|
|
450
|
-
}
|
|
451
|
-
case "route": {
|
|
452
|
-
const source = expr.source ?? "param";
|
|
453
|
-
const routeCtx = ctx.route;
|
|
454
|
-
if (!routeCtx) return "";
|
|
455
|
-
switch (source) {
|
|
456
|
-
case "param":
|
|
457
|
-
return routeCtx.params[expr.name] ?? "";
|
|
458
|
-
case "query":
|
|
459
|
-
return routeCtx.query[expr.name] ?? "";
|
|
460
|
-
case "path":
|
|
461
|
-
return routeCtx.path;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
case "import": {
|
|
465
|
-
const importData = ctx.imports?.[expr.name];
|
|
466
|
-
if (importData === void 0) return void 0;
|
|
467
|
-
if (expr.path) {
|
|
468
|
-
return getNestedValue(importData, expr.path);
|
|
469
|
-
}
|
|
470
|
-
return importData;
|
|
471
|
-
}
|
|
472
|
-
case "data": {
|
|
473
|
-
const dataValue = ctx.imports?.[expr.name];
|
|
474
|
-
if (dataValue === void 0) return void 0;
|
|
475
|
-
if (expr.path) {
|
|
476
|
-
return getNestedValue(dataValue, expr.path);
|
|
477
|
-
}
|
|
478
|
-
return dataValue;
|
|
479
|
-
}
|
|
480
|
-
case "ref":
|
|
481
|
-
return null;
|
|
482
|
-
case "index": {
|
|
483
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
484
|
-
const base = evaluate(expr.base, ctx);
|
|
485
|
-
const key = evaluate(expr.key, ctx);
|
|
486
|
-
if (base == null || key == null) return void 0;
|
|
487
|
-
if (typeof key === "string" && forbiddenKeys.has(key)) return void 0;
|
|
488
|
-
return base[key];
|
|
489
|
-
}
|
|
490
|
-
case "param": {
|
|
491
|
-
return void 0;
|
|
492
|
-
}
|
|
493
|
-
case "style": {
|
|
494
|
-
return evaluateStyle(expr, ctx);
|
|
495
|
-
}
|
|
496
|
-
case "concat": {
|
|
497
|
-
return expr.items.map((item) => {
|
|
498
|
-
const val = evaluate(item, ctx);
|
|
499
|
-
return val == null ? "" : String(val);
|
|
500
|
-
}).join("");
|
|
501
|
-
}
|
|
502
|
-
case "validity": {
|
|
503
|
-
return false;
|
|
504
|
-
}
|
|
505
|
-
case "call": {
|
|
506
|
-
const callExpr = expr;
|
|
507
|
-
if (callExpr.target === null) {
|
|
508
|
-
const globalArgs = callExpr.args?.map((arg) => {
|
|
509
|
-
if (arg.expr === "lambda") return arg;
|
|
510
|
-
return evaluate(arg, ctx);
|
|
511
|
-
}) ?? [];
|
|
512
|
-
return callGlobalFunction(callExpr.method, globalArgs);
|
|
513
|
-
}
|
|
514
|
-
const target = evaluate(callExpr.target, ctx);
|
|
515
|
-
if (target == null) return void 0;
|
|
516
|
-
const args = callExpr.args?.map((arg) => {
|
|
517
|
-
if (arg.expr === "lambda") return arg;
|
|
518
|
-
return evaluate(arg, ctx);
|
|
519
|
-
}) ?? [];
|
|
520
|
-
if (Array.isArray(target)) {
|
|
521
|
-
return callArrayMethod(target, callExpr.method, args, ctx, callExpr.args);
|
|
522
|
-
}
|
|
523
|
-
if (typeof target === "string") {
|
|
524
|
-
return callStringMethod(target, callExpr.method, args);
|
|
525
|
-
}
|
|
526
|
-
if (target === Math) {
|
|
527
|
-
return callMathMethod(callExpr.method, args);
|
|
528
|
-
}
|
|
529
|
-
if (target === Date) {
|
|
530
|
-
return callDateStaticMethod(callExpr.method, args);
|
|
531
|
-
}
|
|
532
|
-
if (target instanceof Date) {
|
|
533
|
-
return callDateInstanceMethod(target, callExpr.method);
|
|
534
|
-
}
|
|
535
|
-
return void 0;
|
|
536
|
-
}
|
|
537
|
-
case "lambda": {
|
|
538
|
-
return void 0;
|
|
539
|
-
}
|
|
540
|
-
case "array": {
|
|
541
|
-
const arrayExpr = expr;
|
|
542
|
-
return arrayExpr.elements.map((elem) => evaluate(elem, ctx));
|
|
543
|
-
}
|
|
544
|
-
case "obj": {
|
|
545
|
-
const objExpr = expr;
|
|
546
|
-
const result = {};
|
|
547
|
-
for (const [key, value] of Object.entries(objExpr.props)) {
|
|
548
|
-
result[key] = evaluate(value, ctx);
|
|
549
|
-
}
|
|
550
|
-
return result;
|
|
551
|
-
}
|
|
552
|
-
default: {
|
|
553
|
-
const _exhaustiveCheck = expr;
|
|
554
|
-
throw new Error(`Unknown expression type: ${JSON.stringify(_exhaustiveCheck)}`);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
function getNestedValue(obj, path) {
|
|
559
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
560
|
-
const parts = path.split(".");
|
|
561
|
-
let value = obj;
|
|
562
|
-
for (const part of parts) {
|
|
563
|
-
if (forbiddenKeys.has(part)) {
|
|
564
|
-
return void 0;
|
|
565
|
-
}
|
|
566
|
-
if (value == null) {
|
|
567
|
-
return void 0;
|
|
568
|
-
}
|
|
569
|
-
if (Array.isArray(value)) {
|
|
570
|
-
const index = Number(part);
|
|
571
|
-
if (Number.isInteger(index) && index >= 0) {
|
|
572
|
-
value = value[index];
|
|
573
|
-
} else {
|
|
574
|
-
value = value[part];
|
|
575
|
-
}
|
|
576
|
-
} else if (typeof value === "object") {
|
|
577
|
-
value = value[part];
|
|
578
|
-
} else {
|
|
579
|
-
return void 0;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
return value;
|
|
583
|
-
}
|
|
584
|
-
function evaluateBinary(op, left, right, ctx) {
|
|
585
|
-
if (op === "&&") {
|
|
586
|
-
const leftVal2 = evaluate(left, ctx);
|
|
587
|
-
if (!leftVal2) return leftVal2;
|
|
588
|
-
return evaluate(right, ctx);
|
|
589
|
-
}
|
|
590
|
-
if (op === "||") {
|
|
591
|
-
const leftVal2 = evaluate(left, ctx);
|
|
592
|
-
if (leftVal2) return leftVal2;
|
|
593
|
-
return evaluate(right, ctx);
|
|
594
|
-
}
|
|
595
|
-
const leftVal = evaluate(left, ctx);
|
|
596
|
-
const rightVal = evaluate(right, ctx);
|
|
597
|
-
switch (op) {
|
|
598
|
-
case "+":
|
|
599
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
600
|
-
return leftVal + rightVal;
|
|
601
|
-
}
|
|
602
|
-
return String(leftVal) + String(rightVal);
|
|
603
|
-
case "-":
|
|
604
|
-
return (typeof leftVal === "number" ? leftVal : 0) - (typeof rightVal === "number" ? rightVal : 0);
|
|
605
|
-
case "*":
|
|
606
|
-
return (typeof leftVal === "number" ? leftVal : 0) * (typeof rightVal === "number" ? rightVal : 0);
|
|
607
|
-
case "/": {
|
|
608
|
-
const dividend = typeof leftVal === "number" ? leftVal : 0;
|
|
609
|
-
const divisor = typeof rightVal === "number" ? rightVal : 0;
|
|
610
|
-
if (divisor === 0) {
|
|
611
|
-
return dividend === 0 ? NaN : dividend > 0 ? Infinity : -Infinity;
|
|
612
|
-
}
|
|
613
|
-
return dividend / divisor;
|
|
614
|
-
}
|
|
615
|
-
case "%": {
|
|
616
|
-
const dividend = typeof leftVal === "number" ? leftVal : 0;
|
|
617
|
-
const divisor = typeof rightVal === "number" ? rightVal : 0;
|
|
618
|
-
if (divisor === 0) return NaN;
|
|
619
|
-
return dividend % divisor;
|
|
620
|
-
}
|
|
621
|
-
case "==":
|
|
622
|
-
return leftVal === rightVal;
|
|
623
|
-
case "!=":
|
|
624
|
-
return leftVal !== rightVal;
|
|
625
|
-
case "<":
|
|
626
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
627
|
-
return leftVal < rightVal;
|
|
628
|
-
}
|
|
629
|
-
return String(leftVal) < String(rightVal);
|
|
630
|
-
case "<=":
|
|
631
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
632
|
-
return leftVal <= rightVal;
|
|
633
|
-
}
|
|
634
|
-
return String(leftVal) <= String(rightVal);
|
|
635
|
-
case ">":
|
|
636
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
637
|
-
return leftVal > rightVal;
|
|
638
|
-
}
|
|
639
|
-
return String(leftVal) > String(rightVal);
|
|
640
|
-
case ">=":
|
|
641
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
642
|
-
return leftVal >= rightVal;
|
|
643
|
-
}
|
|
644
|
-
return String(leftVal) >= String(rightVal);
|
|
645
|
-
default:
|
|
646
|
-
throw new Error("Unknown binary operator: " + op);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
function evaluateStyle(expr, ctx) {
|
|
650
|
-
const preset = ctx.styles?.[expr.name];
|
|
651
|
-
if (!preset) return "";
|
|
652
|
-
let classes = preset.base;
|
|
653
|
-
if (preset.variants) {
|
|
654
|
-
for (const variantKey of Object.keys(preset.variants)) {
|
|
655
|
-
let variantValueStr = null;
|
|
656
|
-
if (expr.variants?.[variantKey]) {
|
|
657
|
-
let variantValue;
|
|
658
|
-
try {
|
|
659
|
-
variantValue = evaluate(expr.variants[variantKey], ctx);
|
|
660
|
-
} catch {
|
|
661
|
-
continue;
|
|
662
|
-
}
|
|
663
|
-
if (variantValue != null) {
|
|
664
|
-
variantValueStr = String(variantValue);
|
|
665
|
-
}
|
|
666
|
-
} else if (preset.defaultVariants?.[variantKey] !== void 0) {
|
|
667
|
-
variantValueStr = preset.defaultVariants[variantKey];
|
|
668
|
-
}
|
|
669
|
-
if (variantValueStr !== null) {
|
|
670
|
-
const variantClasses = preset.variants[variantKey]?.[variantValueStr];
|
|
671
|
-
if (variantClasses) {
|
|
672
|
-
classes += " " + variantClasses;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
return classes.trim();
|
|
678
|
-
}
|
|
679
158
|
function formatValue(value) {
|
|
680
159
|
if (value === null || value === void 0) {
|
|
681
160
|
return "";
|
|
@@ -685,6 +164,11 @@ function formatValue(value) {
|
|
|
685
164
|
}
|
|
686
165
|
return String(value);
|
|
687
166
|
}
|
|
167
|
+
|
|
168
|
+
// src/renderer.ts
|
|
169
|
+
function isEventHandler(value) {
|
|
170
|
+
return typeof value === "object" && value !== null && "event" in value && "action" in value;
|
|
171
|
+
}
|
|
688
172
|
async function renderNode(node, ctx) {
|
|
689
173
|
switch (node.kind) {
|
|
690
174
|
case "element":
|
|
@@ -726,7 +210,7 @@ async function renderElement(node, ctx) {
|
|
|
726
210
|
if (isEventHandler(propValue)) {
|
|
727
211
|
continue;
|
|
728
212
|
}
|
|
729
|
-
const value =
|
|
213
|
+
const value = coreEvaluate(propValue, toCoreContext(ctx));
|
|
730
214
|
if (value === false) {
|
|
731
215
|
continue;
|
|
732
216
|
}
|
|
@@ -752,11 +236,11 @@ async function renderElement(node, ctx) {
|
|
|
752
236
|
return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
|
|
753
237
|
}
|
|
754
238
|
function renderText(node, ctx) {
|
|
755
|
-
const value =
|
|
239
|
+
const value = coreEvaluate(node.value, toCoreContext(ctx));
|
|
756
240
|
return escapeHtml(formatValue(value));
|
|
757
241
|
}
|
|
758
242
|
async function renderIf(node, ctx) {
|
|
759
|
-
const condition =
|
|
243
|
+
const condition = coreEvaluate(node.condition, toCoreContext(ctx));
|
|
760
244
|
if (condition) {
|
|
761
245
|
const content = await renderNode(node.then, ctx);
|
|
762
246
|
return `<!--if:then-->${content}`;
|
|
@@ -768,7 +252,7 @@ async function renderIf(node, ctx) {
|
|
|
768
252
|
return "<!--if:none-->";
|
|
769
253
|
}
|
|
770
254
|
async function renderEach(node, ctx) {
|
|
771
|
-
const items =
|
|
255
|
+
const items = coreEvaluate(node.items, toCoreContext(ctx));
|
|
772
256
|
if (!Array.isArray(items)) {
|
|
773
257
|
return "";
|
|
774
258
|
}
|
|
@@ -791,13 +275,14 @@ async function renderEach(node, ctx) {
|
|
|
791
275
|
return result;
|
|
792
276
|
}
|
|
793
277
|
async function renderMarkdown(node, ctx) {
|
|
794
|
-
const content =
|
|
278
|
+
const content = coreEvaluate(node.content, toCoreContext(ctx));
|
|
795
279
|
const html = await parseMarkdownSSRAsync(formatValue(content));
|
|
796
280
|
return `<div class="constela-markdown">${html}</div>`;
|
|
797
281
|
}
|
|
798
282
|
async function renderCode(node, ctx) {
|
|
799
|
-
const
|
|
800
|
-
const
|
|
283
|
+
const coreCtx = toCoreContext(ctx);
|
|
284
|
+
const language = formatValue(coreEvaluate(node.language, coreCtx));
|
|
285
|
+
const content = formatValue(coreEvaluate(node.content, coreCtx));
|
|
801
286
|
const highlightedCode = await renderCodeSSR(content, language);
|
|
802
287
|
const languageBadge = language ? `<div class="absolute right-12 top-3 z-10 rounded bg-muted-foreground/20 px-2 py-0.5 text-xs font-medium text-muted-foreground">${escapeHtml(language)}</div>` : "";
|
|
803
288
|
const copyButton = `<button class="constela-copy-btn absolute right-3 top-3 z-10 flex h-8 w-8 items-center justify-center rounded-md border border-border bg-background/80 opacity-0 transition-opacity hover:bg-muted group-hover:opacity-100" data-copy-target="code" aria-label="Copy code"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>`;
|
|
@@ -816,7 +301,7 @@ async function renderLocalState(node, ctx) {
|
|
|
816
301
|
const initial = field.initial;
|
|
817
302
|
if (initial && typeof initial === "object" && "expr" in initial) {
|
|
818
303
|
const evalCtx = { ...ctx, locals: progressiveLocals };
|
|
819
|
-
localStateValues[name] =
|
|
304
|
+
localStateValues[name] = coreEvaluate(initial, toCoreContext(evalCtx));
|
|
820
305
|
} else {
|
|
821
306
|
localStateValues[name] = initial;
|
|
822
307
|
}
|
|
@@ -887,581 +372,11 @@ async function renderToString(program, options) {
|
|
|
887
372
|
}
|
|
888
373
|
|
|
889
374
|
// src/streaming.ts
|
|
890
|
-
import { isCookieInitialExpr as isCookieInitialExpr2 } from "@constela/core";
|
|
891
|
-
var VOID_ELEMENTS2 = /* @__PURE__ */ new Set([
|
|
892
|
-
"area",
|
|
893
|
-
"base",
|
|
894
|
-
"br",
|
|
895
|
-
"col",
|
|
896
|
-
"embed",
|
|
897
|
-
"hr",
|
|
898
|
-
"img",
|
|
899
|
-
"input",
|
|
900
|
-
"link",
|
|
901
|
-
"meta",
|
|
902
|
-
"param",
|
|
903
|
-
"source",
|
|
904
|
-
"track",
|
|
905
|
-
"wbr"
|
|
906
|
-
]);
|
|
907
|
-
var SAFE_ARRAY_METHODS2 = /* @__PURE__ */ new Set([
|
|
908
|
-
"length",
|
|
909
|
-
"at",
|
|
910
|
-
"includes",
|
|
911
|
-
"slice",
|
|
912
|
-
"indexOf",
|
|
913
|
-
"join",
|
|
914
|
-
"filter",
|
|
915
|
-
"map",
|
|
916
|
-
"find",
|
|
917
|
-
"findIndex",
|
|
918
|
-
"some",
|
|
919
|
-
"every"
|
|
920
|
-
]);
|
|
921
|
-
var SAFE_STRING_METHODS2 = /* @__PURE__ */ new Set([
|
|
922
|
-
"length",
|
|
923
|
-
"charAt",
|
|
924
|
-
"substring",
|
|
925
|
-
"slice",
|
|
926
|
-
"split",
|
|
927
|
-
"trim",
|
|
928
|
-
"toUpperCase",
|
|
929
|
-
"toLowerCase",
|
|
930
|
-
"replace",
|
|
931
|
-
"includes",
|
|
932
|
-
"startsWith",
|
|
933
|
-
"endsWith",
|
|
934
|
-
"indexOf"
|
|
935
|
-
]);
|
|
936
|
-
var SAFE_MATH_METHODS2 = /* @__PURE__ */ new Set([
|
|
937
|
-
"min",
|
|
938
|
-
"max",
|
|
939
|
-
"round",
|
|
940
|
-
"floor",
|
|
941
|
-
"ceil",
|
|
942
|
-
"abs",
|
|
943
|
-
"sqrt",
|
|
944
|
-
"pow",
|
|
945
|
-
"random",
|
|
946
|
-
"sin",
|
|
947
|
-
"cos",
|
|
948
|
-
"tan"
|
|
949
|
-
]);
|
|
950
|
-
var SAFE_DATE_STATIC_METHODS2 = /* @__PURE__ */ new Set(["now", "parse"]);
|
|
951
|
-
var SAFE_DATE_INSTANCE_METHODS2 = /* @__PURE__ */ new Set([
|
|
952
|
-
"toISOString",
|
|
953
|
-
"toDateString",
|
|
954
|
-
"toTimeString",
|
|
955
|
-
"getTime",
|
|
956
|
-
"getFullYear",
|
|
957
|
-
"getMonth",
|
|
958
|
-
"getDate",
|
|
959
|
-
"getHours",
|
|
960
|
-
"getMinutes",
|
|
961
|
-
"getSeconds",
|
|
962
|
-
"getMilliseconds"
|
|
963
|
-
]);
|
|
375
|
+
import { isCookieInitialExpr as isCookieInitialExpr2, evaluate as coreEvaluate2 } from "@constela/core";
|
|
964
376
|
var CHUNK_SIZE_THRESHOLD = 1024;
|
|
965
377
|
function isEventHandler2(value) {
|
|
966
378
|
return typeof value === "object" && value !== null && "event" in value && "action" in value;
|
|
967
379
|
}
|
|
968
|
-
function createLambdaFunction2(lambda, ctx) {
|
|
969
|
-
return (item, index) => {
|
|
970
|
-
const lambdaLocals = {
|
|
971
|
-
...ctx.locals,
|
|
972
|
-
[lambda.param]: item
|
|
973
|
-
};
|
|
974
|
-
if (lambda.index !== void 0) {
|
|
975
|
-
lambdaLocals[lambda.index] = index;
|
|
976
|
-
}
|
|
977
|
-
return evaluate2(lambda.body, { ...ctx, locals: lambdaLocals });
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
function callArrayMethod2(target, method, args, ctx, rawArgs) {
|
|
981
|
-
if (!SAFE_ARRAY_METHODS2.has(method)) return void 0;
|
|
982
|
-
switch (method) {
|
|
983
|
-
case "length":
|
|
984
|
-
return target.length;
|
|
985
|
-
case "at": {
|
|
986
|
-
const index = typeof args[0] === "number" ? args[0] : 0;
|
|
987
|
-
return target.at(index);
|
|
988
|
-
}
|
|
989
|
-
case "includes": {
|
|
990
|
-
const searchElement = args[0];
|
|
991
|
-
const fromIndex = typeof args[1] === "number" ? args[1] : void 0;
|
|
992
|
-
return target.includes(searchElement, fromIndex);
|
|
993
|
-
}
|
|
994
|
-
case "slice": {
|
|
995
|
-
const start = typeof args[0] === "number" ? args[0] : void 0;
|
|
996
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
997
|
-
return target.slice(start, end);
|
|
998
|
-
}
|
|
999
|
-
case "indexOf": {
|
|
1000
|
-
const searchElement = args[0];
|
|
1001
|
-
const fromIndex = typeof args[1] === "number" ? args[1] : void 0;
|
|
1002
|
-
return target.indexOf(searchElement, fromIndex);
|
|
1003
|
-
}
|
|
1004
|
-
case "join": {
|
|
1005
|
-
const separator = typeof args[0] === "string" ? args[0] : ",";
|
|
1006
|
-
return target.join(separator);
|
|
1007
|
-
}
|
|
1008
|
-
case "filter": {
|
|
1009
|
-
const lambdaExpr = rawArgs?.[0];
|
|
1010
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
1011
|
-
const fn = createLambdaFunction2(lambdaExpr, ctx);
|
|
1012
|
-
return target.filter((item, index) => !!fn(item, index));
|
|
1013
|
-
}
|
|
1014
|
-
case "map": {
|
|
1015
|
-
const lambdaExpr = rawArgs?.[0];
|
|
1016
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
1017
|
-
const fn = createLambdaFunction2(lambdaExpr, ctx);
|
|
1018
|
-
return target.map((item, index) => fn(item, index));
|
|
1019
|
-
}
|
|
1020
|
-
case "find": {
|
|
1021
|
-
const lambdaExpr = rawArgs?.[0];
|
|
1022
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
1023
|
-
const fn = createLambdaFunction2(lambdaExpr, ctx);
|
|
1024
|
-
return target.find((item, index) => !!fn(item, index));
|
|
1025
|
-
}
|
|
1026
|
-
case "findIndex": {
|
|
1027
|
-
const lambdaExpr = rawArgs?.[0];
|
|
1028
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
1029
|
-
const fn = createLambdaFunction2(lambdaExpr, ctx);
|
|
1030
|
-
return target.findIndex((item, index) => !!fn(item, index));
|
|
1031
|
-
}
|
|
1032
|
-
case "some": {
|
|
1033
|
-
const lambdaExpr = rawArgs?.[0];
|
|
1034
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
1035
|
-
const fn = createLambdaFunction2(lambdaExpr, ctx);
|
|
1036
|
-
return target.some((item, index) => !!fn(item, index));
|
|
1037
|
-
}
|
|
1038
|
-
case "every": {
|
|
1039
|
-
const lambdaExpr = rawArgs?.[0];
|
|
1040
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
1041
|
-
const fn = createLambdaFunction2(lambdaExpr, ctx);
|
|
1042
|
-
return target.every((item, index) => !!fn(item, index));
|
|
1043
|
-
}
|
|
1044
|
-
default:
|
|
1045
|
-
return void 0;
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
function callStringMethod2(target, method, args) {
|
|
1049
|
-
if (!SAFE_STRING_METHODS2.has(method)) return void 0;
|
|
1050
|
-
switch (method) {
|
|
1051
|
-
case "length":
|
|
1052
|
-
return target.length;
|
|
1053
|
-
case "charAt": {
|
|
1054
|
-
const index = typeof args[0] === "number" ? args[0] : 0;
|
|
1055
|
-
return target.charAt(index);
|
|
1056
|
-
}
|
|
1057
|
-
case "substring": {
|
|
1058
|
-
const start = typeof args[0] === "number" ? args[0] : 0;
|
|
1059
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
1060
|
-
return target.substring(start, end);
|
|
1061
|
-
}
|
|
1062
|
-
case "slice": {
|
|
1063
|
-
const start = typeof args[0] === "number" ? args[0] : void 0;
|
|
1064
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
1065
|
-
return target.slice(start, end);
|
|
1066
|
-
}
|
|
1067
|
-
case "split": {
|
|
1068
|
-
const separator = typeof args[0] === "string" ? args[0] : "";
|
|
1069
|
-
return target.split(separator);
|
|
1070
|
-
}
|
|
1071
|
-
case "trim":
|
|
1072
|
-
return target.trim();
|
|
1073
|
-
case "toUpperCase":
|
|
1074
|
-
return target.toUpperCase();
|
|
1075
|
-
case "toLowerCase":
|
|
1076
|
-
return target.toLowerCase();
|
|
1077
|
-
case "replace": {
|
|
1078
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
1079
|
-
const replace = typeof args[1] === "string" ? args[1] : "";
|
|
1080
|
-
return target.replace(search, replace);
|
|
1081
|
-
}
|
|
1082
|
-
case "includes": {
|
|
1083
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
1084
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
1085
|
-
return target.includes(search, position);
|
|
1086
|
-
}
|
|
1087
|
-
case "startsWith": {
|
|
1088
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
1089
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
1090
|
-
return target.startsWith(search, position);
|
|
1091
|
-
}
|
|
1092
|
-
case "endsWith": {
|
|
1093
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
1094
|
-
const length = typeof args[1] === "number" ? args[1] : void 0;
|
|
1095
|
-
return target.endsWith(search, length);
|
|
1096
|
-
}
|
|
1097
|
-
case "indexOf": {
|
|
1098
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
1099
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
1100
|
-
return target.indexOf(search, position);
|
|
1101
|
-
}
|
|
1102
|
-
default:
|
|
1103
|
-
return void 0;
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
function callMathMethod2(method, args) {
|
|
1107
|
-
if (!SAFE_MATH_METHODS2.has(method)) return void 0;
|
|
1108
|
-
const numbers = args.filter((a) => typeof a === "number");
|
|
1109
|
-
switch (method) {
|
|
1110
|
-
case "min":
|
|
1111
|
-
return numbers.length > 0 ? Math.min(...numbers) : void 0;
|
|
1112
|
-
case "max":
|
|
1113
|
-
return numbers.length > 0 ? Math.max(...numbers) : void 0;
|
|
1114
|
-
case "round":
|
|
1115
|
-
return numbers[0] !== void 0 ? Math.round(numbers[0]) : void 0;
|
|
1116
|
-
case "floor":
|
|
1117
|
-
return numbers[0] !== void 0 ? Math.floor(numbers[0]) : void 0;
|
|
1118
|
-
case "ceil":
|
|
1119
|
-
return numbers[0] !== void 0 ? Math.ceil(numbers[0]) : void 0;
|
|
1120
|
-
case "abs":
|
|
1121
|
-
return numbers[0] !== void 0 ? Math.abs(numbers[0]) : void 0;
|
|
1122
|
-
case "sqrt":
|
|
1123
|
-
return numbers[0] !== void 0 ? Math.sqrt(numbers[0]) : void 0;
|
|
1124
|
-
case "pow":
|
|
1125
|
-
return numbers[0] !== void 0 && numbers[1] !== void 0 ? Math.pow(numbers[0], numbers[1]) : void 0;
|
|
1126
|
-
case "random":
|
|
1127
|
-
return Math.random();
|
|
1128
|
-
case "sin":
|
|
1129
|
-
return numbers[0] !== void 0 ? Math.sin(numbers[0]) : void 0;
|
|
1130
|
-
case "cos":
|
|
1131
|
-
return numbers[0] !== void 0 ? Math.cos(numbers[0]) : void 0;
|
|
1132
|
-
case "tan":
|
|
1133
|
-
return numbers[0] !== void 0 ? Math.tan(numbers[0]) : void 0;
|
|
1134
|
-
default:
|
|
1135
|
-
return void 0;
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
function callDateStaticMethod2(method, args) {
|
|
1139
|
-
if (!SAFE_DATE_STATIC_METHODS2.has(method)) return void 0;
|
|
1140
|
-
switch (method) {
|
|
1141
|
-
case "now":
|
|
1142
|
-
return Date.now();
|
|
1143
|
-
case "parse": {
|
|
1144
|
-
const dateString = args[0];
|
|
1145
|
-
return typeof dateString === "string" ? Date.parse(dateString) : void 0;
|
|
1146
|
-
}
|
|
1147
|
-
default:
|
|
1148
|
-
return void 0;
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
function callDateInstanceMethod2(target, method) {
|
|
1152
|
-
if (!SAFE_DATE_INSTANCE_METHODS2.has(method)) return void 0;
|
|
1153
|
-
switch (method) {
|
|
1154
|
-
case "toISOString":
|
|
1155
|
-
return target.toISOString();
|
|
1156
|
-
case "toDateString":
|
|
1157
|
-
return target.toDateString();
|
|
1158
|
-
case "toTimeString":
|
|
1159
|
-
return target.toTimeString();
|
|
1160
|
-
case "getTime":
|
|
1161
|
-
return target.getTime();
|
|
1162
|
-
case "getFullYear":
|
|
1163
|
-
return target.getFullYear();
|
|
1164
|
-
case "getMonth":
|
|
1165
|
-
return target.getMonth();
|
|
1166
|
-
case "getDate":
|
|
1167
|
-
return target.getDate();
|
|
1168
|
-
case "getHours":
|
|
1169
|
-
return target.getHours();
|
|
1170
|
-
case "getMinutes":
|
|
1171
|
-
return target.getMinutes();
|
|
1172
|
-
case "getSeconds":
|
|
1173
|
-
return target.getSeconds();
|
|
1174
|
-
case "getMilliseconds":
|
|
1175
|
-
return target.getMilliseconds();
|
|
1176
|
-
default:
|
|
1177
|
-
return void 0;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
function evaluate2(expr, ctx) {
|
|
1181
|
-
switch (expr.expr) {
|
|
1182
|
-
case "lit":
|
|
1183
|
-
return expr.value;
|
|
1184
|
-
case "state":
|
|
1185
|
-
return ctx.state.get(expr.name);
|
|
1186
|
-
case "local":
|
|
1187
|
-
return ctx.locals[expr.name];
|
|
1188
|
-
case "var": {
|
|
1189
|
-
let varName = expr.name;
|
|
1190
|
-
let pathParts = [];
|
|
1191
|
-
if (varName.includes(".")) {
|
|
1192
|
-
const parts = varName.split(".");
|
|
1193
|
-
varName = parts[0];
|
|
1194
|
-
pathParts = parts.slice(1);
|
|
1195
|
-
}
|
|
1196
|
-
if (expr.path) {
|
|
1197
|
-
pathParts = pathParts.concat(expr.path.split("."));
|
|
1198
|
-
}
|
|
1199
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1200
|
-
for (const part of pathParts) {
|
|
1201
|
-
if (forbiddenKeys.has(part)) {
|
|
1202
|
-
return void 0;
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
let value = ctx.locals[varName];
|
|
1206
|
-
for (const part of pathParts) {
|
|
1207
|
-
if (value == null) break;
|
|
1208
|
-
value = value[part];
|
|
1209
|
-
}
|
|
1210
|
-
return value;
|
|
1211
|
-
}
|
|
1212
|
-
case "bin":
|
|
1213
|
-
return evaluateBinary2(expr.op, expr.left, expr.right, ctx);
|
|
1214
|
-
case "not":
|
|
1215
|
-
return !evaluate2(expr.operand, ctx);
|
|
1216
|
-
case "cond":
|
|
1217
|
-
return evaluate2(expr.if, ctx) ? evaluate2(expr.then, ctx) : evaluate2(expr.else, ctx);
|
|
1218
|
-
case "get": {
|
|
1219
|
-
const baseValue = evaluate2(expr.base, ctx);
|
|
1220
|
-
if (baseValue == null) return void 0;
|
|
1221
|
-
const pathParts = expr.path.split(".");
|
|
1222
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1223
|
-
let value = baseValue;
|
|
1224
|
-
for (const part of pathParts) {
|
|
1225
|
-
if (forbiddenKeys.has(part)) return void 0;
|
|
1226
|
-
if (value == null) return void 0;
|
|
1227
|
-
value = value[part];
|
|
1228
|
-
}
|
|
1229
|
-
return value;
|
|
1230
|
-
}
|
|
1231
|
-
case "route": {
|
|
1232
|
-
const source = expr.source ?? "param";
|
|
1233
|
-
const routeCtx = ctx.route;
|
|
1234
|
-
if (!routeCtx) return "";
|
|
1235
|
-
switch (source) {
|
|
1236
|
-
case "param":
|
|
1237
|
-
return routeCtx.params[expr.name] ?? "";
|
|
1238
|
-
case "query":
|
|
1239
|
-
return routeCtx.query[expr.name] ?? "";
|
|
1240
|
-
case "path":
|
|
1241
|
-
return routeCtx.path;
|
|
1242
|
-
default:
|
|
1243
|
-
return "";
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
case "import": {
|
|
1247
|
-
const importData = ctx.imports?.[expr.name];
|
|
1248
|
-
if (importData === void 0) return void 0;
|
|
1249
|
-
if (expr.path) {
|
|
1250
|
-
return getNestedValue2(importData, expr.path);
|
|
1251
|
-
}
|
|
1252
|
-
return importData;
|
|
1253
|
-
}
|
|
1254
|
-
case "data": {
|
|
1255
|
-
const dataValue = ctx.imports?.[expr.name];
|
|
1256
|
-
if (dataValue === void 0) return void 0;
|
|
1257
|
-
if (expr.path) {
|
|
1258
|
-
return getNestedValue2(dataValue, expr.path);
|
|
1259
|
-
}
|
|
1260
|
-
return dataValue;
|
|
1261
|
-
}
|
|
1262
|
-
case "ref":
|
|
1263
|
-
return null;
|
|
1264
|
-
case "index": {
|
|
1265
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1266
|
-
const base = evaluate2(expr.base, ctx);
|
|
1267
|
-
const key = evaluate2(expr.key, ctx);
|
|
1268
|
-
if (base == null || key == null) return void 0;
|
|
1269
|
-
if (typeof key === "string" && forbiddenKeys.has(key)) return void 0;
|
|
1270
|
-
return base[key];
|
|
1271
|
-
}
|
|
1272
|
-
case "param": {
|
|
1273
|
-
return void 0;
|
|
1274
|
-
}
|
|
1275
|
-
case "style": {
|
|
1276
|
-
return evaluateStyle2(expr, ctx);
|
|
1277
|
-
}
|
|
1278
|
-
case "concat": {
|
|
1279
|
-
return expr.items.map((item) => {
|
|
1280
|
-
const val = evaluate2(item, ctx);
|
|
1281
|
-
return val == null ? "" : String(val);
|
|
1282
|
-
}).join("");
|
|
1283
|
-
}
|
|
1284
|
-
case "validity": {
|
|
1285
|
-
return false;
|
|
1286
|
-
}
|
|
1287
|
-
case "call": {
|
|
1288
|
-
const callExpr = expr;
|
|
1289
|
-
if (callExpr.target === null) {
|
|
1290
|
-
return void 0;
|
|
1291
|
-
}
|
|
1292
|
-
const target = evaluate2(callExpr.target, ctx);
|
|
1293
|
-
if (target == null) return void 0;
|
|
1294
|
-
const args = callExpr.args?.map((arg) => {
|
|
1295
|
-
if (arg.expr === "lambda") return arg;
|
|
1296
|
-
return evaluate2(arg, ctx);
|
|
1297
|
-
}) ?? [];
|
|
1298
|
-
if (Array.isArray(target)) {
|
|
1299
|
-
return callArrayMethod2(target, callExpr.method, args, ctx, callExpr.args);
|
|
1300
|
-
}
|
|
1301
|
-
if (typeof target === "string") {
|
|
1302
|
-
return callStringMethod2(target, callExpr.method, args);
|
|
1303
|
-
}
|
|
1304
|
-
if (target === Math) {
|
|
1305
|
-
return callMathMethod2(callExpr.method, args);
|
|
1306
|
-
}
|
|
1307
|
-
if (target === Date) {
|
|
1308
|
-
return callDateStaticMethod2(callExpr.method, args);
|
|
1309
|
-
}
|
|
1310
|
-
if (target instanceof Date) {
|
|
1311
|
-
return callDateInstanceMethod2(target, callExpr.method);
|
|
1312
|
-
}
|
|
1313
|
-
return void 0;
|
|
1314
|
-
}
|
|
1315
|
-
case "lambda": {
|
|
1316
|
-
return void 0;
|
|
1317
|
-
}
|
|
1318
|
-
case "array": {
|
|
1319
|
-
const arrayExpr = expr;
|
|
1320
|
-
return arrayExpr.elements.map((elem) => evaluate2(elem, ctx));
|
|
1321
|
-
}
|
|
1322
|
-
case "obj": {
|
|
1323
|
-
const objExpr = expr;
|
|
1324
|
-
const result = {};
|
|
1325
|
-
for (const [key, value] of Object.entries(objExpr.props)) {
|
|
1326
|
-
result[key] = evaluate2(value, ctx);
|
|
1327
|
-
}
|
|
1328
|
-
return result;
|
|
1329
|
-
}
|
|
1330
|
-
default: {
|
|
1331
|
-
return void 0;
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
function getNestedValue2(obj, path) {
|
|
1336
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1337
|
-
const parts = path.split(".");
|
|
1338
|
-
let value = obj;
|
|
1339
|
-
for (const part of parts) {
|
|
1340
|
-
if (forbiddenKeys.has(part)) {
|
|
1341
|
-
return void 0;
|
|
1342
|
-
}
|
|
1343
|
-
if (value == null) {
|
|
1344
|
-
return void 0;
|
|
1345
|
-
}
|
|
1346
|
-
if (Array.isArray(value)) {
|
|
1347
|
-
const index = Number(part);
|
|
1348
|
-
if (Number.isInteger(index) && index >= 0) {
|
|
1349
|
-
value = value[index];
|
|
1350
|
-
} else {
|
|
1351
|
-
value = value[part];
|
|
1352
|
-
}
|
|
1353
|
-
} else if (typeof value === "object") {
|
|
1354
|
-
value = value[part];
|
|
1355
|
-
} else {
|
|
1356
|
-
return void 0;
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
return value;
|
|
1360
|
-
}
|
|
1361
|
-
function evaluateBinary2(op, left, right, ctx) {
|
|
1362
|
-
if (op === "&&") {
|
|
1363
|
-
const leftVal2 = evaluate2(left, ctx);
|
|
1364
|
-
if (!leftVal2) return leftVal2;
|
|
1365
|
-
return evaluate2(right, ctx);
|
|
1366
|
-
}
|
|
1367
|
-
if (op === "||") {
|
|
1368
|
-
const leftVal2 = evaluate2(left, ctx);
|
|
1369
|
-
if (leftVal2) return leftVal2;
|
|
1370
|
-
return evaluate2(right, ctx);
|
|
1371
|
-
}
|
|
1372
|
-
const leftVal = evaluate2(left, ctx);
|
|
1373
|
-
const rightVal = evaluate2(right, ctx);
|
|
1374
|
-
switch (op) {
|
|
1375
|
-
case "+":
|
|
1376
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
1377
|
-
return leftVal + rightVal;
|
|
1378
|
-
}
|
|
1379
|
-
return String(leftVal) + String(rightVal);
|
|
1380
|
-
case "-":
|
|
1381
|
-
return (typeof leftVal === "number" ? leftVal : 0) - (typeof rightVal === "number" ? rightVal : 0);
|
|
1382
|
-
case "*":
|
|
1383
|
-
return (typeof leftVal === "number" ? leftVal : 0) * (typeof rightVal === "number" ? rightVal : 0);
|
|
1384
|
-
case "/": {
|
|
1385
|
-
const dividend = typeof leftVal === "number" ? leftVal : 0;
|
|
1386
|
-
const divisor = typeof rightVal === "number" ? rightVal : 0;
|
|
1387
|
-
if (divisor === 0) {
|
|
1388
|
-
return dividend === 0 ? NaN : dividend > 0 ? Infinity : -Infinity;
|
|
1389
|
-
}
|
|
1390
|
-
return dividend / divisor;
|
|
1391
|
-
}
|
|
1392
|
-
case "%": {
|
|
1393
|
-
const dividend = typeof leftVal === "number" ? leftVal : 0;
|
|
1394
|
-
const divisor = typeof rightVal === "number" ? rightVal : 0;
|
|
1395
|
-
if (divisor === 0) return NaN;
|
|
1396
|
-
return dividend % divisor;
|
|
1397
|
-
}
|
|
1398
|
-
case "==":
|
|
1399
|
-
return leftVal === rightVal;
|
|
1400
|
-
case "!=":
|
|
1401
|
-
return leftVal !== rightVal;
|
|
1402
|
-
case "<":
|
|
1403
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
1404
|
-
return leftVal < rightVal;
|
|
1405
|
-
}
|
|
1406
|
-
return String(leftVal) < String(rightVal);
|
|
1407
|
-
case "<=":
|
|
1408
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
1409
|
-
return leftVal <= rightVal;
|
|
1410
|
-
}
|
|
1411
|
-
return String(leftVal) <= String(rightVal);
|
|
1412
|
-
case ">":
|
|
1413
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
1414
|
-
return leftVal > rightVal;
|
|
1415
|
-
}
|
|
1416
|
-
return String(leftVal) > String(rightVal);
|
|
1417
|
-
case ">=":
|
|
1418
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
1419
|
-
return leftVal >= rightVal;
|
|
1420
|
-
}
|
|
1421
|
-
return String(leftVal) >= String(rightVal);
|
|
1422
|
-
default:
|
|
1423
|
-
throw new Error("Unknown binary operator: " + op);
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
function evaluateStyle2(expr, ctx) {
|
|
1427
|
-
const preset = ctx.styles?.[expr.name];
|
|
1428
|
-
if (!preset) return "";
|
|
1429
|
-
let classes = preset.base;
|
|
1430
|
-
if (preset.variants) {
|
|
1431
|
-
for (const variantKey of Object.keys(preset.variants)) {
|
|
1432
|
-
let variantValueStr = null;
|
|
1433
|
-
if (expr.variants?.[variantKey]) {
|
|
1434
|
-
let variantValue;
|
|
1435
|
-
try {
|
|
1436
|
-
variantValue = evaluate2(expr.variants[variantKey], ctx);
|
|
1437
|
-
} catch {
|
|
1438
|
-
continue;
|
|
1439
|
-
}
|
|
1440
|
-
if (variantValue != null) {
|
|
1441
|
-
variantValueStr = String(variantValue);
|
|
1442
|
-
}
|
|
1443
|
-
} else if (preset.defaultVariants?.[variantKey] !== void 0) {
|
|
1444
|
-
variantValueStr = preset.defaultVariants[variantKey];
|
|
1445
|
-
}
|
|
1446
|
-
if (variantValueStr !== null) {
|
|
1447
|
-
const variantClasses = preset.variants[variantKey]?.[variantValueStr];
|
|
1448
|
-
if (variantClasses) {
|
|
1449
|
-
classes += " " + variantClasses;
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
return classes.trim();
|
|
1455
|
-
}
|
|
1456
|
-
function formatValue2(value) {
|
|
1457
|
-
if (value === null || value === void 0) {
|
|
1458
|
-
return "";
|
|
1459
|
-
}
|
|
1460
|
-
if (typeof value === "object") {
|
|
1461
|
-
return JSON.stringify(value);
|
|
1462
|
-
}
|
|
1463
|
-
return String(value);
|
|
1464
|
-
}
|
|
1465
380
|
function flush(ctx, force = false) {
|
|
1466
381
|
if (ctx.aborted) return;
|
|
1467
382
|
const { buffer, options, controller } = ctx;
|
|
@@ -1547,14 +462,14 @@ async function renderSuspenseToStream(node, ctx) {
|
|
|
1547
462
|
async function renderElementToStream(node, ctx) {
|
|
1548
463
|
if (checkAbort(ctx)) return;
|
|
1549
464
|
const tag = node.tag;
|
|
1550
|
-
const isVoid =
|
|
465
|
+
const isVoid = VOID_ELEMENTS.has(tag);
|
|
1551
466
|
let attrs = "";
|
|
1552
467
|
if (node.props) {
|
|
1553
468
|
for (const [propName, propValue] of Object.entries(node.props)) {
|
|
1554
469
|
if (isEventHandler2(propValue)) {
|
|
1555
470
|
continue;
|
|
1556
471
|
}
|
|
1557
|
-
const value =
|
|
472
|
+
const value = coreEvaluate2(propValue, toCoreContext(ctx));
|
|
1558
473
|
if (value === false) {
|
|
1559
474
|
continue;
|
|
1560
475
|
}
|
|
@@ -1581,12 +496,12 @@ async function renderElementToStream(node, ctx) {
|
|
|
1581
496
|
write(ctx, "</" + tag + ">");
|
|
1582
497
|
}
|
|
1583
498
|
function renderTextToStream(node, ctx) {
|
|
1584
|
-
const value =
|
|
1585
|
-
write(ctx, escapeHtml(
|
|
499
|
+
const value = coreEvaluate2(node.value, toCoreContext(ctx));
|
|
500
|
+
write(ctx, escapeHtml(formatValue(value)));
|
|
1586
501
|
}
|
|
1587
502
|
async function renderIfToStream(node, ctx) {
|
|
1588
503
|
if (checkAbort(ctx)) return;
|
|
1589
|
-
const condition =
|
|
504
|
+
const condition = coreEvaluate2(node.condition, toCoreContext(ctx));
|
|
1590
505
|
if (condition) {
|
|
1591
506
|
write(ctx, "<!--if:then-->");
|
|
1592
507
|
await renderNodeToStream(node.then, ctx);
|
|
@@ -1599,7 +514,7 @@ async function renderIfToStream(node, ctx) {
|
|
|
1599
514
|
}
|
|
1600
515
|
async function renderEachToStream(node, ctx) {
|
|
1601
516
|
if (checkAbort(ctx)) return;
|
|
1602
|
-
const items =
|
|
517
|
+
const items = coreEvaluate2(node.items, toCoreContext(ctx));
|
|
1603
518
|
if (!Array.isArray(items)) {
|
|
1604
519
|
return;
|
|
1605
520
|
}
|
|
@@ -1624,12 +539,13 @@ async function renderEachToStream(node, ctx) {
|
|
|
1624
539
|
}
|
|
1625
540
|
}
|
|
1626
541
|
async function renderMarkdownToStream(node, ctx) {
|
|
1627
|
-
const content =
|
|
1628
|
-
write(ctx, '<div class="constela-markdown">' + escapeHtml(
|
|
542
|
+
const content = coreEvaluate2(node.content, toCoreContext(ctx));
|
|
543
|
+
write(ctx, '<div class="constela-markdown">' + escapeHtml(formatValue(content)) + "</div>");
|
|
1629
544
|
}
|
|
1630
545
|
async function renderCodeToStream(node, ctx) {
|
|
1631
|
-
const
|
|
1632
|
-
const
|
|
546
|
+
const coreCtx = toCoreContext(ctx);
|
|
547
|
+
const language = formatValue(coreEvaluate2(node.language, coreCtx));
|
|
548
|
+
const content = formatValue(coreEvaluate2(node.content, coreCtx));
|
|
1633
549
|
const languageBadge = language ? '<div class="absolute right-12 top-3 z-10 rounded bg-muted-foreground/20 px-2 py-0.5 text-xs font-medium text-muted-foreground">' + escapeHtml(language) + "</div>" : "";
|
|
1634
550
|
const copyButton = '<button class="constela-copy-btn absolute right-3 top-3 z-10 flex h-8 w-8 items-center justify-center rounded-md border border-border bg-background/80 opacity-0 transition-opacity hover:bg-muted group-hover:opacity-100" data-copy-target="code" aria-label="Copy code"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>';
|
|
1635
551
|
write(ctx, '<div class="constela-code" data-code-content="' + escapeHtml(content) + '"><div class="group relative">' + languageBadge + copyButton + "<pre><code>" + escapeHtml(content) + "</code></pre></div></div>");
|
|
@@ -1648,7 +564,7 @@ async function renderLocalStateToStream(node, ctx) {
|
|
|
1648
564
|
const initial = field.initial;
|
|
1649
565
|
if (initial && typeof initial === "object" && "expr" in initial) {
|
|
1650
566
|
const evalCtx = { ...ctx, locals: progressiveLocals };
|
|
1651
|
-
localStateValues[name] =
|
|
567
|
+
localStateValues[name] = coreEvaluate2(initial, toCoreContext(evalCtx));
|
|
1652
568
|
} else {
|
|
1653
569
|
localStateValues[name] = initial;
|
|
1654
570
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.0",
|
|
4
4
|
"description": "Server-side rendering for Constela UI framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@constela/compiler": "^0.15.
|
|
19
|
-
"@constela/core": "^0.
|
|
18
|
+
"@constela/compiler": "^0.15.21",
|
|
19
|
+
"@constela/core": "^0.22.0"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"isomorphic-dompurify": "^2.35.0",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"tsup": "^8.0.0",
|
|
30
30
|
"typescript": "^5.3.0",
|
|
31
31
|
"vitest": "^2.0.0",
|
|
32
|
-
"@constela/compiler": "0.15.
|
|
33
|
-
"@constela/core": "0.
|
|
32
|
+
"@constela/compiler": "0.15.21",
|
|
33
|
+
"@constela/core": "0.22.0"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=20.0.0"
|