@mintjamsinc/ichigojs 0.1.33 → 0.1.35
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 +260 -53
- package/dist/ichigo.cjs.map +1 -1
- package/dist/ichigo.esm.js +260 -54
- 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 +260 -53
- package/dist/ichigo.umd.js.map +1 -1
- package/dist/ichigo.umd.min.js +1 -1
- package/dist/types/ichigo/util/ExpressionEvaluator.d.ts +100 -0
- package/dist/types/ichigo/util/ExpressionEvaluatorOptions.d.ts +20 -0
- package/dist/types/ichigo/util/ReactiveProxy.d.ts +15 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/ichigo.cjs
CHANGED
|
@@ -6734,6 +6734,70 @@
|
|
|
6734
6734
|
}
|
|
6735
6735
|
}
|
|
6736
6736
|
}
|
|
6737
|
+
else if (node.type === 'MemberExpression') {
|
|
6738
|
+
// Reconstruct chain parts from a MemberExpression (e.g. a.b.c)
|
|
6739
|
+
const parts = [];
|
|
6740
|
+
let cur = node;
|
|
6741
|
+
let stop = false;
|
|
6742
|
+
while (cur && !stop) {
|
|
6743
|
+
// property part (right side)
|
|
6744
|
+
if (cur.property) {
|
|
6745
|
+
if (!cur.computed && cur.property.type === 'Identifier') {
|
|
6746
|
+
parts.unshift(cur.property.name);
|
|
6747
|
+
}
|
|
6748
|
+
else if (cur.computed && cur.property.type === 'Literal') {
|
|
6749
|
+
parts.unshift(String(cur.property.value));
|
|
6750
|
+
}
|
|
6751
|
+
else if (cur.computed && cur.property.type === 'Identifier') {
|
|
6752
|
+
// e.g. obj[prop] -> include the prop identifier (it will also be added separately)
|
|
6753
|
+
parts.unshift(cur.property.name);
|
|
6754
|
+
}
|
|
6755
|
+
else {
|
|
6756
|
+
// unknown property shape (e.g. expression) — stop adding chain here
|
|
6757
|
+
// inner expressions will be visited separately by walk.full
|
|
6758
|
+
stop = true;
|
|
6759
|
+
break;
|
|
6760
|
+
}
|
|
6761
|
+
}
|
|
6762
|
+
// object part (left side)
|
|
6763
|
+
if (cur.object) {
|
|
6764
|
+
if (cur.object.type === 'Identifier') {
|
|
6765
|
+
parts.unshift(cur.object.name);
|
|
6766
|
+
break;
|
|
6767
|
+
}
|
|
6768
|
+
else if (cur.object.type === 'ThisExpression') {
|
|
6769
|
+
// For `this.x` or `this.a.b` we don't want to include 'this' itself.
|
|
6770
|
+
// Stop unwrapping here; we'll drop a leading 'this' later.
|
|
6771
|
+
break;
|
|
6772
|
+
}
|
|
6773
|
+
else if (cur.object.type === 'MemberExpression') {
|
|
6774
|
+
// continue unwrapping
|
|
6775
|
+
cur = cur.object;
|
|
6776
|
+
}
|
|
6777
|
+
else {
|
|
6778
|
+
// other object types (CallExpression, etc.) — stop here
|
|
6779
|
+
stop = true;
|
|
6780
|
+
break;
|
|
6781
|
+
}
|
|
6782
|
+
}
|
|
6783
|
+
else {
|
|
6784
|
+
break;
|
|
6785
|
+
}
|
|
6786
|
+
}
|
|
6787
|
+
if (parts.length > 0) {
|
|
6788
|
+
// Add progressive chains: 'a', 'a.b', 'a.b.c'
|
|
6789
|
+
for (let i = 0; i < parts.length; i++) {
|
|
6790
|
+
const chain = parts.slice(0, i + 1).join('.');
|
|
6791
|
+
identifiers.add(chain);
|
|
6792
|
+
// Also apply functionDependencies lookup for the chain key
|
|
6793
|
+
if (functionDependencies[chain]) {
|
|
6794
|
+
for (const dependency of functionDependencies[chain]) {
|
|
6795
|
+
identifiers.add(dependency);
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
6798
|
+
}
|
|
6799
|
+
}
|
|
6800
|
+
}
|
|
6737
6801
|
});
|
|
6738
6802
|
return Array.from(identifiers);
|
|
6739
6803
|
}
|
|
@@ -6939,6 +7003,8 @@
|
|
|
6939
7003
|
* The identifiers extracted from the expression.
|
|
6940
7004
|
*/
|
|
6941
7005
|
identifiers;
|
|
7006
|
+
// The original extracted identifiers (may include member chains like 'a.b')
|
|
7007
|
+
originalIdentifiers;
|
|
6942
7008
|
/**
|
|
6943
7009
|
* The bindings to use for evaluating the expression.
|
|
6944
7010
|
*/
|
|
@@ -6954,10 +7020,11 @@
|
|
|
6954
7020
|
/**
|
|
6955
7021
|
* Private constructor. Use ExpressionEvaluator.create() to create instances.
|
|
6956
7022
|
*/
|
|
6957
|
-
constructor(expression, bindings, identifiers, evaluatorFunc, additionalContext) {
|
|
7023
|
+
constructor(expression, bindings, identifiers, originalIdentifiers, evaluatorFunc, additionalContext) {
|
|
6958
7024
|
this.expression = expression;
|
|
6959
7025
|
this.bindings = bindings;
|
|
6960
7026
|
this.identifiers = identifiers;
|
|
7027
|
+
this.originalIdentifiers = originalIdentifiers;
|
|
6961
7028
|
this.evaluatorFunc = evaluatorFunc;
|
|
6962
7029
|
this.additionalContext = additionalContext;
|
|
6963
7030
|
}
|
|
@@ -6971,12 +7038,22 @@
|
|
|
6971
7038
|
* @returns An ExpressionEvaluator instance.
|
|
6972
7039
|
*/
|
|
6973
7040
|
static create(expression, bindings, functionDependencies, options) {
|
|
6974
|
-
// Extract identifiers from the expression
|
|
6975
|
-
const
|
|
7041
|
+
// Extract identifiers from the expression (may include member chains like 'a.b')
|
|
7042
|
+
const extractedIdentifiers = ExpressionUtils.extractIdentifiers(expression, functionDependencies);
|
|
7043
|
+
// For compilation we must only pass simple identifier names (no dots).
|
|
7044
|
+
// Use the base (left-most) segment of member chains and preserve order.
|
|
7045
|
+
const baseIdentifiers = [];
|
|
7046
|
+
for (const id of extractedIdentifiers) {
|
|
7047
|
+
const base = id.split('.')[0];
|
|
7048
|
+
if (!baseIdentifiers.includes(base)) {
|
|
7049
|
+
baseIdentifiers.push(base);
|
|
7050
|
+
}
|
|
7051
|
+
}
|
|
6976
7052
|
// Apply custom rewrite if provided (used by VOnDirective)
|
|
6977
7053
|
let processedExpression = expression;
|
|
6978
7054
|
if (options?.rewriteExpression) {
|
|
6979
|
-
|
|
7055
|
+
// Pass the original extracted identifiers (may include member chains)
|
|
7056
|
+
processedExpression = options.rewriteExpression(expression, extractedIdentifiers);
|
|
6980
7057
|
}
|
|
6981
7058
|
// Build cache key including options that affect compilation
|
|
6982
7059
|
const cacheKey = JSON.stringify({
|
|
@@ -6986,12 +7063,12 @@
|
|
|
6986
7063
|
// Check cache
|
|
6987
7064
|
let evaluatorFunc = this.cache.get(cacheKey);
|
|
6988
7065
|
if (!evaluatorFunc) {
|
|
6989
|
-
// Compile the expression
|
|
6990
|
-
evaluatorFunc = this.compileExpression(processedExpression,
|
|
7066
|
+
// Compile the expression using base identifiers (no dots)
|
|
7067
|
+
evaluatorFunc = this.compileExpression(processedExpression, baseIdentifiers, options);
|
|
6991
7068
|
// Cache the compiled function
|
|
6992
7069
|
this.cache.set(cacheKey, evaluatorFunc);
|
|
6993
7070
|
}
|
|
6994
|
-
return new ExpressionEvaluator(expression, bindings,
|
|
7071
|
+
return new ExpressionEvaluator(expression, bindings, baseIdentifiers, extractedIdentifiers, evaluatorFunc, options?.additionalContext);
|
|
6995
7072
|
}
|
|
6996
7073
|
/**
|
|
6997
7074
|
* Compiles an expression into a function.
|
|
@@ -7002,7 +7079,7 @@
|
|
|
7002
7079
|
* @returns A compiled function.
|
|
7003
7080
|
*/
|
|
7004
7081
|
static compileExpression(expression, identifiers, options) {
|
|
7005
|
-
// Build parameter list: globals first, then identifiers, then additional context
|
|
7082
|
+
// Build parameter list: globals first, then identifiers (base names), then additional context
|
|
7006
7083
|
const params = [
|
|
7007
7084
|
...Object.keys(ExpressionEvaluator.GLOBAL_WHITELIST),
|
|
7008
7085
|
...identifiers
|
|
@@ -7059,7 +7136,8 @@
|
|
|
7059
7136
|
* Gets the list of identifiers extracted from the expression.
|
|
7060
7137
|
*/
|
|
7061
7138
|
get dependentIdentifiers() {
|
|
7062
|
-
|
|
7139
|
+
// Return the original extracted identifiers (may include member chains like 'a.b')
|
|
7140
|
+
return this.originalIdentifiers;
|
|
7063
7141
|
}
|
|
7064
7142
|
/**
|
|
7065
7143
|
* Clears the expression cache.
|
|
@@ -7624,6 +7702,11 @@
|
|
|
7624
7702
|
* These objects will not be wrapped with Proxy.
|
|
7625
7703
|
*/
|
|
7626
7704
|
static rawObjects = new WeakSet();
|
|
7705
|
+
/**
|
|
7706
|
+
* A WeakMap to store the path for each proxy object.
|
|
7707
|
+
* This allows retrieving the source path of an object for computed property mapping.
|
|
7708
|
+
*/
|
|
7709
|
+
static proxyPaths = new WeakMap();
|
|
7627
7710
|
/**
|
|
7628
7711
|
* Creates a reactive proxy for the given object.
|
|
7629
7712
|
* The proxy will call the onChange callback whenever a property is modified.
|
|
@@ -7722,6 +7805,10 @@
|
|
|
7722
7805
|
pathMap.set(path, proxy);
|
|
7723
7806
|
// Track that this proxy wraps the target to prevent double-wrapping
|
|
7724
7807
|
this.proxyToTarget.set(proxy, target);
|
|
7808
|
+
// Store the path for this proxy (for computed property mapping)
|
|
7809
|
+
if (path) {
|
|
7810
|
+
this.proxyPaths.set(proxy, path);
|
|
7811
|
+
}
|
|
7725
7812
|
return proxy;
|
|
7726
7813
|
}
|
|
7727
7814
|
/**
|
|
@@ -7771,6 +7858,21 @@
|
|
|
7771
7858
|
static isRaw(obj) {
|
|
7772
7859
|
return typeof obj === 'object' && obj !== null && this.rawObjects.has(obj);
|
|
7773
7860
|
}
|
|
7861
|
+
/**
|
|
7862
|
+
* Gets the source path for a proxy object.
|
|
7863
|
+
* This is used to map computed property values back to their source paths.
|
|
7864
|
+
* For example, if a computed property returns `model.elements[0]`,
|
|
7865
|
+
* this method returns "model.elements[0]" for that object.
|
|
7866
|
+
*
|
|
7867
|
+
* @param obj The proxy object to get the path for.
|
|
7868
|
+
* @returns The source path, or undefined if not found.
|
|
7869
|
+
*/
|
|
7870
|
+
static getPath(obj) {
|
|
7871
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
7872
|
+
return undefined;
|
|
7873
|
+
}
|
|
7874
|
+
return this.proxyPaths.get(obj);
|
|
7875
|
+
}
|
|
7774
7876
|
}
|
|
7775
7877
|
|
|
7776
7878
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
|
@@ -8286,12 +8388,21 @@
|
|
|
8286
8388
|
const evaluators = matches.map(match => {
|
|
8287
8389
|
const expression = match[1].trim();
|
|
8288
8390
|
const ids = ExpressionUtils.extractIdentifiers(expression, functionDependencies);
|
|
8289
|
-
//
|
|
8391
|
+
// Keep chain-style identifiers (a, a.b, a.b.c) for metadata
|
|
8290
8392
|
this.#identifiers.push(...ids.filter(id => !this.#identifiers.includes(id)));
|
|
8291
|
-
|
|
8393
|
+
// Build base parameter names (no dots), preserving order of first appearance
|
|
8394
|
+
const baseArgs = [];
|
|
8395
|
+
for (const id of ids) {
|
|
8396
|
+
const base = id.split('.')[0];
|
|
8397
|
+
if (!baseArgs.includes(base)) {
|
|
8398
|
+
baseArgs.push(base);
|
|
8399
|
+
}
|
|
8400
|
+
}
|
|
8401
|
+
const args = baseArgs.join(", ");
|
|
8292
8402
|
const funcBody = `return (${expression});`;
|
|
8293
8403
|
return {
|
|
8294
8404
|
ids,
|
|
8405
|
+
baseArgs,
|
|
8295
8406
|
func: new Function(args, funcBody)
|
|
8296
8407
|
};
|
|
8297
8408
|
});
|
|
@@ -8299,17 +8410,13 @@
|
|
|
8299
8410
|
this.#evaluate = (bindings) => {
|
|
8300
8411
|
let result = text;
|
|
8301
8412
|
evaluators.forEach((evaluator, i) => {
|
|
8302
|
-
//
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
if (value !== undefined) {
|
|
8413
|
+
// Build values for baseArgs (no dots) in the same order as function parameters
|
|
8414
|
+
const values = evaluator.baseArgs.map((name) => {
|
|
8415
|
+
const value = bindings.get(name);
|
|
8416
|
+
if (value !== undefined)
|
|
8307
8417
|
return value;
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
if (id in GLOBAL_OBJECTS) {
|
|
8311
|
-
return GLOBAL_OBJECTS[id];
|
|
8312
|
-
}
|
|
8418
|
+
if (name in GLOBAL_OBJECTS)
|
|
8419
|
+
return GLOBAL_OBJECTS[name];
|
|
8313
8420
|
return undefined;
|
|
8314
8421
|
});
|
|
8315
8422
|
// Evaluate the expression and replace {{...}} in the text
|
|
@@ -10113,10 +10220,16 @@
|
|
|
10113
10220
|
// Evaluate the options expression
|
|
10114
10221
|
let options;
|
|
10115
10222
|
if (optionsDirective && optionsDirective.expression) {
|
|
10116
|
-
// Evaluate the options expression
|
|
10223
|
+
// Evaluate the options expression using base identifiers (no dots)
|
|
10117
10224
|
const identifiers = optionsDirective.dependentIdentifiers;
|
|
10118
|
-
const
|
|
10119
|
-
const
|
|
10225
|
+
const baseArgs = [];
|
|
10226
|
+
for (const id of identifiers) {
|
|
10227
|
+
const base = id.split('.')[0];
|
|
10228
|
+
if (!baseArgs.includes(base))
|
|
10229
|
+
baseArgs.push(base);
|
|
10230
|
+
}
|
|
10231
|
+
const values = baseArgs.map(name => this.#vNode.bindings?.get(name));
|
|
10232
|
+
const args = baseArgs.join(", ");
|
|
10120
10233
|
const funcBody = `return (${optionsDirective.expression});`;
|
|
10121
10234
|
const func = new Function(args, funcBody);
|
|
10122
10235
|
options = func(...values);
|
|
@@ -10189,8 +10302,14 @@
|
|
|
10189
10302
|
}
|
|
10190
10303
|
// For inline expressions, evaluate normally
|
|
10191
10304
|
// Note: inline expressions receive entries and $ctx as parameters
|
|
10192
|
-
const
|
|
10193
|
-
const
|
|
10305
|
+
const baseArgs = [];
|
|
10306
|
+
for (const id of identifiers) {
|
|
10307
|
+
const base = id.split('.')[0];
|
|
10308
|
+
if (!baseArgs.includes(base))
|
|
10309
|
+
baseArgs.push(base);
|
|
10310
|
+
}
|
|
10311
|
+
const values = baseArgs.map(name => vNode.bindings?.get(name));
|
|
10312
|
+
const args = [...baseArgs, 'entries', '$ctx'].join(", ");
|
|
10194
10313
|
const funcBody = `return (${expression});`;
|
|
10195
10314
|
const func = new Function(args, funcBody);
|
|
10196
10315
|
return func.call(bindings?.raw, ...values, entries, $ctx);
|
|
@@ -10854,24 +10973,31 @@
|
|
|
10854
10973
|
const replacements = [];
|
|
10855
10974
|
const parsedAst = parse(`(${expression})`, { ecmaVersion: 'latest' });
|
|
10856
10975
|
// Collect all identifier nodes that should be replaced
|
|
10857
|
-
// Use walk.
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10976
|
+
// Use walk.ancestor to check parent context and skip MemberExpression properties
|
|
10977
|
+
ancestor(parsedAst, {
|
|
10978
|
+
Identifier(node, _state, ancestors) {
|
|
10979
|
+
// Skip if not in our identifier set
|
|
10980
|
+
if (!bindingIdentifiers.has(node.name)) {
|
|
10981
|
+
return;
|
|
10982
|
+
}
|
|
10983
|
+
// Check if this identifier is a property of a MemberExpression
|
|
10984
|
+
// (e.g., in 'obj.prop', we should skip 'prop')
|
|
10985
|
+
if (ancestors.length >= 2) {
|
|
10986
|
+
const parent = ancestors[ancestors.length - 2];
|
|
10987
|
+
if (parent.type === 'MemberExpression') {
|
|
10988
|
+
// Skip if this identifier is the property (not the object) of a non-computed member access
|
|
10989
|
+
if (!parent.computed && parent.property === node) {
|
|
10990
|
+
return;
|
|
10991
|
+
}
|
|
10992
|
+
}
|
|
10993
|
+
}
|
|
10994
|
+
// Add to replacements list (adjust for the wrapping parentheses)
|
|
10995
|
+
replacements.push({
|
|
10996
|
+
start: node.start - 1,
|
|
10997
|
+
end: node.end - 1,
|
|
10998
|
+
name: node.name
|
|
10999
|
+
});
|
|
10865
11000
|
}
|
|
10866
|
-
// Note: We cannot easily determine parent context with walk.full
|
|
10867
|
-
// So we'll include all identifiers and rely on position-based replacement
|
|
10868
|
-
// This is simpler and works correctly for inline expressions
|
|
10869
|
-
// Add to replacements list (adjust for the wrapping parentheses)
|
|
10870
|
-
replacements.push({
|
|
10871
|
-
start: node.start - 1,
|
|
10872
|
-
end: node.end - 1,
|
|
10873
|
-
name: node.name
|
|
10874
|
-
});
|
|
10875
11001
|
});
|
|
10876
11002
|
// Sort replacements by start position (descending) to replace from end to start
|
|
10877
11003
|
replacements.sort((a, b) => b.start - a.start);
|
|
@@ -11013,10 +11139,16 @@
|
|
|
11013
11139
|
// Evaluate the options expression
|
|
11014
11140
|
let options;
|
|
11015
11141
|
if (optionsDirective && optionsDirective.expression) {
|
|
11016
|
-
// Evaluate the options expression
|
|
11142
|
+
// Evaluate the options expression using base identifiers (no dots)
|
|
11017
11143
|
const identifiers = optionsDirective.dependentIdentifiers;
|
|
11018
|
-
const
|
|
11019
|
-
const
|
|
11144
|
+
const baseArgs = [];
|
|
11145
|
+
for (const id of identifiers) {
|
|
11146
|
+
const base = id.split('.')[0];
|
|
11147
|
+
if (!baseArgs.includes(base))
|
|
11148
|
+
baseArgs.push(base);
|
|
11149
|
+
}
|
|
11150
|
+
const values = baseArgs.map(name => this.#vNode.bindings?.get(name));
|
|
11151
|
+
const args = baseArgs.join(", ");
|
|
11020
11152
|
const funcBody = `return (${optionsDirective.expression});`;
|
|
11021
11153
|
const func = new Function(args, funcBody);
|
|
11022
11154
|
options = func(...values);
|
|
@@ -11097,8 +11229,14 @@
|
|
|
11097
11229
|
}
|
|
11098
11230
|
// For inline expressions, evaluate normally
|
|
11099
11231
|
// Note: inline expressions receive entries, observer, options, and $ctx as parameters
|
|
11100
|
-
const
|
|
11101
|
-
const
|
|
11232
|
+
const baseArgs = [];
|
|
11233
|
+
for (const id of identifiers) {
|
|
11234
|
+
const base = id.split('.')[0];
|
|
11235
|
+
if (!baseArgs.includes(base))
|
|
11236
|
+
baseArgs.push(base);
|
|
11237
|
+
}
|
|
11238
|
+
const values = baseArgs.map(name => vNode.bindings?.get(name));
|
|
11239
|
+
const args = [...baseArgs, 'entries', 'observer', 'options', '$ctx'].join(", ");
|
|
11102
11240
|
const funcBody = `return (${expression});`;
|
|
11103
11241
|
const func = new Function(args, funcBody);
|
|
11104
11242
|
return func.call(bindings?.raw, ...values, entries, observer, options, $ctx);
|
|
@@ -11222,10 +11360,16 @@
|
|
|
11222
11360
|
// Evaluate the options expression
|
|
11223
11361
|
let options;
|
|
11224
11362
|
if (optionsDirective && optionsDirective.expression) {
|
|
11225
|
-
// Evaluate the options expression
|
|
11363
|
+
// Evaluate the options expression using base identifiers (no dots)
|
|
11226
11364
|
const identifiers = optionsDirective.dependentIdentifiers;
|
|
11227
|
-
const
|
|
11228
|
-
const
|
|
11365
|
+
const baseArgs = [];
|
|
11366
|
+
for (const id of identifiers) {
|
|
11367
|
+
const base = id.split('.')[0];
|
|
11368
|
+
if (!baseArgs.includes(base))
|
|
11369
|
+
baseArgs.push(base);
|
|
11370
|
+
}
|
|
11371
|
+
const values = baseArgs.map(name => this.#vNode.bindings?.get(name));
|
|
11372
|
+
const args = baseArgs.join(", ");
|
|
11229
11373
|
const funcBody = `return (${optionsDirective.expression});`;
|
|
11230
11374
|
const func = new Function(args, funcBody);
|
|
11231
11375
|
options = func(...values);
|
|
@@ -11298,8 +11442,14 @@
|
|
|
11298
11442
|
}
|
|
11299
11443
|
// For inline expressions, evaluate normally
|
|
11300
11444
|
// Note: inline expressions receive entries and $ctx as parameters
|
|
11301
|
-
const
|
|
11302
|
-
const
|
|
11445
|
+
const baseArgs = [];
|
|
11446
|
+
for (const id of identifiers) {
|
|
11447
|
+
const base = id.split('.')[0];
|
|
11448
|
+
if (!baseArgs.includes(base))
|
|
11449
|
+
baseArgs.push(base);
|
|
11450
|
+
}
|
|
11451
|
+
const values = baseArgs.map(name => vNode.bindings?.get(name));
|
|
11452
|
+
const args = [...baseArgs, 'entries', '$ctx'].join(", ");
|
|
11303
11453
|
const funcBody = `return (${expression});`;
|
|
11304
11454
|
const func = new Function(args, funcBody);
|
|
11305
11455
|
return func.call(bindings?.raw, ...values, entries, $ctx);
|
|
@@ -11896,6 +12046,12 @@
|
|
|
11896
12046
|
* A dictionary mapping computed property names to their dependencies.
|
|
11897
12047
|
*/
|
|
11898
12048
|
#computedDependencies;
|
|
12049
|
+
/**
|
|
12050
|
+
* A map tracking source paths for computed property values.
|
|
12051
|
+
* Maps source path (e.g., "model.elements[0]") to computed property name (e.g., "selectedElement").
|
|
12052
|
+
* This allows changes to source paths to be mapped to computed property changes.
|
|
12053
|
+
*/
|
|
12054
|
+
#computedSourcePaths = new Map();
|
|
11899
12055
|
/**
|
|
11900
12056
|
* Flag to indicate if an update is already scheduled.
|
|
11901
12057
|
*/
|
|
@@ -12133,11 +12289,45 @@
|
|
|
12133
12289
|
#update() {
|
|
12134
12290
|
// Re-evaluate computed properties that depend on changed values
|
|
12135
12291
|
this.#recomputeProperties();
|
|
12292
|
+
// Apply computed source path mappings to changes
|
|
12293
|
+
// This converts paths like "model.elements[0].executionListeners"
|
|
12294
|
+
// to "selectedElement.executionListeners" when selectedElement points to model.elements[0]
|
|
12295
|
+
this.#applyComputedPathMappings();
|
|
12136
12296
|
// Update the DOM
|
|
12137
12297
|
this.#vNode?.update();
|
|
12138
12298
|
// Clear the set of changed identifiers after the update
|
|
12139
12299
|
this.#bindings?.clearChanges();
|
|
12140
12300
|
}
|
|
12301
|
+
/**
|
|
12302
|
+
* Applies computed source path mappings to the current changes.
|
|
12303
|
+
* For each changed path, if it starts with a source path that maps to a computed property,
|
|
12304
|
+
* adds the corresponding computed property path to the changes.
|
|
12305
|
+
*/
|
|
12306
|
+
#applyComputedPathMappings() {
|
|
12307
|
+
if (this.#computedSourcePaths.size === 0 || !this.#bindings) {
|
|
12308
|
+
return;
|
|
12309
|
+
}
|
|
12310
|
+
const changes = this.#bindings.changes;
|
|
12311
|
+
const mappedPaths = [];
|
|
12312
|
+
for (const changedPath of changes) {
|
|
12313
|
+
for (const [sourcePath, computedName] of this.#computedSourcePaths) {
|
|
12314
|
+
// Check if the changed path starts with or equals the source path
|
|
12315
|
+
if (changedPath === sourcePath) {
|
|
12316
|
+
// Exact match: mark the computed property itself as changed
|
|
12317
|
+
mappedPaths.push(computedName);
|
|
12318
|
+
}
|
|
12319
|
+
else if (changedPath.startsWith(sourcePath + '.') || changedPath.startsWith(sourcePath + '[')) {
|
|
12320
|
+
// Subpath match: convert "model.elements[0].x" to "selectedElement.x"
|
|
12321
|
+
const suffix = changedPath.slice(sourcePath.length);
|
|
12322
|
+
mappedPaths.push(computedName + suffix);
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
12325
|
+
}
|
|
12326
|
+
// Add all mapped paths to the changes
|
|
12327
|
+
for (const path of mappedPaths) {
|
|
12328
|
+
this.#bindings.markChanged(path);
|
|
12329
|
+
}
|
|
12330
|
+
}
|
|
12141
12331
|
/**
|
|
12142
12332
|
* Recursively recomputes computed properties based on changed identifiers.
|
|
12143
12333
|
* @param isInitialization - If true, computes all computed properties regardless of dependencies
|
|
@@ -12199,6 +12389,22 @@
|
|
|
12199
12389
|
this.#bindings?.setSilent(key, newValue);
|
|
12200
12390
|
this.#bindings?.markChanged(key);
|
|
12201
12391
|
allChanges.add(key);
|
|
12392
|
+
// Track source path mapping for computed property values
|
|
12393
|
+
// This allows changes like "model.elements[0].x" to be mapped to "selectedElement.x"
|
|
12394
|
+
if (typeof newValue === 'object' && newValue !== null) {
|
|
12395
|
+
const sourcePath = ReactiveProxy.getPath(newValue);
|
|
12396
|
+
if (sourcePath) {
|
|
12397
|
+
// Remove old mapping for this computed property
|
|
12398
|
+
for (const [path, name] of this.#computedSourcePaths) {
|
|
12399
|
+
if (name === key) {
|
|
12400
|
+
this.#computedSourcePaths.delete(path);
|
|
12401
|
+
break;
|
|
12402
|
+
}
|
|
12403
|
+
}
|
|
12404
|
+
// Add new mapping
|
|
12405
|
+
this.#computedSourcePaths.set(sourcePath, key);
|
|
12406
|
+
}
|
|
12407
|
+
}
|
|
12202
12408
|
}
|
|
12203
12409
|
}
|
|
12204
12410
|
catch (error) {
|
|
@@ -12295,6 +12501,7 @@
|
|
|
12295
12501
|
}
|
|
12296
12502
|
}
|
|
12297
12503
|
|
|
12504
|
+
exports.ExpressionUtils = ExpressionUtils;
|
|
12298
12505
|
exports.ReactiveProxy = ReactiveProxy;
|
|
12299
12506
|
exports.VComponent = VComponent;
|
|
12300
12507
|
exports.VComponentRegistry = VComponentRegistry;
|