@mintjamsinc/ichigojs 0.1.84 → 0.1.86

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.
@@ -6760,28 +6760,29 @@ class ExpressionUtils {
6760
6760
  }
6761
6761
  }
6762
6762
  else if (node.type === 'MemberExpression') {
6763
- // Reconstruct chain parts from a MemberExpression (e.g. a.b.c)
6763
+ // Reconstruct chain parts from a MemberExpression (e.g. a.b.c). Each part
6764
+ // carries its own separator so that the chain is spelled the way the reactive
6765
+ // proxy reports changes: array indices in brackets, properties after a dot
6766
+ // (e.g. "items[0].name").
6764
6767
  const parts = [];
6765
6768
  let cur = node;
6766
- let stop = false;
6767
- while (cur && !stop) {
6769
+ while (cur) {
6768
6770
  // property part (right side)
6769
6771
  if (cur.property) {
6770
6772
  if (!cur.computed && cur.property.type === 'Identifier') {
6771
- parts.unshift(cur.property.name);
6773
+ parts.unshift(`.${cur.property.name}`);
6774
+ }
6775
+ else if (cur.computed && cur.property.type === 'Literal' && typeof cur.property.value === 'number') {
6776
+ parts.unshift(`[${cur.property.value}]`);
6772
6777
  }
6773
6778
  else if (cur.computed && cur.property.type === 'Literal') {
6774
- parts.unshift(String(cur.property.value));
6779
+ parts.unshift(`.${String(cur.property.value)}`);
6775
6780
  }
6776
- else if (cur.computed && cur.property.type === 'Identifier') {
6777
- // e.g. obj[prop] -> include the prop identifier (it will also be added separately)
6778
- parts.unshift(cur.property.name);
6779
- }
6780
- else {
6781
- // unknown property shape (e.g. expression) — stop adding chain here
6782
- // inner expressions will be visited separately by walk.full
6783
- stop = true;
6784
- break;
6781
+ else if (cur.computed) {
6782
+ // e.g. items[i] or items[i + 1]: the index is only known when the
6783
+ // expression runs, so "[*]" stands for any index or key. Identifiers
6784
+ // inside the index expression are visited separately by walk.full.
6785
+ parts.unshift('[*]');
6785
6786
  }
6786
6787
  }
6787
6788
  // object part (left side)
@@ -6801,7 +6802,6 @@ class ExpressionUtils {
6801
6802
  }
6802
6803
  else {
6803
6804
  // other object types (CallExpression, etc.) — stop here
6804
- stop = true;
6805
6805
  break;
6806
6806
  }
6807
6807
  }
@@ -6809,10 +6809,15 @@ class ExpressionUtils {
6809
6809
  break;
6810
6810
  }
6811
6811
  }
6812
- if (parts.length > 0) {
6813
- // Add progressive chains: 'a', 'a.b', 'a.b.c'
6812
+ // A chain that does not start at a name (e.g. `this.a.b` or `f().b`) begins
6813
+ // with its first property; one that begins with an index names no binding.
6814
+ if (parts.length > 0 && parts[0].startsWith('.')) {
6815
+ parts[0] = parts[0].substring(1);
6816
+ }
6817
+ if (parts.length > 0 && !parts[0].startsWith('[')) {
6818
+ // Add progressive chains: 'a', 'a.b', 'a.b[0]', 'a.b[0].c'
6814
6819
  for (let i = 0; i < parts.length; i++) {
6815
- const chain = parts.slice(0, i + 1).join('.');
6820
+ const chain = parts.slice(0, i + 1).join('');
6816
6821
  identifiers.add(chain);
6817
6822
  // Also apply functionDependencies lookup for the chain key
6818
6823
  if (functionDependencies[chain]) {
@@ -6826,6 +6831,16 @@ class ExpressionUtils {
6826
6831
  });
6827
6832
  return Array.from(identifiers);
6828
6833
  }
6834
+ /**
6835
+ * Returns the binding name an identifier chain starts with
6836
+ * (e.g. "items" for "items[0].name" or "user.name").
6837
+ * @param identifier An identifier or member chain returned by extractIdentifiers.
6838
+ * @returns The left-most name of the chain.
6839
+ */
6840
+ static baseIdentifier(identifier) {
6841
+ const end = identifier.search(/[.[]/);
6842
+ return end === -1 ? identifier : identifier.substring(0, end);
6843
+ }
6829
6844
  /**
6830
6845
  * Analyzes the dependencies of functions in the provided dictionary.
6831
6846
  * @param functions A dictionary mapping function names to their implementations.
@@ -7240,7 +7255,7 @@ class ExpressionEvaluator {
7240
7255
  // Use the base (left-most) segment of member chains and preserve order.
7241
7256
  const baseIdentifiers = [];
7242
7257
  for (const id of extractedIdentifiers) {
7243
- const base = id.split('.')[0];
7258
+ const base = ExpressionUtils.baseIdentifier(id);
7244
7259
  if (!baseIdentifiers.includes(base)) {
7245
7260
  baseIdentifiers.push(base);
7246
7261
  }
@@ -7781,13 +7796,20 @@ class VBindDirective {
7781
7796
  }
7782
7797
  /**
7783
7798
  * Updates a regular attribute.
7799
+ * An attribute that already holds the value is left alone: setting `src` on
7800
+ * an <iframe>, even to the same URL, loads its page again.
7784
7801
  */
7785
7802
  #updateAttribute(element, name, value) {
7786
7803
  if (value == null || value === false) {
7787
- element.removeAttribute(name);
7804
+ if (element.hasAttribute(name)) {
7805
+ element.removeAttribute(name);
7806
+ }
7788
7807
  }
7789
7808
  else {
7790
- element.setAttribute(name, String(value));
7809
+ const text = String(value);
7810
+ if (element.getAttribute(name) !== text) {
7811
+ element.setAttribute(name, text);
7812
+ }
7791
7813
  }
7792
7814
  }
7793
7815
  }
@@ -8027,6 +8049,11 @@ class ReactiveProxy {
8027
8049
  * This allows mapping variable names to their actual source paths for dependency tracking.
8028
8050
  */
8029
8051
  static pathAliases = new Map();
8052
+ /**
8053
+ * Compiled patterns for identifiers that contain a "[*]" index, keyed by the
8054
+ * identifier and whether descendants of the path also match.
8055
+ */
8056
+ static pathPatterns = new Map();
8030
8057
  /**
8031
8058
  * The `Object.prototype.toString` tags of the *only* value types we deeply
8032
8059
  * proxy. Everything else is returned untouched (raw).
@@ -8389,24 +8416,47 @@ class ReactiveProxy {
8389
8416
  */
8390
8417
  static doesChangeMatchIdentifier(changePath, identifier) {
8391
8418
  // Direct match
8392
- if (changePath === identifier) {
8419
+ if (this.pathMatches(changePath, identifier)) {
8393
8420
  return true;
8394
8421
  }
8395
- // Check if the identifier has an alias that matches
8422
+ // Check if the change path is the resolved identifier or lies below it
8423
+ // (handles cases like array item changes)
8396
8424
  const resolvedIdentifier = this.resolvePathAlias(identifier);
8397
- if (resolvedIdentifier && changePath === resolvedIdentifier) {
8425
+ if (resolvedIdentifier && this.pathMatches(changePath, resolvedIdentifier, true)) {
8398
8426
  return true;
8399
8427
  }
8400
- // Check if change path starts with the resolved identifier
8401
- // (handles cases like array item changes)
8402
- if (resolvedIdentifier) {
8403
- if (changePath.startsWith(resolvedIdentifier + '.') ||
8404
- changePath.startsWith(resolvedIdentifier + '[')) {
8405
- return true;
8406
- }
8407
- }
8408
8428
  return false;
8409
8429
  }
8430
+ /**
8431
+ * Checks whether a change path names the location an identifier refers to.
8432
+ * A "[*]" index in the identifier (e.g. "items[*].name" for `items[i].name`)
8433
+ * stands for an index known only when the expression runs and matches any
8434
+ * one index or key.
8435
+ *
8436
+ * @param changePath The path that was changed (e.g., "items[2].name")
8437
+ * @param identifier The identifier to check (e.g., "items[*].name")
8438
+ * @param descendants Whether a change below the identifier also matches
8439
+ * @returns True if the change path matches the identifier
8440
+ */
8441
+ static pathMatches(changePath, identifier, descendants = false) {
8442
+ if (changePath === identifier) {
8443
+ return true;
8444
+ }
8445
+ if (!identifier.includes('[*]')) {
8446
+ return descendants && (changePath.startsWith(identifier + '.') || changePath.startsWith(identifier + '['));
8447
+ }
8448
+ const cacheKey = descendants ? identifier + ' ' : identifier;
8449
+ let pattern = this.pathPatterns.get(cacheKey);
8450
+ if (!pattern) {
8451
+ const source = identifier
8452
+ .split('[*]')
8453
+ .map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
8454
+ .join('(?:\\[[^\\]]*\\]|\\.[^.[]+)');
8455
+ pattern = new RegExp(`^${source}${descendants ? '(?:[.[].*)?' : ''}$`);
8456
+ this.pathPatterns.set(cacheKey, pattern);
8457
+ }
8458
+ return pattern.test(changePath);
8459
+ }
8410
8460
  }
8411
8461
 
8412
8462
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
@@ -8902,18 +8952,15 @@ class VBindings {
8902
8952
  * global aliases (computed properties etc.).
8903
8953
  */
8904
8954
  doesChangeMatchIdentifier(changePath, identifier) {
8905
- // Direct match
8906
- if (changePath === identifier) {
8955
+ // Direct match (an index "[*]" in the identifier matches any index)
8956
+ if (ReactiveProxy.pathMatches(changePath, identifier)) {
8907
8957
  return true;
8908
8958
  }
8909
8959
  // Resolve via local (scoped) alias chain
8910
8960
  const resolved = this.resolveAlias(identifier);
8911
8961
  if (resolved) {
8912
- if (changePath === resolved) {
8913
- return true;
8914
- }
8915
- // changePath is a descendant of resolved (e.g. "files[0].isModified" for resolved "files[0]")
8916
- if (changePath.startsWith(resolved + '.') || changePath.startsWith(resolved + '[')) {
8962
+ // changePath is resolved itself or a descendant of it (e.g. "files[0].isModified" for resolved "files[0]")
8963
+ if (ReactiveProxy.pathMatches(changePath, resolved, true)) {
8917
8964
  return true;
8918
8965
  }
8919
8966
  // changePath is an ancestor of resolved (e.g. "files" for resolved "files[0].isModified")
@@ -9978,7 +10025,7 @@ class VTextEvaluator {
9978
10025
  // Build base parameter names (no dots), preserving order of first appearance
9979
10026
  const baseArgs = [];
9980
10027
  for (const id of ids) {
9981
- const base = id.split('.')[0];
10028
+ const base = ExpressionUtils.baseIdentifier(id);
9982
10029
  if (!baseArgs.includes(base)) {
9983
10030
  baseArgs.push(base);
9984
10031
  }
@@ -12054,6 +12101,11 @@ class VHtmlDirective {
12054
12101
  * The expression evaluator for this directive.
12055
12102
  */
12056
12103
  #evaluator;
12104
+ /**
12105
+ * The HTML last set on the element. The same HTML is not set again: that
12106
+ * would replace the elements inside, and load their frames and images again.
12107
+ */
12108
+ #html;
12057
12109
  /**
12058
12110
  * @param context The context for parsing the directive.
12059
12111
  */
@@ -12104,10 +12156,14 @@ class VHtmlDirective {
12104
12156
  get dependentIdentifiers() {
12105
12157
  return identifiers;
12106
12158
  },
12107
- applyToDOM() {
12159
+ applyToDOM: () => {
12108
12160
  const element = vNode.node;
12109
- const htmlContent = evaluator.evaluate();
12110
- element.innerHTML = htmlContent ?? '';
12161
+ const htmlContent = evaluator.evaluate() ?? '';
12162
+ if (htmlContent === this.#html) {
12163
+ return;
12164
+ }
12165
+ this.#html = htmlContent;
12166
+ element.innerHTML = htmlContent;
12111
12167
  }
12112
12168
  };
12113
12169
  return updater;
@@ -12314,7 +12370,7 @@ class VIntersectionDirective {
12314
12370
  const identifiers = optionsDirective.dependentIdentifiers;
12315
12371
  const baseArgs = [];
12316
12372
  for (const id of identifiers) {
12317
- const base = id.split('.')[0];
12373
+ const base = ExpressionUtils.baseIdentifier(id);
12318
12374
  if (!baseArgs.includes(base))
12319
12375
  baseArgs.push(base);
12320
12376
  }
@@ -12394,7 +12450,7 @@ class VIntersectionDirective {
12394
12450
  // Note: inline expressions receive entries and $ctx as parameters
12395
12451
  const baseArgs = [];
12396
12452
  for (const id of identifiers) {
12397
- const base = id.split('.')[0];
12453
+ const base = ExpressionUtils.baseIdentifier(id);
12398
12454
  if (!baseArgs.includes(base))
12399
12455
  baseArgs.push(base);
12400
12456
  }
@@ -13532,7 +13588,7 @@ class VPerformanceDirective {
13532
13588
  const identifiers = optionsDirective.dependentIdentifiers;
13533
13589
  const baseArgs = [];
13534
13590
  for (const id of identifiers) {
13535
- const base = id.split('.')[0];
13591
+ const base = ExpressionUtils.baseIdentifier(id);
13536
13592
  if (!baseArgs.includes(base))
13537
13593
  baseArgs.push(base);
13538
13594
  }
@@ -13620,7 +13676,7 @@ class VPerformanceDirective {
13620
13676
  // Note: inline expressions receive entries, observer, options, and $ctx as parameters
13621
13677
  const baseArgs = [];
13622
13678
  for (const id of identifiers) {
13623
- const base = id.split('.')[0];
13679
+ const base = ExpressionUtils.baseIdentifier(id);
13624
13680
  if (!baseArgs.includes(base))
13625
13681
  baseArgs.push(base);
13626
13682
  }
@@ -13753,7 +13809,7 @@ class VResizeDirective {
13753
13809
  const identifiers = optionsDirective.dependentIdentifiers;
13754
13810
  const baseArgs = [];
13755
13811
  for (const id of identifiers) {
13756
- const base = id.split('.')[0];
13812
+ const base = ExpressionUtils.baseIdentifier(id);
13757
13813
  if (!baseArgs.includes(base))
13758
13814
  baseArgs.push(base);
13759
13815
  }
@@ -13833,7 +13889,7 @@ class VResizeDirective {
13833
13889
  // Note: inline expressions receive entries and $ctx as parameters
13834
13890
  const baseArgs = [];
13835
13891
  for (const id of identifiers) {
13836
- const base = id.split('.')[0];
13892
+ const base = ExpressionUtils.baseIdentifier(id);
13837
13893
  if (!baseArgs.includes(base))
13838
13894
  baseArgs.push(base);
13839
13895
  }