jq79 0.3.28 → 0.3.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jq79",
3
- "version": "0.3.28",
3
+ "version": "0.3.30",
4
4
  "description": "Mini reactive component library: single-file components, Svelte-style setup scripts, fine-grained proxy reactivity. Single-file build, zero dependencies.",
5
5
  "keywords": [
6
6
  "reactive",
package/src/jq79.ts CHANGED
@@ -51,12 +51,35 @@ const elementToAST = (el: Element): TemplateNode => ({
51
51
  // precise instead of "read everything up front". `extras` are passed as
52
52
  // function parameters (outside the `with`), so scope keys still win but names
53
53
  // like $event resolve when the scope doesn't shadow them
54
+ //
55
+ // Compiled functions are cached: an expression is re-evaluated on every effect
56
+ // run - once per interpolation, once per :each item - while the set of distinct
57
+ // expressions is fixed by the source. The `extras` names are part of the key,
58
+ // not just the expression: they become the function's parameters, so the same
59
+ // expression compiled with and without $event is two different functions. A
60
+ // syntactically invalid expression caches its failure (null) so it isn't
61
+ // recompiled, and rethrown as undefined, exactly as before
62
+ const compiled = new Map<string, Function | null>()
63
+
64
+ const compileExpr = (expr: string, params: string[]): Function | null => {
65
+ const key = `${params.join(",")}|${expr}`
66
+ let fn = compiled.get(key)
67
+ if (fn === undefined) {
68
+ try {
69
+ fn = new Function("$scope", ...params, `with ($scope) { return (${expr}); }`)
70
+ } catch {
71
+ fn = null // a syntax error: it will never compile, so don't try again
72
+ }
73
+ compiled.set(key, fn)
74
+ }
75
+ return fn
76
+ }
77
+
54
78
  const evalExpr = (expr: string, scope: Record<string, any>, extras?: Record<string, any>): any => {
79
+ const fn = compileExpr(expr, extras ? Object.keys(extras) : [])
80
+ if (!fn) return undefined
55
81
  try {
56
- return new Function("$scope", ...Object.keys(extras ?? {}), `with ($scope) { return (${expr}); }`)(
57
- scope,
58
- ...Object.values(extras ?? {})
59
- )
82
+ return fn(scope, ...(extras ? Object.values(extras) : []))
60
83
  } catch {
61
84
  return undefined
62
85
  }