@codemirror/state 6.7.0 → 6.7.2

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 CHANGED
@@ -1,3 +1,15 @@
1
+ ## 6.7.2 (2026-08-31)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where mapping through specific types of changes could end up violating ordering and overlapping invariants.
6
+
7
+ ## 6.7.1 (2026-07-05)
8
+
9
+ ### Bug fixes
10
+
11
+ Make sure facet providers, precedence extensions, and compartment instances have the `extension` field the `Extension` type claims they have.
12
+
1
13
  ## 6.7.0 (2026-06-23)
2
14
 
3
15
  ### New features
package/dist/index.cjs CHANGED
@@ -1671,6 +1671,7 @@ class FacetProvider {
1671
1671
  }
1672
1672
  };
1673
1673
  }
1674
+ get extension() { return this; }
1674
1675
  }
1675
1676
  function compareArray(a, b, compare) {
1676
1677
  if (a.length != b.length)
@@ -1868,6 +1869,7 @@ class PrecExtension {
1868
1869
  this.inner = inner;
1869
1870
  this.prec = prec;
1870
1871
  }
1872
+ get extension() { return this; }
1871
1873
  }
1872
1874
  /**
1873
1875
  Extension compartments can be used to make a configuration
@@ -1902,6 +1904,7 @@ class CompartmentInstance {
1902
1904
  this.compartment = compartment;
1903
1905
  this.inner = inner;
1904
1906
  }
1907
+ get extension() { return this; }
1905
1908
  }
1906
1909
  class Configuration {
1907
1910
  constructor(base, compartments, dynamicSlots, address, staticValues, facets) {
@@ -2011,6 +2014,8 @@ function flatten(extension, compartments, newCompartments) {
2011
2014
  else {
2012
2015
  let content = ext.extension;
2013
2016
  if (!content)
2017
+ throw new Error(`Unrecognized extension value in extension set (${ext}).`);
2018
+ if (content == ext)
2014
2019
  throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);
2015
2020
  inner(content, prec);
2016
2021
  }
@@ -3077,7 +3082,7 @@ class Chunk {
3077
3082
  this.value = value;
3078
3083
  this.maxPoint = maxPoint;
3079
3084
  }
3080
- get length() { return this.to[this.to.length - 1]; }
3085
+ get length() { return last(this.to); }
3081
3086
  // Find the index of the given position and side. Use the ranges'
3082
3087
  // `from` pos when `end == false`, `to` when `end == true`.
3083
3088
  findIndex(pos, side, end, startAt = 0) {
@@ -3100,9 +3105,9 @@ class Chunk {
3100
3105
  if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false)
3101
3106
  return false;
3102
3107
  }
3103
- map(offset, changes) {
3108
+ map(offset, changes, basePos, baseSide, spill) {
3104
3109
  let value = [], from = [], to = [], newPos = -1, maxPoint = -1;
3105
- for (let i = 0; i < this.value.length; i++) {
3110
+ iter: for (let i = 0; i < this.value.length; i++) {
3106
3111
  let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo;
3107
3112
  if (curFrom == curTo) {
3108
3113
  let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode);
@@ -3127,9 +3132,27 @@ class Chunk {
3127
3132
  newPos = newFrom;
3128
3133
  if (val.point)
3129
3134
  maxPoint = Math.max(maxPoint, newTo - newFrom);
3130
- value.push(val);
3131
- from.push(newFrom - newPos);
3132
- to.push(newTo - newPos);
3135
+ if ((newFrom - basePos || val.startSide - baseSide) >= 0) {
3136
+ value.push(val);
3137
+ from.push(newFrom - newPos);
3138
+ to.push(newTo - newPos);
3139
+ basePos = newTo;
3140
+ baseSide = val.endSide;
3141
+ }
3142
+ else {
3143
+ if (newFrom == newTo) { // Try to reorder points to fit in here
3144
+ for (let i = value.length - 1; i > 0; i--) {
3145
+ if ((newFrom - to[i - 1] || val.startSide - value[i - 1].endSide) <= 0) {
3146
+ value.splice(i, 0, val);
3147
+ from.splice(i, 0, newFrom);
3148
+ to.splice(i, 0, newTo);
3149
+ continue iter;
3150
+ }
3151
+ }
3152
+ }
3153
+ // Otherwise, spill into a new layer
3154
+ spill(newFrom, newTo, val);
3155
+ }
3133
3156
  }
3134
3157
  return { mapped: value.length ? new Chunk(from, to, value, maxPoint) : null, pos: newPos };
3135
3158
  }
@@ -3243,6 +3266,12 @@ class RangeSet {
3243
3266
  if (changes.empty || this.isEmpty)
3244
3267
  return this;
3245
3268
  let chunks = [], chunkPos = [], maxPoint = -1;
3269
+ let spilled;
3270
+ let spill = (from, to, value) => {
3271
+ if (!spilled)
3272
+ spilled = new RangeSetBuilder();
3273
+ spilled.add(from, to, value);
3274
+ };
3246
3275
  for (let i = 0; i < this.chunk.length; i++) {
3247
3276
  let start = this.chunkPos[i], chunk = this.chunk[i];
3248
3277
  let touch = changes.touchesRange(start, start + chunk.length);
@@ -3252,7 +3281,9 @@ class RangeSet {
3252
3281
  chunkPos.push(changes.mapPos(start));
3253
3282
  }
3254
3283
  else if (touch === true) {
3255
- let { mapped, pos } = chunk.map(start, changes);
3284
+ let [prevPos, prevSide] = !chunks.length ? [-1, -1]
3285
+ : [last(chunkPos) + last(chunks).length, last(last(chunks).value).endSide];
3286
+ let { mapped, pos } = chunk.map(start, changes, prevPos, prevSide, spill);
3256
3287
  if (mapped) {
3257
3288
  maxPoint = Math.max(maxPoint, mapped.maxPoint);
3258
3289
  chunks.push(mapped);
@@ -3261,6 +3292,8 @@ class RangeSet {
3261
3292
  }
3262
3293
  }
3263
3294
  let next = this.nextLayer.map(changes);
3295
+ if (spilled)
3296
+ next = spilled.finishInner(next);
3264
3297
  return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next || RangeSet.empty, maxPoint);
3265
3298
  }
3266
3299
  /**
@@ -3402,7 +3435,7 @@ class RangeSet {
3402
3435
  static join(sets) {
3403
3436
  if (!sets.length)
3404
3437
  return RangeSet.empty;
3405
- let result = sets[sets.length - 1];
3438
+ let result = last(sets);
3406
3439
  for (let i = sets.length - 2; i >= 0; i--) {
3407
3440
  for (let layer = sets[i]; layer != RangeSet.empty; layer = layer.nextLayer)
3408
3441
  result = new RangeSet(layer.chunkPos, layer.chunk, result, Math.max(layer.maxPoint, result.maxPoint));
@@ -3414,6 +3447,7 @@ class RangeSet {
3414
3447
  The empty set of ranges.
3415
3448
  */
