@constela/server 17.0.1 → 18.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -24
- package/dist/index.js +60 -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,38 @@ 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
|
+
bindFunction: (fn, parent) => fn.bind(parent)
|
|
132
|
+
};
|
|
133
|
+
function toCoreContext(ctx) {
|
|
134
|
+
return {
|
|
135
|
+
state: ctx.state,
|
|
136
|
+
locals: ctx.locals,
|
|
137
|
+
route: ctx.route,
|
|
138
|
+
imports: ctx.imports,
|
|
139
|
+
styles: ctx.styles,
|
|
140
|
+
env: ssrAdapter
|
|
141
|
+
};
|
|
142
|
+
}
|
|
112
143
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
113
144
|
"area",
|
|
114
145
|
"base",
|
|
@@ -125,557 +156,6 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
125
156
|
"track",
|
|
126
157
|
"wbr"
|
|
127
158
|
]);
|
|
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
159
|
function formatValue(value) {
|
|
680
160
|
if (value === null || value === void 0) {
|
|
681
161
|
return "";
|
|
@@ -685,6 +165,11 @@ function formatValue(value) {
|
|
|
685
165
|
}
|
|
686
166
|
return String(value);
|
|
687
167
|
}
|
|
168
|
+
|
|
169
|
+
// src/renderer.ts
|
|
170
|
+
function isEventHandler(value) {
|
|
171
|
+
return typeof value === "object" && value !== null && "event" in value && "action" in value;
|
|
172
|
+
}
|
|
688
173
|
async function renderNode(node, ctx) {
|
|
689
174
|
switch (node.kind) {
|
|
690
175
|
case "element":
|
|
@@ -726,7 +211,7 @@ async function renderElement(node, ctx) {
|
|
|
726
211
|
if (isEventHandler(propValue)) {
|
|
727
212
|
continue;
|
|
728
213
|
}
|
|
729
|
-
const value =
|
|
214
|
+
const value = coreEvaluate(propValue, toCoreContext(ctx));
|
|
730
215
|
if (value === false) {
|
|
731
216
|
continue;
|
|
732
217
|
}
|
|
@@ -752,11 +237,11 @@ async function renderElement(node, ctx) {
|
|
|
752
237
|
return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
|
|
753
238
|
}
|
|
754
239
|
function renderText(node, ctx) {
|
|
755
|
-
const value =
|
|
240
|
+
const value = coreEvaluate(node.value, toCoreContext(ctx));
|
|
756
241
|
return escapeHtml(formatValue(value));
|
|
757
242
|
}
|
|
758
243
|
async function renderIf(node, ctx) {
|
|
759
|
-
const condition =
|
|
244
|
+
const condition = coreEvaluate(node.condition, toCoreContext(ctx));
|
|
760
245
|
if (condition) {
|
|
761
246
|
const content = await renderNode(node.then, ctx);
|
|
762
247
|
return `<!--if:then-->${content}`;
|
|
@@ -768,7 +253,7 @@ async function renderIf(node, ctx) {
|
|
|
768
253
|
return "<!--if:none-->";
|
|
769
254
|
}
|
|
770
255
|
async function renderEach(node, ctx) {
|
|
771
|
-
const items =
|
|
256
|
+
const items = coreEvaluate(node.items, toCoreContext(ctx));
|
|
772
257
|
if (!Array.isArray(items)) {
|
|
773
258
|
return "";
|
|
774
259
|
}
|
|
@@ -791,13 +276,14 @@ async function renderEach(node, ctx) {
|
|
|
791
276
|
return result;
|
|
792
277
|
}
|
|
793
278
|
async function renderMarkdown(node, ctx) {
|
|
794
|
-
const content =
|
|
279
|
+
const content = coreEvaluate(node.content, toCoreContext(ctx));
|
|
795
280
|
const html = await parseMarkdownSSRAsync(formatValue(content));
|
|
796
281
|
return `<div class="constela-markdown">${html}</div>`;
|
|
797
282
|
}
|
|
798
283
|
async function renderCode(node, ctx) {
|
|
799
|
-
const
|
|
800
|
-
const
|
|
284
|
+
const coreCtx = toCoreContext(ctx);
|
|
285
|
+
const language = formatValue(coreEvaluate(node.language, coreCtx));
|
|
286
|
+
const content = formatValue(coreEvaluate(node.content, coreCtx));
|
|
801
287
|
const highlightedCode = await renderCodeSSR(content, language);
|
|
802
288
|
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
289
|
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 +302,7 @@ async function renderLocalState(node, ctx) {
|
|
|
816
302
|
const initial = field.initial;
|
|
817
303
|
if (initial && typeof initial === "object" && "expr" in initial) {
|
|
818
304
|
const evalCtx = { ...ctx, locals: progressiveLocals };
|
|
819
|
-
localStateValues[name] =
|
|
305
|
+
localStateValues[name] = coreEvaluate(initial, toCoreContext(evalCtx));
|
|
820
306
|
} else {
|
|
821
307
|
localStateValues[name] = initial;
|
|
822
308
|
}
|
|
@@ -887,581 +373,11 @@ async function renderToString(program, options) {
|
|
|
887
373
|
}
|
|
888
374
|
|
|
889
375
|
// 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
|
-
]);
|
|
376
|
+
import { isCookieInitialExpr as isCookieInitialExpr2, evaluate as coreEvaluate2 } from "@constela/core";
|
|
964
377
|
var CHUNK_SIZE_THRESHOLD = 1024;
|
|
965
378
|
function isEventHandler2(value) {
|
|
966
379
|
return typeof value === "object" && value !== null && "event" in value && "action" in value;
|
|
967
380
|
}
|
|
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
381
|
function flush(ctx, force = false) {
|
|
1466
382
|
if (ctx.aborted) return;
|
|
1467
383
|
const { buffer, options, controller } = ctx;
|
|
@@ -1547,14 +463,14 @@ async function renderSuspenseToStream(node, ctx) {
|
|
|
1547
463
|
async function renderElementToStream(node, ctx) {
|
|
1548
464
|
if (checkAbort(ctx)) return;
|
|
1549
465
|
const tag = node.tag;
|
|
1550
|
-
const isVoid =
|
|
466
|
+
const isVoid = VOID_ELEMENTS.has(tag);
|
|
1551
467
|
let attrs = "";
|
|
1552
468
|
if (node.props) {
|
|
1553
469
|
for (const [propName, propValue] of Object.entries(node.props)) {
|
|
1554
470
|
if (isEventHandler2(propValue)) {
|
|
1555
471
|
continue;
|
|
1556
472
|
}
|
|
1557
|
-
const value =
|
|
473
|
+
const value = coreEvaluate2(propValue, toCoreContext(ctx));
|
|
1558
474
|
if (value === false) {
|
|
1559
475
|
continue;
|
|
1560
476
|
}
|
|
@@ -1581,12 +497,12 @@ async function renderElementToStream(node, ctx) {
|
|
|
1581
497
|
write(ctx, "</" + tag + ">");
|
|
1582
498
|
}
|
|
1583
499
|
function renderTextToStream(node, ctx) {
|
|
1584
|
-
const value =
|
|
1585
|
-
write(ctx, escapeHtml(
|
|
500
|
+
const value = coreEvaluate2(node.value, toCoreContext(ctx));
|
|
501
|
+
write(ctx, escapeHtml(formatValue(value)));
|
|
1586
502
|
}
|
|
1587
503
|
async function renderIfToStream(node, ctx) {
|
|
1588
504
|
if (checkAbort(ctx)) return;
|
|
1589
|
-
const condition =
|
|
505
|
+
const condition = coreEvaluate2(node.condition, toCoreContext(ctx));
|
|
1590
506
|
if (condition) {
|
|
1591
507
|
write(ctx, "<!--if:then-->");
|
|
1592
508
|
await renderNodeToStream(node.then, ctx);
|
|
@@ -1599,7 +515,7 @@ async function renderIfToStream(node, ctx) {
|
|
|
1599
515
|
}
|
|
1600
516
|
async function renderEachToStream(node, ctx) {
|
|
1601
517
|
if (checkAbort(ctx)) return;
|
|
1602
|
-
const items =
|
|
518
|
+
const items = coreEvaluate2(node.items, toCoreContext(ctx));
|
|
1603
519
|
if (!Array.isArray(items)) {
|
|
1604
520
|
return;
|
|
1605
521
|
}
|
|
@@ -1624,12 +540,13 @@ async function renderEachToStream(node, ctx) {
|
|
|
1624
540
|
}
|
|
1625
541
|
}
|
|
1626
542
|
async function renderMarkdownToStream(node, ctx) {
|
|
1627
|
-
const content =
|
|
1628
|
-
write(ctx, '<div class="constela-markdown">' + escapeHtml(
|
|
543
|
+
const content = coreEvaluate2(node.content, toCoreContext(ctx));
|
|
544
|
+
write(ctx, '<div class="constela-markdown">' + escapeHtml(formatValue(content)) + "</div>");
|
|
1629
545
|
}
|
|
1630
546
|
async function renderCodeToStream(node, ctx) {
|
|
1631
|
-
const
|
|
1632
|
-
const
|
|
547
|
+
const coreCtx = toCoreContext(ctx);
|
|
548
|
+
const language = formatValue(coreEvaluate2(node.language, coreCtx));
|
|
549
|
+
const content = formatValue(coreEvaluate2(node.content, coreCtx));
|
|
1633
550
|
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
551
|
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
552
|
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 +565,7 @@ async function renderLocalStateToStream(node, ctx) {
|
|
|
1648
565
|
const initial = field.initial;
|
|
1649
566
|
if (initial && typeof initial === "object" && "expr" in initial) {
|
|
1650
567
|
const evalCtx = { ...ctx, locals: progressiveLocals };
|
|
1651
|
-
localStateValues[name] =
|
|
568
|
+
localStateValues[name] = coreEvaluate2(initial, toCoreContext(evalCtx));
|
|
1652
569
|
} else {
|
|
1653
570
|
localStateValues[name] = initial;
|
|
1654
571
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.1",
|
|
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.22",
|
|
19
|
+
"@constela/core": "^0.22.1"
|
|
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.22",
|
|
33
|
+
"@constela/core": "0.22.1"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=20.0.0"
|