micra.js 2.3.2 → 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 +57 -0
- package/README.md +7 -4
- package/dist/index.d.ts +1 -1
- package/dist/micra.cjs.js +296 -48
- package/dist/micra.cjs.js.map +3 -3
- package/dist/micra.esm.js +296 -48
- package/dist/micra.esm.js.map +3 -3
- package/dist/micra.js +296 -48
- 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 +2 -2
- package/src/core/mount.ts +4 -0
- 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 -121
package/dist/micra.esm.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
|
|
|
3
3
|
// src/utils/fetch.ts
|
|
4
4
|
function getCSRF() {
|
|
@@ -81,42 +81,196 @@ function debug() {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// src/utils/expr.ts
|
|
84
|
-
var exprCache = /* @__PURE__ */ new Map();
|
|
85
|
-
var warnedRuntime = /* @__PURE__ */ new Set();
|
|
86
|
-
var SIMPLE_PATH = /^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/;
|
|
87
84
|
var ALLOWED_GLOBALS = new Set(
|
|
88
85
|
"Math,JSON,Date,String,Number,Boolean,Array,Object,parseInt,parseFloat,isNaN,isFinite,NaN,Infinity,undefined".split(",")
|
|
89
86
|
);
|
|
90
|
-
var
|
|
91
|
-
var PARAM_SAFE = "$safe";
|
|
92
|
-
var SAFE_OUTER = new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
93
|
-
has(_target, key) {
|
|
94
|
-
if (typeof key !== "string") return false;
|
|
95
|
-
if (key === PARAM_S || key === PARAM_SAFE) return false;
|
|
96
|
-
return !ALLOWED_GLOBALS.has(key);
|
|
97
|
-
},
|
|
98
|
-
get() {
|
|
99
|
-
return void 0;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
var safeWrapCache = /* @__PURE__ */ new WeakMap();
|
|
87
|
+
var BLOCKED_PROPS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
103
88
|
var OBJ_PROTO_KEYS = new Set(Object.getOwnPropertyNames(Object.prototype));
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
89
|
+
var PUNCT = [
|
|
90
|
+
"===",
|
|
91
|
+
"!==",
|
|
92
|
+
"==",
|
|
93
|
+
"!=",
|
|
94
|
+
"<=",
|
|
95
|
+
">=",
|
|
96
|
+
"&&",
|
|
97
|
+
"||",
|
|
98
|
+
"(",
|
|
99
|
+
")",
|
|
100
|
+
".",
|
|
101
|
+
",",
|
|
102
|
+
"?",
|
|
103
|
+
":",
|
|
104
|
+
"!",
|
|
105
|
+
"<",
|
|
106
|
+
">",
|
|
107
|
+
"+",
|
|
108
|
+
"-",
|
|
109
|
+
"*",
|
|
110
|
+
"/",
|
|
111
|
+
"%"
|
|
112
|
+
];
|
|
113
|
+
function tokenize(src) {
|
|
114
|
+
var _a;
|
|
115
|
+
const toks = [];
|
|
116
|
+
let i = 0;
|
|
117
|
+
const n = src.length;
|
|
118
|
+
while (i < n) {
|
|
119
|
+
const c = src[i];
|
|
120
|
+
if (c === " " || c === " " || c === "\n" || c === "\r" || c === "\f") {
|
|
121
|
+
i++;
|
|
122
|
+
continue;
|
|
113
123
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
if (c === '"' || c === "'") {
|
|
125
|
+
let s = "";
|
|
126
|
+
i++;
|
|
127
|
+
while (i < n && src[i] !== c) {
|
|
128
|
+
if (src[i] === "\\") {
|
|
129
|
+
s += (_a = src[i + 1]) != null ? _a : "";
|
|
130
|
+
i += 2;
|
|
131
|
+
} else {
|
|
132
|
+
s += src[i];
|
|
133
|
+
i++;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (src[i] !== c) throw 0;
|
|
137
|
+
i++;
|
|
138
|
+
toks.push({ t: "str", v: s });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (c >= "0" && c <= "9") {
|
|
142
|
+
let s = "";
|
|
143
|
+
while (i < n && (src[i] >= "0" && src[i] <= "9" || src[i] === ".")) {
|
|
144
|
+
s += src[i];
|
|
145
|
+
i++;
|
|
146
|
+
}
|
|
147
|
+
toks.push({ t: "num", v: s });
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (/[A-Za-z_$]/.test(c)) {
|
|
151
|
+
let s = "";
|
|
152
|
+
while (i < n && /[A-Za-z0-9_$]/.test(src[i])) {
|
|
153
|
+
s += src[i];
|
|
154
|
+
i++;
|
|
155
|
+
}
|
|
156
|
+
toks.push({ t: "id", v: s });
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const m = PUNCT.find((p) => src.startsWith(p, i));
|
|
160
|
+
if (!m) throw 0;
|
|
161
|
+
toks.push({ t: "p", v: m });
|
|
162
|
+
i += m.length;
|
|
163
|
+
}
|
|
164
|
+
return toks;
|
|
165
|
+
}
|
|
166
|
+
var BIN_PREC = {
|
|
167
|
+
"||": 1,
|
|
168
|
+
"&&": 2,
|
|
169
|
+
"==": 3,
|
|
170
|
+
"!=": 3,
|
|
171
|
+
"===": 3,
|
|
172
|
+
"!==": 3,
|
|
173
|
+
"<": 4,
|
|
174
|
+
"<=": 4,
|
|
175
|
+
">": 4,
|
|
176
|
+
">=": 4,
|
|
177
|
+
"+": 5,
|
|
178
|
+
"-": 5,
|
|
179
|
+
"*": 6,
|
|
180
|
+
"/": 6,
|
|
181
|
+
"%": 6
|
|
182
|
+
};
|
|
183
|
+
function parse(toks) {
|
|
184
|
+
let pos = 0;
|
|
185
|
+
const peek = () => toks[pos];
|
|
186
|
+
const next = () => toks[pos++];
|
|
187
|
+
const eat = (v) => {
|
|
188
|
+
var _a;
|
|
189
|
+
if (((_a = peek()) == null ? void 0 : _a.v) !== v) throw 0;
|
|
190
|
+
pos++;
|
|
191
|
+
};
|
|
192
|
+
function parseExpr() {
|
|
193
|
+
var _a;
|
|
194
|
+
const c = parseBin(1);
|
|
195
|
+
if (((_a = peek()) == null ? void 0 : _a.v) === "?") {
|
|
196
|
+
next();
|
|
197
|
+
const a = parseExpr();
|
|
198
|
+
eat(":");
|
|
199
|
+
const b = parseExpr();
|
|
200
|
+
return { k: "tern", c, a, b };
|
|
201
|
+
}
|
|
202
|
+
return c;
|
|
203
|
+
}
|
|
204
|
+
function parseBin(minPrec) {
|
|
205
|
+
let left = parseUnary();
|
|
206
|
+
for (; ; ) {
|
|
207
|
+
const t = peek();
|
|
208
|
+
const prec = t && t.t === "p" ? BIN_PREC[t.v] : void 0;
|
|
209
|
+
if (prec === void 0 || prec < minPrec) break;
|
|
210
|
+
next();
|
|
211
|
+
const right = parseBin(prec + 1);
|
|
212
|
+
left = { k: "bin", op: t.v, l: left, r: right };
|
|
213
|
+
}
|
|
214
|
+
return left;
|
|
215
|
+
}
|
|
216
|
+
function parseUnary() {
|
|
217
|
+
const t = peek();
|
|
218
|
+
if (t && t.t === "p" && (t.v === "!" || t.v === "-")) {
|
|
219
|
+
next();
|
|
220
|
+
return { k: "un", op: t.v, x: parseUnary() };
|
|
221
|
+
}
|
|
222
|
+
return parsePostfix();
|
|
223
|
+
}
|
|
224
|
+
function parsePostfix() {
|
|
225
|
+
var _a, _b;
|
|
226
|
+
let node = parsePrimary();
|
|
227
|
+
for (; ; ) {
|
|
228
|
+
const t = peek();
|
|
229
|
+
if ((t == null ? void 0 : t.v) === ".") {
|
|
230
|
+
next();
|
|
231
|
+
const id = next();
|
|
232
|
+
if (!id || id.t !== "id") throw 0;
|
|
233
|
+
node = { k: "mem", o: node, p: id.v };
|
|
234
|
+
} else if ((t == null ? void 0 : t.v) === "(") {
|
|
235
|
+
next();
|
|
236
|
+
const args = [];
|
|
237
|
+
if (((_a = peek()) == null ? void 0 : _a.v) !== ")") {
|
|
238
|
+
args.push(parseExpr());
|
|
239
|
+
while (((_b = peek()) == null ? void 0 : _b.v) === ",") {
|
|
240
|
+
next();
|
|
241
|
+
args.push(parseExpr());
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
eat(")");
|
|
245
|
+
node = { k: "call", c: node, a: args };
|
|
246
|
+
} else break;
|
|
247
|
+
}
|
|
248
|
+
return node;
|
|
249
|
+
}
|
|
250
|
+
function parsePrimary() {
|
|
251
|
+
const t = next();
|
|
252
|
+
if (!t) throw 0;
|
|
253
|
+
if (t.t === "num") return { k: "lit", v: Number(t.v) };
|
|
254
|
+
if (t.t === "str") return { k: "lit", v: t.v };
|
|
255
|
+
if (t.v === "(") {
|
|
256
|
+
const e = parseExpr();
|
|
257
|
+
eat(")");
|
|
258
|
+
return e;
|
|
259
|
+
}
|
|
260
|
+
if (t.t === "id") {
|
|
261
|
+
if (t.v === "true") return { k: "lit", v: true };
|
|
262
|
+
if (t.v === "false") return { k: "lit", v: false };
|
|
263
|
+
if (t.v === "null") return { k: "lit", v: null };
|
|
264
|
+
if (t.v === "undefined") return { k: "lit", v: void 0 };
|
|
265
|
+
return { k: "id", n: t.v };
|
|
266
|
+
}
|
|
267
|
+
throw 0;
|
|
268
|
+
}
|
|
269
|
+
const ast = parseExpr();
|
|
270
|
+
if (pos !== toks.length) throw 0;
|
|
271
|
+
return ast;
|
|
117
272
|
}
|
|
118
273
|
function safeStateHas(state, key) {
|
|
119
|
-
if (typeof key !== "string") return false;
|
|
120
274
|
if (!Reflect.has(state, key)) return false;
|
|
121
275
|
if (!OBJ_PROTO_KEYS.has(key)) return true;
|
|
122
276
|
let obj = state;
|
|
@@ -126,6 +280,87 @@ function safeStateHas(state, key) {
|
|
|
126
280
|
}
|
|
127
281
|
return false;
|
|
128
282
|
}
|
|
283
|
+
function resolveIdent(name, scope) {
|
|
284
|
+
if (safeStateHas(scope, name)) return scope[name];
|
|
285
|
+
if (ALLOWED_GLOBALS.has(name)) return globalThis[name];
|
|
286
|
+
return void 0;
|
|
287
|
+
}
|
|
288
|
+
function evalNode(node, scope) {
|
|
289
|
+
switch (node.k) {
|
|
290
|
+
case "lit":
|
|
291
|
+
return node.v;
|
|
292
|
+
case "id":
|
|
293
|
+
return resolveIdent(node.n, scope);
|
|
294
|
+
case "mem": {
|
|
295
|
+
const o = evalNode(node.o, scope);
|
|
296
|
+
if (o == null || BLOCKED_PROPS.has(node.p)) return void 0;
|
|
297
|
+
return o[node.p];
|
|
298
|
+
}
|
|
299
|
+
case "un": {
|
|
300
|
+
const x = evalNode(node.x, scope);
|
|
301
|
+
return node.op === "!" ? !x : -x;
|
|
302
|
+
}
|
|
303
|
+
case "tern":
|
|
304
|
+
return evalNode(node.c, scope) ? evalNode(node.a, scope) : evalNode(node.b, scope);
|
|
305
|
+
case "bin": {
|
|
306
|
+
const op = node.op;
|
|
307
|
+
if (op === "&&") {
|
|
308
|
+
const l2 = evalNode(node.l, scope);
|
|
309
|
+
return l2 ? evalNode(node.r, scope) : l2;
|
|
310
|
+
}
|
|
311
|
+
if (op === "||") {
|
|
312
|
+
const l2 = evalNode(node.l, scope);
|
|
313
|
+
return l2 ? l2 : evalNode(node.r, scope);
|
|
314
|
+
}
|
|
315
|
+
const l = evalNode(node.l, scope);
|
|
316
|
+
const r = evalNode(node.r, scope);
|
|
317
|
+
switch (op) {
|
|
318
|
+
case "+":
|
|
319
|
+
return l + r;
|
|
320
|
+
case "-":
|
|
321
|
+
return l - r;
|
|
322
|
+
case "*":
|
|
323
|
+
return l * r;
|
|
324
|
+
case "/":
|
|
325
|
+
return l / r;
|
|
326
|
+
case "%":
|
|
327
|
+
return l % r;
|
|
328
|
+
case "<":
|
|
329
|
+
return l < r;
|
|
330
|
+
case "<=":
|
|
331
|
+
return l <= r;
|
|
332
|
+
case ">":
|
|
333
|
+
return l > r;
|
|
334
|
+
case ">=":
|
|
335
|
+
return l >= r;
|
|
336
|
+
case "==":
|
|
337
|
+
return l == r;
|
|
338
|
+
case "!=":
|
|
339
|
+
return l != r;
|
|
340
|
+
case "===":
|
|
341
|
+
return l === r;
|
|
342
|
+
case "!==":
|
|
343
|
+
return l !== r;
|
|
344
|
+
}
|
|
345
|
+
return void 0;
|
|
346
|
+
}
|
|
347
|
+
case "call": {
|
|
348
|
+
let fn;
|
|
349
|
+
let self;
|
|
350
|
+
if (node.c.k === "mem") {
|
|
351
|
+
self = evalNode(node.c.o, scope);
|
|
352
|
+
fn = self == null || BLOCKED_PROPS.has(node.c.p) ? void 0 : self[node.c.p];
|
|
353
|
+
} else {
|
|
354
|
+
fn = evalNode(node.c, scope);
|
|
355
|
+
}
|
|
356
|
+
if (typeof fn !== "function") throw new TypeError("not a function");
|
|
357
|
+
return fn.apply(self, node.a.map((x) => evalNode(x, scope)));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
var exprCache = /* @__PURE__ */ new Map();
|
|
362
|
+
var warnedRuntime = /* @__PURE__ */ new Set();
|
|
363
|
+
var SIMPLE_PATH = /^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/;
|
|
129
364
|
function evalExpr(expr, state) {
|
|
130
365
|
let cached = exprCache.get(expr);
|
|
131
366
|
if (!cached) {
|
|
@@ -133,26 +368,24 @@ function evalExpr(expr, state) {
|
|
|
133
368
|
cached = { kind: "path", parts: expr.split(".") };
|
|
134
369
|
} else {
|
|
135
370
|
try {
|
|
136
|
-
cached = {
|
|
137
|
-
kind: "fn",
|
|
138
|
-
fn: new Function("$s", "$safe", `with($safe){with($s){return (${expr})}}`)
|
|
139
|
-
};
|
|
371
|
+
cached = { kind: "ast", ast: parse(tokenize(expr)) };
|
|
140
372
|
} catch {
|
|
141
373
|
warn(`invalid expression "${expr}"`);
|
|
142
|
-
cached = { kind: "
|
|
374
|
+
cached = { kind: "err" };
|
|
143
375
|
}
|
|
144
376
|
}
|
|
145
377
|
exprCache.set(expr, cached);
|
|
146
378
|
}
|
|
147
379
|
if (cached.kind === "path") {
|
|
148
|
-
|
|
149
|
-
return
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
380
|
+
const parts = cached.parts;
|
|
381
|
+
if (!safeStateHas(state, parts[0])) return void 0;
|
|
382
|
+
let obj = state;
|
|
383
|
+
for (const key of parts) obj = obj != null ? obj[key] : void 0;
|
|
384
|
+
return obj;
|
|
153
385
|
}
|
|
386
|
+
if (cached.kind === "err") return void 0;
|
|
154
387
|
try {
|
|
155
|
-
return cached.
|
|
388
|
+
return evalNode(cached.ast, state);
|
|
156
389
|
} catch (e) {
|
|
157
390
|
if (!warnedRuntime.has(expr)) {
|
|
158
391
|
warnedRuntime.add(expr);
|
|
@@ -312,6 +545,23 @@ function track(instance, el, type, fn) {
|
|
|
312
545
|
el.addEventListener(type, fn);
|
|
313
546
|
((_a = instance.__micraListeners) != null ? _a : instance.__micraListeners = []).push({ el, type, fn });
|
|
314
547
|
}
|
|
548
|
+
function runHandler(instance, el, value, e) {
|
|
549
|
+
var _a;
|
|
550
|
+
if (value.includes("(")) {
|
|
551
|
+
let base;
|
|
552
|
+
for (let n = el; n && !base; n = n.parentElement) {
|
|
553
|
+
base = n._itemState;
|
|
554
|
+
}
|
|
555
|
+
const scope = Object.create((_a = base != null ? base : instance.__micraExpr) != null ? _a : null);
|
|
556
|
+
scope["$event"] = e;
|
|
557
|
+
scope["event"] = e;
|
|
558
|
+
evalExpr(value, scope);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const fn = instance[value];
|
|
562
|
+
if (typeof fn === "function") fn.call(instance, e);
|
|
563
|
+
else warn(`method "${value}" not found`);
|
|
564
|
+
}
|
|
315
565
|
function bindDataOn(els, instance) {
|
|
316
566
|
var _a;
|
|
317
567
|
for (const el of els) {
|
|
@@ -323,13 +573,12 @@ function bindDataOn(els, instance) {
|
|
|
323
573
|
const [evSpec, method] = part.trim().split(":");
|
|
324
574
|
if (!evSpec || !method) continue;
|
|
325
575
|
const [evName, ...mods] = evSpec.split(".");
|
|
576
|
+
const handler = method.trim();
|
|
326
577
|
track(instance, el, evName, (e) => {
|
|
327
578
|
if (mods.includes("prevent")) e.preventDefault();
|
|
328
579
|
if (mods.includes("stop")) e.stopPropagation();
|
|
329
580
|
if (mods.includes("self") && e.target !== el) return;
|
|
330
|
-
|
|
331
|
-
if (typeof fn === "function") fn.call(instance, e);
|
|
332
|
-
else warn(`method "${method.trim()}" not found`);
|
|
581
|
+
runHandler(instance, el, handler, e);
|
|
333
582
|
});
|
|
334
583
|
}
|
|
335
584
|
}
|
|
@@ -342,14 +591,12 @@ function bindAtEvents(els, instance) {
|
|
|
342
591
|
for (const attr of Array.from(el.attributes)) {
|
|
343
592
|
if (!attr.name.startsWith("@")) continue;
|
|
344
593
|
const [evSpec, ...rest] = attr.name.slice(1).split(".");
|
|
345
|
-
const
|
|
594
|
+
const handler = attr.value.trim();
|
|
346
595
|
track(instance, el, evSpec, (e) => {
|
|
347
596
|
if (rest.includes("prevent")) e.preventDefault();
|
|
348
597
|
if (rest.includes("stop")) e.stopPropagation();
|
|
349
598
|
if (rest.includes("self") && e.target !== el) return;
|
|
350
|
-
|
|
351
|
-
if (typeof fn === "function") fn.call(instance, e);
|
|
352
|
-
else warn(`method "${method}" not found`);
|
|
599
|
+
runHandler(instance, el, handler, e);
|
|
353
600
|
});
|
|
354
601
|
bound = true;
|
|
355
602
|
}
|
|
@@ -759,6 +1006,7 @@ function mount(selector, definition) {
|
|
|
759
1006
|
return Object.prototype.hasOwnProperty.call(instance, key) && typeof instance[key] === "function";
|
|
760
1007
|
}
|
|
761
1008
|
});
|
|
1009
|
+
instance.__micraExpr = exprState;
|
|
762
1010
|
let warnedReentry = false;
|
|
763
1011
|
instance.render = function() {
|
|
764
1012
|
var _a2;
|