micra.js 2.3.1 → 2.4.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/CHANGELOG.md +96 -0
- package/README.md +22 -2
- package/dist/index.d.ts +1 -1
- package/dist/micra.cjs.js +306 -67
- package/dist/micra.cjs.js.map +3 -3
- package/dist/micra.esm.js +306 -67
- package/dist/micra.esm.js.map +3 -3
- package/dist/micra.js +306 -67
- package/dist/micra.js.map +3 -3
- package/dist/micra.min.js +3 -2
- package/dist/types.d.ts +1 -0
- package/dist/utils/expr.d.ts +29 -22
- package/llms-full.txt +19 -19
- package/llms.txt +3 -3
- package/package.json +3 -3
- package/src/core/mount.ts +4 -0
- package/src/dom/each.ts +19 -2
- package/src/dom/events.ts +37 -10
- package/src/index.ts +1 -1
- package/src/types.ts +1 -0
- package/src/utils/expr.ts +278 -122
package/dist/micra.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Micra.js v2.
|
|
1
|
+
/* Micra.js v2.4.0 — https://github.com/micra-js/micra — MIT */
|
|
2
2
|
"use strict";
|
|
3
3
|
var Micra = (() => {
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -116,56 +116,196 @@ var Micra = (() => {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
// src/utils/expr.ts
|
|
119
|
-
var
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
var
|
|
123
|
-
"Math",
|
|
124
|
-
"JSON",
|
|
125
|
-
"Date",
|
|
126
|
-
"String",
|
|
127
|
-
"Number",
|
|
128
|
-
"Boolean",
|
|
129
|
-
"Array",
|
|
130
|
-
"Object",
|
|
131
|
-
"parseInt",
|
|
132
|
-
"parseFloat",
|
|
133
|
-
"isNaN",
|
|
134
|
-
"isFinite",
|
|
135
|
-
"NaN",
|
|
136
|
-
"Infinity",
|
|
137
|
-
"undefined"
|
|
138
|
-
]);
|
|
139
|
-
var PARAM_S = "$s";
|
|
140
|
-
var PARAM_SAFE = "$safe";
|
|
141
|
-
var SAFE_OUTER = new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
142
|
-
has(_target, key) {
|
|
143
|
-
if (typeof key !== "string") return false;
|
|
144
|
-
if (key === PARAM_S || key === PARAM_SAFE) return false;
|
|
145
|
-
return !ALLOWED_GLOBALS.has(key);
|
|
146
|
-
},
|
|
147
|
-
get() {
|
|
148
|
-
return void 0;
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
var safeWrapCache = /* @__PURE__ */ new WeakMap();
|
|
119
|
+
var ALLOWED_GLOBALS = new Set(
|
|
120
|
+
"Math,JSON,Date,String,Number,Boolean,Array,Object,parseInt,parseFloat,isNaN,isFinite,NaN,Infinity,undefined".split(",")
|
|
121
|
+
);
|
|
122
|
+
var BLOCKED_PROPS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
152
123
|
var OBJ_PROTO_KEYS = new Set(Object.getOwnPropertyNames(Object.prototype));
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
124
|
+
var PUNCT = [
|
|
125
|
+
"===",
|
|
126
|
+
"!==",
|
|
127
|
+
"==",
|
|
128
|
+
"!=",
|
|
129
|
+
"<=",
|
|
130
|
+
">=",
|
|
131
|
+
"&&",
|
|
132
|
+
"||",
|
|
133
|
+
"(",
|
|
134
|
+
")",
|
|
135
|
+
".",
|
|
136
|
+
",",
|
|
137
|
+
"?",
|
|
138
|
+
":",
|
|
139
|
+
"!",
|
|
140
|
+
"<",
|
|
141
|
+
">",
|
|
142
|
+
"+",
|
|
143
|
+
"-",
|
|
144
|
+
"*",
|
|
145
|
+
"/",
|
|
146
|
+
"%"
|
|
147
|
+
];
|
|
148
|
+
function tokenize(src) {
|
|
149
|
+
var _a;
|
|
150
|
+
const toks = [];
|
|
151
|
+
let i = 0;
|
|
152
|
+
const n = src.length;
|
|
153
|
+
while (i < n) {
|
|
154
|
+
const c = src[i];
|
|
155
|
+
if (c === " " || c === " " || c === "\n" || c === "\r" || c === "\f") {
|
|
156
|
+
i++;
|
|
157
|
+
continue;
|
|
162
158
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
159
|
+
if (c === '"' || c === "'") {
|
|
160
|
+
let s = "";
|
|
161
|
+
i++;
|
|
162
|
+
while (i < n && src[i] !== c) {
|
|
163
|
+
if (src[i] === "\\") {
|
|
164
|
+
s += (_a = src[i + 1]) != null ? _a : "";
|
|
165
|
+
i += 2;
|
|
166
|
+
} else {
|
|
167
|
+
s += src[i];
|
|
168
|
+
i++;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (src[i] !== c) throw 0;
|
|
172
|
+
i++;
|
|
173
|
+
toks.push({ t: "str", v: s });
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (c >= "0" && c <= "9") {
|
|
177
|
+
let s = "";
|
|
178
|
+
while (i < n && (src[i] >= "0" && src[i] <= "9" || src[i] === ".")) {
|
|
179
|
+
s += src[i];
|
|
180
|
+
i++;
|
|
181
|
+
}
|
|
182
|
+
toks.push({ t: "num", v: s });
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (/[A-Za-z_$]/.test(c)) {
|
|
186
|
+
let s = "";
|
|
187
|
+
while (i < n && /[A-Za-z0-9_$]/.test(src[i])) {
|
|
188
|
+
s += src[i];
|
|
189
|
+
i++;
|
|
190
|
+
}
|
|
191
|
+
toks.push({ t: "id", v: s });
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const m = PUNCT.find((p) => src.startsWith(p, i));
|
|
195
|
+
if (!m) throw 0;
|
|
196
|
+
toks.push({ t: "p", v: m });
|
|
197
|
+
i += m.length;
|
|
198
|
+
}
|
|
199
|
+
return toks;
|
|
200
|
+
}
|
|
201
|
+
var BIN_PREC = {
|
|
202
|
+
"||": 1,
|
|
203
|
+
"&&": 2,
|
|
204
|
+
"==": 3,
|
|
205
|
+
"!=": 3,
|
|
206
|
+
"===": 3,
|
|
207
|
+
"!==": 3,
|
|
208
|
+
"<": 4,
|
|
209
|
+
"<=": 4,
|
|
210
|
+
">": 4,
|
|
211
|
+
">=": 4,
|
|
212
|
+
"+": 5,
|
|
213
|
+
"-": 5,
|
|
214
|
+
"*": 6,
|
|
215
|
+
"/": 6,
|
|
216
|
+
"%": 6
|
|
217
|
+
};
|
|
218
|
+
function parse(toks) {
|
|
219
|
+
let pos = 0;
|
|
220
|
+
const peek = () => toks[pos];
|
|
221
|
+
const next = () => toks[pos++];
|
|
222
|
+
const eat = (v) => {
|
|
223
|
+
var _a;
|
|
224
|
+
if (((_a = peek()) == null ? void 0 : _a.v) !== v) throw 0;
|
|
225
|
+
pos++;
|
|
226
|
+
};
|
|
227
|
+
function parseExpr() {
|
|
228
|
+
var _a;
|
|
229
|
+
const c = parseBin(1);
|
|
230
|
+
if (((_a = peek()) == null ? void 0 : _a.v) === "?") {
|
|
231
|
+
next();
|
|
232
|
+
const a = parseExpr();
|
|
233
|
+
eat(":");
|
|
234
|
+
const b = parseExpr();
|
|
235
|
+
return { k: "tern", c, a, b };
|
|
236
|
+
}
|
|
237
|
+
return c;
|
|
238
|
+
}
|
|
239
|
+
function parseBin(minPrec) {
|
|
240
|
+
let left = parseUnary();
|
|
241
|
+
for (; ; ) {
|
|
242
|
+
const t = peek();
|
|
243
|
+
const prec = t && t.t === "p" ? BIN_PREC[t.v] : void 0;
|
|
244
|
+
if (prec === void 0 || prec < minPrec) break;
|
|
245
|
+
next();
|
|
246
|
+
const right = parseBin(prec + 1);
|
|
247
|
+
left = { k: "bin", op: t.v, l: left, r: right };
|
|
248
|
+
}
|
|
249
|
+
return left;
|
|
250
|
+
}
|
|
251
|
+
function parseUnary() {
|
|
252
|
+
const t = peek();
|
|
253
|
+
if (t && t.t === "p" && (t.v === "!" || t.v === "-")) {
|
|
254
|
+
next();
|
|
255
|
+
return { k: "un", op: t.v, x: parseUnary() };
|
|
256
|
+
}
|
|
257
|
+
return parsePostfix();
|
|
258
|
+
}
|
|
259
|
+
function parsePostfix() {
|
|
260
|
+
var _a, _b;
|
|
261
|
+
let node = parsePrimary();
|
|
262
|
+
for (; ; ) {
|
|
263
|
+
const t = peek();
|
|
264
|
+
if ((t == null ? void 0 : t.v) === ".") {
|
|
265
|
+
next();
|
|
266
|
+
const id = next();
|
|
267
|
+
if (!id || id.t !== "id") throw 0;
|
|
268
|
+
node = { k: "mem", o: node, p: id.v };
|
|
269
|
+
} else if ((t == null ? void 0 : t.v) === "(") {
|
|
270
|
+
next();
|
|
271
|
+
const args = [];
|
|
272
|
+
if (((_a = peek()) == null ? void 0 : _a.v) !== ")") {
|
|
273
|
+
args.push(parseExpr());
|
|
274
|
+
while (((_b = peek()) == null ? void 0 : _b.v) === ",") {
|
|
275
|
+
next();
|
|
276
|
+
args.push(parseExpr());
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
eat(")");
|
|
280
|
+
node = { k: "call", c: node, a: args };
|
|
281
|
+
} else break;
|
|
282
|
+
}
|
|
283
|
+
return node;
|
|
284
|
+
}
|
|
285
|
+
function parsePrimary() {
|
|
286
|
+
const t = next();
|
|
287
|
+
if (!t) throw 0;
|
|
288
|
+
if (t.t === "num") return { k: "lit", v: Number(t.v) };
|
|
289
|
+
if (t.t === "str") return { k: "lit", v: t.v };
|
|
290
|
+
if (t.v === "(") {
|
|
291
|
+
const e = parseExpr();
|
|
292
|
+
eat(")");
|
|
293
|
+
return e;
|
|
294
|
+
}
|
|
295
|
+
if (t.t === "id") {
|
|
296
|
+
if (t.v === "true") return { k: "lit", v: true };
|
|
297
|
+
if (t.v === "false") return { k: "lit", v: false };
|
|
298
|
+
if (t.v === "null") return { k: "lit", v: null };
|
|
299
|
+
if (t.v === "undefined") return { k: "lit", v: void 0 };
|
|
300
|
+
return { k: "id", n: t.v };
|
|
301
|
+
}
|
|
302
|
+
throw 0;
|
|
303
|
+
}
|
|
304
|
+
const ast = parseExpr();
|
|
305
|
+
if (pos !== toks.length) throw 0;
|
|
306
|
+
return ast;
|
|
166
307
|
}
|
|
167
308
|
function safeStateHas(state, key) {
|
|
168
|
-
if (typeof key !== "string") return false;
|
|
169
309
|
if (!Reflect.has(state, key)) return false;
|
|
170
310
|
if (!OBJ_PROTO_KEYS.has(key)) return true;
|
|
171
311
|
let obj = state;
|
|
@@ -175,6 +315,87 @@ var Micra = (() => {
|
|
|
175
315
|
}
|
|
176
316
|
return false;
|
|
177
317
|
}
|
|
318
|
+
function resolveIdent(name, scope) {
|
|
319
|
+
if (safeStateHas(scope, name)) return scope[name];
|
|
320
|
+
if (ALLOWED_GLOBALS.has(name)) return globalThis[name];
|
|
321
|
+
return void 0;
|
|
322
|
+
}
|
|
323
|
+
function evalNode(node, scope) {
|
|
324
|
+
switch (node.k) {
|
|
325
|
+
case "lit":
|
|
326
|
+
return node.v;
|
|
327
|
+
case "id":
|
|
328
|
+
return resolveIdent(node.n, scope);
|
|
329
|
+
case "mem": {
|
|
330
|
+
const o = evalNode(node.o, scope);
|
|
331
|
+
if (o == null || BLOCKED_PROPS.has(node.p)) return void 0;
|
|
332
|
+
return o[node.p];
|
|
333
|
+
}
|
|
334
|
+
case "un": {
|
|
335
|
+
const x = evalNode(node.x, scope);
|
|
336
|
+
return node.op === "!" ? !x : -x;
|
|
337
|
+
}
|
|
338
|
+
case "tern":
|
|
339
|
+
return evalNode(node.c, scope) ? evalNode(node.a, scope) : evalNode(node.b, scope);
|
|
340
|
+
case "bin": {
|
|
341
|
+
const op = node.op;
|
|
342
|
+
if (op === "&&") {
|
|
343
|
+
const l2 = evalNode(node.l, scope);
|
|
344
|
+
return l2 ? evalNode(node.r, scope) : l2;
|
|
345
|
+
}
|
|
346
|
+
if (op === "||") {
|
|
347
|
+
const l2 = evalNode(node.l, scope);
|
|
348
|
+
return l2 ? l2 : evalNode(node.r, scope);
|
|
349
|
+
}
|
|
350
|
+
const l = evalNode(node.l, scope);
|
|
351
|
+
const r = evalNode(node.r, scope);
|
|
352
|
+
switch (op) {
|
|
353
|
+
case "+":
|
|
354
|
+
return l + r;
|
|
355
|
+
case "-":
|
|
356
|
+
return l - r;
|
|
357
|
+
case "*":
|
|
358
|
+
return l * r;
|
|
359
|
+
case "/":
|
|
360
|
+
return l / r;
|
|
361
|
+
case "%":
|
|
362
|
+
return l % r;
|
|
363
|
+
case "<":
|
|
364
|
+
return l < r;
|
|
365
|
+
case "<=":
|
|
366
|
+
return l <= r;
|
|
367
|
+
case ">":
|
|
368
|
+
return l > r;
|
|
369
|
+
case ">=":
|
|
370
|
+
return l >= r;
|
|
371
|
+
case "==":
|
|
372
|
+
return l == r;
|
|
373
|
+
case "!=":
|
|
374
|
+
return l != r;
|
|
375
|
+
case "===":
|
|
376
|
+
return l === r;
|
|
377
|
+
case "!==":
|
|
378
|
+
return l !== r;
|
|
379
|
+
}
|
|
380
|
+
return void 0;
|
|
381
|
+
}
|
|
382
|
+
case "call": {
|
|
383
|
+
let fn;
|
|
384
|
+
let self;
|
|
385
|
+
if (node.c.k === "mem") {
|
|
386
|
+
self = evalNode(node.c.o, scope);
|
|
387
|
+
fn = self == null || BLOCKED_PROPS.has(node.c.p) ? void 0 : self[node.c.p];
|
|
388
|
+
} else {
|
|
389
|
+
fn = evalNode(node.c, scope);
|
|
390
|
+
}
|
|
391
|
+
if (typeof fn !== "function") throw new TypeError("not a function");
|
|
392
|
+
return fn.apply(self, node.a.map((x) => evalNode(x, scope)));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
var exprCache = /* @__PURE__ */ new Map();
|
|
397
|
+
var warnedRuntime = /* @__PURE__ */ new Set();
|
|
398
|
+
var SIMPLE_PATH = /^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/;
|
|
178
399
|
function evalExpr(expr, state) {
|
|
179
400
|
let cached = exprCache.get(expr);
|
|
180
401
|
if (!cached) {
|
|
@@ -182,26 +403,24 @@ var Micra = (() => {
|
|
|
182
403
|
cached = { kind: "path", parts: expr.split(".") };
|
|
183
404
|
} else {
|
|
184
405
|
try {
|
|
185
|
-
cached = {
|
|
186
|
-
kind: "fn",
|
|
187
|
-
fn: new Function("$s", "$safe", `with($safe){with($s){return (${expr})}}`)
|
|
188
|
-
};
|
|
406
|
+
cached = { kind: "ast", ast: parse(tokenize(expr)) };
|
|
189
407
|
} catch {
|
|
190
408
|
warn(`invalid expression "${expr}"`);
|
|
191
|
-
cached = { kind: "
|
|
409
|
+
cached = { kind: "err" };
|
|
192
410
|
}
|
|
193
411
|
}
|
|
194
412
|
exprCache.set(expr, cached);
|
|
195
413
|
}
|
|
196
414
|
if (cached.kind === "path") {
|
|
197
|
-
|
|
198
|
-
return
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
415
|
+
const parts = cached.parts;
|
|
416
|
+
if (!safeStateHas(state, parts[0])) return void 0;
|
|
417
|
+
let obj = state;
|
|
418
|
+
for (const key of parts) obj = obj != null ? obj[key] : void 0;
|
|
419
|
+
return obj;
|
|
202
420
|
}
|
|
421
|
+
if (cached.kind === "err") return void 0;
|
|
203
422
|
try {
|
|
204
|
-
return cached.
|
|
423
|
+
return evalNode(cached.ast, state);
|
|
205
424
|
} catch (e) {
|
|
206
425
|
if (!warnedRuntime.has(expr)) {
|
|
207
426
|
warnedRuntime.add(expr);
|
|
@@ -361,6 +580,23 @@ var Micra = (() => {
|
|
|
361
580
|
el.addEventListener(type, fn);
|
|
362
581
|
((_a = instance.__micraListeners) != null ? _a : instance.__micraListeners = []).push({ el, type, fn });
|
|
363
582
|
}
|
|
583
|
+
function runHandler(instance, el, value, e) {
|
|
584
|
+
var _a;
|
|
585
|
+
if (value.includes("(")) {
|
|
586
|
+
let base;
|
|
587
|
+
for (let n = el; n && !base; n = n.parentElement) {
|
|
588
|
+
base = n._itemState;
|
|
589
|
+
}
|
|
590
|
+
const scope = Object.create((_a = base != null ? base : instance.__micraExpr) != null ? _a : null);
|
|
591
|
+
scope["$event"] = e;
|
|
592
|
+
scope["event"] = e;
|
|
593
|
+
evalExpr(value, scope);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
const fn = instance[value];
|
|
597
|
+
if (typeof fn === "function") fn.call(instance, e);
|
|
598
|
+
else warn(`method "${value}" not found`);
|
|
599
|
+
}
|
|
364
600
|
function bindDataOn(els, instance) {
|
|
365
601
|
var _a;
|
|
366
602
|
for (const el of els) {
|
|
@@ -372,13 +608,12 @@ var Micra = (() => {
|
|
|
372
608
|
const [evSpec, method] = part.trim().split(":");
|
|
373
609
|
if (!evSpec || !method) continue;
|
|
374
610
|
const [evName, ...mods] = evSpec.split(".");
|
|
611
|
+
const handler = method.trim();
|
|
375
612
|
track(instance, el, evName, (e) => {
|
|
376
613
|
if (mods.includes("prevent")) e.preventDefault();
|
|
377
614
|
if (mods.includes("stop")) e.stopPropagation();
|
|
378
615
|
if (mods.includes("self") && e.target !== el) return;
|
|
379
|
-
|
|
380
|
-
if (typeof fn === "function") fn.call(instance, e);
|
|
381
|
-
else warn(`method "${method.trim()}" not found`);
|
|
616
|
+
runHandler(instance, el, handler, e);
|
|
382
617
|
});
|
|
383
618
|
}
|
|
384
619
|
}
|
|
@@ -391,14 +626,12 @@ var Micra = (() => {
|
|
|
391
626
|
for (const attr of Array.from(el.attributes)) {
|
|
392
627
|
if (!attr.name.startsWith("@")) continue;
|
|
393
628
|
const [evSpec, ...rest] = attr.name.slice(1).split(".");
|
|
394
|
-
const
|
|
629
|
+
const handler = attr.value.trim();
|
|
395
630
|
track(instance, el, evSpec, (e) => {
|
|
396
631
|
if (rest.includes("prevent")) e.preventDefault();
|
|
397
632
|
if (rest.includes("stop")) e.stopPropagation();
|
|
398
633
|
if (rest.includes("self") && e.target !== el) return;
|
|
399
|
-
|
|
400
|
-
if (typeof fn === "function") fn.call(instance, e);
|
|
401
|
-
else warn(`method "${method}" not found`);
|
|
634
|
+
runHandler(instance, el, handler, e);
|
|
402
635
|
});
|
|
403
636
|
bound = true;
|
|
404
637
|
}
|
|
@@ -574,8 +807,13 @@ var Micra = (() => {
|
|
|
574
807
|
function createRowNode(tmpl, state, instance) {
|
|
575
808
|
const frag = tmpl.content.cloneNode(true);
|
|
576
809
|
let node;
|
|
577
|
-
|
|
578
|
-
|
|
810
|
+
const first = frag.firstElementChild;
|
|
811
|
+
const single = !!first && !first.nextElementSibling && !Array.prototype.some.call(
|
|
812
|
+
frag.childNodes,
|
|
813
|
+
(c) => c.nodeType === 3 && /[^\x00- ]/.test(c.textContent)
|
|
814
|
+
);
|
|
815
|
+
if (single) {
|
|
816
|
+
node = first;
|
|
579
817
|
} else {
|
|
580
818
|
node = document.createElement("micra-each-item");
|
|
581
819
|
node.style.display = "contents";
|
|
@@ -803,6 +1041,7 @@ var Micra = (() => {
|
|
|
803
1041
|
return Object.prototype.hasOwnProperty.call(instance, key) && typeof instance[key] === "function";
|
|
804
1042
|
}
|
|
805
1043
|
});
|
|
1044
|
+
instance.__micraExpr = exprState;
|
|
806
1045
|
let warnedReentry = false;
|
|
807
1046
|
instance.render = function() {
|
|
808
1047
|
var _a2;
|