3416
3449
  RangeSet.empty = new RangeSet([], [], null, -1);
3450
+ function last(arr) { return arr[arr.length - 1]; }
3417
3451
  function lazySort(ranges) {
3418
3452
  if (ranges.length > 1)
3419
3453
  for (let prev = ranges[0], i = 1; i < ranges.length; i++) {
package/dist/index.js CHANGED
@@ -1668,6 +1668,7 @@ class FacetProvider {
1668
1668
  }
1669
1669
  };
1670
1670
  }
1671
+ get extension() { return this; }
1671
1672
  }
1672
1673
  function compareArray(a, b, compare) {
1673
1674
  if (a.length != b.length)
@@ -1865,6 +1866,7 @@ class PrecExtension {
1865
1866
  this.inner = inner;
1866
1867
  this.prec = prec;
1867
1868
  }
1869
+ get extension() { return this; }
1868
1870
  }
1869
1871
  /**
1870
1872
  Extension compartments can be used to make a configuration
@@ -1899,6 +1901,7 @@ class CompartmentInstance {
1899
1901
  this.compartment = compartment;
1900
1902
  this.inner = inner;
1901
1903
  }
1904
+ get extension() { return this; }
1902
1905
  }
1903
1906
  class Configuration {
1904
1907
  constructor(base, compartments, dynamicSlots, address, staticValues, facets) {
@@ -2008,6 +2011,8 @@ function flatten(extension, compartments, newCompartments) {
2008
2011
  else {
2009
2012
  let content = ext.extension;
2010
2013
  if (!content)
2014
+ throw new Error(`Unrecognized extension value in extension set (${ext}).`);
2015
+ if (content == ext)
2011
2016
  throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);
2012
2017
  inner(content, prec);
2013
2018
  }
@@ -3073,7 +3078,7 @@ class Chunk {
3073
3078
  this.value = value;
3074
3079
  this.maxPoint = maxPoint;
3075
3080
  }
3076
- get length() { return this.to[this.to.length - 1]; }
3081
+ get length() { return last(this.to); }
3077
3082
  // Find the index of the given position and side. Use the ranges'
3078
3083
  // `from` pos when `end == false`, `to` when `end == true`.
3079
3084
  findIndex(pos, side, end, startAt = 0) {
@@ -3096,9 +3101,9 @@ class Chunk {
3096
3101
  if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false)
3097
3102
  return false;
3098
3103
  }
3099
- map(offset, changes) {
3104
+ map(offset, changes, basePos, baseSide, spill) {
3100
3105
  let value = [], from = [], to = [], newPos = -1, maxPoint = -1;
3101
- for (let i = 0; i < this.value.length; i++) {
3106
+ iter: for (let i = 0; i < this.value.length; i++) {
3102
3107
  let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo;
3103
3108
  if (curFrom == curTo) {
3104
3109
  let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode);
@@ -3123,9 +3128,27 @@ class Chunk {
3123
3128
  newPos = newFrom;
3124
3129
  if (val.point)
3125
3130
  maxPoint = Math.max(maxPoint, newTo - newFrom);
3126
- value.push(val);
3127
- from.push(newFrom - newPos);
3128
- to.push(newTo - newPos);
3131
+ if ((newFrom - basePos || val.startSide - baseSide) >= 0) {
3132
+ value.push(val);
3133
+ from.push(newFrom - newPos);
3134
+ to.push(newTo - newPos);
3135
+ basePos = newTo;
3136
+ baseSide = val.endSide;
3137
+ }
3138
+ else {
3139
+ if (newFrom == newTo) { // Try to reorder points to fit in here
3140
+ for (let i = value.length - 1; i > 0; i--) {
3141
+ if ((newFrom - to[i - 1] || val.startSide - value[i - 1].endSide) <= 0) {
3142
+ value.splice(i, 0, val);
3143
+ from.splice(i, 0, newFrom);
3144
+ to.splice(i, 0, newTo);
3145
+ continue iter;
3146
+ }
3147
+ }
3148
+ }
3149
+ // Otherwise, spill into a new layer
3150
+ spill(newFrom, newTo, val);
3151
+ }
3129
3152
  }
3130
3153
  return { mapped: value.length ? new Chunk(from, to, value, maxPoint) : null, pos: newPos };
3131
3154
  }
@@ -3239,6 +3262,12 @@ class RangeSet {
3239
3262
  if (changes.empty || this.isEmpty)
3240
3263
  return this;
3241
3264
  let chunks = [], chunkPos = [], maxPoint = -1;
3265
+ let spilled;
3266
+ let spill = (from, to, value) => {
3267
+ if (!spilled)
3268
+ spilled = new RangeSetBuilder();
3269
+ spilled.add(from, to, value);
3270
+ };
3242
3271
  for (let i = 0; i < this.chunk.length; i++) {
3243
3272
  let start = this.chunkPos[i], chunk = this.chunk[i];
3244
3273
  let touch = changes.touchesRange(start, start + chunk.length);
@@ -3248,7 +3277,9 @@ class RangeSet {
3248
3277
  chunkPos.push(changes.mapPos(start));
3249
3278
  }
3250
3279
  else if (touch === true) {
3251
- let { mapped, pos } = chunk.map(start, changes);
3280
+ let [prevPos, prevSide] = !chunks.length ? [-1, -1]
3281
+ : [last(chunkPos) + last(chunks).length, last(last(chunks).value).endSide];
3282
+ let { mapped, pos } = chunk.map(start, changes, prevPos, prevSide, spill);
3252
3283
  if (mapped) {
3253
3284
  maxPoint = Math.max(maxPoint, mapped.maxPoint);
3254
3285
  chunks.push(mapped);
@@ -3257,6 +3288,8 @@ class RangeSet {
3257
3288
  }
3258
3289
  }
3259
3290
  let next = this.nextLayer.map(changes);
3291
+ if (spilled)
3292
+ next = spilled.finishInner(next);
3260
3293
  return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next || RangeSet.empty, maxPoint);
3261
3294
  }
3262
3295
  /**
@@ -3398,7 +3431,7 @@ class RangeSet {
3398
3431
  static join(sets) {
3399
3432
  if (!sets.length)
3400
3433
  return RangeSet.empty;
3401
- let result = sets[sets.length - 1];
3434
+ let result = last(sets);
3402
3435
  for (let i = sets.length - 2; i >= 0; i--) {
3403
3436
  for (let layer = sets[i]; layer != RangeSet.empty; layer = layer.nextLayer)
3404
3437
  result = new RangeSet(layer.chunkPos, layer.chunk, result, Math.max(layer.maxPoint, result.maxPoint));
@@ -3410,6 +3443,7 @@ class RangeSet {
3410
3443
  The empty set of ranges.
3411
3444
  */
3412
3445
  RangeSet.empty = /*@__PURE__*/new RangeSet([], [], null, -1);
3446
+ function last(arr) { return arr[arr.length - 1]; }
3413
3447
  function lazySort(ranges) {
3414
3448
  if (ranges.length > 1)
3415
3449
  for (let prev = ranges[0], i = 1; i < ranges.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/state",
3
- "version": "6.7.0",
3
+ "version": "6.7.2",
4
4
  "description": "Editor state data structures for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",