summitjs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +105 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/dist/summit.cjs +3324 -0
- package/dist/summit.cjs.map +1 -0
- package/dist/summit.d.cts +269 -0
- package/dist/summit.d.ts +269 -0
- package/dist/summit.js +3304 -0
- package/dist/summit.js.map +1 -0
- package/dist/summit.min.js +7 -0
- package/dist/summit.min.js.map +1 -0
- package/package.json +79 -0
package/dist/summit.js
ADDED
|
@@ -0,0 +1,3304 @@
|
|
|
1
|
+
// src/reactivity/effect.ts
|
|
2
|
+
var activeEffect;
|
|
3
|
+
var effectStack = [];
|
|
4
|
+
var batchDepth = 0;
|
|
5
|
+
var pendingEffects = /* @__PURE__ */ new Set();
|
|
6
|
+
function effect(fn, options = {}) {
|
|
7
|
+
const runner = createReactiveEffect(fn, options);
|
|
8
|
+
if (!options.lazy) runner();
|
|
9
|
+
return runner;
|
|
10
|
+
}
|
|
11
|
+
function createReactiveEffect(fn, options) {
|
|
12
|
+
const runner = function reactiveEffect() {
|
|
13
|
+
if (!runner.active) return fn();
|
|
14
|
+
if (effectStack.includes(runner)) return void 0;
|
|
15
|
+
cleanupDeps(runner);
|
|
16
|
+
try {
|
|
17
|
+
effectStack.push(runner);
|
|
18
|
+
activeEffect = runner;
|
|
19
|
+
return fn();
|
|
20
|
+
} finally {
|
|
21
|
+
effectStack.pop();
|
|
22
|
+
activeEffect = effectStack[effectStack.length - 1];
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
runner.deps = [];
|
|
26
|
+
runner.active = true;
|
|
27
|
+
runner.scheduler = options.scheduler;
|
|
28
|
+
runner.onStop = options.onStop;
|
|
29
|
+
runner.raw = fn;
|
|
30
|
+
return runner;
|
|
31
|
+
}
|
|
32
|
+
function cleanupDeps(runner) {
|
|
33
|
+
const { deps } = runner;
|
|
34
|
+
for (const dep of deps) dep.delete(runner);
|
|
35
|
+
deps.length = 0;
|
|
36
|
+
}
|
|
37
|
+
function stop(runner) {
|
|
38
|
+
if (runner.active) {
|
|
39
|
+
cleanupDeps(runner);
|
|
40
|
+
runner.onStop?.();
|
|
41
|
+
runner.active = false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function track(dep) {
|
|
45
|
+
if (activeEffect) {
|
|
46
|
+
if (!dep.has(activeEffect)) {
|
|
47
|
+
dep.add(activeEffect);
|
|
48
|
+
activeEffect.deps.push(dep);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function trigger(dep) {
|
|
53
|
+
const effects = [...dep];
|
|
54
|
+
for (const eff of effects) {
|
|
55
|
+
if (eff === activeEffect) continue;
|
|
56
|
+
if (batchDepth > 0) {
|
|
57
|
+
pendingEffects.add(eff);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
runEffect(eff);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function runEffect(eff) {
|
|
64
|
+
if (eff.scheduler) eff.scheduler();
|
|
65
|
+
else eff();
|
|
66
|
+
}
|
|
67
|
+
function untrack(fn) {
|
|
68
|
+
const prev = activeEffect;
|
|
69
|
+
activeEffect = void 0;
|
|
70
|
+
try {
|
|
71
|
+
return fn();
|
|
72
|
+
} finally {
|
|
73
|
+
activeEffect = prev;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function batch(fn) {
|
|
77
|
+
batchDepth++;
|
|
78
|
+
try {
|
|
79
|
+
return fn();
|
|
80
|
+
} finally {
|
|
81
|
+
if (--batchDepth === 0) flushBatch();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function flushBatch() {
|
|
85
|
+
if (pendingEffects.size === 0) return;
|
|
86
|
+
const effects = [...pendingEffects];
|
|
87
|
+
pendingEffects.clear();
|
|
88
|
+
for (const eff of effects) {
|
|
89
|
+
if (eff.active) runEffect(eff);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/reactivity/signal.ts
|
|
94
|
+
function signal(initial) {
|
|
95
|
+
let value = initial;
|
|
96
|
+
const dep = /* @__PURE__ */ new Set();
|
|
97
|
+
const read = function() {
|
|
98
|
+
track(dep);
|
|
99
|
+
return value;
|
|
100
|
+
};
|
|
101
|
+
read.set = (next) => {
|
|
102
|
+
const nextValue = typeof next === "function" ? next(value) : next;
|
|
103
|
+
if (!Object.is(nextValue, value)) {
|
|
104
|
+
value = nextValue;
|
|
105
|
+
trigger(dep);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
read.peek = () => value;
|
|
109
|
+
return read;
|
|
110
|
+
}
|
|
111
|
+
function isSignal(x) {
|
|
112
|
+
return typeof x === "function" && typeof x.set === "function" && typeof x.peek === "function";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/reactivity/computed.ts
|
|
116
|
+
function computed(getter) {
|
|
117
|
+
let value;
|
|
118
|
+
let dirty = true;
|
|
119
|
+
const dep = /* @__PURE__ */ new Set();
|
|
120
|
+
const runner = effect(getter, {
|
|
121
|
+
lazy: true,
|
|
122
|
+
scheduler: () => {
|
|
123
|
+
if (!dirty) {
|
|
124
|
+
dirty = true;
|
|
125
|
+
trigger(dep);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const read = function() {
|
|
130
|
+
if (dirty) {
|
|
131
|
+
value = runner();
|
|
132
|
+
dirty = false;
|
|
133
|
+
}
|
|
134
|
+
track(dep);
|
|
135
|
+
return value;
|
|
136
|
+
};
|
|
137
|
+
read.peek = () => {
|
|
138
|
+
if (dirty) {
|
|
139
|
+
value = runner();
|
|
140
|
+
dirty = false;
|
|
141
|
+
}
|
|
142
|
+
return value;
|
|
143
|
+
};
|
|
144
|
+
return read;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/reactivity/reactive.ts
|
|
148
|
+
var RAW = /* @__PURE__ */ Symbol("summit.raw");
|
|
149
|
+
var ITERATE_KEY = /* @__PURE__ */ Symbol("summit.iterate");
|
|
150
|
+
var targetMap = /* @__PURE__ */ new WeakMap();
|
|
151
|
+
var proxyMap = /* @__PURE__ */ new WeakMap();
|
|
152
|
+
function getDep(target, key) {
|
|
153
|
+
let depsMap = targetMap.get(target);
|
|
154
|
+
if (!depsMap) targetMap.set(target, depsMap = /* @__PURE__ */ new Map());
|
|
155
|
+
let dep = depsMap.get(key);
|
|
156
|
+
if (!dep) depsMap.set(key, dep = /* @__PURE__ */ new Set());
|
|
157
|
+
return dep;
|
|
158
|
+
}
|
|
159
|
+
function trackProp(target, key) {
|
|
160
|
+
track(getDep(target, key));
|
|
161
|
+
}
|
|
162
|
+
function triggerProp(target, key) {
|
|
163
|
+
const depsMap = targetMap.get(target);
|
|
164
|
+
if (!depsMap) return;
|
|
165
|
+
const dep = depsMap.get(key);
|
|
166
|
+
if (dep) trigger(dep);
|
|
167
|
+
}
|
|
168
|
+
function isObject(x) {
|
|
169
|
+
return x !== null && typeof x === "object";
|
|
170
|
+
}
|
|
171
|
+
function isPlainObject(o) {
|
|
172
|
+
const proto = Object.getPrototypeOf(o);
|
|
173
|
+
return proto === Object.prototype || proto === null;
|
|
174
|
+
}
|
|
175
|
+
function shouldWrap(o) {
|
|
176
|
+
return isObject(o) && (Array.isArray(o) || isPlainObject(o));
|
|
177
|
+
}
|
|
178
|
+
var handlers = {
|
|
179
|
+
get(target, key, receiver) {
|
|
180
|
+
if (key === RAW) return target;
|
|
181
|
+
const result = Reflect.get(target, key, receiver);
|
|
182
|
+
if (typeof key === "symbol") return result;
|
|
183
|
+
trackProp(target, key);
|
|
184
|
+
if (shouldWrap(result)) return reactive(result);
|
|
185
|
+
return result;
|
|
186
|
+
},
|
|
187
|
+
set(target, key, value, receiver) {
|
|
188
|
+
const raw = isObject(value) ? toRaw(value) : value;
|
|
189
|
+
const isArray = Array.isArray(target);
|
|
190
|
+
const hadKey = isArray ? Number(key) < target.length : Object.prototype.hasOwnProperty.call(target, key);
|
|
191
|
+
const oldValue = target[key];
|
|
192
|
+
const result = Reflect.set(target, key, raw, receiver);
|
|
193
|
+
if (!hadKey) {
|
|
194
|
+
triggerProp(target, key);
|
|
195
|
+
triggerProp(target, isArray ? "length" : ITERATE_KEY);
|
|
196
|
+
} else if (!Object.is(oldValue, raw)) {
|
|
197
|
+
triggerProp(target, key);
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
},
|
|
201
|
+
has(target, key) {
|
|
202
|
+
trackProp(target, key);
|
|
203
|
+
return Reflect.has(target, key);
|
|
204
|
+
},
|
|
205
|
+
deleteProperty(target, key) {
|
|
206
|
+
const had = Object.prototype.hasOwnProperty.call(target, key);
|
|
207
|
+
const result = Reflect.deleteProperty(target, key);
|
|
208
|
+
if (had && result) {
|
|
209
|
+
triggerProp(target, key);
|
|
210
|
+
triggerProp(target, ITERATE_KEY);
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
},
|
|
214
|
+
ownKeys(target) {
|
|
215
|
+
trackProp(target, Array.isArray(target) ? "length" : ITERATE_KEY);
|
|
216
|
+
return Reflect.ownKeys(target);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
function reactive(target) {
|
|
220
|
+
if (!shouldWrap(target)) return target;
|
|
221
|
+
if (target[RAW]) return target;
|
|
222
|
+
const existing = proxyMap.get(target);
|
|
223
|
+
if (existing) return existing;
|
|
224
|
+
const proxy = new Proxy(target, handlers);
|
|
225
|
+
proxyMap.set(target, proxy);
|
|
226
|
+
return proxy;
|
|
227
|
+
}
|
|
228
|
+
function toRaw(observed) {
|
|
229
|
+
const raw = observed && observed[RAW];
|
|
230
|
+
return raw ? toRaw(raw) : observed;
|
|
231
|
+
}
|
|
232
|
+
function isReactive(x) {
|
|
233
|
+
return isObject(x) && Boolean(x[RAW]);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/reactivity/scheduler.ts
|
|
237
|
+
var queue = /* @__PURE__ */ new Set();
|
|
238
|
+
var flushing = false;
|
|
239
|
+
var flushPromise = null;
|
|
240
|
+
var resolved = Promise.resolve();
|
|
241
|
+
function queueJob(job) {
|
|
242
|
+
queue.add(job);
|
|
243
|
+
if (!flushing) {
|
|
244
|
+
flushing = true;
|
|
245
|
+
flushPromise = resolved.then(flushJobs);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function flushJobs() {
|
|
249
|
+
const jobs = [...queue];
|
|
250
|
+
queue.clear();
|
|
251
|
+
flushing = false;
|
|
252
|
+
flushPromise = null;
|
|
253
|
+
for (const job of jobs) job();
|
|
254
|
+
}
|
|
255
|
+
function nextTick(callback) {
|
|
256
|
+
const p = flushPromise ?? resolved;
|
|
257
|
+
return callback ? p.then(() => void callback()) : p.then(() => void 0);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/reactivity/index.ts
|
|
261
|
+
function domEffect(fn) {
|
|
262
|
+
let runner;
|
|
263
|
+
runner = effect(fn, {
|
|
264
|
+
lazy: true,
|
|
265
|
+
scheduler: () => queueJob(runner)
|
|
266
|
+
});
|
|
267
|
+
runner();
|
|
268
|
+
return () => stop(runner);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/registry/registry.ts
|
|
272
|
+
var directives = /* @__PURE__ */ new Map();
|
|
273
|
+
var magics = /* @__PURE__ */ new Map();
|
|
274
|
+
var dataProviders = /* @__PURE__ */ new Map();
|
|
275
|
+
var storeRoot = reactive({});
|
|
276
|
+
var binds = /* @__PURE__ */ new Map();
|
|
277
|
+
var DEFAULT_PRIORITY = 100;
|
|
278
|
+
function registerDirective(name, handler, priority = DEFAULT_PRIORITY) {
|
|
279
|
+
directives.set(name, { handler, priority });
|
|
280
|
+
}
|
|
281
|
+
function getDirective(name) {
|
|
282
|
+
return directives.get(name);
|
|
283
|
+
}
|
|
284
|
+
function directiveNames() {
|
|
285
|
+
return [...directives.keys()];
|
|
286
|
+
}
|
|
287
|
+
function registerMagic(name, factory) {
|
|
288
|
+
magics.set(name, factory);
|
|
289
|
+
}
|
|
290
|
+
function getMagic(name) {
|
|
291
|
+
return magics.get(name);
|
|
292
|
+
}
|
|
293
|
+
function magicNames() {
|
|
294
|
+
return [...magics.keys()];
|
|
295
|
+
}
|
|
296
|
+
function registerData(name, provider) {
|
|
297
|
+
dataProviders.set(name, provider);
|
|
298
|
+
}
|
|
299
|
+
function getData(name) {
|
|
300
|
+
return dataProviders.get(name);
|
|
301
|
+
}
|
|
302
|
+
function setStore(name, value) {
|
|
303
|
+
storeRoot[name] = value;
|
|
304
|
+
}
|
|
305
|
+
function getStore(name) {
|
|
306
|
+
return storeRoot[name];
|
|
307
|
+
}
|
|
308
|
+
function getStoreRoot() {
|
|
309
|
+
return storeRoot;
|
|
310
|
+
}
|
|
311
|
+
function registerBind(name, provider) {
|
|
312
|
+
binds.set(name, provider);
|
|
313
|
+
}
|
|
314
|
+
function getBind(name) {
|
|
315
|
+
return binds.get(name);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/scope/scope.ts
|
|
319
|
+
function createScope(raw) {
|
|
320
|
+
const proxy = reactive(raw);
|
|
321
|
+
const descriptors = Object.getOwnPropertyDescriptors(raw);
|
|
322
|
+
for (const key of Object.keys(descriptors)) {
|
|
323
|
+
const desc = descriptors[key];
|
|
324
|
+
if (typeof desc.get === "function") {
|
|
325
|
+
const getter = desc.get;
|
|
326
|
+
const setter = desc.set;
|
|
327
|
+
const cached = computed(() => getter.call(proxy));
|
|
328
|
+
Object.defineProperty(raw, key, {
|
|
329
|
+
get: () => cached(),
|
|
330
|
+
set: setter ? (v) => setter.call(proxy, v) : void 0,
|
|
331
|
+
enumerable: desc.enumerable,
|
|
332
|
+
configurable: true
|
|
333
|
+
});
|
|
334
|
+
} else if (typeof desc.value === "function") {
|
|
335
|
+
raw[key] = desc.value.bind(proxy);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return proxy;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/evaluator/lexer.ts
|
|
342
|
+
var PUNCTUATORS = [
|
|
343
|
+
"...",
|
|
344
|
+
"===",
|
|
345
|
+
"!==",
|
|
346
|
+
"**=",
|
|
347
|
+
"&&=",
|
|
348
|
+
"||=",
|
|
349
|
+
"??=",
|
|
350
|
+
"==",
|
|
351
|
+
"!=",
|
|
352
|
+
"<=",
|
|
353
|
+
">=",
|
|
354
|
+
"&&",
|
|
355
|
+
"||",
|
|
356
|
+
"??",
|
|
357
|
+
"?.",
|
|
358
|
+
"=>",
|
|
359
|
+
"++",
|
|
360
|
+
"--",
|
|
361
|
+
"+=",
|
|
362
|
+
"-=",
|
|
363
|
+
"*=",
|
|
364
|
+
"/=",
|
|
365
|
+
"%=",
|
|
366
|
+
"**",
|
|
367
|
+
"(",
|
|
368
|
+
")",
|
|
369
|
+
"[",
|
|
370
|
+
"]",
|
|
371
|
+
"{",
|
|
372
|
+
"}",
|
|
373
|
+
".",
|
|
374
|
+
",",
|
|
375
|
+
";",
|
|
376
|
+
":",
|
|
377
|
+
"?",
|
|
378
|
+
"+",
|
|
379
|
+
"-",
|
|
380
|
+
"*",
|
|
381
|
+
"/",
|
|
382
|
+
"%",
|
|
383
|
+
"<",
|
|
384
|
+
">",
|
|
385
|
+
"=",
|
|
386
|
+
"!"
|
|
387
|
+
];
|
|
388
|
+
var LexError = class extends Error {
|
|
389
|
+
};
|
|
390
|
+
function isIdentStart(ch) {
|
|
391
|
+
return /[A-Za-z_$]/.test(ch);
|
|
392
|
+
}
|
|
393
|
+
function isIdentPart(ch) {
|
|
394
|
+
return /[A-Za-z0-9_$]/.test(ch);
|
|
395
|
+
}
|
|
396
|
+
function isDigit(ch) {
|
|
397
|
+
return ch >= "0" && ch <= "9";
|
|
398
|
+
}
|
|
399
|
+
function tokenize(input) {
|
|
400
|
+
const tokens2 = [];
|
|
401
|
+
let i = 0;
|
|
402
|
+
const n = input.length;
|
|
403
|
+
while (i < n) {
|
|
404
|
+
const ch = input[i];
|
|
405
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
406
|
+
i++;
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
if (isDigit(ch) || ch === "." && isDigit(input[i + 1] ?? "")) {
|
|
410
|
+
const start2 = i;
|
|
411
|
+
if (ch === "0" && (input[i + 1] === "x" || input[i + 1] === "X")) {
|
|
412
|
+
i += 2;
|
|
413
|
+
while (i < n && /[0-9a-fA-F]/.test(input[i])) i++;
|
|
414
|
+
} else {
|
|
415
|
+
while (i < n && isDigit(input[i])) i++;
|
|
416
|
+
if (input[i] === ".") {
|
|
417
|
+
i++;
|
|
418
|
+
while (i < n && isDigit(input[i])) i++;
|
|
419
|
+
}
|
|
420
|
+
if (input[i] === "e" || input[i] === "E") {
|
|
421
|
+
i++;
|
|
422
|
+
if (input[i] === "+" || input[i] === "-") i++;
|
|
423
|
+
while (i < n && isDigit(input[i])) i++;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
tokens2.push({ type: "num", value: input.slice(start2, i), start: start2, end: i });
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (ch === '"' || ch === "'") {
|
|
430
|
+
const start2 = i;
|
|
431
|
+
const quote = ch;
|
|
432
|
+
i++;
|
|
433
|
+
let value = "";
|
|
434
|
+
while (i < n && input[i] !== quote) {
|
|
435
|
+
if (input[i] === "\\") {
|
|
436
|
+
value += readEscape(input, i);
|
|
437
|
+
i += 2;
|
|
438
|
+
} else {
|
|
439
|
+
value += input[i];
|
|
440
|
+
i++;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (i >= n) throw new LexError(`Unterminated string in expression: ${input}`);
|
|
444
|
+
i++;
|
|
445
|
+
tokens2.push({ type: "str", value, start: start2, end: i });
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
if (ch === "`") {
|
|
449
|
+
const start2 = i;
|
|
450
|
+
i++;
|
|
451
|
+
let raw = "";
|
|
452
|
+
let depth = 0;
|
|
453
|
+
while (i < n) {
|
|
454
|
+
const c = input[i];
|
|
455
|
+
if (c === "\\") {
|
|
456
|
+
raw += input[i] + (input[i + 1] ?? "");
|
|
457
|
+
i += 2;
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
if (c === "`" && depth === 0) break;
|
|
461
|
+
if (c === "$" && input[i + 1] === "{") {
|
|
462
|
+
depth++;
|
|
463
|
+
raw += "${";
|
|
464
|
+
i += 2;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
if (c === "}" && depth > 0) {
|
|
468
|
+
depth--;
|
|
469
|
+
raw += "}";
|
|
470
|
+
i++;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
raw += c;
|
|
474
|
+
i++;
|
|
475
|
+
}
|
|
476
|
+
if (i >= n) throw new LexError(`Unterminated template literal: ${input}`);
|
|
477
|
+
i++;
|
|
478
|
+
tokens2.push({ type: "tmpl", value: raw, raw, start: start2, end: i });
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (isIdentStart(ch)) {
|
|
482
|
+
const start2 = i;
|
|
483
|
+
i++;
|
|
484
|
+
while (i < n && isIdentPart(input[i])) i++;
|
|
485
|
+
tokens2.push({ type: "ident", value: input.slice(start2, i), start: start2, end: i });
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
let matched = false;
|
|
489
|
+
for (const p of PUNCTUATORS) {
|
|
490
|
+
if (input.startsWith(p, i)) {
|
|
491
|
+
tokens2.push({ type: "punc", value: p, start: i, end: i + p.length });
|
|
492
|
+
i += p.length;
|
|
493
|
+
matched = true;
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (!matched) {
|
|
498
|
+
throw new LexError(`Unexpected character '${ch}' in expression: ${input}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
tokens2.push({ type: "eof", value: "", start: n, end: n });
|
|
502
|
+
return tokens2;
|
|
503
|
+
}
|
|
504
|
+
function readEscape(input, at) {
|
|
505
|
+
const next = input[at + 1];
|
|
506
|
+
switch (next) {
|
|
507
|
+
case "n":
|
|
508
|
+
return "\n";
|
|
509
|
+
case "t":
|
|
510
|
+
return " ";
|
|
511
|
+
case "r":
|
|
512
|
+
return "\r";
|
|
513
|
+
case "b":
|
|
514
|
+
return "\b";
|
|
515
|
+
case "f":
|
|
516
|
+
return "\f";
|
|
517
|
+
case "v":
|
|
518
|
+
return "\v";
|
|
519
|
+
case "0":
|
|
520
|
+
return "\0";
|
|
521
|
+
case "\\":
|
|
522
|
+
return "\\";
|
|
523
|
+
case "'":
|
|
524
|
+
return "'";
|
|
525
|
+
case '"':
|
|
526
|
+
return '"';
|
|
527
|
+
case "`":
|
|
528
|
+
return "`";
|
|
529
|
+
default:
|
|
530
|
+
return next ?? "";
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/evaluator/parser.ts
|
|
535
|
+
var ParseError = class extends Error {
|
|
536
|
+
};
|
|
537
|
+
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
538
|
+
"true",
|
|
539
|
+
"false",
|
|
540
|
+
"null",
|
|
541
|
+
"undefined",
|
|
542
|
+
"this",
|
|
543
|
+
"typeof",
|
|
544
|
+
"void",
|
|
545
|
+
"in",
|
|
546
|
+
"instanceof",
|
|
547
|
+
"if",
|
|
548
|
+
"else",
|
|
549
|
+
"return",
|
|
550
|
+
"let",
|
|
551
|
+
"const",
|
|
552
|
+
"var",
|
|
553
|
+
"for",
|
|
554
|
+
"of",
|
|
555
|
+
"while",
|
|
556
|
+
"break",
|
|
557
|
+
"continue"
|
|
558
|
+
]);
|
|
559
|
+
var BINARY_PREC = {
|
|
560
|
+
"??": 1,
|
|
561
|
+
"||": 2,
|
|
562
|
+
"&&": 3,
|
|
563
|
+
"==": 7,
|
|
564
|
+
"!=": 7,
|
|
565
|
+
"===": 7,
|
|
566
|
+
"!==": 7,
|
|
567
|
+
"<": 8,
|
|
568
|
+
">": 8,
|
|
569
|
+
"<=": 8,
|
|
570
|
+
">=": 8,
|
|
571
|
+
in: 8,
|
|
572
|
+
instanceof: 8,
|
|
573
|
+
"+": 10,
|
|
574
|
+
"-": 10,
|
|
575
|
+
"*": 11,
|
|
576
|
+
"/": 11,
|
|
577
|
+
"%": 11,
|
|
578
|
+
"**": 12
|
|
579
|
+
};
|
|
580
|
+
var ASSIGN_OPS = /* @__PURE__ */ new Set(["=", "+=", "-=", "*=", "/=", "%=", "**=", "&&=", "||=", "??="]);
|
|
581
|
+
var Parser = class {
|
|
582
|
+
constructor(source) {
|
|
583
|
+
this.pos = 0;
|
|
584
|
+
this.tokens = tokenize(source);
|
|
585
|
+
}
|
|
586
|
+
peek(offset = 0) {
|
|
587
|
+
return this.tokens[this.pos + offset] ?? this.tokens[this.tokens.length - 1];
|
|
588
|
+
}
|
|
589
|
+
next() {
|
|
590
|
+
return this.tokens[this.pos++] ?? this.tokens[this.tokens.length - 1];
|
|
591
|
+
}
|
|
592
|
+
isPunc(value, offset = 0) {
|
|
593
|
+
const t = this.peek(offset);
|
|
594
|
+
return t.type === "punc" && t.value === value;
|
|
595
|
+
}
|
|
596
|
+
isKeyword(value, offset = 0) {
|
|
597
|
+
const t = this.peek(offset);
|
|
598
|
+
return t.type === "ident" && t.value === value;
|
|
599
|
+
}
|
|
600
|
+
eatPunc(value) {
|
|
601
|
+
if (!this.isPunc(value)) {
|
|
602
|
+
throw new ParseError(`Expected '${value}' but found '${this.peek().value || "end of input"}'`);
|
|
603
|
+
}
|
|
604
|
+
this.pos++;
|
|
605
|
+
}
|
|
606
|
+
atEnd() {
|
|
607
|
+
return this.peek().type === "eof";
|
|
608
|
+
}
|
|
609
|
+
// --- Entry points ---
|
|
610
|
+
parseProgram() {
|
|
611
|
+
const body = [];
|
|
612
|
+
while (!this.atEnd()) {
|
|
613
|
+
if (this.isPunc(";")) {
|
|
614
|
+
this.pos++;
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
body.push(this.parseStatement());
|
|
618
|
+
}
|
|
619
|
+
return { type: "Program", body };
|
|
620
|
+
}
|
|
621
|
+
parseExpressionProgram() {
|
|
622
|
+
const expr = this.parseExpression();
|
|
623
|
+
if (!this.atEnd()) {
|
|
624
|
+
throw new ParseError(`Unexpected trailing input '${this.peek().value}'`);
|
|
625
|
+
}
|
|
626
|
+
return { type: "Program", body: [{ type: "ExpressionStatement", expression: expr }] };
|
|
627
|
+
}
|
|
628
|
+
// --- Statements ---
|
|
629
|
+
parseStatement() {
|
|
630
|
+
if (this.isPunc("{")) return this.parseBlock();
|
|
631
|
+
if (this.isKeyword("if")) return this.parseIf();
|
|
632
|
+
if (this.isKeyword("return")) return this.parseReturn();
|
|
633
|
+
if (this.isKeyword("let") || this.isKeyword("const") || this.isKeyword("var")) {
|
|
634
|
+
const decl = this.parseVarDecl();
|
|
635
|
+
this.consumeSemi();
|
|
636
|
+
return decl;
|
|
637
|
+
}
|
|
638
|
+
if (this.isKeyword("for")) return this.parseFor();
|
|
639
|
+
if (this.isKeyword("while")) return this.parseWhile();
|
|
640
|
+
if (this.isKeyword("break")) {
|
|
641
|
+
this.pos++;
|
|
642
|
+
this.consumeSemi();
|
|
643
|
+
return { type: "BreakStatement" };
|
|
644
|
+
}
|
|
645
|
+
if (this.isKeyword("continue")) {
|
|
646
|
+
this.pos++;
|
|
647
|
+
this.consumeSemi();
|
|
648
|
+
return { type: "ContinueStatement" };
|
|
649
|
+
}
|
|
650
|
+
const expression = this.parseExpression();
|
|
651
|
+
this.consumeSemi();
|
|
652
|
+
return { type: "ExpressionStatement", expression };
|
|
653
|
+
}
|
|
654
|
+
consumeSemi() {
|
|
655
|
+
if (this.isPunc(";")) this.pos++;
|
|
656
|
+
}
|
|
657
|
+
parseBlock() {
|
|
658
|
+
this.eatPunc("{");
|
|
659
|
+
const body = [];
|
|
660
|
+
while (!this.isPunc("}") && !this.atEnd()) {
|
|
661
|
+
if (this.isPunc(";")) {
|
|
662
|
+
this.pos++;
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
body.push(this.parseStatement());
|
|
666
|
+
}
|
|
667
|
+
this.eatPunc("}");
|
|
668
|
+
return { type: "BlockStatement", body };
|
|
669
|
+
}
|
|
670
|
+
parseIf() {
|
|
671
|
+
this.pos++;
|
|
672
|
+
this.eatPunc("(");
|
|
673
|
+
const test = this.parseExpression();
|
|
674
|
+
this.eatPunc(")");
|
|
675
|
+
const consequent = this.parseStatement();
|
|
676
|
+
let alternate = null;
|
|
677
|
+
if (this.isKeyword("else")) {
|
|
678
|
+
this.pos++;
|
|
679
|
+
alternate = this.parseStatement();
|
|
680
|
+
}
|
|
681
|
+
return { type: "IfStatement", test, consequent, alternate };
|
|
682
|
+
}
|
|
683
|
+
parseReturn() {
|
|
684
|
+
this.pos++;
|
|
685
|
+
let argument = null;
|
|
686
|
+
if (!this.isPunc(";") && !this.isPunc("}") && !this.atEnd()) {
|
|
687
|
+
argument = this.parseExpression();
|
|
688
|
+
}
|
|
689
|
+
this.consumeSemi();
|
|
690
|
+
return { type: "ReturnStatement", argument };
|
|
691
|
+
}
|
|
692
|
+
parseVarDecl() {
|
|
693
|
+
const kind = this.next().value;
|
|
694
|
+
const declarations = [];
|
|
695
|
+
do {
|
|
696
|
+
const id2 = this.parsePattern();
|
|
697
|
+
let init2 = null;
|
|
698
|
+
if (this.isPunc("=")) {
|
|
699
|
+
this.pos++;
|
|
700
|
+
init2 = this.parseAssignment();
|
|
701
|
+
}
|
|
702
|
+
declarations.push({ id: id2, init: init2 });
|
|
703
|
+
} while (this.isPunc(",") && (this.pos++, true));
|
|
704
|
+
return { type: "VariableDeclaration", kind, declarations };
|
|
705
|
+
}
|
|
706
|
+
parseFor() {
|
|
707
|
+
this.pos++;
|
|
708
|
+
this.eatPunc("(");
|
|
709
|
+
let init2 = null;
|
|
710
|
+
if (this.isKeyword("let") || this.isKeyword("const") || this.isKeyword("var")) {
|
|
711
|
+
const kind = this.next().value;
|
|
712
|
+
const pattern = this.parsePattern();
|
|
713
|
+
if (this.isKeyword("of")) {
|
|
714
|
+
this.pos++;
|
|
715
|
+
const right = this.parseExpression();
|
|
716
|
+
this.eatPunc(")");
|
|
717
|
+
const body2 = this.parseStatement();
|
|
718
|
+
return {
|
|
719
|
+
type: "ForOfStatement",
|
|
720
|
+
left: { type: "VariableDeclaration", kind, declarations: [{ id: pattern, init: null }] },
|
|
721
|
+
right,
|
|
722
|
+
body: body2
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
let declInit = null;
|
|
726
|
+
if (this.isPunc("=")) {
|
|
727
|
+
this.pos++;
|
|
728
|
+
declInit = this.parseAssignment();
|
|
729
|
+
}
|
|
730
|
+
const declarations = [{ id: pattern, init: declInit }];
|
|
731
|
+
while (this.isPunc(",")) {
|
|
732
|
+
this.pos++;
|
|
733
|
+
const id2 = this.parsePattern();
|
|
734
|
+
let vi = null;
|
|
735
|
+
if (this.isPunc("=")) {
|
|
736
|
+
this.pos++;
|
|
737
|
+
vi = this.parseAssignment();
|
|
738
|
+
}
|
|
739
|
+
declarations.push({ id: id2, init: vi });
|
|
740
|
+
}
|
|
741
|
+
init2 = { type: "VariableDeclaration", kind, declarations };
|
|
742
|
+
} else if (!this.isPunc(";")) {
|
|
743
|
+
init2 = this.parseExpression();
|
|
744
|
+
}
|
|
745
|
+
this.eatPunc(";");
|
|
746
|
+
const test = this.isPunc(";") ? null : this.parseExpression();
|
|
747
|
+
this.eatPunc(";");
|
|
748
|
+
const update = this.isPunc(")") ? null : this.parseExpression();
|
|
749
|
+
this.eatPunc(")");
|
|
750
|
+
const body = this.parseStatement();
|
|
751
|
+
return { type: "ForStatement", init: init2, test, update, body };
|
|
752
|
+
}
|
|
753
|
+
parseWhile() {
|
|
754
|
+
this.pos++;
|
|
755
|
+
this.eatPunc("(");
|
|
756
|
+
const test = this.parseExpression();
|
|
757
|
+
this.eatPunc(")");
|
|
758
|
+
const body = this.parseStatement();
|
|
759
|
+
return { type: "WhileStatement", test, body };
|
|
760
|
+
}
|
|
761
|
+
// --- Expressions ---
|
|
762
|
+
parseExpression() {
|
|
763
|
+
return this.parseAssignment();
|
|
764
|
+
}
|
|
765
|
+
parseAssignment() {
|
|
766
|
+
if (this.isArrowAhead()) return this.parseArrow();
|
|
767
|
+
const left = this.parseConditional();
|
|
768
|
+
const t = this.peek();
|
|
769
|
+
if (t.type === "punc" && ASSIGN_OPS.has(t.value)) {
|
|
770
|
+
this.pos++;
|
|
771
|
+
const right = this.parseAssignment();
|
|
772
|
+
return { type: "AssignmentExpression", operator: t.value, left, right };
|
|
773
|
+
}
|
|
774
|
+
return left;
|
|
775
|
+
}
|
|
776
|
+
parseConditional() {
|
|
777
|
+
const test = this.parseBinary(1);
|
|
778
|
+
if (this.isPunc("?")) {
|
|
779
|
+
this.pos++;
|
|
780
|
+
const consequent = this.parseAssignment();
|
|
781
|
+
this.eatPunc(":");
|
|
782
|
+
const alternate = this.parseAssignment();
|
|
783
|
+
return { type: "ConditionalExpression", test, consequent, alternate };
|
|
784
|
+
}
|
|
785
|
+
return test;
|
|
786
|
+
}
|
|
787
|
+
parseBinary(minPrec) {
|
|
788
|
+
let left = this.parseUnary();
|
|
789
|
+
for (; ; ) {
|
|
790
|
+
const t = this.peek();
|
|
791
|
+
const op = t.type === "punc" ? t.value : t.type === "ident" && (t.value === "in" || t.value === "instanceof") ? t.value : null;
|
|
792
|
+
if (op === null) break;
|
|
793
|
+
const prec = BINARY_PREC[op];
|
|
794
|
+
if (prec === void 0 || prec < minPrec) break;
|
|
795
|
+
this.pos++;
|
|
796
|
+
const rightAssoc = op === "**";
|
|
797
|
+
const right = this.parseBinary(rightAssoc ? prec : prec + 1);
|
|
798
|
+
if (op === "&&" || op === "||" || op === "??") {
|
|
799
|
+
left = { type: "LogicalExpression", operator: op, left, right };
|
|
800
|
+
} else {
|
|
801
|
+
left = { type: "BinaryExpression", operator: op, left, right };
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return left;
|
|
805
|
+
}
|
|
806
|
+
parseUnary() {
|
|
807
|
+
const t = this.peek();
|
|
808
|
+
if (t.type === "punc" && (t.value === "!" || t.value === "-" || t.value === "+")) {
|
|
809
|
+
this.pos++;
|
|
810
|
+
return { type: "UnaryExpression", operator: t.value, argument: this.parseUnary() };
|
|
811
|
+
}
|
|
812
|
+
if (t.type === "ident" && (t.value === "typeof" || t.value === "void")) {
|
|
813
|
+
this.pos++;
|
|
814
|
+
return { type: "UnaryExpression", operator: t.value, argument: this.parseUnary() };
|
|
815
|
+
}
|
|
816
|
+
if (t.type === "punc" && (t.value === "++" || t.value === "--")) {
|
|
817
|
+
this.pos++;
|
|
818
|
+
return { type: "UpdateExpression", operator: t.value, prefix: true, argument: this.parseUnary() };
|
|
819
|
+
}
|
|
820
|
+
return this.parsePostfix();
|
|
821
|
+
}
|
|
822
|
+
parsePostfix() {
|
|
823
|
+
let node = this.parseCallMember();
|
|
824
|
+
const t = this.peek();
|
|
825
|
+
if (t.type === "punc" && (t.value === "++" || t.value === "--")) {
|
|
826
|
+
this.pos++;
|
|
827
|
+
node = { type: "UpdateExpression", operator: t.value, prefix: false, argument: node };
|
|
828
|
+
}
|
|
829
|
+
return node;
|
|
830
|
+
}
|
|
831
|
+
parseCallMember() {
|
|
832
|
+
let node = this.parsePrimary();
|
|
833
|
+
for (; ; ) {
|
|
834
|
+
if (this.isPunc(".")) {
|
|
835
|
+
this.pos++;
|
|
836
|
+
const name = this.next();
|
|
837
|
+
node = {
|
|
838
|
+
type: "MemberExpression",
|
|
839
|
+
object: node,
|
|
840
|
+
property: { type: "Identifier", name: name.value },
|
|
841
|
+
computed: false,
|
|
842
|
+
optional: false
|
|
843
|
+
};
|
|
844
|
+
} else if (this.isPunc("?.")) {
|
|
845
|
+
this.pos++;
|
|
846
|
+
if (this.isPunc("(")) {
|
|
847
|
+
node = { type: "CallExpression", callee: node, arguments: this.parseArguments(), optional: true };
|
|
848
|
+
} else if (this.isPunc("[")) {
|
|
849
|
+
this.pos++;
|
|
850
|
+
const property = this.parseExpression();
|
|
851
|
+
this.eatPunc("]");
|
|
852
|
+
node = { type: "MemberExpression", object: node, property, computed: true, optional: true };
|
|
853
|
+
} else {
|
|
854
|
+
const name = this.next();
|
|
855
|
+
node = {
|
|
856
|
+
type: "MemberExpression",
|
|
857
|
+
object: node,
|
|
858
|
+
property: { type: "Identifier", name: name.value },
|
|
859
|
+
computed: false,
|
|
860
|
+
optional: true
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
} else if (this.isPunc("[")) {
|
|
864
|
+
this.pos++;
|
|
865
|
+
const property = this.parseExpression();
|
|
866
|
+
this.eatPunc("]");
|
|
867
|
+
node = { type: "MemberExpression", object: node, property, computed: true, optional: false };
|
|
868
|
+
} else if (this.isPunc("(")) {
|
|
869
|
+
node = { type: "CallExpression", callee: node, arguments: this.parseArguments(), optional: false };
|
|
870
|
+
} else {
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return node;
|
|
875
|
+
}
|
|
876
|
+
parseArguments() {
|
|
877
|
+
this.eatPunc("(");
|
|
878
|
+
const args = [];
|
|
879
|
+
while (!this.isPunc(")") && !this.atEnd()) {
|
|
880
|
+
if (this.isPunc("...")) {
|
|
881
|
+
this.pos++;
|
|
882
|
+
args.push({ type: "SpreadElement", argument: this.parseAssignment() });
|
|
883
|
+
} else {
|
|
884
|
+
args.push(this.parseAssignment());
|
|
885
|
+
}
|
|
886
|
+
if (this.isPunc(",")) this.pos++;
|
|
887
|
+
else break;
|
|
888
|
+
}
|
|
889
|
+
this.eatPunc(")");
|
|
890
|
+
return args;
|
|
891
|
+
}
|
|
892
|
+
parsePrimary() {
|
|
893
|
+
const t = this.peek();
|
|
894
|
+
if (t.type === "num") {
|
|
895
|
+
this.pos++;
|
|
896
|
+
const value = t.value.startsWith("0x") || t.value.startsWith("0X") ? parseInt(t.value, 16) : Number(t.value);
|
|
897
|
+
return { type: "NumberLiteral", value };
|
|
898
|
+
}
|
|
899
|
+
if (t.type === "str") {
|
|
900
|
+
this.pos++;
|
|
901
|
+
return { type: "StringLiteral", value: t.value };
|
|
902
|
+
}
|
|
903
|
+
if (t.type === "tmpl") {
|
|
904
|
+
this.pos++;
|
|
905
|
+
return this.parseTemplate(t.raw ?? "");
|
|
906
|
+
}
|
|
907
|
+
if (t.type === "ident") {
|
|
908
|
+
if (t.value === "true" || t.value === "false") {
|
|
909
|
+
this.pos++;
|
|
910
|
+
return { type: "BooleanLiteral", value: t.value === "true" };
|
|
911
|
+
}
|
|
912
|
+
if (t.value === "null") {
|
|
913
|
+
this.pos++;
|
|
914
|
+
return { type: "NullLiteral" };
|
|
915
|
+
}
|
|
916
|
+
if (t.value === "undefined") {
|
|
917
|
+
this.pos++;
|
|
918
|
+
return { type: "UndefinedLiteral" };
|
|
919
|
+
}
|
|
920
|
+
if (t.value === "this") {
|
|
921
|
+
this.pos++;
|
|
922
|
+
return { type: "ThisExpression" };
|
|
923
|
+
}
|
|
924
|
+
this.pos++;
|
|
925
|
+
return { type: "Identifier", name: t.value };
|
|
926
|
+
}
|
|
927
|
+
if (this.isPunc("(")) {
|
|
928
|
+
this.pos++;
|
|
929
|
+
const first = this.parseAssignment();
|
|
930
|
+
if (this.isPunc(",")) {
|
|
931
|
+
const expressions = [first];
|
|
932
|
+
while (this.isPunc(",")) {
|
|
933
|
+
this.pos++;
|
|
934
|
+
expressions.push(this.parseAssignment());
|
|
935
|
+
}
|
|
936
|
+
this.eatPunc(")");
|
|
937
|
+
return { type: "SequenceExpression", expressions };
|
|
938
|
+
}
|
|
939
|
+
this.eatPunc(")");
|
|
940
|
+
return first;
|
|
941
|
+
}
|
|
942
|
+
if (this.isPunc("[")) {
|
|
943
|
+
return this.parseArray();
|
|
944
|
+
}
|
|
945
|
+
if (this.isPunc("{")) {
|
|
946
|
+
return this.parseObject();
|
|
947
|
+
}
|
|
948
|
+
throw new ParseError(`Unexpected token '${t.value || "end of input"}' in expression`);
|
|
949
|
+
}
|
|
950
|
+
parseArray() {
|
|
951
|
+
this.eatPunc("[");
|
|
952
|
+
const elements = [];
|
|
953
|
+
while (!this.isPunc("]") && !this.atEnd()) {
|
|
954
|
+
if (this.isPunc(",")) {
|
|
955
|
+
elements.push(null);
|
|
956
|
+
this.pos++;
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
if (this.isPunc("...")) {
|
|
960
|
+
this.pos++;
|
|
961
|
+
elements.push({ type: "SpreadElement", argument: this.parseAssignment() });
|
|
962
|
+
} else {
|
|
963
|
+
elements.push(this.parseAssignment());
|
|
964
|
+
}
|
|
965
|
+
if (this.isPunc(",")) this.pos++;
|
|
966
|
+
else break;
|
|
967
|
+
}
|
|
968
|
+
this.eatPunc("]");
|
|
969
|
+
return { type: "ArrayExpression", elements };
|
|
970
|
+
}
|
|
971
|
+
parseObject() {
|
|
972
|
+
this.eatPunc("{");
|
|
973
|
+
const properties = [];
|
|
974
|
+
while (!this.isPunc("}") && !this.atEnd()) {
|
|
975
|
+
if (this.isPunc("...")) {
|
|
976
|
+
this.pos++;
|
|
977
|
+
properties.push({ type: "SpreadElement", argument: this.parseAssignment() });
|
|
978
|
+
} else {
|
|
979
|
+
properties.push(this.parseObjectProperty());
|
|
980
|
+
}
|
|
981
|
+
if (this.isPunc(",")) this.pos++;
|
|
982
|
+
else break;
|
|
983
|
+
}
|
|
984
|
+
this.eatPunc("}");
|
|
985
|
+
return { type: "ObjectExpression", properties };
|
|
986
|
+
}
|
|
987
|
+
parseObjectProperty() {
|
|
988
|
+
if ((this.isKeyword("get") || this.isKeyword("set")) && !this.isPunc(":", 1) && !this.isPunc(",", 1) && !this.isPunc("(", 1) && !this.isPunc("}", 1)) {
|
|
989
|
+
const kind = this.next().value;
|
|
990
|
+
const { key: key2, computed: computed3 } = this.parsePropertyKey();
|
|
991
|
+
const fn = this.parseMethodTail();
|
|
992
|
+
return { key: key2, computed: computed3, value: fn, kind, shorthand: false };
|
|
993
|
+
}
|
|
994
|
+
const { key, computed: computed2, keyName } = this.parsePropertyKey();
|
|
995
|
+
if (this.isPunc("(")) {
|
|
996
|
+
const fn = this.parseMethodTail();
|
|
997
|
+
return { key, computed: computed2, value: fn, kind: "method", shorthand: false };
|
|
998
|
+
}
|
|
999
|
+
if (this.isPunc(":")) {
|
|
1000
|
+
this.pos++;
|
|
1001
|
+
const value = this.parseAssignment();
|
|
1002
|
+
return { key, computed: computed2, value, kind: "init", shorthand: false };
|
|
1003
|
+
}
|
|
1004
|
+
if (keyName !== null && !computed2) {
|
|
1005
|
+
return { key, computed: computed2, value: { type: "Identifier", name: keyName }, kind: "init", shorthand: true };
|
|
1006
|
+
}
|
|
1007
|
+
throw new ParseError(`Invalid object property near '${this.peek().value}'`);
|
|
1008
|
+
}
|
|
1009
|
+
parsePropertyKey() {
|
|
1010
|
+
if (this.isPunc("[")) {
|
|
1011
|
+
this.pos++;
|
|
1012
|
+
const key = this.parseAssignment();
|
|
1013
|
+
this.eatPunc("]");
|
|
1014
|
+
return { key, computed: true, keyName: null };
|
|
1015
|
+
}
|
|
1016
|
+
const t = this.next();
|
|
1017
|
+
if (t.type === "str") return { key: { type: "StringLiteral", value: t.value }, computed: false, keyName: t.value };
|
|
1018
|
+
if (t.type === "num")
|
|
1019
|
+
return { key: { type: "StringLiteral", value: String(Number(t.value)) }, computed: false, keyName: null };
|
|
1020
|
+
if (t.type === "ident") return { key: { type: "StringLiteral", value: t.value }, computed: false, keyName: t.value };
|
|
1021
|
+
throw new ParseError(`Invalid property key '${t.value}'`);
|
|
1022
|
+
}
|
|
1023
|
+
parseMethodTail() {
|
|
1024
|
+
const params = this.parseParamList();
|
|
1025
|
+
const body = this.parseBlock();
|
|
1026
|
+
return { type: "ArrowFunction", params, body, expression: false };
|
|
1027
|
+
}
|
|
1028
|
+
// --- Arrow functions ---
|
|
1029
|
+
isArrowAhead() {
|
|
1030
|
+
const t = this.peek();
|
|
1031
|
+
if (t.type === "ident" && !KEYWORDS.has(t.value) && this.isPunc("=>", 1)) return true;
|
|
1032
|
+
if (this.isPunc("(")) {
|
|
1033
|
+
let depth = 0;
|
|
1034
|
+
let i = this.pos;
|
|
1035
|
+
for (; i < this.tokens.length; i++) {
|
|
1036
|
+
const tok = this.tokens[i];
|
|
1037
|
+
if (tok.type === "punc" && tok.value === "(") depth++;
|
|
1038
|
+
else if (tok.type === "punc" && tok.value === ")") {
|
|
1039
|
+
depth--;
|
|
1040
|
+
if (depth === 0) break;
|
|
1041
|
+
} else if (tok.type === "eof") return false;
|
|
1042
|
+
}
|
|
1043
|
+
const after = this.tokens[i + 1];
|
|
1044
|
+
return !!after && after.type === "punc" && after.value === "=>";
|
|
1045
|
+
}
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1048
|
+
parseArrow() {
|
|
1049
|
+
let params;
|
|
1050
|
+
if (this.peek().type === "ident") {
|
|
1051
|
+
params = [{ type: "Identifier", name: this.next().value }];
|
|
1052
|
+
} else {
|
|
1053
|
+
params = this.parseParamList();
|
|
1054
|
+
}
|
|
1055
|
+
this.eatPunc("=>");
|
|
1056
|
+
if (this.isPunc("{")) {
|
|
1057
|
+
const body2 = this.parseBlock();
|
|
1058
|
+
return { type: "ArrowFunction", params, body: body2, expression: false };
|
|
1059
|
+
}
|
|
1060
|
+
const body = this.parseAssignment();
|
|
1061
|
+
return { type: "ArrowFunction", params, body, expression: true };
|
|
1062
|
+
}
|
|
1063
|
+
parseParamList() {
|
|
1064
|
+
this.eatPunc("(");
|
|
1065
|
+
const params = [];
|
|
1066
|
+
while (!this.isPunc(")") && !this.atEnd()) {
|
|
1067
|
+
params.push(this.parsePattern());
|
|
1068
|
+
if (this.isPunc(",")) this.pos++;
|
|
1069
|
+
else break;
|
|
1070
|
+
}
|
|
1071
|
+
this.eatPunc(")");
|
|
1072
|
+
return params;
|
|
1073
|
+
}
|
|
1074
|
+
// --- Patterns ---
|
|
1075
|
+
parsePattern() {
|
|
1076
|
+
let pattern;
|
|
1077
|
+
if (this.isPunc("...")) {
|
|
1078
|
+
this.pos++;
|
|
1079
|
+
return { type: "RestElement", argument: this.parsePattern() };
|
|
1080
|
+
}
|
|
1081
|
+
if (this.isPunc("{")) {
|
|
1082
|
+
pattern = this.parseObjectPattern();
|
|
1083
|
+
} else if (this.isPunc("[")) {
|
|
1084
|
+
pattern = this.parseArrayPattern();
|
|
1085
|
+
} else {
|
|
1086
|
+
const t = this.next();
|
|
1087
|
+
if (t.type !== "ident") throw new ParseError(`Invalid binding target '${t.value}'`);
|
|
1088
|
+
pattern = { type: "Identifier", name: t.value };
|
|
1089
|
+
}
|
|
1090
|
+
if (this.isPunc("=")) {
|
|
1091
|
+
this.pos++;
|
|
1092
|
+
const right = this.parseAssignment();
|
|
1093
|
+
return { type: "AssignmentPattern", left: pattern, right };
|
|
1094
|
+
}
|
|
1095
|
+
return pattern;
|
|
1096
|
+
}
|
|
1097
|
+
parseObjectPattern() {
|
|
1098
|
+
this.eatPunc("{");
|
|
1099
|
+
const properties = [];
|
|
1100
|
+
let rest = null;
|
|
1101
|
+
while (!this.isPunc("}") && !this.atEnd()) {
|
|
1102
|
+
if (this.isPunc("...")) {
|
|
1103
|
+
this.pos++;
|
|
1104
|
+
const t = this.next();
|
|
1105
|
+
rest = { type: "Identifier", name: t.value };
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
const { key, computed: computed2, keyName } = this.parsePropertyKey();
|
|
1109
|
+
let value;
|
|
1110
|
+
if (this.isPunc(":")) {
|
|
1111
|
+
this.pos++;
|
|
1112
|
+
value = this.parsePattern();
|
|
1113
|
+
} else {
|
|
1114
|
+
value = { type: "Identifier", name: keyName ?? "" };
|
|
1115
|
+
if (this.isPunc("=")) {
|
|
1116
|
+
this.pos++;
|
|
1117
|
+
value = { type: "AssignmentPattern", left: value, right: this.parseAssignment() };
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
properties.push({ key, value, computed: computed2 });
|
|
1121
|
+
if (this.isPunc(",")) this.pos++;
|
|
1122
|
+
else break;
|
|
1123
|
+
}
|
|
1124
|
+
this.eatPunc("}");
|
|
1125
|
+
return { type: "ObjectPattern", properties, rest };
|
|
1126
|
+
}
|
|
1127
|
+
parseArrayPattern() {
|
|
1128
|
+
this.eatPunc("[");
|
|
1129
|
+
const elements = [];
|
|
1130
|
+
let rest = null;
|
|
1131
|
+
while (!this.isPunc("]") && !this.atEnd()) {
|
|
1132
|
+
if (this.isPunc(",")) {
|
|
1133
|
+
elements.push(null);
|
|
1134
|
+
this.pos++;
|
|
1135
|
+
continue;
|
|
1136
|
+
}
|
|
1137
|
+
if (this.isPunc("...")) {
|
|
1138
|
+
this.pos++;
|
|
1139
|
+
rest = this.parsePattern();
|
|
1140
|
+
break;
|
|
1141
|
+
}
|
|
1142
|
+
elements.push(this.parsePattern());
|
|
1143
|
+
if (this.isPunc(",")) this.pos++;
|
|
1144
|
+
else break;
|
|
1145
|
+
}
|
|
1146
|
+
this.eatPunc("]");
|
|
1147
|
+
return { type: "ArrayPattern", elements, rest };
|
|
1148
|
+
}
|
|
1149
|
+
// --- Template literals ---
|
|
1150
|
+
parseTemplate(raw) {
|
|
1151
|
+
const quasis = [];
|
|
1152
|
+
const expressions = [];
|
|
1153
|
+
let current = "";
|
|
1154
|
+
let i = 0;
|
|
1155
|
+
while (i < raw.length) {
|
|
1156
|
+
if (raw[i] === "$" && raw[i + 1] === "{") {
|
|
1157
|
+
quasis.push(current);
|
|
1158
|
+
current = "";
|
|
1159
|
+
i += 2;
|
|
1160
|
+
let depth = 1;
|
|
1161
|
+
let src = "";
|
|
1162
|
+
while (i < raw.length && depth > 0) {
|
|
1163
|
+
const c = raw[i];
|
|
1164
|
+
if (c === "{") depth++;
|
|
1165
|
+
else if (c === "}") {
|
|
1166
|
+
depth--;
|
|
1167
|
+
if (depth === 0) break;
|
|
1168
|
+
}
|
|
1169
|
+
src += c;
|
|
1170
|
+
i++;
|
|
1171
|
+
}
|
|
1172
|
+
i++;
|
|
1173
|
+
const stmt = parse(src, "expression").body[0];
|
|
1174
|
+
expressions.push(stmt && stmt.type === "ExpressionStatement" ? stmt.expression : { type: "UndefinedLiteral" });
|
|
1175
|
+
} else {
|
|
1176
|
+
current += raw[i];
|
|
1177
|
+
i++;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
quasis.push(current);
|
|
1181
|
+
return { type: "TemplateLiteral", quasis, expressions };
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
var cache = /* @__PURE__ */ new Map();
|
|
1185
|
+
function parse(source, mode) {
|
|
1186
|
+
const key = mode + "\0" + source;
|
|
1187
|
+
const cached = cache.get(key);
|
|
1188
|
+
if (cached) return cached;
|
|
1189
|
+
const parser = new Parser(source);
|
|
1190
|
+
const program = mode === "expression" ? parser.parseExpressionProgram() : parser.parseProgram();
|
|
1191
|
+
cache.set(key, program);
|
|
1192
|
+
return program;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// src/evaluator/interpreter.ts
|
|
1196
|
+
var ReturnSignal = class {
|
|
1197
|
+
constructor(value) {
|
|
1198
|
+
this.value = value;
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
var BreakSignal = class {
|
|
1202
|
+
};
|
|
1203
|
+
var ContinueSignal = class {
|
|
1204
|
+
};
|
|
1205
|
+
var LexicalScope = class {
|
|
1206
|
+
constructor(parent) {
|
|
1207
|
+
this.parent = parent;
|
|
1208
|
+
this.vars = /* @__PURE__ */ new Map();
|
|
1209
|
+
}
|
|
1210
|
+
declare(name, value, constant) {
|
|
1211
|
+
this.vars.set(name, { value, constant });
|
|
1212
|
+
}
|
|
1213
|
+
find(name) {
|
|
1214
|
+
let s = this;
|
|
1215
|
+
while (s) {
|
|
1216
|
+
if (s.vars.has(name)) return s;
|
|
1217
|
+
s = s.parent;
|
|
1218
|
+
}
|
|
1219
|
+
return null;
|
|
1220
|
+
}
|
|
1221
|
+
has(name) {
|
|
1222
|
+
return this.find(name) !== null;
|
|
1223
|
+
}
|
|
1224
|
+
get(name) {
|
|
1225
|
+
return this.find(name)?.vars.get(name)?.value;
|
|
1226
|
+
}
|
|
1227
|
+
set(name, value) {
|
|
1228
|
+
const owner = this.find(name);
|
|
1229
|
+
if (!owner) return false;
|
|
1230
|
+
const entry = owner.vars.get(name);
|
|
1231
|
+
if (entry.constant) throw new TypeError(`Assignment to constant '${name}'`);
|
|
1232
|
+
entry.value = value;
|
|
1233
|
+
return true;
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
var GLOBAL_ALLOW = /* @__PURE__ */ new Set([
|
|
1237
|
+
"Math",
|
|
1238
|
+
"JSON",
|
|
1239
|
+
"Date",
|
|
1240
|
+
"Object",
|
|
1241
|
+
"Array",
|
|
1242
|
+
"Number",
|
|
1243
|
+
"String",
|
|
1244
|
+
"Boolean",
|
|
1245
|
+
"parseInt",
|
|
1246
|
+
"parseFloat",
|
|
1247
|
+
"isNaN",
|
|
1248
|
+
"isFinite",
|
|
1249
|
+
"RegExp",
|
|
1250
|
+
"Map",
|
|
1251
|
+
"Set",
|
|
1252
|
+
"WeakMap",
|
|
1253
|
+
"WeakSet",
|
|
1254
|
+
"Promise",
|
|
1255
|
+
"Intl",
|
|
1256
|
+
"console",
|
|
1257
|
+
"window",
|
|
1258
|
+
"document",
|
|
1259
|
+
"location",
|
|
1260
|
+
"navigator",
|
|
1261
|
+
"history",
|
|
1262
|
+
"localStorage",
|
|
1263
|
+
"sessionStorage",
|
|
1264
|
+
"setTimeout",
|
|
1265
|
+
"clearTimeout",
|
|
1266
|
+
"setInterval",
|
|
1267
|
+
"clearInterval",
|
|
1268
|
+
"requestAnimationFrame",
|
|
1269
|
+
"cancelAnimationFrame",
|
|
1270
|
+
"fetch",
|
|
1271
|
+
"alert",
|
|
1272
|
+
"confirm",
|
|
1273
|
+
"prompt",
|
|
1274
|
+
"structuredClone",
|
|
1275
|
+
"URL",
|
|
1276
|
+
"URLSearchParams",
|
|
1277
|
+
"encodeURIComponent",
|
|
1278
|
+
"decodeURIComponent",
|
|
1279
|
+
"NaN",
|
|
1280
|
+
"Infinity"
|
|
1281
|
+
]);
|
|
1282
|
+
function addGlobals(names) {
|
|
1283
|
+
for (const n of names) GLOBAL_ALLOW.add(n);
|
|
1284
|
+
}
|
|
1285
|
+
function memberGet(obj, key) {
|
|
1286
|
+
if (obj == null) return void 0;
|
|
1287
|
+
return obj[key];
|
|
1288
|
+
}
|
|
1289
|
+
var Interpreter = class {
|
|
1290
|
+
constructor(root) {
|
|
1291
|
+
this.root = root;
|
|
1292
|
+
}
|
|
1293
|
+
run(program, thisVal) {
|
|
1294
|
+
const scope = new LexicalScope(null);
|
|
1295
|
+
let result;
|
|
1296
|
+
try {
|
|
1297
|
+
for (const stmt of program.body) {
|
|
1298
|
+
if (stmt.type === "ExpressionStatement") {
|
|
1299
|
+
result = this.evalExpr(stmt.expression, scope, thisVal);
|
|
1300
|
+
} else {
|
|
1301
|
+
this.execStmt(stmt, scope, thisVal);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
} catch (signal2) {
|
|
1305
|
+
if (signal2 instanceof ReturnSignal) return signal2.value;
|
|
1306
|
+
throw signal2;
|
|
1307
|
+
}
|
|
1308
|
+
return result;
|
|
1309
|
+
}
|
|
1310
|
+
// --- Statements ---
|
|
1311
|
+
execBlock(body, scope, thisVal) {
|
|
1312
|
+
for (const stmt of body) this.execStmt(stmt, scope, thisVal);
|
|
1313
|
+
}
|
|
1314
|
+
execStmt(node, scope, thisVal) {
|
|
1315
|
+
switch (node.type) {
|
|
1316
|
+
case "ExpressionStatement":
|
|
1317
|
+
this.evalExpr(node.expression, scope, thisVal);
|
|
1318
|
+
return;
|
|
1319
|
+
case "BlockStatement":
|
|
1320
|
+
this.execBlock(node.body, new LexicalScope(scope), thisVal);
|
|
1321
|
+
return;
|
|
1322
|
+
case "IfStatement":
|
|
1323
|
+
if (this.evalExpr(node.test, scope, thisVal)) this.execStmt(node.consequent, scope, thisVal);
|
|
1324
|
+
else if (node.alternate) this.execStmt(node.alternate, scope, thisVal);
|
|
1325
|
+
return;
|
|
1326
|
+
case "ReturnStatement":
|
|
1327
|
+
throw new ReturnSignal(node.argument ? this.evalExpr(node.argument, scope, thisVal) : void 0);
|
|
1328
|
+
case "VariableDeclaration":
|
|
1329
|
+
for (const decl of node.declarations) {
|
|
1330
|
+
const value = decl.init ? this.evalExpr(decl.init, scope, thisVal) : void 0;
|
|
1331
|
+
this.bindPattern(decl.id, value, scope, node.kind === "const");
|
|
1332
|
+
}
|
|
1333
|
+
return;
|
|
1334
|
+
case "WhileStatement":
|
|
1335
|
+
while (this.evalExpr(node.test, scope, thisVal)) {
|
|
1336
|
+
try {
|
|
1337
|
+
this.execStmt(node.body, new LexicalScope(scope), thisVal);
|
|
1338
|
+
} catch (s) {
|
|
1339
|
+
if (s instanceof BreakSignal) break;
|
|
1340
|
+
if (s instanceof ContinueSignal) continue;
|
|
1341
|
+
throw s;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return;
|
|
1345
|
+
case "ForOfStatement": {
|
|
1346
|
+
const iterable = this.evalExpr(node.right, scope, thisVal);
|
|
1347
|
+
for (const item of iterable ?? []) {
|
|
1348
|
+
const loopScope = new LexicalScope(scope);
|
|
1349
|
+
if (node.left.type === "VariableDeclaration") {
|
|
1350
|
+
this.bindPattern(node.left.declarations[0].id, item, loopScope, node.left.kind === "const");
|
|
1351
|
+
} else {
|
|
1352
|
+
this.assignPattern(node.left, item, loopScope, thisVal);
|
|
1353
|
+
}
|
|
1354
|
+
try {
|
|
1355
|
+
this.execStmt(node.body, loopScope, thisVal);
|
|
1356
|
+
} catch (s) {
|
|
1357
|
+
if (s instanceof BreakSignal) break;
|
|
1358
|
+
if (s instanceof ContinueSignal) continue;
|
|
1359
|
+
throw s;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
case "ForStatement": {
|
|
1365
|
+
const forScope = new LexicalScope(scope);
|
|
1366
|
+
if (node.init) {
|
|
1367
|
+
if (node.init.type === "VariableDeclaration") this.execStmt(node.init, forScope, thisVal);
|
|
1368
|
+
else this.evalExpr(node.init, forScope, thisVal);
|
|
1369
|
+
}
|
|
1370
|
+
while (node.test ? this.evalExpr(node.test, forScope, thisVal) : true) {
|
|
1371
|
+
try {
|
|
1372
|
+
this.execStmt(node.body, new LexicalScope(forScope), thisVal);
|
|
1373
|
+
} catch (s) {
|
|
1374
|
+
if (s instanceof BreakSignal) break;
|
|
1375
|
+
if (s instanceof ContinueSignal) ; else throw s;
|
|
1376
|
+
}
|
|
1377
|
+
if (node.update) this.evalExpr(node.update, forScope, thisVal);
|
|
1378
|
+
}
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
case "BreakStatement":
|
|
1382
|
+
throw new BreakSignal();
|
|
1383
|
+
case "ContinueStatement":
|
|
1384
|
+
throw new ContinueSignal();
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
// --- Expressions ---
|
|
1388
|
+
evalExpr(node, scope, thisVal) {
|
|
1389
|
+
switch (node.type) {
|
|
1390
|
+
case "NumberLiteral":
|
|
1391
|
+
case "StringLiteral":
|
|
1392
|
+
case "BooleanLiteral":
|
|
1393
|
+
return node.value;
|
|
1394
|
+
case "NullLiteral":
|
|
1395
|
+
return null;
|
|
1396
|
+
case "UndefinedLiteral":
|
|
1397
|
+
return void 0;
|
|
1398
|
+
case "ThisExpression":
|
|
1399
|
+
return thisVal;
|
|
1400
|
+
case "Identifier":
|
|
1401
|
+
return this.resolve(node.name, scope);
|
|
1402
|
+
case "TemplateLiteral": {
|
|
1403
|
+
let out = node.quasis[0] ?? "";
|
|
1404
|
+
for (let i = 0; i < node.expressions.length; i++) {
|
|
1405
|
+
out += String(this.evalExpr(node.expressions[i], scope, thisVal) ?? "");
|
|
1406
|
+
out += node.quasis[i + 1] ?? "";
|
|
1407
|
+
}
|
|
1408
|
+
return out;
|
|
1409
|
+
}
|
|
1410
|
+
case "ArrayExpression": {
|
|
1411
|
+
const arr = [];
|
|
1412
|
+
for (const el of node.elements) {
|
|
1413
|
+
if (el === null) arr.push(void 0);
|
|
1414
|
+
else if (el.type === "SpreadElement") arr.push(...this.evalExpr(el.argument, scope, thisVal));
|
|
1415
|
+
else arr.push(this.evalExpr(el, scope, thisVal));
|
|
1416
|
+
}
|
|
1417
|
+
return arr;
|
|
1418
|
+
}
|
|
1419
|
+
case "ObjectExpression":
|
|
1420
|
+
return this.evalObject(node, scope, thisVal);
|
|
1421
|
+
case "UnaryExpression": {
|
|
1422
|
+
const arg = this.evalExpr(node.argument, scope, thisVal);
|
|
1423
|
+
switch (node.operator) {
|
|
1424
|
+
case "!":
|
|
1425
|
+
return !arg;
|
|
1426
|
+
case "-":
|
|
1427
|
+
return -arg;
|
|
1428
|
+
case "+":
|
|
1429
|
+
return +arg;
|
|
1430
|
+
case "typeof":
|
|
1431
|
+
return typeof arg;
|
|
1432
|
+
case "void":
|
|
1433
|
+
return void 0;
|
|
1434
|
+
}
|
|
1435
|
+
return void 0;
|
|
1436
|
+
}
|
|
1437
|
+
case "UpdateExpression": {
|
|
1438
|
+
const old = Number(this.evalTarget(node.argument, scope, thisVal));
|
|
1439
|
+
const next = node.operator === "++" ? old + 1 : old - 1;
|
|
1440
|
+
this.assign(node.argument, next, scope, thisVal);
|
|
1441
|
+
return node.prefix ? next : old;
|
|
1442
|
+
}
|
|
1443
|
+
case "BinaryExpression":
|
|
1444
|
+
return this.evalBinary(
|
|
1445
|
+
node.operator,
|
|
1446
|
+
this.evalExpr(node.left, scope, thisVal),
|
|
1447
|
+
this.evalExpr(node.right, scope, thisVal)
|
|
1448
|
+
);
|
|
1449
|
+
case "LogicalExpression": {
|
|
1450
|
+
const left = this.evalExpr(node.left, scope, thisVal);
|
|
1451
|
+
if (node.operator === "&&") return left ? this.evalExpr(node.right, scope, thisVal) : left;
|
|
1452
|
+
if (node.operator === "||") return left ? left : this.evalExpr(node.right, scope, thisVal);
|
|
1453
|
+
return left ?? this.evalExpr(node.right, scope, thisVal);
|
|
1454
|
+
}
|
|
1455
|
+
case "ConditionalExpression":
|
|
1456
|
+
return this.evalExpr(node.test, scope, thisVal) ? this.evalExpr(node.consequent, scope, thisVal) : this.evalExpr(node.alternate, scope, thisVal);
|
|
1457
|
+
case "AssignmentExpression":
|
|
1458
|
+
return this.evalAssignment(node, scope, thisVal);
|
|
1459
|
+
case "MemberExpression": {
|
|
1460
|
+
const obj = this.evalExpr(node.object, scope, thisVal);
|
|
1461
|
+
if (node.optional && obj == null) return void 0;
|
|
1462
|
+
const key = node.computed ? this.evalExpr(node.property, scope, thisVal) : node.property.name;
|
|
1463
|
+
return memberGet(obj, key);
|
|
1464
|
+
}
|
|
1465
|
+
case "CallExpression":
|
|
1466
|
+
return this.evalCall(node, scope, thisVal);
|
|
1467
|
+
case "ArrowFunction":
|
|
1468
|
+
return this.makeFunction(
|
|
1469
|
+
node,
|
|
1470
|
+
scope,
|
|
1471
|
+
/* lexicalThis */
|
|
1472
|
+
thisVal,
|
|
1473
|
+
/* dynamic */
|
|
1474
|
+
false
|
|
1475
|
+
);
|
|
1476
|
+
case "SequenceExpression": {
|
|
1477
|
+
let v;
|
|
1478
|
+
for (const e of node.expressions) v = this.evalExpr(e, scope, thisVal);
|
|
1479
|
+
return v;
|
|
1480
|
+
}
|
|
1481
|
+
case "SpreadElement":
|
|
1482
|
+
return this.evalExpr(node.argument, scope, thisVal);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
evalObject(node, scope, thisVal) {
|
|
1486
|
+
const obj = {};
|
|
1487
|
+
for (const prop of node.properties) {
|
|
1488
|
+
if (prop.type === "SpreadElement") {
|
|
1489
|
+
Object.assign(obj, this.evalExpr(prop.argument, scope, thisVal));
|
|
1490
|
+
continue;
|
|
1491
|
+
}
|
|
1492
|
+
const p = prop;
|
|
1493
|
+
const key = p.computed ? String(this.evalExpr(p.key, scope, thisVal)) : p.key.value;
|
|
1494
|
+
if (p.kind === "get") {
|
|
1495
|
+
const fn = this.makeFunction(p.value, scope, thisVal, true);
|
|
1496
|
+
Object.defineProperty(obj, key, { get: fn, enumerable: true, configurable: true });
|
|
1497
|
+
} else if (p.kind === "set") {
|
|
1498
|
+
const fn = this.makeFunction(p.value, scope, thisVal, true);
|
|
1499
|
+
Object.defineProperty(obj, key, { set: fn, enumerable: true, configurable: true });
|
|
1500
|
+
} else if (p.kind === "method") {
|
|
1501
|
+
obj[key] = this.makeFunction(p.value, scope, thisVal, true);
|
|
1502
|
+
} else {
|
|
1503
|
+
obj[key] = this.evalExpr(p.value, scope, thisVal);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
return obj;
|
|
1507
|
+
}
|
|
1508
|
+
evalCall(node, scope, thisVal) {
|
|
1509
|
+
let fn;
|
|
1510
|
+
let callThis = void 0;
|
|
1511
|
+
if (node.callee.type === "MemberExpression") {
|
|
1512
|
+
const m = node.callee;
|
|
1513
|
+
const obj = this.evalExpr(m.object, scope, thisVal);
|
|
1514
|
+
if (m.optional && obj == null) return void 0;
|
|
1515
|
+
callThis = obj;
|
|
1516
|
+
const key = m.computed ? this.evalExpr(m.property, scope, thisVal) : m.property.name;
|
|
1517
|
+
fn = memberGet(obj, key);
|
|
1518
|
+
} else {
|
|
1519
|
+
fn = this.evalExpr(node.callee, scope, thisVal);
|
|
1520
|
+
}
|
|
1521
|
+
if (node.optional && fn == null) return void 0;
|
|
1522
|
+
const args = this.evalArguments(node.arguments, scope, thisVal);
|
|
1523
|
+
if (typeof fn !== "function") {
|
|
1524
|
+
if (fn == null) return void 0;
|
|
1525
|
+
throw new TypeError(`Expression value is not a function`);
|
|
1526
|
+
}
|
|
1527
|
+
return fn.apply(callThis, args);
|
|
1528
|
+
}
|
|
1529
|
+
evalArguments(nodes, scope, thisVal) {
|
|
1530
|
+
const args = [];
|
|
1531
|
+
for (const a of nodes) {
|
|
1532
|
+
if (a.type === "SpreadElement") args.push(...this.evalExpr(a.argument, scope, thisVal));
|
|
1533
|
+
else args.push(this.evalExpr(a, scope, thisVal));
|
|
1534
|
+
}
|
|
1535
|
+
return args;
|
|
1536
|
+
}
|
|
1537
|
+
evalBinary(op, l, r) {
|
|
1538
|
+
switch (op) {
|
|
1539
|
+
case "+":
|
|
1540
|
+
return l + r;
|
|
1541
|
+
case "-":
|
|
1542
|
+
return l - r;
|
|
1543
|
+
case "*":
|
|
1544
|
+
return l * r;
|
|
1545
|
+
case "/":
|
|
1546
|
+
return l / r;
|
|
1547
|
+
case "%":
|
|
1548
|
+
return l % r;
|
|
1549
|
+
case "**":
|
|
1550
|
+
return l ** r;
|
|
1551
|
+
case "==":
|
|
1552
|
+
return l == r;
|
|
1553
|
+
case "!=":
|
|
1554
|
+
return l != r;
|
|
1555
|
+
case "===":
|
|
1556
|
+
return l === r;
|
|
1557
|
+
case "!==":
|
|
1558
|
+
return l !== r;
|
|
1559
|
+
case "<":
|
|
1560
|
+
return l < r;
|
|
1561
|
+
case ">":
|
|
1562
|
+
return l > r;
|
|
1563
|
+
case "<=":
|
|
1564
|
+
return l <= r;
|
|
1565
|
+
case ">=":
|
|
1566
|
+
return l >= r;
|
|
1567
|
+
case "in":
|
|
1568
|
+
return l in r;
|
|
1569
|
+
case "instanceof":
|
|
1570
|
+
return l instanceof r;
|
|
1571
|
+
}
|
|
1572
|
+
return void 0;
|
|
1573
|
+
}
|
|
1574
|
+
evalAssignment(node, scope, thisVal) {
|
|
1575
|
+
const op = node.operator;
|
|
1576
|
+
if (op === "=") {
|
|
1577
|
+
const value2 = this.evalExpr(node.right, scope, thisVal);
|
|
1578
|
+
this.assign(node.left, value2, scope, thisVal);
|
|
1579
|
+
return value2;
|
|
1580
|
+
}
|
|
1581
|
+
const current = this.evalTarget(node.left, scope, thisVal);
|
|
1582
|
+
let value;
|
|
1583
|
+
if (op === "&&=") {
|
|
1584
|
+
if (!current) return current;
|
|
1585
|
+
value = this.evalExpr(node.right, scope, thisVal);
|
|
1586
|
+
} else if (op === "||=") {
|
|
1587
|
+
if (current) return current;
|
|
1588
|
+
value = this.evalExpr(node.right, scope, thisVal);
|
|
1589
|
+
} else if (op === "??=") {
|
|
1590
|
+
if (current != null) return current;
|
|
1591
|
+
value = this.evalExpr(node.right, scope, thisVal);
|
|
1592
|
+
} else {
|
|
1593
|
+
const rhs = this.evalExpr(node.right, scope, thisVal);
|
|
1594
|
+
value = this.evalBinary(op.slice(0, -1), current, rhs);
|
|
1595
|
+
}
|
|
1596
|
+
this.assign(node.left, value, scope, thisVal);
|
|
1597
|
+
return value;
|
|
1598
|
+
}
|
|
1599
|
+
/** Read the current value of an assignment target (for compound ops). */
|
|
1600
|
+
evalTarget(node, scope, thisVal) {
|
|
1601
|
+
return this.evalExpr(node, scope, thisVal);
|
|
1602
|
+
}
|
|
1603
|
+
assign(target, value, scope, thisVal) {
|
|
1604
|
+
if (target.type === "Identifier") {
|
|
1605
|
+
if (!scope.set(target.name, value)) this.root.set(target.name, value);
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
if (target.type === "MemberExpression") {
|
|
1609
|
+
const obj = this.evalExpr(target.object, scope, thisVal);
|
|
1610
|
+
if (obj == null) throw new TypeError("Cannot assign to a property of null or undefined");
|
|
1611
|
+
const key = target.computed ? this.evalExpr(target.property, scope, thisVal) : target.property.name;
|
|
1612
|
+
obj[key] = value;
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
throw new TypeError("Invalid assignment target");
|
|
1616
|
+
}
|
|
1617
|
+
resolve(name, scope) {
|
|
1618
|
+
if (scope.has(name)) return scope.get(name);
|
|
1619
|
+
if (this.root.has(name)) return this.root.get(name);
|
|
1620
|
+
if (GLOBAL_ALLOW.has(name)) return globalThis[name];
|
|
1621
|
+
return void 0;
|
|
1622
|
+
}
|
|
1623
|
+
// --- Functions ---
|
|
1624
|
+
makeFunction(node, definingScope, lexicalThis, dynamicThis) {
|
|
1625
|
+
const self = this;
|
|
1626
|
+
return function(...args) {
|
|
1627
|
+
const fnScope = new LexicalScope(definingScope);
|
|
1628
|
+
self.bindParams(node.params, args, fnScope);
|
|
1629
|
+
const usedThis = dynamicThis ? this : lexicalThis;
|
|
1630
|
+
if (node.expression) {
|
|
1631
|
+
return self.evalExpr(node.body, fnScope, usedThis);
|
|
1632
|
+
}
|
|
1633
|
+
try {
|
|
1634
|
+
self.execBlock(node.body.body, new LexicalScope(fnScope), usedThis);
|
|
1635
|
+
} catch (signal2) {
|
|
1636
|
+
if (signal2 instanceof ReturnSignal) return signal2.value;
|
|
1637
|
+
throw signal2;
|
|
1638
|
+
}
|
|
1639
|
+
return void 0;
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
bindParams(params, args, scope) {
|
|
1643
|
+
for (let i = 0; i < params.length; i++) {
|
|
1644
|
+
const p = params[i];
|
|
1645
|
+
if (p.type === "RestElement") {
|
|
1646
|
+
this.bindPattern(p.argument, args.slice(i), scope, false);
|
|
1647
|
+
break;
|
|
1648
|
+
}
|
|
1649
|
+
this.bindPattern(p, args[i], scope, false);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
bindPattern(pattern, value, scope, constant) {
|
|
1653
|
+
switch (pattern.type) {
|
|
1654
|
+
case "Identifier":
|
|
1655
|
+
scope.declare(pattern.name, value, constant);
|
|
1656
|
+
return;
|
|
1657
|
+
case "AssignmentPattern":
|
|
1658
|
+
this.bindPattern(pattern.left, value === void 0 ? this.evalExpr(pattern.right, scope, void 0) : value, scope, constant);
|
|
1659
|
+
return;
|
|
1660
|
+
case "RestElement":
|
|
1661
|
+
this.bindPattern(pattern.argument, value, scope, constant);
|
|
1662
|
+
return;
|
|
1663
|
+
case "ObjectPattern": {
|
|
1664
|
+
const obj = value ?? {};
|
|
1665
|
+
const used = /* @__PURE__ */ new Set();
|
|
1666
|
+
for (const prop of pattern.properties) {
|
|
1667
|
+
const key = prop.computed ? String(this.evalExpr(prop.key, scope, void 0)) : prop.key.value;
|
|
1668
|
+
used.add(key);
|
|
1669
|
+
this.bindPattern(prop.value, obj[key], scope, constant);
|
|
1670
|
+
}
|
|
1671
|
+
if (pattern.rest) {
|
|
1672
|
+
const rest = {};
|
|
1673
|
+
for (const k of Object.keys(obj)) if (!used.has(k)) rest[k] = obj[k];
|
|
1674
|
+
scope.declare(pattern.rest.name, rest, constant);
|
|
1675
|
+
}
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
case "ArrayPattern": {
|
|
1679
|
+
const arr = value ?? [];
|
|
1680
|
+
for (let i = 0; i < pattern.elements.length; i++) {
|
|
1681
|
+
const el = pattern.elements[i];
|
|
1682
|
+
if (el) this.bindPattern(el, arr[i], scope, constant);
|
|
1683
|
+
}
|
|
1684
|
+
if (pattern.rest) this.bindPattern(pattern.rest, arr.slice(pattern.elements.length), scope, constant);
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
/** Assign into an existing pattern target (for-of without declaration). */
|
|
1690
|
+
assignPattern(pattern, value, scope, thisVal) {
|
|
1691
|
+
if (pattern.type === "Identifier") {
|
|
1692
|
+
if (!scope.set(pattern.name, value)) this.root.set(pattern.name, value);
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
this.bindPattern(pattern, value, scope, false);
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
|
|
1699
|
+
// src/evaluator/index.ts
|
|
1700
|
+
function evaluateExpression(source, root, thisVal) {
|
|
1701
|
+
const program = parse(source, "expression");
|
|
1702
|
+
return new Interpreter(root).run(program, thisVal);
|
|
1703
|
+
}
|
|
1704
|
+
function evaluateAction(source, root, thisVal) {
|
|
1705
|
+
const program = parse(source, "program");
|
|
1706
|
+
return new Interpreter(root).run(program, thisVal);
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
// src/errors.ts
|
|
1710
|
+
var DOCS = "https://velofy.github.io/summit";
|
|
1711
|
+
function distance(a, b) {
|
|
1712
|
+
const m = a.length;
|
|
1713
|
+
const n = b.length;
|
|
1714
|
+
if (!m) return n;
|
|
1715
|
+
if (!n) return m;
|
|
1716
|
+
let prev = Array.from({ length: n + 1 }, (_, j) => j);
|
|
1717
|
+
for (let i = 1; i <= m; i++) {
|
|
1718
|
+
const curr = [i];
|
|
1719
|
+
for (let j = 1; j <= n; j++) {
|
|
1720
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
1721
|
+
curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
|
|
1722
|
+
}
|
|
1723
|
+
prev = curr;
|
|
1724
|
+
}
|
|
1725
|
+
return prev[n];
|
|
1726
|
+
}
|
|
1727
|
+
function suggest(name, candidates) {
|
|
1728
|
+
let best = null;
|
|
1729
|
+
let bestD = Infinity;
|
|
1730
|
+
for (const c of candidates) {
|
|
1731
|
+
const d = distance(name, c);
|
|
1732
|
+
if (d < bestD) {
|
|
1733
|
+
bestD = d;
|
|
1734
|
+
best = c;
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
const limit = name.length <= 4 ? 1 : 2;
|
|
1738
|
+
return best !== null && bestD <= limit ? best : null;
|
|
1739
|
+
}
|
|
1740
|
+
function describeEl(el) {
|
|
1741
|
+
const tag = el.tagName.toLowerCase();
|
|
1742
|
+
const id2 = el.id ? `#${el.id}` : "";
|
|
1743
|
+
const cls = el.classList.length ? "." + Array.from(el.classList).slice(0, 2).join(".") : "";
|
|
1744
|
+
return `<${tag}${id2}${cls}>`;
|
|
1745
|
+
}
|
|
1746
|
+
function build(code, message, ctx) {
|
|
1747
|
+
const lines = [`[summit] ${code}: ${message}`];
|
|
1748
|
+
if (ctx.hint) lines.push(` ${ctx.hint}`);
|
|
1749
|
+
if (ctx.expression) lines.push(` expression: ${ctx.expression.trim()}`);
|
|
1750
|
+
if (ctx.el) lines.push(` element: ${describeEl(ctx.el)}`);
|
|
1751
|
+
lines.push(` docs: ${DOCS}/${ctx.doc ? ctx.doc + "/" : ""}`);
|
|
1752
|
+
return lines.join("\n");
|
|
1753
|
+
}
|
|
1754
|
+
function warn(code, message, ctx = {}) {
|
|
1755
|
+
if (ctx.cause !== void 0) console.warn(build(code, message, ctx), "\n ", ctx.cause);
|
|
1756
|
+
else console.warn(build(code, message, ctx));
|
|
1757
|
+
}
|
|
1758
|
+
function fail(code, message, ctx = {}) {
|
|
1759
|
+
if (ctx.cause !== void 0) console.error(build(code, message, ctx), "\n ", ctx.cause);
|
|
1760
|
+
else console.error(build(code, message, ctx));
|
|
1761
|
+
}
|
|
1762
|
+
var seen = /* @__PURE__ */ new Set();
|
|
1763
|
+
function warnOnce(key, code, message, ctx = {}) {
|
|
1764
|
+
if (seen.has(key)) return;
|
|
1765
|
+
seen.add(key);
|
|
1766
|
+
warn(code, message, ctx);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
// src/dom.ts
|
|
1770
|
+
var metaMap = /* @__PURE__ */ new WeakMap();
|
|
1771
|
+
function meta(node) {
|
|
1772
|
+
let m = metaMap.get(node);
|
|
1773
|
+
if (!m) metaMap.set(node, m = {});
|
|
1774
|
+
return m;
|
|
1775
|
+
}
|
|
1776
|
+
var markerCount = 0;
|
|
1777
|
+
function nextMarker() {
|
|
1778
|
+
return ++markerCount;
|
|
1779
|
+
}
|
|
1780
|
+
function addCleanup(el, fn) {
|
|
1781
|
+
const m = meta(el);
|
|
1782
|
+
(m.cleanups ?? (m.cleanups = [])).push(fn);
|
|
1783
|
+
}
|
|
1784
|
+
function runCleanups(el) {
|
|
1785
|
+
const m = metaMap.get(el);
|
|
1786
|
+
if (!m) return;
|
|
1787
|
+
if (m.cleanups) {
|
|
1788
|
+
for (const fn of m.cleanups) {
|
|
1789
|
+
try {
|
|
1790
|
+
fn();
|
|
1791
|
+
} catch (err) {
|
|
1792
|
+
fail("E601", "a cleanup callback threw during teardown.", { doc: "lifecycle", cause: err });
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
m.cleanups = [];
|
|
1796
|
+
}
|
|
1797
|
+
if (m.destroyCallbacks) {
|
|
1798
|
+
for (const fn of m.destroyCallbacks) {
|
|
1799
|
+
try {
|
|
1800
|
+
fn();
|
|
1801
|
+
} catch (err) {
|
|
1802
|
+
fail("E602", "a destroy() callback threw during teardown.", { doc: "lifecycle", cause: err });
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
m.destroyCallbacks = [];
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
function resolveScopes(el) {
|
|
1809
|
+
const own = metaMap.get(el)?.scopes;
|
|
1810
|
+
if (own) return own;
|
|
1811
|
+
let parent = el.parentElement;
|
|
1812
|
+
while (parent) {
|
|
1813
|
+
const s = metaMap.get(parent)?.scopes;
|
|
1814
|
+
if (s) return s;
|
|
1815
|
+
parent = parent.parentElement;
|
|
1816
|
+
}
|
|
1817
|
+
return [];
|
|
1818
|
+
}
|
|
1819
|
+
function closestRoot(el) {
|
|
1820
|
+
let cur = el;
|
|
1821
|
+
while (cur) {
|
|
1822
|
+
if (metaMap.get(cur)?.isRoot) return cur;
|
|
1823
|
+
cur = cur.parentElement;
|
|
1824
|
+
}
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
function refsFor(el) {
|
|
1828
|
+
const root = closestRoot(el) ?? el;
|
|
1829
|
+
const m = meta(root);
|
|
1830
|
+
return m.refs ?? (m.refs = {});
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
// src/scope/environment.ts
|
|
1834
|
+
var DOLLAR = 36;
|
|
1835
|
+
function makeEnv(el, locals) {
|
|
1836
|
+
const scopes = resolveScopes(el);
|
|
1837
|
+
const thisVal = scopes.length ? scopes[scopes.length - 1] : void 0;
|
|
1838
|
+
const ctx = {
|
|
1839
|
+
el,
|
|
1840
|
+
scopes,
|
|
1841
|
+
evaluate: (expression) => evaluateExpression(expression, env, thisVal),
|
|
1842
|
+
effect: (fn) => {
|
|
1843
|
+
const dispose = domEffect(fn);
|
|
1844
|
+
addCleanup(el, dispose);
|
|
1845
|
+
},
|
|
1846
|
+
cleanup: (fn) => addCleanup(el, fn)
|
|
1847
|
+
};
|
|
1848
|
+
const env = {
|
|
1849
|
+
has(name) {
|
|
1850
|
+
if (locals && name in locals) return true;
|
|
1851
|
+
for (let i = scopes.length - 1; i >= 0; i--) {
|
|
1852
|
+
if (name in scopes[i]) return true;
|
|
1853
|
+
}
|
|
1854
|
+
if (name.charCodeAt(0) === DOLLAR && getMagic(name.slice(1))) return true;
|
|
1855
|
+
return false;
|
|
1856
|
+
},
|
|
1857
|
+
get(name) {
|
|
1858
|
+
if (locals && name in locals) return locals[name];
|
|
1859
|
+
for (let i = scopes.length - 1; i >= 0; i--) {
|
|
1860
|
+
if (name in scopes[i]) return scopes[i][name];
|
|
1861
|
+
}
|
|
1862
|
+
if (name.charCodeAt(0) === DOLLAR) {
|
|
1863
|
+
const factory = getMagic(name.slice(1));
|
|
1864
|
+
if (factory) return factory(ctx);
|
|
1865
|
+
}
|
|
1866
|
+
return void 0;
|
|
1867
|
+
},
|
|
1868
|
+
set(name, value) {
|
|
1869
|
+
for (let i = scopes.length - 1; i >= 0; i--) {
|
|
1870
|
+
if (name in scopes[i]) {
|
|
1871
|
+
scopes[i][name] = value;
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
if (scopes.length) scopes[scopes.length - 1][name] = value;
|
|
1876
|
+
}
|
|
1877
|
+
};
|
|
1878
|
+
return {
|
|
1879
|
+
env,
|
|
1880
|
+
thisVal,
|
|
1881
|
+
evaluate: (expression) => evaluateExpression(expression, env, thisVal),
|
|
1882
|
+
evaluateAction: (expression, extraLocals) => {
|
|
1883
|
+
if (!extraLocals) return evaluateAction(expression, env, thisVal);
|
|
1884
|
+
const layered = {
|
|
1885
|
+
has: (n) => n in extraLocals ? true : env.has(n),
|
|
1886
|
+
get: (n) => n in extraLocals ? extraLocals[n] : env.get(n),
|
|
1887
|
+
set: (n, v) => env.set(n, v)
|
|
1888
|
+
};
|
|
1889
|
+
return evaluateAction(expression, layered, thisVal);
|
|
1890
|
+
}
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
function attachMagics(rawTarget, el, scopes) {
|
|
1894
|
+
const ctx = {
|
|
1895
|
+
el,
|
|
1896
|
+
scopes,
|
|
1897
|
+
evaluate: (expression) => evaluateExpression(expression, makeEnv(el).env, scopes.length ? scopes[scopes.length - 1] : void 0),
|
|
1898
|
+
effect: (fn) => addCleanup(el, domEffect(fn)),
|
|
1899
|
+
cleanup: (fn) => addCleanup(el, fn)
|
|
1900
|
+
};
|
|
1901
|
+
for (const name of magicNames()) {
|
|
1902
|
+
Object.defineProperty(rawTarget, "$" + name, {
|
|
1903
|
+
get: () => getMagic(name)(ctx),
|
|
1904
|
+
enumerable: false,
|
|
1905
|
+
configurable: true
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// src/lifecycle/attributes.ts
|
|
1911
|
+
function parseAttribute(rawName, expression) {
|
|
1912
|
+
let name = rawName;
|
|
1913
|
+
if (name[0] === "@") name = "on:" + name.slice(1);
|
|
1914
|
+
else if (name[0] === ":") name = "bind:" + name.slice(1);
|
|
1915
|
+
else if (name.startsWith("s-")) name = name.slice(2);
|
|
1916
|
+
else return null;
|
|
1917
|
+
const parts = name.split(".");
|
|
1918
|
+
const head = parts[0];
|
|
1919
|
+
const modifiers = parts.slice(1);
|
|
1920
|
+
const colon = head.indexOf(":");
|
|
1921
|
+
let dirName;
|
|
1922
|
+
let value;
|
|
1923
|
+
if (colon === -1) {
|
|
1924
|
+
dirName = head;
|
|
1925
|
+
value = null;
|
|
1926
|
+
} else {
|
|
1927
|
+
dirName = head.slice(0, colon);
|
|
1928
|
+
value = head.slice(colon + 1);
|
|
1929
|
+
}
|
|
1930
|
+
return { name: dirName, value, modifiers, expression, raw: rawName };
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
// src/magics/persist.ts
|
|
1934
|
+
var MARK = "__summitPersist";
|
|
1935
|
+
function createPersist(initial) {
|
|
1936
|
+
return {
|
|
1937
|
+
[MARK]: true,
|
|
1938
|
+
initial,
|
|
1939
|
+
key: null,
|
|
1940
|
+
as(key) {
|
|
1941
|
+
this.key = String(key);
|
|
1942
|
+
return this;
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
function isPersistMarker(value) {
|
|
1947
|
+
return !!value && typeof value === "object" && value[MARK] === true;
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
// src/lifecycle/tree.ts
|
|
1951
|
+
var STRUCTURAL = /* @__PURE__ */ new Set(["if", "for", "teleport"]);
|
|
1952
|
+
var SPECIAL = /* @__PURE__ */ new Set(["data", "ignore"]);
|
|
1953
|
+
var summitGlobal;
|
|
1954
|
+
function setSummitGlobal(g) {
|
|
1955
|
+
summitGlobal = g;
|
|
1956
|
+
}
|
|
1957
|
+
function collectDirectives(el) {
|
|
1958
|
+
const out = [];
|
|
1959
|
+
for (const attr of Array.from(el.attributes)) {
|
|
1960
|
+
const parsed = parseAttribute(attr.name, attr.value);
|
|
1961
|
+
if (!parsed) continue;
|
|
1962
|
+
if (SPECIAL.has(parsed.name) || getDirective(parsed.name)) {
|
|
1963
|
+
out.push(parsed);
|
|
1964
|
+
} else {
|
|
1965
|
+
const hit = suggest(parsed.name, [...directiveNames(), ...SPECIAL]);
|
|
1966
|
+
warnOnce(
|
|
1967
|
+
`dir:${parsed.name}`,
|
|
1968
|
+
"E201",
|
|
1969
|
+
`unknown directive "${attr.name}".`,
|
|
1970
|
+
{
|
|
1971
|
+
el,
|
|
1972
|
+
doc: hit ? `s-${hit}` : "start",
|
|
1973
|
+
hint: hit ? `Did you mean "s-${hit}"?` : "See the directive reference."
|
|
1974
|
+
}
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
return out;
|
|
1979
|
+
}
|
|
1980
|
+
function priorityOf(name) {
|
|
1981
|
+
return getDirective(name)?.priority ?? DEFAULT_PRIORITY;
|
|
1982
|
+
}
|
|
1983
|
+
function makeUtils(el, scopes) {
|
|
1984
|
+
const handle = makeEnv(el);
|
|
1985
|
+
return {
|
|
1986
|
+
evaluate: (expression) => handle.evaluate(expression),
|
|
1987
|
+
evaluateAction: (expression, locals) => handle.evaluateAction(expression, locals),
|
|
1988
|
+
effect: (fn) => {
|
|
1989
|
+
const dispose = domEffect(fn);
|
|
1990
|
+
addCleanup(el, dispose);
|
|
1991
|
+
},
|
|
1992
|
+
cleanup: (fn) => addCleanup(el, fn),
|
|
1993
|
+
initTree,
|
|
1994
|
+
destroyTree,
|
|
1995
|
+
scopes,
|
|
1996
|
+
makeEnv: (e, locals) => makeEnv(e, locals).env,
|
|
1997
|
+
Summit: summitGlobal
|
|
1998
|
+
};
|
|
1999
|
+
}
|
|
2000
|
+
function runDirective(el, dmeta, scopes) {
|
|
2001
|
+
const entry = getDirective(dmeta.name);
|
|
2002
|
+
if (!entry) return;
|
|
2003
|
+
try {
|
|
2004
|
+
entry.handler(el, dmeta, makeUtils(el, scopes));
|
|
2005
|
+
} catch (err) {
|
|
2006
|
+
fail("E301", `s-${dmeta.name} failed while evaluating its expression.`, {
|
|
2007
|
+
el,
|
|
2008
|
+
expression: dmeta.expression,
|
|
2009
|
+
doc: `s-${dmeta.name}`,
|
|
2010
|
+
hint: "Every name in the expression must be state from an enclosing s-data, or an allowed global.",
|
|
2011
|
+
cause: err
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
var DATA_PROVIDER_RE = /^([A-Za-z_$][\w$]*)\s*(\(([\s\S]*)\))?$/;
|
|
2016
|
+
function resolvePersist(scope, el) {
|
|
2017
|
+
const hasLS = typeof localStorage !== "undefined";
|
|
2018
|
+
for (const key of Object.keys(scope)) {
|
|
2019
|
+
const marker = scope[key];
|
|
2020
|
+
if (!isPersistMarker(marker)) continue;
|
|
2021
|
+
const storeKey = marker.key ?? key;
|
|
2022
|
+
let value = marker.initial;
|
|
2023
|
+
if (hasLS) {
|
|
2024
|
+
try {
|
|
2025
|
+
const stored = localStorage.getItem(storeKey);
|
|
2026
|
+
if (stored != null) value = JSON.parse(stored);
|
|
2027
|
+
} catch {
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
scope[key] = value;
|
|
2031
|
+
if (hasLS) {
|
|
2032
|
+
const dispose = domEffect(() => {
|
|
2033
|
+
try {
|
|
2034
|
+
localStorage.setItem(storeKey, JSON.stringify(scope[key]));
|
|
2035
|
+
} catch {
|
|
2036
|
+
}
|
|
2037
|
+
});
|
|
2038
|
+
addCleanup(el, dispose);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
function initData(el, dmeta, parentScopes) {
|
|
2043
|
+
const parentEnv = makeEnv(el);
|
|
2044
|
+
const expr = dmeta.expression.trim();
|
|
2045
|
+
let raw;
|
|
2046
|
+
const match = expr.match(DATA_PROVIDER_RE);
|
|
2047
|
+
if (match && getData(match[1])) {
|
|
2048
|
+
const provider = getData(match[1]);
|
|
2049
|
+
const args = match[2] ? parentEnv.evaluate("[" + (match[3] ?? "") + "]") : [];
|
|
2050
|
+
raw = provider(...args);
|
|
2051
|
+
} else if (expr === "") {
|
|
2052
|
+
raw = {};
|
|
2053
|
+
} else {
|
|
2054
|
+
raw = parentEnv.evaluate("(" + expr + ")");
|
|
2055
|
+
}
|
|
2056
|
+
if (raw === null || typeof raw !== "object") raw = {};
|
|
2057
|
+
const scope = createScope(raw);
|
|
2058
|
+
resolvePersist(scope, el);
|
|
2059
|
+
const newScopes = [...parentScopes, scope];
|
|
2060
|
+
const m = meta(el);
|
|
2061
|
+
m.scopes = newScopes;
|
|
2062
|
+
m.isRoot = true;
|
|
2063
|
+
m.refs = {};
|
|
2064
|
+
attachMagics(raw, el, newScopes);
|
|
2065
|
+
const initFn = scope["init"];
|
|
2066
|
+
if (typeof initFn === "function") {
|
|
2067
|
+
try {
|
|
2068
|
+
initFn();
|
|
2069
|
+
} catch (err) {
|
|
2070
|
+
fail("E101", "s-data init() threw.", { el, doc: "s-data", cause: err });
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
const destroyFn = scope["destroy"];
|
|
2074
|
+
if (typeof destroyFn === "function") {
|
|
2075
|
+
addCleanup(el, () => {
|
|
2076
|
+
try {
|
|
2077
|
+
destroyFn();
|
|
2078
|
+
} catch (err) {
|
|
2079
|
+
fail("E102", "s-data destroy() threw.", { el, doc: "s-data", cause: err });
|
|
2080
|
+
}
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
return newScopes;
|
|
2084
|
+
}
|
|
2085
|
+
function initTree(el, scopesArg) {
|
|
2086
|
+
const m = meta(el);
|
|
2087
|
+
if (m.initialized || m.ignore) return;
|
|
2088
|
+
if (el.hasAttribute("s-ignore")) {
|
|
2089
|
+
m.ignore = true;
|
|
2090
|
+
m.initialized = true;
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
let scopes = scopesArg ?? resolveScopes(el);
|
|
2094
|
+
m.scopes = scopes;
|
|
2095
|
+
m.marker = nextMarker();
|
|
2096
|
+
const dirs = collectDirectives(el);
|
|
2097
|
+
const dataDir = dirs.find((d) => d.name === "data");
|
|
2098
|
+
if (dataDir) scopes = initData(el, dataDir, scopes);
|
|
2099
|
+
const structural = dirs.find((d) => STRUCTURAL.has(d.name));
|
|
2100
|
+
if (structural) {
|
|
2101
|
+
m.initialized = true;
|
|
2102
|
+
runDirective(el, structural, scopes);
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
const rest = dirs.filter((d) => d.name !== "data").sort((a, b) => priorityOf(a.name) - priorityOf(b.name));
|
|
2106
|
+
for (const d of rest) runDirective(el, d, scopes);
|
|
2107
|
+
m.initialized = true;
|
|
2108
|
+
for (const child of Array.from(el.children)) {
|
|
2109
|
+
initTree(child, scopes);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
function destroyTree(el) {
|
|
2113
|
+
runCleanups(el);
|
|
2114
|
+
for (const child of Array.from(el.children)) {
|
|
2115
|
+
destroyTree(child);
|
|
2116
|
+
}
|
|
2117
|
+
meta(el).initialized = false;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
// src/lifecycle/observer.ts
|
|
2121
|
+
var observer = null;
|
|
2122
|
+
function startObserver(root) {
|
|
2123
|
+
if (observer) return;
|
|
2124
|
+
observer = new MutationObserver(handleMutations);
|
|
2125
|
+
observer.observe(root, { childList: true, subtree: true });
|
|
2126
|
+
}
|
|
2127
|
+
function handleMutations(records) {
|
|
2128
|
+
const removed = [];
|
|
2129
|
+
const added = [];
|
|
2130
|
+
for (const rec of records) {
|
|
2131
|
+
if (rec.type !== "childList") continue;
|
|
2132
|
+
rec.removedNodes.forEach((n) => {
|
|
2133
|
+
if (n.nodeType === 1) removed.push(n);
|
|
2134
|
+
});
|
|
2135
|
+
rec.addedNodes.forEach((n) => {
|
|
2136
|
+
if (n.nodeType === 1) added.push(n);
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
for (const el of removed) {
|
|
2140
|
+
if (!el.isConnected) destroyTree(el);
|
|
2141
|
+
}
|
|
2142
|
+
for (const el of added) {
|
|
2143
|
+
if (el.isConnected && !meta(el).initialized) initTree(el);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
// src/directives/text.ts
|
|
2148
|
+
function toDisplay(value) {
|
|
2149
|
+
return value == null ? "" : String(value);
|
|
2150
|
+
}
|
|
2151
|
+
var text = (el, meta2, utils) => {
|
|
2152
|
+
utils.effect(() => {
|
|
2153
|
+
el.textContent = toDisplay(utils.evaluate(meta2.expression));
|
|
2154
|
+
});
|
|
2155
|
+
};
|
|
2156
|
+
var html = (el, meta2, utils) => {
|
|
2157
|
+
utils.effect(() => {
|
|
2158
|
+
el.innerHTML = toDisplay(utils.evaluate(meta2.expression));
|
|
2159
|
+
let child = el.firstElementChild;
|
|
2160
|
+
while (child) {
|
|
2161
|
+
utils.initTree(child, utils.scopes);
|
|
2162
|
+
child = child.nextElementSibling;
|
|
2163
|
+
}
|
|
2164
|
+
});
|
|
2165
|
+
};
|
|
2166
|
+
|
|
2167
|
+
// src/directives/shared.ts
|
|
2168
|
+
var BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
|
|
2169
|
+
"disabled",
|
|
2170
|
+
"checked",
|
|
2171
|
+
"required",
|
|
2172
|
+
"readonly",
|
|
2173
|
+
"hidden",
|
|
2174
|
+
"selected",
|
|
2175
|
+
"open",
|
|
2176
|
+
"multiple",
|
|
2177
|
+
"autofocus",
|
|
2178
|
+
"novalidate",
|
|
2179
|
+
"autoplay",
|
|
2180
|
+
"controls",
|
|
2181
|
+
"loop",
|
|
2182
|
+
"muted",
|
|
2183
|
+
"playsinline",
|
|
2184
|
+
"default",
|
|
2185
|
+
"ismap",
|
|
2186
|
+
"reversed",
|
|
2187
|
+
"async",
|
|
2188
|
+
"defer",
|
|
2189
|
+
"inert"
|
|
2190
|
+
]);
|
|
2191
|
+
var PROP_ATTRS = /* @__PURE__ */ new Set(["value", "checked", "selected", "indeterminate", "muted", "volume"]);
|
|
2192
|
+
function camelCase(input) {
|
|
2193
|
+
return input.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
2194
|
+
}
|
|
2195
|
+
function kebabCase(input) {
|
|
2196
|
+
return input.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
|
|
2197
|
+
}
|
|
2198
|
+
function classTokens(value) {
|
|
2199
|
+
if (!value) return [];
|
|
2200
|
+
if (typeof value === "string") return value.split(/\s+/).filter(Boolean);
|
|
2201
|
+
if (Array.isArray(value)) return value.flatMap((v) => classTokens(v));
|
|
2202
|
+
if (typeof value === "object") {
|
|
2203
|
+
return Object.entries(value).filter(([, on2]) => on2).map(([cls]) => cls);
|
|
2204
|
+
}
|
|
2205
|
+
return [];
|
|
2206
|
+
}
|
|
2207
|
+
function mergeClass(base, value) {
|
|
2208
|
+
const set = /* @__PURE__ */ new Set();
|
|
2209
|
+
for (const t of base.split(/\s+/)) if (t) set.add(t);
|
|
2210
|
+
for (const t of classTokens(value)) set.add(t);
|
|
2211
|
+
return [...set].join(" ");
|
|
2212
|
+
}
|
|
2213
|
+
function mergeStyle(base, value) {
|
|
2214
|
+
const parts = [];
|
|
2215
|
+
if (base) parts.push(base.trim().replace(/;?\s*$/, ""));
|
|
2216
|
+
if (typeof value === "string") {
|
|
2217
|
+
parts.push(value.trim().replace(/;?\s*$/, ""));
|
|
2218
|
+
} else if (value && typeof value === "object") {
|
|
2219
|
+
for (const [prop, val] of Object.entries(value)) {
|
|
2220
|
+
if (val == null || val === false) continue;
|
|
2221
|
+
parts.push(`${kebabCase(prop)}: ${String(val)}`);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
return parts.filter(Boolean).join("; ");
|
|
2225
|
+
}
|
|
2226
|
+
function applyAttribute(el, name, value) {
|
|
2227
|
+
if (BOOLEAN_ATTRS.has(name)) {
|
|
2228
|
+
if (value) el.setAttribute(name, "");
|
|
2229
|
+
else el.removeAttribute(name);
|
|
2230
|
+
if (name in el) el[name] = !!value;
|
|
2231
|
+
return;
|
|
2232
|
+
}
|
|
2233
|
+
if (PROP_ATTRS.has(name) && name in el) {
|
|
2234
|
+
el[name] = value;
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
2237
|
+
if (value === false || value == null) {
|
|
2238
|
+
el.removeAttribute(name);
|
|
2239
|
+
} else {
|
|
2240
|
+
el.setAttribute(name, String(value));
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
// src/directives/bind.ts
|
|
2245
|
+
var bind = (el, meta2, utils) => {
|
|
2246
|
+
if (meta2.value === null) {
|
|
2247
|
+
applyBindObject(el, meta2.expression, utils);
|
|
2248
|
+
return;
|
|
2249
|
+
}
|
|
2250
|
+
const name = meta2.modifiers.includes("camel") ? camelCase(meta2.value) : meta2.value;
|
|
2251
|
+
if (name === "class") {
|
|
2252
|
+
const base = el.getAttribute("class") ?? "";
|
|
2253
|
+
utils.effect(() => {
|
|
2254
|
+
el.setAttribute("class", mergeClass(base, utils.evaluate(meta2.expression)));
|
|
2255
|
+
});
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
if (name === "style") {
|
|
2259
|
+
const base = el.getAttribute("style") ?? "";
|
|
2260
|
+
utils.effect(() => {
|
|
2261
|
+
const merged = mergeStyle(base, utils.evaluate(meta2.expression));
|
|
2262
|
+
if (merged) el.setAttribute("style", merged);
|
|
2263
|
+
else el.removeAttribute("style");
|
|
2264
|
+
});
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
utils.effect(() => {
|
|
2268
|
+
applyAttribute(el, name, utils.evaluate(meta2.expression));
|
|
2269
|
+
});
|
|
2270
|
+
};
|
|
2271
|
+
function applyBindObject(el, expression, utils) {
|
|
2272
|
+
const obj = utils.evaluate(expression);
|
|
2273
|
+
if (!obj || typeof obj !== "object") return;
|
|
2274
|
+
for (const [key, raw] of Object.entries(obj)) {
|
|
2275
|
+
if (key[0] === "@") {
|
|
2276
|
+
const event = key.slice(1);
|
|
2277
|
+
const handler = raw;
|
|
2278
|
+
el.addEventListener(event, handler);
|
|
2279
|
+
utils.cleanup(() => el.removeEventListener(event, handler));
|
|
2280
|
+
} else if (key[0] === ":") {
|
|
2281
|
+
const attr = key.slice(1);
|
|
2282
|
+
const getter = raw;
|
|
2283
|
+
utils.effect(() => applyAttribute(el, attr, typeof getter === "function" ? getter() : getter));
|
|
2284
|
+
} else {
|
|
2285
|
+
applyAttribute(el, key, raw);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
// src/directives/on.ts
|
|
2291
|
+
var SYSTEM = /* @__PURE__ */ new Set(["shift", "ctrl", "alt", "cmd", "meta"]);
|
|
2292
|
+
var BEHAVIOR = /* @__PURE__ */ new Set([
|
|
2293
|
+
"prevent",
|
|
2294
|
+
"stop",
|
|
2295
|
+
"self",
|
|
2296
|
+
"outside",
|
|
2297
|
+
"once",
|
|
2298
|
+
"capture",
|
|
2299
|
+
"passive",
|
|
2300
|
+
"window",
|
|
2301
|
+
"document",
|
|
2302
|
+
"camel",
|
|
2303
|
+
"dot",
|
|
2304
|
+
"debounce",
|
|
2305
|
+
"throttle"
|
|
2306
|
+
]);
|
|
2307
|
+
var KEY_ALIASES = {
|
|
2308
|
+
enter: "Enter",
|
|
2309
|
+
tab: "Tab",
|
|
2310
|
+
space: " ",
|
|
2311
|
+
esc: "Escape",
|
|
2312
|
+
escape: "Escape",
|
|
2313
|
+
up: "ArrowUp",
|
|
2314
|
+
down: "ArrowDown",
|
|
2315
|
+
left: "ArrowLeft",
|
|
2316
|
+
right: "ArrowRight",
|
|
2317
|
+
"arrow-up": "ArrowUp",
|
|
2318
|
+
"arrow-down": "ArrowDown",
|
|
2319
|
+
"arrow-left": "ArrowLeft",
|
|
2320
|
+
"arrow-right": "ArrowRight",
|
|
2321
|
+
"page-up": "PageUp",
|
|
2322
|
+
"page-down": "PageDown",
|
|
2323
|
+
home: "Home",
|
|
2324
|
+
end: "End",
|
|
2325
|
+
delete: "Delete",
|
|
2326
|
+
backspace: "Backspace"
|
|
2327
|
+
};
|
|
2328
|
+
function isDuration(m) {
|
|
2329
|
+
return /^\d+(ms|s)?$/.test(m);
|
|
2330
|
+
}
|
|
2331
|
+
function parseDuration(m) {
|
|
2332
|
+
if (m.endsWith("ms")) return parseInt(m, 10);
|
|
2333
|
+
if (m.endsWith("s")) return parseInt(m, 10) * 1e3;
|
|
2334
|
+
return parseInt(m, 10);
|
|
2335
|
+
}
|
|
2336
|
+
function durationFor(mods, name) {
|
|
2337
|
+
const i = mods.indexOf(name);
|
|
2338
|
+
if (i === -1) return null;
|
|
2339
|
+
const next = mods[i + 1];
|
|
2340
|
+
return next && isDuration(next) ? parseDuration(next) : 250;
|
|
2341
|
+
}
|
|
2342
|
+
function matchKey(e, mod) {
|
|
2343
|
+
const key = e.key;
|
|
2344
|
+
if (!key) return false;
|
|
2345
|
+
const alias = KEY_ALIASES[mod];
|
|
2346
|
+
if (alias) return key === alias;
|
|
2347
|
+
return kebabCase(key).toLowerCase() === mod.toLowerCase() || key.toLowerCase() === mod.toLowerCase();
|
|
2348
|
+
}
|
|
2349
|
+
function passesSystem(e, mods) {
|
|
2350
|
+
const k = e;
|
|
2351
|
+
if (mods.includes("shift") && !k.shiftKey) return false;
|
|
2352
|
+
if (mods.includes("ctrl") && !k.ctrlKey) return false;
|
|
2353
|
+
if (mods.includes("alt") && !k.altKey) return false;
|
|
2354
|
+
if ((mods.includes("cmd") || mods.includes("meta")) && !k.metaKey) return false;
|
|
2355
|
+
return true;
|
|
2356
|
+
}
|
|
2357
|
+
function debounce(fn, ms) {
|
|
2358
|
+
let t;
|
|
2359
|
+
return (e) => {
|
|
2360
|
+
clearTimeout(t);
|
|
2361
|
+
t = setTimeout(() => fn(e), ms);
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
function throttle(fn, ms) {
|
|
2365
|
+
let last = 0;
|
|
2366
|
+
let scheduled;
|
|
2367
|
+
return (e) => {
|
|
2368
|
+
const now = Date.now();
|
|
2369
|
+
const remaining = ms - (now - last);
|
|
2370
|
+
if (remaining <= 0) {
|
|
2371
|
+
last = now;
|
|
2372
|
+
fn(e);
|
|
2373
|
+
} else if (!scheduled) {
|
|
2374
|
+
scheduled = setTimeout(() => {
|
|
2375
|
+
last = Date.now();
|
|
2376
|
+
scheduled = void 0;
|
|
2377
|
+
fn(e);
|
|
2378
|
+
}, remaining);
|
|
2379
|
+
}
|
|
2380
|
+
};
|
|
2381
|
+
}
|
|
2382
|
+
var on = (el, meta2, utils) => {
|
|
2383
|
+
const mods = meta2.modifiers;
|
|
2384
|
+
let event = meta2.value ?? "";
|
|
2385
|
+
if (mods.includes("camel")) event = camelCase(event);
|
|
2386
|
+
if (mods.includes("dot")) event = event.replace(/-/g, ".");
|
|
2387
|
+
const keyMods = mods.filter((m) => !SYSTEM.has(m) && !BEHAVIOR.has(m) && !isDuration(m));
|
|
2388
|
+
const target = mods.includes("window") ? window : mods.includes("document") || mods.includes("outside") ? document : el;
|
|
2389
|
+
const options = {};
|
|
2390
|
+
if (mods.includes("capture")) options.capture = true;
|
|
2391
|
+
if (mods.includes("passive")) options.passive = true;
|
|
2392
|
+
if (mods.includes("once")) options.once = true;
|
|
2393
|
+
const invoke = (e) => {
|
|
2394
|
+
if (mods.includes("self") && e.target !== el) return;
|
|
2395
|
+
if (mods.includes("outside")) {
|
|
2396
|
+
const t = e.target;
|
|
2397
|
+
if (el === t || el.contains(t)) return;
|
|
2398
|
+
if (!document.documentElement.contains(t)) return;
|
|
2399
|
+
}
|
|
2400
|
+
if (keyMods.length && !keyMods.some((k) => matchKey(e, k))) return;
|
|
2401
|
+
if (!passesSystem(e, mods)) return;
|
|
2402
|
+
if (mods.includes("prevent")) e.preventDefault();
|
|
2403
|
+
if (mods.includes("stop")) e.stopPropagation();
|
|
2404
|
+
try {
|
|
2405
|
+
const result = utils.evaluateAction(meta2.expression, { $event: e });
|
|
2406
|
+
if (typeof result === "function") result(e);
|
|
2407
|
+
} catch (err) {
|
|
2408
|
+
fail("E301", `@${event} handler failed while evaluating its expression.`, {
|
|
2409
|
+
el,
|
|
2410
|
+
expression: meta2.expression,
|
|
2411
|
+
doc: "s-on",
|
|
2412
|
+
hint: "Names must be state from an enclosing s-data, a $magic, or an allowed global.",
|
|
2413
|
+
cause: err
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
const debounceMs = durationFor(mods, "debounce");
|
|
2418
|
+
const throttleMs = durationFor(mods, "throttle");
|
|
2419
|
+
let handler = invoke;
|
|
2420
|
+
if (debounceMs != null) handler = debounce(invoke, debounceMs);
|
|
2421
|
+
else if (throttleMs != null) handler = throttle(invoke, throttleMs);
|
|
2422
|
+
target.addEventListener(event, handler, options);
|
|
2423
|
+
utils.cleanup(() => target.removeEventListener(event, handler, options));
|
|
2424
|
+
};
|
|
2425
|
+
|
|
2426
|
+
// src/directives/model.ts
|
|
2427
|
+
function coerce(value, mods) {
|
|
2428
|
+
if (mods.includes("number")) {
|
|
2429
|
+
const n = parseFloat(value);
|
|
2430
|
+
return isNaN(n) ? value : n;
|
|
2431
|
+
}
|
|
2432
|
+
if (mods.includes("boolean")) {
|
|
2433
|
+
if (value === "true") return true;
|
|
2434
|
+
if (value === "false") return false;
|
|
2435
|
+
return Boolean(value);
|
|
2436
|
+
}
|
|
2437
|
+
return value;
|
|
2438
|
+
}
|
|
2439
|
+
function debounce2(fn, ms) {
|
|
2440
|
+
let t;
|
|
2441
|
+
return () => {
|
|
2442
|
+
clearTimeout(t);
|
|
2443
|
+
t = setTimeout(fn, ms);
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
function durationFor2(mods, name) {
|
|
2447
|
+
const i = mods.indexOf(name);
|
|
2448
|
+
if (i === -1) return null;
|
|
2449
|
+
const next = mods[i + 1];
|
|
2450
|
+
if (next && /^\d+(ms|s)?$/.test(next)) {
|
|
2451
|
+
return next.endsWith("s") && !next.endsWith("ms") ? parseInt(next, 10) * 1e3 : parseInt(next, 10);
|
|
2452
|
+
}
|
|
2453
|
+
return 250;
|
|
2454
|
+
}
|
|
2455
|
+
var model = (el, meta2, utils) => {
|
|
2456
|
+
const input = el;
|
|
2457
|
+
const select = el;
|
|
2458
|
+
const mods = meta2.modifiers;
|
|
2459
|
+
const expr = meta2.expression;
|
|
2460
|
+
const type = input.type;
|
|
2461
|
+
const tag = el.tagName;
|
|
2462
|
+
const getValue = () => utils.evaluate(expr);
|
|
2463
|
+
const setValue = (v) => {
|
|
2464
|
+
utils.evaluateAction(expr + " = $model", { $model: v });
|
|
2465
|
+
};
|
|
2466
|
+
if (mods.includes("fill")) {
|
|
2467
|
+
const current = getValue();
|
|
2468
|
+
if (current === void 0 || current === null || current === "") {
|
|
2469
|
+
setValue(coerce(input.value ?? input.getAttribute("value") ?? "", mods));
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
const readFromElement = () => {
|
|
2473
|
+
if (type === "checkbox") {
|
|
2474
|
+
const current = getValue();
|
|
2475
|
+
if (Array.isArray(current)) {
|
|
2476
|
+
const next = new Set(current);
|
|
2477
|
+
if (input.checked) next.add(input.value);
|
|
2478
|
+
else next.delete(input.value);
|
|
2479
|
+
return [...next];
|
|
2480
|
+
}
|
|
2481
|
+
return input.checked;
|
|
2482
|
+
}
|
|
2483
|
+
if (type === "radio") {
|
|
2484
|
+
return coerce(input.value, mods);
|
|
2485
|
+
}
|
|
2486
|
+
if (tag === "SELECT" && select.multiple) {
|
|
2487
|
+
return Array.from(select.selectedOptions).map((o) => o.value);
|
|
2488
|
+
}
|
|
2489
|
+
return coerce(input.value, mods);
|
|
2490
|
+
};
|
|
2491
|
+
const writeToElement = (value) => {
|
|
2492
|
+
if (type === "checkbox") {
|
|
2493
|
+
input.checked = Array.isArray(value) ? value.map(String).includes(input.value) : !!value;
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
if (type === "radio") {
|
|
2497
|
+
input.checked = String(value) === input.value;
|
|
2498
|
+
return;
|
|
2499
|
+
}
|
|
2500
|
+
if (tag === "SELECT" && select.multiple) {
|
|
2501
|
+
const set = new Set(value?.map(String) ?? []);
|
|
2502
|
+
for (const opt of Array.from(select.options)) opt.selected = set.has(opt.value);
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
const str = value == null ? "" : String(value);
|
|
2506
|
+
if (input.value !== str) input.value = str;
|
|
2507
|
+
};
|
|
2508
|
+
utils.effect(() => writeToElement(getValue()));
|
|
2509
|
+
let eventName = "input";
|
|
2510
|
+
if (tag === "SELECT" || type === "checkbox" || type === "radio") eventName = "change";
|
|
2511
|
+
if (mods.includes("lazy") || mods.includes("change")) eventName = "change";
|
|
2512
|
+
if (mods.includes("blur")) eventName = "blur";
|
|
2513
|
+
let onEvent = () => setValue(readFromElement());
|
|
2514
|
+
const debounceMs = durationFor2(mods, "debounce");
|
|
2515
|
+
if (debounceMs != null) onEvent = debounce2(onEvent, debounceMs);
|
|
2516
|
+
el.addEventListener(eventName, onEvent);
|
|
2517
|
+
utils.cleanup(() => el.removeEventListener(eventName, onEvent));
|
|
2518
|
+
el._summitModel = {
|
|
2519
|
+
get: getValue,
|
|
2520
|
+
set: setValue
|
|
2521
|
+
};
|
|
2522
|
+
};
|
|
2523
|
+
|
|
2524
|
+
// src/directives/transition.ts
|
|
2525
|
+
var configs = /* @__PURE__ */ new WeakMap();
|
|
2526
|
+
function config(el) {
|
|
2527
|
+
let c = configs.get(el);
|
|
2528
|
+
if (!c) configs.set(el, c = { classMode: false });
|
|
2529
|
+
return c;
|
|
2530
|
+
}
|
|
2531
|
+
function hasTransition(el) {
|
|
2532
|
+
return configs.has(el);
|
|
2533
|
+
}
|
|
2534
|
+
function tokens(list) {
|
|
2535
|
+
return list ? list.split(/\s+/).filter(Boolean) : [];
|
|
2536
|
+
}
|
|
2537
|
+
function durationMod(mods, name) {
|
|
2538
|
+
const i = mods.indexOf(name);
|
|
2539
|
+
if (i === -1) return void 0;
|
|
2540
|
+
const next = mods[i + 1];
|
|
2541
|
+
if (!next) return void 0;
|
|
2542
|
+
if (next.endsWith("ms")) return parseInt(next, 10);
|
|
2543
|
+
if (next.endsWith("s")) return parseInt(next, 10) * 1e3;
|
|
2544
|
+
return parseInt(next, 10);
|
|
2545
|
+
}
|
|
2546
|
+
var transition = (el, meta2) => {
|
|
2547
|
+
const c = config(el);
|
|
2548
|
+
const mods = meta2.modifiers;
|
|
2549
|
+
if (meta2.value) {
|
|
2550
|
+
c.classMode = true;
|
|
2551
|
+
const key = meta2.value;
|
|
2552
|
+
const map = {
|
|
2553
|
+
enter: "enter",
|
|
2554
|
+
"enter-start": "enterStart",
|
|
2555
|
+
"enter-end": "enterEnd",
|
|
2556
|
+
leave: "leave",
|
|
2557
|
+
"leave-start": "leaveStart",
|
|
2558
|
+
"leave-end": "leaveEnd"
|
|
2559
|
+
};
|
|
2560
|
+
c[map[key]] = meta2.expression;
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2563
|
+
c.duration = durationMod(mods, "duration") ?? c.duration;
|
|
2564
|
+
c.delay = durationMod(mods, "delay") ?? c.delay;
|
|
2565
|
+
if (mods.includes("opacity")) c.opacity = true;
|
|
2566
|
+
if (mods.includes("scale")) {
|
|
2567
|
+
const i = mods.indexOf("scale");
|
|
2568
|
+
const next = mods[i + 1];
|
|
2569
|
+
c.scale = next && /^\d+$/.test(next) ? parseInt(next, 10) / 100 : 0.95;
|
|
2570
|
+
}
|
|
2571
|
+
if (!mods.includes("opacity") && c.scale === void 0) {
|
|
2572
|
+
c.opacity = true;
|
|
2573
|
+
c.scale = 0.95;
|
|
2574
|
+
}
|
|
2575
|
+
};
|
|
2576
|
+
function afterDuration(el, fallback, done) {
|
|
2577
|
+
const computed2 = getComputedStyle(el).transitionDuration;
|
|
2578
|
+
const ms = computed2 && computed2 !== "0s" ? parseFloat(computed2) * 1e3 : fallback;
|
|
2579
|
+
if (ms <= 0) {
|
|
2580
|
+
requestAnimationFrame(() => done());
|
|
2581
|
+
} else {
|
|
2582
|
+
setTimeout(done, ms);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
function transitionIn(el, done) {
|
|
2586
|
+
const c = configs.get(el);
|
|
2587
|
+
if (!c) {
|
|
2588
|
+
return;
|
|
2589
|
+
}
|
|
2590
|
+
if (c.classMode) {
|
|
2591
|
+
el.classList.add(...tokens(c.enter), ...tokens(c.enterStart));
|
|
2592
|
+
requestAnimationFrame(() => {
|
|
2593
|
+
el.classList.remove(...tokens(c.enterStart));
|
|
2594
|
+
el.classList.add(...tokens(c.enterEnd));
|
|
2595
|
+
afterDuration(el, c.duration ?? 150, () => {
|
|
2596
|
+
el.classList.remove(...tokens(c.enter), ...tokens(c.enterEnd));
|
|
2597
|
+
});
|
|
2598
|
+
});
|
|
2599
|
+
return;
|
|
2600
|
+
}
|
|
2601
|
+
const dur = c.duration ?? 150;
|
|
2602
|
+
el.style.transition = "none";
|
|
2603
|
+
if (c.opacity) el.style.opacity = "0";
|
|
2604
|
+
if (c.scale !== void 0) el.style.transform = `scale(${c.scale})`;
|
|
2605
|
+
requestAnimationFrame(() => {
|
|
2606
|
+
el.style.transition = `all ${dur}ms ease-out ${c.delay ?? 0}ms`;
|
|
2607
|
+
if (c.opacity) el.style.opacity = "1";
|
|
2608
|
+
if (c.scale !== void 0) el.style.transform = "scale(1)";
|
|
2609
|
+
setTimeout(() => {
|
|
2610
|
+
el.style.removeProperty("transition");
|
|
2611
|
+
el.style.removeProperty("opacity");
|
|
2612
|
+
el.style.removeProperty("transform");
|
|
2613
|
+
}, dur + (c.delay ?? 0));
|
|
2614
|
+
});
|
|
2615
|
+
}
|
|
2616
|
+
function transitionOut(el, done) {
|
|
2617
|
+
const c = configs.get(el);
|
|
2618
|
+
if (!c) {
|
|
2619
|
+
done();
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
if (c.classMode) {
|
|
2623
|
+
el.classList.add(...tokens(c.leave), ...tokens(c.leaveStart));
|
|
2624
|
+
requestAnimationFrame(() => {
|
|
2625
|
+
el.classList.remove(...tokens(c.leaveStart));
|
|
2626
|
+
el.classList.add(...tokens(c.leaveEnd));
|
|
2627
|
+
afterDuration(el, c.duration ?? 150, () => {
|
|
2628
|
+
el.classList.remove(...tokens(c.leave), ...tokens(c.leaveEnd));
|
|
2629
|
+
done();
|
|
2630
|
+
});
|
|
2631
|
+
});
|
|
2632
|
+
return;
|
|
2633
|
+
}
|
|
2634
|
+
const dur = c.duration ?? 150;
|
|
2635
|
+
el.style.transition = `all ${dur}ms ease-in ${c.delay ?? 0}ms`;
|
|
2636
|
+
requestAnimationFrame(() => {
|
|
2637
|
+
if (c.opacity) el.style.opacity = "0";
|
|
2638
|
+
if (c.scale !== void 0) el.style.transform = `scale(${c.scale})`;
|
|
2639
|
+
setTimeout(() => {
|
|
2640
|
+
el.style.removeProperty("transition");
|
|
2641
|
+
el.style.removeProperty("opacity");
|
|
2642
|
+
el.style.removeProperty("transform");
|
|
2643
|
+
done();
|
|
2644
|
+
}, dur + (c.delay ?? 0));
|
|
2645
|
+
});
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
// src/directives/show.ts
|
|
2649
|
+
var show = (el, meta2, utils) => {
|
|
2650
|
+
const element = el;
|
|
2651
|
+
const important = meta2.modifiers.includes("important");
|
|
2652
|
+
const originalDisplay = element.style.display === "none" ? "" : element.style.display;
|
|
2653
|
+
const reveal = () => {
|
|
2654
|
+
if (originalDisplay) element.style.display = originalDisplay;
|
|
2655
|
+
else element.style.removeProperty("display");
|
|
2656
|
+
};
|
|
2657
|
+
const conceal = () => {
|
|
2658
|
+
if (important) element.style.setProperty("display", "none", "important");
|
|
2659
|
+
else element.style.setProperty("display", "none");
|
|
2660
|
+
};
|
|
2661
|
+
let first = true;
|
|
2662
|
+
utils.effect(() => {
|
|
2663
|
+
const visible2 = !!utils.evaluate(meta2.expression);
|
|
2664
|
+
const animate = hasTransition(el) && !first;
|
|
2665
|
+
first = false;
|
|
2666
|
+
if (!animate) {
|
|
2667
|
+
if (visible2) reveal();
|
|
2668
|
+
else conceal();
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2671
|
+
if (visible2) {
|
|
2672
|
+
reveal();
|
|
2673
|
+
transitionIn(element);
|
|
2674
|
+
} else {
|
|
2675
|
+
transitionOut(element, conceal);
|
|
2676
|
+
}
|
|
2677
|
+
});
|
|
2678
|
+
};
|
|
2679
|
+
|
|
2680
|
+
// src/directives/conditionals.ts
|
|
2681
|
+
var sIf = (el, meta2, utils) => {
|
|
2682
|
+
const parent = el.parentNode;
|
|
2683
|
+
if (!parent) return;
|
|
2684
|
+
const anchor2 = document.createComment("s-if");
|
|
2685
|
+
parent.insertBefore(anchor2, el);
|
|
2686
|
+
let blueprints;
|
|
2687
|
+
if (el.tagName === "TEMPLATE") {
|
|
2688
|
+
blueprints = Array.from(el.content.children).map(
|
|
2689
|
+
(child) => child.cloneNode(true)
|
|
2690
|
+
);
|
|
2691
|
+
} else {
|
|
2692
|
+
const clone = el.cloneNode(true);
|
|
2693
|
+
clone.removeAttribute(meta2.raw);
|
|
2694
|
+
blueprints = [clone];
|
|
2695
|
+
}
|
|
2696
|
+
el.remove();
|
|
2697
|
+
if (!blueprints.length) return;
|
|
2698
|
+
const scopes = utils.scopes;
|
|
2699
|
+
let current = [];
|
|
2700
|
+
const remove = () => {
|
|
2701
|
+
for (const node of current) {
|
|
2702
|
+
utils.destroyTree(node);
|
|
2703
|
+
node.remove();
|
|
2704
|
+
}
|
|
2705
|
+
current = [];
|
|
2706
|
+
};
|
|
2707
|
+
utils.effect(() => {
|
|
2708
|
+
const condition = !!utils.evaluate(meta2.expression);
|
|
2709
|
+
if (condition && !current.length) {
|
|
2710
|
+
const nodes = blueprints.map((b) => b.cloneNode(true));
|
|
2711
|
+
const frag = document.createDocumentFragment();
|
|
2712
|
+
for (const node of nodes) frag.appendChild(node);
|
|
2713
|
+
anchor2.parentNode?.insertBefore(frag, anchor2.nextSibling);
|
|
2714
|
+
for (const node of nodes) utils.initTree(node, scopes);
|
|
2715
|
+
current = nodes;
|
|
2716
|
+
} else if (!condition && current.length) {
|
|
2717
|
+
remove();
|
|
2718
|
+
}
|
|
2719
|
+
});
|
|
2720
|
+
utils.cleanup(remove);
|
|
2721
|
+
};
|
|
2722
|
+
|
|
2723
|
+
// src/directives/for.ts
|
|
2724
|
+
var FOR_RE = /^\s*(.+?)\s+(?:in|of)\s+([\s\S]+)$/;
|
|
2725
|
+
function parseIterator(raw) {
|
|
2726
|
+
const trimmed = raw.trim();
|
|
2727
|
+
if (trimmed.startsWith("(")) {
|
|
2728
|
+
const inner = trimmed.slice(1, -1);
|
|
2729
|
+
const parts = inner.split(",").map((s) => s.trim());
|
|
2730
|
+
return { item: parts[0], index: parts[1] ?? null };
|
|
2731
|
+
}
|
|
2732
|
+
return { item: trimmed, index: null };
|
|
2733
|
+
}
|
|
2734
|
+
function normalize(source) {
|
|
2735
|
+
if (typeof source === "number") {
|
|
2736
|
+
return Array.from({ length: source }, (_, i) => ({ value: i + 1, index: i }));
|
|
2737
|
+
}
|
|
2738
|
+
if (Array.isArray(source)) {
|
|
2739
|
+
return source.map((value, index) => ({ value, index }));
|
|
2740
|
+
}
|
|
2741
|
+
if (source && typeof source === "object") {
|
|
2742
|
+
return Object.entries(source).map(([k, value], index) => ({
|
|
2743
|
+
value,
|
|
2744
|
+
index,
|
|
2745
|
+
objectKey: k
|
|
2746
|
+
}));
|
|
2747
|
+
}
|
|
2748
|
+
return [];
|
|
2749
|
+
}
|
|
2750
|
+
var sFor = (el, meta2, utils) => {
|
|
2751
|
+
if (el.tagName !== "TEMPLATE") {
|
|
2752
|
+
warn("E401", "s-for must be used on a <template> element.", {
|
|
2753
|
+
el,
|
|
2754
|
+
doc: "s-for",
|
|
2755
|
+
hint: `Wrap the repeated markup: <template s-for="${meta2.expression}"><li>...</li></template>`
|
|
2756
|
+
});
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
const parent = el.parentNode;
|
|
2760
|
+
if (!parent) return;
|
|
2761
|
+
const blueprint = el.content.firstElementChild;
|
|
2762
|
+
if (!blueprint) {
|
|
2763
|
+
warn("E402", "s-for <template> needs exactly one root element.", { el, doc: "s-for" });
|
|
2764
|
+
return;
|
|
2765
|
+
}
|
|
2766
|
+
const { item: itemName, index: indexName } = parseIterator(meta2.expression.replace(FOR_RE, "$1"));
|
|
2767
|
+
const sourceExpr = meta2.expression.replace(FOR_RE, "$2");
|
|
2768
|
+
const keyExpr = el.getAttribute(":key") ?? el.getAttribute("s-bind:key");
|
|
2769
|
+
const anchor2 = document.createComment("s-for");
|
|
2770
|
+
parent.insertBefore(anchor2, el);
|
|
2771
|
+
el.remove();
|
|
2772
|
+
const parentScopes = utils.scopes;
|
|
2773
|
+
let blocks = /* @__PURE__ */ new Map();
|
|
2774
|
+
const keyFor = (it, block) => {
|
|
2775
|
+
if (!keyExpr) return it.objectKey ?? it.index;
|
|
2776
|
+
const env = makeEnv(el, block).env;
|
|
2777
|
+
try {
|
|
2778
|
+
return evaluateExpression(keyExpr, env);
|
|
2779
|
+
} catch {
|
|
2780
|
+
return it.index;
|
|
2781
|
+
}
|
|
2782
|
+
};
|
|
2783
|
+
const makeBlockScope = (it) => {
|
|
2784
|
+
const data = { [itemName]: it.value };
|
|
2785
|
+
if (indexName) data[indexName] = it.objectKey ?? it.index;
|
|
2786
|
+
return reactive(data);
|
|
2787
|
+
};
|
|
2788
|
+
const clear = () => {
|
|
2789
|
+
for (const block of blocks.values()) {
|
|
2790
|
+
utils.destroyTree(block.node);
|
|
2791
|
+
block.node.remove();
|
|
2792
|
+
}
|
|
2793
|
+
blocks.clear();
|
|
2794
|
+
};
|
|
2795
|
+
utils.effect(() => {
|
|
2796
|
+
const items = normalize(utils.evaluate(sourceExpr));
|
|
2797
|
+
const next = /* @__PURE__ */ new Map();
|
|
2798
|
+
const orderedKeys = [];
|
|
2799
|
+
for (const it of items) {
|
|
2800
|
+
let scope = makeBlockScope(it);
|
|
2801
|
+
const key = keyFor(it, scope);
|
|
2802
|
+
orderedKeys.push(key);
|
|
2803
|
+
const existing = blocks.get(key);
|
|
2804
|
+
if (existing) {
|
|
2805
|
+
existing.scope[itemName] = it.value;
|
|
2806
|
+
if (indexName) existing.scope[indexName] = it.objectKey ?? it.index;
|
|
2807
|
+
next.set(key, existing);
|
|
2808
|
+
blocks.delete(key);
|
|
2809
|
+
} else {
|
|
2810
|
+
const node = blueprint.cloneNode(true);
|
|
2811
|
+
utils.initTree(node, [...parentScopes, scope]);
|
|
2812
|
+
next.set(key, { node, scope });
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
for (const block of blocks.values()) {
|
|
2816
|
+
utils.destroyTree(block.node);
|
|
2817
|
+
block.node.remove();
|
|
2818
|
+
}
|
|
2819
|
+
for (const key of orderedKeys) {
|
|
2820
|
+
const block = next.get(key);
|
|
2821
|
+
parent.insertBefore(block.node, anchor2);
|
|
2822
|
+
}
|
|
2823
|
+
blocks = next;
|
|
2824
|
+
});
|
|
2825
|
+
utils.cleanup(clear);
|
|
2826
|
+
};
|
|
2827
|
+
|
|
2828
|
+
// src/directives/teleport.ts
|
|
2829
|
+
var teleport = (el, meta2, utils) => {
|
|
2830
|
+
if (el.tagName !== "TEMPLATE") {
|
|
2831
|
+
warn("E501", "s-teleport must be used on a <template> element.", { el, doc: "s-teleport" });
|
|
2832
|
+
return;
|
|
2833
|
+
}
|
|
2834
|
+
const selector = meta2.expression || meta2.value || "";
|
|
2835
|
+
const target = selector ? document.querySelector(selector) : null;
|
|
2836
|
+
if (!target) {
|
|
2837
|
+
warn("E502", `s-teleport target not found: "${selector}".`, {
|
|
2838
|
+
el,
|
|
2839
|
+
doc: "s-teleport",
|
|
2840
|
+
hint: "The target must be a CSS selector that already exists in the DOM, e.g. body."
|
|
2841
|
+
});
|
|
2842
|
+
return;
|
|
2843
|
+
}
|
|
2844
|
+
const content = el.content;
|
|
2845
|
+
const clones = Array.from(content.children).map((n) => n.cloneNode(true));
|
|
2846
|
+
const frag = document.createDocumentFragment();
|
|
2847
|
+
for (const c of clones) frag.appendChild(c);
|
|
2848
|
+
if (meta2.modifiers.includes("prepend")) target.parentNode?.insertBefore(frag, target);
|
|
2849
|
+
else if (meta2.modifiers.includes("append")) target.parentNode?.insertBefore(frag, target.nextSibling);
|
|
2850
|
+
else target.appendChild(frag);
|
|
2851
|
+
for (const c of clones) utils.initTree(c, utils.scopes);
|
|
2852
|
+
utils.cleanup(() => {
|
|
2853
|
+
for (const c of clones) {
|
|
2854
|
+
utils.destroyTree(c);
|
|
2855
|
+
c.remove();
|
|
2856
|
+
}
|
|
2857
|
+
});
|
|
2858
|
+
};
|
|
2859
|
+
|
|
2860
|
+
// src/idstore.ts
|
|
2861
|
+
var counter = 0;
|
|
2862
|
+
var groups = /* @__PURE__ */ new WeakMap();
|
|
2863
|
+
function allocGroup(el, names) {
|
|
2864
|
+
let map = groups.get(el);
|
|
2865
|
+
if (!map) groups.set(el, map = /* @__PURE__ */ new Map());
|
|
2866
|
+
for (const name of names) map.set(name, ++counter);
|
|
2867
|
+
}
|
|
2868
|
+
function resolveId(el, name, key) {
|
|
2869
|
+
let cur = el;
|
|
2870
|
+
while (cur) {
|
|
2871
|
+
const map = groups.get(cur);
|
|
2872
|
+
if (map && map.has(name)) {
|
|
2873
|
+
const base2 = `${name}-${map.get(name)}`;
|
|
2874
|
+
return key != null ? `${base2}-${key}` : base2;
|
|
2875
|
+
}
|
|
2876
|
+
cur = cur.parentElement;
|
|
2877
|
+
}
|
|
2878
|
+
const base = `${name}-${++counter}`;
|
|
2879
|
+
return key != null ? `${base}-${key}` : base;
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
// src/directives/misc.ts
|
|
2883
|
+
var init = (_el, meta2, utils) => {
|
|
2884
|
+
utils.evaluateAction(meta2.expression);
|
|
2885
|
+
};
|
|
2886
|
+
var effect2 = (_el, meta2, utils) => {
|
|
2887
|
+
utils.effect(() => {
|
|
2888
|
+
utils.evaluateAction(meta2.expression);
|
|
2889
|
+
});
|
|
2890
|
+
};
|
|
2891
|
+
var ref = (el, meta2, utils) => {
|
|
2892
|
+
const evaluated = utils.evaluate(meta2.expression);
|
|
2893
|
+
const name = typeof evaluated === "string" && evaluated ? evaluated : meta2.expression.trim();
|
|
2894
|
+
const refs = refsFor(el);
|
|
2895
|
+
refs[name] = el;
|
|
2896
|
+
utils.cleanup(() => {
|
|
2897
|
+
if (refs[name] === el) delete refs[name];
|
|
2898
|
+
});
|
|
2899
|
+
};
|
|
2900
|
+
var id = (el, meta2, utils) => {
|
|
2901
|
+
const names = utils.evaluate(meta2.expression);
|
|
2902
|
+
if (Array.isArray(names)) allocGroup(el, names.map(String));
|
|
2903
|
+
};
|
|
2904
|
+
var cloak = (el) => {
|
|
2905
|
+
el.removeAttribute("s-cloak");
|
|
2906
|
+
};
|
|
2907
|
+
|
|
2908
|
+
// src/directives/observe.ts
|
|
2909
|
+
var intersect = (el, meta2, utils) => {
|
|
2910
|
+
if (typeof IntersectionObserver === "undefined") return;
|
|
2911
|
+
const onLeave = meta2.value === "leave";
|
|
2912
|
+
const threshold = meta2.modifiers.includes("full") ? 0.99 : meta2.modifiers.includes("half") ? 0.5 : 0;
|
|
2913
|
+
const once = meta2.modifiers.includes("once");
|
|
2914
|
+
const io = new IntersectionObserver(
|
|
2915
|
+
(entries) => {
|
|
2916
|
+
for (const entry of entries) {
|
|
2917
|
+
const active = onLeave ? !entry.isIntersecting : entry.isIntersecting;
|
|
2918
|
+
if (!active) continue;
|
|
2919
|
+
utils.evaluateAction(meta2.expression);
|
|
2920
|
+
if (once) io.disconnect();
|
|
2921
|
+
}
|
|
2922
|
+
},
|
|
2923
|
+
{ threshold }
|
|
2924
|
+
);
|
|
2925
|
+
io.observe(el);
|
|
2926
|
+
utils.cleanup(() => io.disconnect());
|
|
2927
|
+
};
|
|
2928
|
+
var resize = (el, meta2, utils) => {
|
|
2929
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
2930
|
+
const ro = new ResizeObserver((entries) => {
|
|
2931
|
+
const box = entries[0]?.contentRect;
|
|
2932
|
+
utils.evaluateAction(meta2.expression, { $width: box?.width ?? 0, $height: box?.height ?? 0 });
|
|
2933
|
+
});
|
|
2934
|
+
ro.observe(el);
|
|
2935
|
+
utils.cleanup(() => ro.disconnect());
|
|
2936
|
+
};
|
|
2937
|
+
|
|
2938
|
+
// src/directives/focusable.ts
|
|
2939
|
+
var SELECTOR = [
|
|
2940
|
+
"a[href]",
|
|
2941
|
+
"button:not([disabled])",
|
|
2942
|
+
"input:not([disabled]):not([type=hidden])",
|
|
2943
|
+
"select:not([disabled])",
|
|
2944
|
+
"textarea:not([disabled])",
|
|
2945
|
+
"[tabindex]:not([tabindex='-1'])",
|
|
2946
|
+
"[contenteditable]"
|
|
2947
|
+
].join(",");
|
|
2948
|
+
function visible(el) {
|
|
2949
|
+
const r = el.getBoundingClientRect();
|
|
2950
|
+
if (r.width === 0 && r.height === 0) {
|
|
2951
|
+
return el.offsetParent !== null || typeof el.offsetParent === "undefined";
|
|
2952
|
+
}
|
|
2953
|
+
return true;
|
|
2954
|
+
}
|
|
2955
|
+
function focusable(root) {
|
|
2956
|
+
return Array.from(root.querySelectorAll(SELECTOR)).filter(visible);
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
// src/directives/focus.ts
|
|
2960
|
+
var trap = (el, meta2, utils) => {
|
|
2961
|
+
let active = false;
|
|
2962
|
+
let released = null;
|
|
2963
|
+
const onKeydown = (e) => {
|
|
2964
|
+
if (e.key !== "Tab") return;
|
|
2965
|
+
const items = focusable(el);
|
|
2966
|
+
if (!items.length) {
|
|
2967
|
+
e.preventDefault();
|
|
2968
|
+
return;
|
|
2969
|
+
}
|
|
2970
|
+
const first = items[0];
|
|
2971
|
+
const last = items[items.length - 1];
|
|
2972
|
+
const current = document.activeElement;
|
|
2973
|
+
if (e.shiftKey && (current === first || !el.contains(current))) {
|
|
2974
|
+
e.preventDefault();
|
|
2975
|
+
last.focus();
|
|
2976
|
+
} else if (!e.shiftKey && current === last) {
|
|
2977
|
+
e.preventDefault();
|
|
2978
|
+
first.focus();
|
|
2979
|
+
}
|
|
2980
|
+
};
|
|
2981
|
+
const enable = () => {
|
|
2982
|
+
if (active) return;
|
|
2983
|
+
active = true;
|
|
2984
|
+
released = document.activeElement;
|
|
2985
|
+
document.addEventListener("keydown", onKeydown, true);
|
|
2986
|
+
const focusFirst = () => {
|
|
2987
|
+
const items = focusable(el);
|
|
2988
|
+
(items[0] ?? el).focus?.();
|
|
2989
|
+
};
|
|
2990
|
+
if (typeof requestAnimationFrame === "function") requestAnimationFrame(focusFirst);
|
|
2991
|
+
else focusFirst();
|
|
2992
|
+
};
|
|
2993
|
+
const disable = () => {
|
|
2994
|
+
if (!active) return;
|
|
2995
|
+
active = false;
|
|
2996
|
+
document.removeEventListener("keydown", onKeydown, true);
|
|
2997
|
+
released?.focus?.();
|
|
2998
|
+
};
|
|
2999
|
+
utils.effect(() => {
|
|
3000
|
+
if (utils.evaluate(meta2.expression)) enable();
|
|
3001
|
+
else disable();
|
|
3002
|
+
});
|
|
3003
|
+
utils.cleanup(disable);
|
|
3004
|
+
};
|
|
3005
|
+
|
|
3006
|
+
// src/directives/anchor.ts
|
|
3007
|
+
var anchor = (el, meta2, utils) => {
|
|
3008
|
+
const mods = meta2.modifiers;
|
|
3009
|
+
const placement = mods.includes("top") ? "top" : "bottom";
|
|
3010
|
+
const align = mods.includes("end") ? "end" : mods.includes("center") ? "center" : "start";
|
|
3011
|
+
const oi = mods.indexOf("offset");
|
|
3012
|
+
const gap = oi >= 0 && /^\d+$/.test(mods[oi + 1] ?? "") ? Number(mods[oi + 1]) : 8;
|
|
3013
|
+
const node = el;
|
|
3014
|
+
node.style.position = "fixed";
|
|
3015
|
+
if (!node.style.zIndex) node.style.zIndex = "50";
|
|
3016
|
+
node.style.margin = "0";
|
|
3017
|
+
let ref2 = null;
|
|
3018
|
+
const place = () => {
|
|
3019
|
+
if (!ref2 || typeof window === "undefined") return;
|
|
3020
|
+
const r = ref2.getBoundingClientRect();
|
|
3021
|
+
const ew = node.offsetWidth;
|
|
3022
|
+
const eh = node.offsetHeight;
|
|
3023
|
+
const vh = window.innerHeight;
|
|
3024
|
+
const vw = window.innerWidth;
|
|
3025
|
+
let top = placement === "top" ? r.top - eh - gap : r.bottom + gap;
|
|
3026
|
+
if (placement === "bottom" && top + eh > vh && r.top - eh - gap >= 0) top = r.top - eh - gap;
|
|
3027
|
+
if (placement === "top" && top < 0 && r.bottom + gap + eh <= vh) top = r.bottom + gap;
|
|
3028
|
+
let left = align === "end" ? r.right - ew : align === "center" ? r.left + r.width / 2 - ew / 2 : r.left;
|
|
3029
|
+
left = Math.max(8, Math.min(left, vw - ew - 8));
|
|
3030
|
+
node.style.top = `${Math.round(top)}px`;
|
|
3031
|
+
node.style.left = `${Math.round(left)}px`;
|
|
3032
|
+
};
|
|
3033
|
+
utils.effect(() => {
|
|
3034
|
+
const value = utils.evaluate(meta2.expression);
|
|
3035
|
+
ref2 = value && typeof value.getBoundingClientRect === "function" ? value : null;
|
|
3036
|
+
if (ref2) place();
|
|
3037
|
+
});
|
|
3038
|
+
if (typeof window !== "undefined") {
|
|
3039
|
+
const on2 = () => place();
|
|
3040
|
+
window.addEventListener("scroll", on2, true);
|
|
3041
|
+
window.addEventListener("resize", on2);
|
|
3042
|
+
utils.cleanup(() => {
|
|
3043
|
+
window.removeEventListener("scroll", on2, true);
|
|
3044
|
+
window.removeEventListener("resize", on2);
|
|
3045
|
+
});
|
|
3046
|
+
}
|
|
3047
|
+
};
|
|
3048
|
+
|
|
3049
|
+
// src/directives/collapse.ts
|
|
3050
|
+
var DURATION = 250;
|
|
3051
|
+
var collapse = (el, meta2, utils) => {
|
|
3052
|
+
const node = el;
|
|
3053
|
+
node.style.overflow = "hidden";
|
|
3054
|
+
let first = true;
|
|
3055
|
+
utils.effect(() => {
|
|
3056
|
+
const open = !!utils.evaluate(meta2.expression);
|
|
3057
|
+
if (first) {
|
|
3058
|
+
first = false;
|
|
3059
|
+
node.style.height = open ? "auto" : "0px";
|
|
3060
|
+
if (!open) node.setAttribute("hidden", "until-found");
|
|
3061
|
+
return;
|
|
3062
|
+
}
|
|
3063
|
+
node.removeAttribute("hidden");
|
|
3064
|
+
const start2 = node.getBoundingClientRect().height;
|
|
3065
|
+
node.style.height = `${start2}px`;
|
|
3066
|
+
const end = open ? node.scrollHeight : 0;
|
|
3067
|
+
const animate = () => {
|
|
3068
|
+
node.style.transition = `height ${DURATION}ms ease`;
|
|
3069
|
+
node.style.height = `${end}px`;
|
|
3070
|
+
};
|
|
3071
|
+
if (typeof requestAnimationFrame === "function") requestAnimationFrame(animate);
|
|
3072
|
+
else animate();
|
|
3073
|
+
const done = () => {
|
|
3074
|
+
node.style.transition = "";
|
|
3075
|
+
if (open) node.style.height = "auto";
|
|
3076
|
+
node.removeEventListener("transitionend", done);
|
|
3077
|
+
};
|
|
3078
|
+
node.addEventListener("transitionend", done);
|
|
3079
|
+
});
|
|
3080
|
+
};
|
|
3081
|
+
|
|
3082
|
+
// src/directives/mask.ts
|
|
3083
|
+
function matches(token, ch) {
|
|
3084
|
+
if (token === "9") return /\d/.test(ch);
|
|
3085
|
+
if (token === "a") return /[a-zA-Z]/.test(ch);
|
|
3086
|
+
if (token === "*") return /[a-zA-Z0-9]/.test(ch);
|
|
3087
|
+
return false;
|
|
3088
|
+
}
|
|
3089
|
+
function applyMask(value, pattern) {
|
|
3090
|
+
let out = "";
|
|
3091
|
+
let ci = 0;
|
|
3092
|
+
for (const token of pattern) {
|
|
3093
|
+
if (ci >= value.length) break;
|
|
3094
|
+
if (token === "9" || token === "a" || token === "*") {
|
|
3095
|
+
while (ci < value.length) {
|
|
3096
|
+
const ch = value[ci++];
|
|
3097
|
+
if (matches(token, ch)) {
|
|
3098
|
+
out += ch;
|
|
3099
|
+
break;
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
} else {
|
|
3103
|
+
out += token;
|
|
3104
|
+
if (value[ci] === token) ci++;
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
return out;
|
|
3108
|
+
}
|
|
3109
|
+
var mask = (el, meta2, utils) => {
|
|
3110
|
+
const input = el;
|
|
3111
|
+
const pattern = String(utils.evaluate(meta2.expression) ?? meta2.expression);
|
|
3112
|
+
const format = () => {
|
|
3113
|
+
input.value = applyMask(input.value, pattern);
|
|
3114
|
+
};
|
|
3115
|
+
input.addEventListener("input", format);
|
|
3116
|
+
if (input.value) format();
|
|
3117
|
+
utils.cleanup(() => input.removeEventListener("input", format));
|
|
3118
|
+
};
|
|
3119
|
+
|
|
3120
|
+
// src/directives/index.ts
|
|
3121
|
+
function registerBuiltinDirectives() {
|
|
3122
|
+
registerDirective("ref", ref, 10);
|
|
3123
|
+
registerDirective("id", id, 15);
|
|
3124
|
+
registerDirective("if", sIf, 20);
|
|
3125
|
+
registerDirective("for", sFor, 20);
|
|
3126
|
+
registerDirective("teleport", teleport, 20);
|
|
3127
|
+
registerDirective("bind", bind, 50);
|
|
3128
|
+
registerDirective("mask", mask, 55);
|
|
3129
|
+
registerDirective("model", model, 60);
|
|
3130
|
+
registerDirective("on", on, 70);
|
|
3131
|
+
registerDirective("text", text, 80);
|
|
3132
|
+
registerDirective("html", html, 80);
|
|
3133
|
+
registerDirective("transition", transition, 85);
|
|
3134
|
+
registerDirective("anchor", anchor, 88);
|
|
3135
|
+
registerDirective("collapse", collapse, 89);
|
|
3136
|
+
registerDirective("show", show, 90);
|
|
3137
|
+
registerDirective("trap", trap, 95);
|
|
3138
|
+
registerDirective("effect", effect2, 100);
|
|
3139
|
+
registerDirective("intersect", intersect, 100);
|
|
3140
|
+
registerDirective("resize", resize, 100);
|
|
3141
|
+
registerDirective("init", init, 200);
|
|
3142
|
+
registerDirective("cloak", cloak, 1e3);
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
// src/magics/focus.ts
|
|
3146
|
+
function makeFocus(root) {
|
|
3147
|
+
const items = () => focusable(root);
|
|
3148
|
+
const at = (delta) => {
|
|
3149
|
+
const f = items();
|
|
3150
|
+
if (!f.length) return;
|
|
3151
|
+
const i = f.indexOf(document.activeElement);
|
|
3152
|
+
const next = i === -1 ? 0 : (i + delta + f.length) % f.length;
|
|
3153
|
+
f[next]?.focus();
|
|
3154
|
+
};
|
|
3155
|
+
return {
|
|
3156
|
+
focus(target) {
|
|
3157
|
+
target?.focus?.();
|
|
3158
|
+
},
|
|
3159
|
+
first() {
|
|
3160
|
+
items()[0]?.focus();
|
|
3161
|
+
},
|
|
3162
|
+
last() {
|
|
3163
|
+
const f = items();
|
|
3164
|
+
f[f.length - 1]?.focus();
|
|
3165
|
+
},
|
|
3166
|
+
next() {
|
|
3167
|
+
at(1);
|
|
3168
|
+
},
|
|
3169
|
+
previous() {
|
|
3170
|
+
at(-1);
|
|
3171
|
+
},
|
|
3172
|
+
within(el) {
|
|
3173
|
+
return makeFocus(el);
|
|
3174
|
+
}
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
// src/magics/index.ts
|
|
3179
|
+
function registerBuiltinMagics() {
|
|
3180
|
+
registerMagic("el", (ctx) => ctx.el);
|
|
3181
|
+
registerMagic("refs", (ctx) => refsFor(ctx.el));
|
|
3182
|
+
registerMagic("root", (ctx) => closestRoot(ctx.el));
|
|
3183
|
+
registerMagic("data", (ctx) => ctx.scopes.length ? ctx.scopes[ctx.scopes.length - 1] : {});
|
|
3184
|
+
registerMagic("store", () => getStoreRoot());
|
|
3185
|
+
registerMagic("watch", (ctx) => (path, callback) => {
|
|
3186
|
+
let oldValue;
|
|
3187
|
+
let first = true;
|
|
3188
|
+
const dispose = domEffect(() => {
|
|
3189
|
+
const newValue = ctx.evaluate(path);
|
|
3190
|
+
if (first) {
|
|
3191
|
+
oldValue = newValue;
|
|
3192
|
+
first = false;
|
|
3193
|
+
return;
|
|
3194
|
+
}
|
|
3195
|
+
if (Object.is(newValue, oldValue)) return;
|
|
3196
|
+
const previous = oldValue;
|
|
3197
|
+
oldValue = newValue;
|
|
3198
|
+
callback(newValue, previous);
|
|
3199
|
+
});
|
|
3200
|
+
ctx.cleanup(dispose);
|
|
3201
|
+
return dispose;
|
|
3202
|
+
});
|
|
3203
|
+
registerMagic(
|
|
3204
|
+
"dispatch",
|
|
3205
|
+
(ctx) => (name, detail, options = {}) => {
|
|
3206
|
+
const event = new CustomEvent(name, {
|
|
3207
|
+
detail,
|
|
3208
|
+
bubbles: true,
|
|
3209
|
+
composed: true,
|
|
3210
|
+
cancelable: true,
|
|
3211
|
+
...options
|
|
3212
|
+
});
|
|
3213
|
+
return ctx.el.dispatchEvent(event);
|
|
3214
|
+
}
|
|
3215
|
+
);
|
|
3216
|
+
registerMagic("nextTick", () => (callback) => nextTick(callback));
|
|
3217
|
+
registerMagic("id", (ctx) => (name, key) => resolveId(ctx.el, name, key));
|
|
3218
|
+
registerMagic("persist", () => (initial) => createPersist(initial));
|
|
3219
|
+
registerMagic("focus", (ctx) => makeFocus(ctx.el));
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
// src/summit.ts
|
|
3223
|
+
var version = "0.1.0";
|
|
3224
|
+
var started = false;
|
|
3225
|
+
function dispatch(name) {
|
|
3226
|
+
if (typeof document !== "undefined") document.dispatchEvent(new CustomEvent(name));
|
|
3227
|
+
}
|
|
3228
|
+
function start(root) {
|
|
3229
|
+
if (started) return;
|
|
3230
|
+
started = true;
|
|
3231
|
+
const el = root ?? (typeof document !== "undefined" ? document.body : void 0);
|
|
3232
|
+
if (!el) return;
|
|
3233
|
+
dispatch("summit:init");
|
|
3234
|
+
initTree(el);
|
|
3235
|
+
startObserver(el.ownerDocument?.body ?? el);
|
|
3236
|
+
dispatch("summit:initialized");
|
|
3237
|
+
}
|
|
3238
|
+
var Summit = {
|
|
3239
|
+
version,
|
|
3240
|
+
started: () => started,
|
|
3241
|
+
start,
|
|
3242
|
+
data(name, provider) {
|
|
3243
|
+
registerData(name, provider);
|
|
3244
|
+
return this;
|
|
3245
|
+
},
|
|
3246
|
+
directive(name, handler, priority) {
|
|
3247
|
+
registerDirective(name, handler, priority);
|
|
3248
|
+
return this;
|
|
3249
|
+
},
|
|
3250
|
+
magic(name, factory) {
|
|
3251
|
+
registerMagic(name, factory);
|
|
3252
|
+
return this;
|
|
3253
|
+
},
|
|
3254
|
+
bind(name, provider) {
|
|
3255
|
+
registerBind(name, provider);
|
|
3256
|
+
return this;
|
|
3257
|
+
},
|
|
3258
|
+
store(name, value) {
|
|
3259
|
+
if (value === void 0) return getStore(name);
|
|
3260
|
+
if (value !== null && typeof value === "object") {
|
|
3261
|
+
const scoped = createScope(value);
|
|
3262
|
+
setStore(name, scoped);
|
|
3263
|
+
const initFn = scoped["init"];
|
|
3264
|
+
if (typeof initFn === "function") {
|
|
3265
|
+
try {
|
|
3266
|
+
initFn();
|
|
3267
|
+
} catch (err) {
|
|
3268
|
+
fail("E103", `store "${name}" init() threw.`, { doc: "globals-store", cause: err });
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
return scoped;
|
|
3272
|
+
}
|
|
3273
|
+
setStore(name, value);
|
|
3274
|
+
return getStore(name);
|
|
3275
|
+
},
|
|
3276
|
+
plugin(fn) {
|
|
3277
|
+
fn(this);
|
|
3278
|
+
return this;
|
|
3279
|
+
},
|
|
3280
|
+
addGlobals(names) {
|
|
3281
|
+
addGlobals(names);
|
|
3282
|
+
return this;
|
|
3283
|
+
},
|
|
3284
|
+
getBind,
|
|
3285
|
+
signal,
|
|
3286
|
+
computed,
|
|
3287
|
+
effect,
|
|
3288
|
+
reactive,
|
|
3289
|
+
batch,
|
|
3290
|
+
nextTick,
|
|
3291
|
+
initTree,
|
|
3292
|
+
destroyTree
|
|
3293
|
+
};
|
|
3294
|
+
registerBuiltinDirectives();
|
|
3295
|
+
registerBuiltinMagics();
|
|
3296
|
+
setSummitGlobal(Summit);
|
|
3297
|
+
var summit_default = Summit;
|
|
3298
|
+
|
|
3299
|
+
// src/index.ts
|
|
3300
|
+
var src_default = summit_default;
|
|
3301
|
+
|
|
3302
|
+
export { Summit, addGlobals, batch, computed, src_default as default, effect, evaluateAction, evaluateExpression, isReactive, isSignal, nextTick, reactive, signal, stop, toRaw, untrack, version };
|
|
3303
|
+
//# sourceMappingURL=summit.js.map
|
|
3304
|
+
//# sourceMappingURL=summit.js.map
|