@mintjamsinc/ichigojs 0.1.71 → 0.1.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ichigo.cjs +100 -38
- package/dist/ichigo.cjs.map +1 -1
- package/dist/ichigo.esm.js +100 -38
- package/dist/ichigo.esm.js.map +1 -1
- package/dist/ichigo.esm.min.js +1 -1
- package/dist/ichigo.min.cjs +1 -1
- package/dist/ichigo.umd.js +100 -38
- package/dist/ichigo.umd.js.map +1 -1
- package/dist/ichigo.umd.min.js +1 -1
- package/dist/types/ichigo/util/ReactiveProxy.d.ts +27 -0
- package/package.json +1 -1
package/dist/ichigo.esm.js
CHANGED
|
@@ -6939,42 +6939,70 @@ class ExpressionUtils {
|
|
|
6939
6939
|
functionDependencies[funcName] = [];
|
|
6940
6940
|
}
|
|
6941
6941
|
}
|
|
6942
|
-
// Second pass:
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6942
|
+
// Second pass: resolve each function's transitive reactive dependencies.
|
|
6943
|
+
//
|
|
6944
|
+
// A function's direct dependency list mixes two kinds of identifiers: references to other
|
|
6945
|
+
// functions (call edges) and references to reactive data properties (the values we actually
|
|
6946
|
+
// care about). We want, for every function, the full set of reactive properties reachable by
|
|
6947
|
+
// following call edges to any depth.
|
|
6948
|
+
//
|
|
6949
|
+
// Functions are free to reference each other cyclically — a poller that reschedules itself
|
|
6950
|
+
// (`scheduleOperationPoll` -> `pollOperation` -> `scheduleOperationPoll`), a pair of mutually
|
|
6951
|
+
// recursive helpers, or any state machine. This is valid JavaScript, so the resolver must not
|
|
6952
|
+
// treat it as an error. Every function in a cycle (more precisely, a strongly connected
|
|
6953
|
+
// component) is reachable from the others, so they all share the same transitive dependency
|
|
6954
|
+
// set: the union of every member's direct reactive dependencies.
|
|
6955
|
+
//
|
|
6956
|
+
// A depth-first walk that bails out on back-edges cannot compute that correctly — it drops the
|
|
6957
|
+
// dependencies contributed around the cycle and caches incomplete, traversal-order-dependent
|
|
6958
|
+
// results, which would silently break reactivity for any computed that reads reactive data
|
|
6959
|
+
// through a cyclic method. We instead split each function's direct dependencies into reactive
|
|
6960
|
+
// properties and call edges, then propagate reactive properties along call edges until the sets
|
|
6961
|
+
// stop growing (a fixpoint). This converges regardless of cycles and yields the exact transitive
|
|
6962
|
+
// closure for every function, including those participating in a cycle.
|
|
6963
|
+
const directReactive = {};
|
|
6964
|
+
const callEdges = {};
|
|
6965
|
+
for (const funcName of Object.keys(functions)) {
|
|
6966
|
+
const reactive = new Set();
|
|
6967
|
+
const edges = [];
|
|
6968
|
+
for (const dep of functionDependencies[funcName] || []) {
|
|
6959
6969
|
if (dep === funcName)
|
|
6960
|
-
continue; // Skip self-references
|
|
6970
|
+
continue; // Skip self-references.
|
|
6961
6971
|
if (functions[dep]) {
|
|
6962
|
-
//
|
|
6963
|
-
const subDependencies = resolveDependencies(dep);
|
|
6964
|
-
subDependencies.forEach(subDep => allDependencies.add(subDep));
|
|
6972
|
+
edges.push(dep); // Call edge to another function.
|
|
6965
6973
|
}
|
|
6966
6974
|
else {
|
|
6967
|
-
//
|
|
6968
|
-
allDependencies.add(dep);
|
|
6975
|
+
reactive.add(dep); // Reactive data property (terminal dependency).
|
|
6969
6976
|
}
|
|
6970
6977
|
}
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
//
|
|
6978
|
+
directReactive[funcName] = reactive;
|
|
6979
|
+
callEdges[funcName] = edges;
|
|
6980
|
+
}
|
|
6981
|
+
// Seed each function with its own direct reactive dependencies, then propagate along call edges
|
|
6982
|
+
// until no set changes. Each pass can only add properties, and the universe of properties is
|
|
6983
|
+
// finite, so the loop is guaranteed to terminate.
|
|
6984
|
+
const resolved = {};
|
|
6985
|
+
for (const funcName of Object.keys(functions)) {
|
|
6986
|
+
resolved[funcName] = new Set(directReactive[funcName]);
|
|
6987
|
+
}
|
|
6988
|
+
let changed = true;
|
|
6989
|
+
while (changed) {
|
|
6990
|
+
changed = false;
|
|
6991
|
+
for (const funcName of Object.keys(functions)) {
|
|
6992
|
+
const target = resolved[funcName];
|
|
6993
|
+
for (const edge of callEdges[funcName]) {
|
|
6994
|
+
for (const dep of resolved[edge]) {
|
|
6995
|
+
if (!target.has(dep)) {
|
|
6996
|
+
target.add(dep);
|
|
6997
|
+
changed = true;
|
|
6998
|
+
}
|
|
6999
|
+
}
|
|
7000
|
+
}
|
|
7001
|
+
}
|
|
7002
|
+
}
|
|
7003
|
+
const resolvedDependencies = {};
|
|
6976
7004
|
for (const funcName of Object.keys(functions)) {
|
|
6977
|
-
|
|
7005
|
+
resolvedDependencies[funcName] = Array.from(resolved[funcName]);
|
|
6978
7006
|
}
|
|
6979
7007
|
return resolvedDependencies;
|
|
6980
7008
|
}
|
|
@@ -7989,6 +8017,41 @@ class ReactiveProxy {
|
|
|
7989
8017
|
* This allows mapping variable names to their actual source paths for dependency tracking.
|
|
7990
8018
|
*/
|
|
7991
8019
|
static pathAliases = new Map();
|
|
8020
|
+
/**
|
|
8021
|
+
* The `Object.prototype.toString` tags of the *only* value types we deeply
|
|
8022
|
+
* proxy. Everything else is returned untouched (raw).
|
|
8023
|
+
*
|
|
8024
|
+
* Rationale: a Proxy can only safely intercept plain data containers. Built-in
|
|
8025
|
+
* and host objects — `Date`, `RegExp`, `File`, `Blob`, `FileList`, `Promise`,
|
|
8026
|
+
* `WeakMap`/`WeakSet`, typed arrays, DOM nodes, etc. — carry private internal
|
|
8027
|
+
* slots, and invoking their native methods with a Proxy as the `this`/receiver
|
|
8028
|
+
* throws "Illegal invocation". They must therefore never be wrapped. This is an
|
|
8029
|
+
* allow-list rather than a deny-list so that *every* such exotic type is
|
|
8030
|
+
* excluded by default, not just the handful we happened to enumerate.
|
|
8031
|
+
*
|
|
8032
|
+
* Plain user-defined class instances report `[object Object]` (unless they set
|
|
8033
|
+
* `Symbol.toStringTag`) and so remain reactive, preserving prior behaviour.
|
|
8034
|
+
* `Map`/`Set` stay reactive because the proxy specially wraps their mutation
|
|
8035
|
+
* methods (see the `get` trap); `WeakMap`/`WeakSet` are intentionally excluded
|
|
8036
|
+
* since they cannot be wrapped that way and would break the same as `File`.
|
|
8037
|
+
*
|
|
8038
|
+
* Callers that want a plain object kept non-reactive can still opt out
|
|
8039
|
+
* explicitly via {@link markRaw}.
|
|
8040
|
+
*/
|
|
8041
|
+
static REACTIVE_TYPE_TAGS = new Set([
|
|
8042
|
+
'[object Object]',
|
|
8043
|
+
'[object Array]',
|
|
8044
|
+
'[object Arguments]',
|
|
8045
|
+
'[object Map]',
|
|
8046
|
+
'[object Set]',
|
|
8047
|
+
]);
|
|
8048
|
+
/**
|
|
8049
|
+
* Whether the given non-null object value is one we deeply proxy.
|
|
8050
|
+
* See {@link REACTIVE_TYPE_TAGS} for the reasoning.
|
|
8051
|
+
*/
|
|
8052
|
+
static isReactivable(value) {
|
|
8053
|
+
return this.REACTIVE_TYPE_TAGS.has(Object.prototype.toString.call(value));
|
|
8054
|
+
}
|
|
7992
8055
|
/**
|
|
7993
8056
|
* Creates a reactive proxy for the given object.
|
|
7994
8057
|
* The proxy will call the onChange callback whenever a property is modified.
|
|
@@ -8008,11 +8071,10 @@ class ReactiveProxy {
|
|
|
8008
8071
|
if (this.rawObjects.has(target)) {
|
|
8009
8072
|
return target;
|
|
8010
8073
|
}
|
|
8011
|
-
//
|
|
8012
|
-
//
|
|
8013
|
-
//
|
|
8014
|
-
|
|
8015
|
-
if (typeTag === '[object Date]' || typeTag === '[object RegExp]' || typeTag === '[object Error]') {
|
|
8074
|
+
// Only deeply proxy plain data containers; return every built-in/host
|
|
8075
|
+
// object (Date, File, Blob, Promise, WeakMap, DOM nodes, …) as-is, since
|
|
8076
|
+
// their native methods break when invoked through a Proxy receiver.
|
|
8077
|
+
if (!this.isReactivable(target)) {
|
|
8016
8078
|
return target;
|
|
8017
8079
|
}
|
|
8018
8080
|
// Check if the target is already a proxy - if so, return it as-is to prevent double-wrapping
|
|
@@ -8048,10 +8110,10 @@ class ReactiveProxy {
|
|
|
8048
8110
|
if (ReactiveProxy.rawObjects.has(value)) {
|
|
8049
8111
|
return value;
|
|
8050
8112
|
}
|
|
8051
|
-
//
|
|
8052
|
-
//
|
|
8053
|
-
|
|
8054
|
-
if (
|
|
8113
|
+
// Only deeply proxy plain data containers; hand back built-in
|
|
8114
|
+
// and host objects (Date, File, Blob, Promise, WeakMap, DOM
|
|
8115
|
+
// nodes, …) untouched so their native methods keep working.
|
|
8116
|
+
if (!ReactiveProxy.isReactivable(value)) {
|
|
8055
8117
|
return value;
|
|
8056
8118
|
}
|
|
8057
8119
|
// Build the nested path
|