@codemirror/state 6.0.1 → 6.1.0

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,13 @@
1
+ ## 6.1.0 (2022-06-30)
2
+
3
+ ### Bug fixes
4
+
5
+ Refine change mapping to preserve insertions made by concurrent changes.
6
+
7
+ ### New features
8
+
9
+ The `enables` option to `Facet.define` may now take a function, which will be called with the facet value to create the extensions.
10
+
1
11
  ## 6.0.1 (2022-06-17)
2
12
 
3
13
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1130,51 +1130,65 @@ function iterChanges(desc, f, individual) {
1130
1130
  }
1131
1131
  }
1132
1132
  function mapSet(setA, setB, before, mkSet = false) {
1133
+ // Produce a copy of setA that applies to the document after setB
1134
+ // has been applied (assuming both start at the same document).
1133
1135
  let sections = [], insert = mkSet ? [] : null;
1134
1136
  let a = new SectionIter(setA), b = new SectionIter(setB);
1135
- for (let posA = 0, posB = 0;;) {
1136
- if (a.ins == -1) {
1137
- posA += a.len;
1138
- a.next();
1139
- }
1140
- else if (b.ins == -1 && posB < posA) {
1141
- let skip = Math.min(b.len, posA - posB);
1142
- b.forward(skip);
1143
- addSection(sections, skip, -1);
1144
- posB += skip;
1137
+ // Iterate over both sets in parallel. inserted tracks, for changes
1138
+ // in A that have to be processed piece-by-piece, whether their
1139
+ // content has been inserted already, and refers to the section
1140
+ // index.
1141
+ for (let inserted = -1;;) {
1142
+ if (a.ins == -1 && b.ins == -1) {
1143
+ // Move across ranges skipped by both sets.
1144
+ let len = Math.min(a.len, b.len);
1145
+ addSection(sections, len, -1);
1146
+ a.forward(len);
1147
+ b.forward(len);
1145
1148
  }
1146
- else if (b.ins >= 0 && (a.done || posB < posA || posB == posA && (b.len < a.len || b.len == a.len && !before))) {
1149
+ else if (b.ins >= 0 && (a.ins < 0 || inserted == a.i || a.off == 0 && (b.len < a.len || b.len == a.len && !before))) {
1150
+ // If there's a change in B that comes before the next change in
1151
+ // A (ordered by start pos, then len, then before flag), skip
1152
+ // that (and process any changes in A it covers).
1153
+ let len = b.len;
1147
1154
  addSection(sections, b.ins, -1);
1148
- while (posA > posB && !a.done && posA + a.len < posB + b.len) {
1149
- posA += a.len;
1150
- a.next();
1155
+ while (len) {
1156
+ let piece = Math.min(a.len, len);
1157
+ if (a.ins >= 0 && inserted < a.i && a.len <= piece) {
1158
+ addSection(sections, 0, a.ins);
1159
+ if (insert)
1160
+ addInsert(insert, sections, a.text);
1161
+ inserted = a.i;
1162
+ }
1163
+ a.forward(piece);
1164
+ len -= piece;
1151
1165
  }
1152
- posB += b.len;
1153
1166
  b.next();
1154
1167
  }
1155
1168
  else if (a.ins >= 0) {
1156
- let len = 0, end = posA + a.len;
1157
- for (;;) {
1158
- if (b.ins >= 0 && posB > posA && posB + b.len < end) {
1159
- len += b.ins;
1160
- posB += b.len;
1161
- b.next();
1169
+ // Process the part of a change in A up to the start of the next
1170
+ // non-deletion change in B (if overlapping).
1171
+ let len = 0, left = a.len;
1172
+ while (left) {
1173
+ if (b.ins == -1) {
1174
+ let piece = Math.min(left, b.len);
1175
+ len += piece;
1176
+ left -= piece;
1177
+ b.forward(piece);
1162
1178
  }
1163
- else if (b.ins == -1 && posB < end) {
1164
- let skip = Math.min(b.len, end - posB);
1165
- len += skip;
1166
- b.forward(skip);
1167
- posB += skip;
1179
+ else if (b.ins == 0 && b.len < left) {
1180
+ left -= b.len;
1181
+ b.next();
1168
1182
  }
1169
1183
  else {
1170
1184
  break;
1171
1185
  }
1172
1186
  }
1173
- addSection(sections, len, a.ins);
1174
- if (insert)
1187
+ addSection(sections, len, inserted < a.i ? a.ins : 0);
1188
+ if (insert && inserted < a.i)
1175
1189
  addInsert(insert, sections, a.text);
1176
- posA = end;
1177
- a.next();
1190
+ inserted = a.i;
1191
+ a.forward(a.len - left);
1178
1192
  }
1179
1193
  else if (a.done && b.done) {
1180
1194
  return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
@@ -1556,21 +1570,17 @@ class Facet {
1556
1570
  /**
1557
1571
  @internal
1558
1572
  */
1559
- compare, isStatic,
1560
- /**
1561
- @internal
1562
- */
1563
- extensions) {
1573
+ compare, isStatic, enables) {
1564
1574
  this.combine = combine;
1565
1575
  this.compareInput = compareInput;
1566
1576
  this.compare = compare;
1567
1577
  this.isStatic = isStatic;
1568
- this.extensions = extensions;
1569
1578
  /**
1570
1579
  @internal
1571
1580
  */
1572
1581
  this.id = nextID++;
1573
1582
  this.default = combine([]);
1583
+ this.extensions = typeof enables == "function" ? enables(this) : enables;
1574
1584
  }
1575
1585
  /**
1576
1586
  Define a new facet.
@@ -2712,7 +2722,7 @@ class EditorState {
2712
2722
  if (fields)
2713
2723
  for (let prop in fields) {
2714
2724
  let value = fields[prop];
2715
- if (value instanceof StateField)
2725
+ if (value instanceof StateField && this.config.address[value.id] != null)
2716
2726
  result[prop] = value.spec.toJSON(this.field(fields[prop]), this);
2717
2727
  }
2718
2728
  return result;
@@ -2729,8 +2739,10 @@ class EditorState {
2729
2739
  let fieldInit = [];
2730
2740
  if (fields)
2731
2741
  for (let prop in fields) {
2732
- let field = fields[prop], value = json[prop];
2733
- fieldInit.push(field.init(state => field.spec.fromJSON(value, state)));
2742
+ if (Object.prototype.hasOwnProperty.call(json, prop)) {
2743
+ let field = fields[prop], value = json[prop];
2744
+ fieldInit.push(field.init(state => field.spec.fromJSON(value, state)));
2745
+ }
2734
2746
  }
2735
2747
  return EditorState.create({
2736
2748
  doc: json.doc,
package/dist/index.d.ts CHANGED
@@ -505,13 +505,14 @@ declare type FacetConfig<Input, Output> = {
505
505
  */
506
506
  static?: boolean;
507
507
  /**
508
- If given, these extension(s) will be added to any state where
509
- this facet is provided. (Note that, while a facet's default
510
- value can be read from a state even if the facet wasn't present
511
- in the state at all, these extensions won't be added in that
508
+ If given, these extension(s) (or the result of calling the given
509
+ function with the facet) will be added to any state where this
510
+ facet is provided. (Note that, while a facet's default value can
511
+ be read from a state even if the facet wasn't present in the
512
+ state at all, these extensions won't be added in that
512
513
  situation.)
513
514
  */
514
- enables?: Extension;
515
+ enables?: Extension | ((self: Facet<Input, Output>) => Extension);
515
516
  };
516
517
  /**
517
518
  A facet is a labeled value that is associated with an editor
package/dist/index.js CHANGED
@@ -1125,51 +1125,65 @@ function iterChanges(desc, f, individual) {
1125
1125
  }
1126
1126
  }
1127
1127
  function mapSet(setA, setB, before, mkSet = false) {
1128
+ // Produce a copy of setA that applies to the document after setB
1129
+ // has been applied (assuming both start at the same document).
1128
1130
  let sections = [], insert = mkSet ? [] : null;
1129
1131
  let a = new SectionIter(setA), b = new SectionIter(setB);
1130
- for (let posA = 0, posB = 0;;) {
1131
- if (a.ins == -1) {
1132
- posA += a.len;
1133
- a.next();
1134
- }
1135
- else if (b.ins == -1 && posB < posA) {
1136
- let skip = Math.min(b.len, posA - posB);
1137
- b.forward(skip);
1138
- addSection(sections, skip, -1);
1139
- posB += skip;
1132
+ // Iterate over both sets in parallel. inserted tracks, for changes
1133
+ // in A that have to be processed piece-by-piece, whether their
1134
+ // content has been inserted already, and refers to the section
1135
+ // index.
1136
+ for (let inserted = -1;;) {
1137
+ if (a.ins == -1 && b.ins == -1) {
1138
+ // Move across ranges skipped by both sets.
1139
+ let len = Math.min(a.len, b.len);
1140
+ addSection(sections, len, -1);
1141
+ a.forward(len);
1142
+ b.forward(len);
1140
1143
  }
1141
- else if (b.ins >= 0 && (a.done || posB < posA || posB == posA && (b.len < a.len || b.len == a.len && !before))) {
1144
+ else if (b.ins >= 0 && (a.ins < 0 || inserted == a.i || a.off == 0 && (b.len < a.len || b.len == a.len && !before))) {
1145
+ // If there's a change in B that comes before the next change in
1146
+ // A (ordered by start pos, then len, then before flag), skip
1147
+ // that (and process any changes in A it covers).
1148
+ let len = b.len;
1142
1149
  addSection(sections, b.ins, -1);
1143
- while (posA > posB && !a.done && posA + a.len < posB + b.len) {
1144
- posA += a.len;
1145
- a.next();
1150
+ while (len) {
1151
+ let piece = Math.min(a.len, len);
1152
+ if (a.ins >= 0 && inserted < a.i && a.len <= piece) {
1153
+ addSection(sections, 0, a.ins);
1154
+ if (insert)
1155
+ addInsert(insert, sections, a.text);
1156
+ inserted = a.i;
1157
+ }
1158
+ a.forward(piece);
1159
+ len -= piece;
1146
1160
  }
1147
- posB += b.len;
1148
1161
  b.next();
1149
1162
  }
1150
1163
  else if (a.ins >= 0) {
1151
- let len = 0, end = posA + a.len;
1152
- for (;;) {
1153
- if (b.ins >= 0 && posB > posA && posB + b.len < end) {
1154
- len += b.ins;
1155
- posB += b.len;
1156
- b.next();
1164
+ // Process the part of a change in A up to the start of the next
1165
+ // non-deletion change in B (if overlapping).
1166
+ let len = 0, left = a.len;
1167
+ while (left) {
1168
+ if (b.ins == -1) {
1169
+ let piece = Math.min(left, b.len);
1170
+ len += piece;
1171
+ left -= piece;
1172
+ b.forward(piece);
1157
1173
  }
1158
- else if (b.ins == -1 && posB < end) {
1159
- let skip = Math.min(b.len, end - posB);
1160
- len += skip;
1161
- b.forward(skip);
1162
- posB += skip;
1174
+ else if (b.ins == 0 && b.len < left) {
1175
+ left -= b.len;
1176
+ b.next();
1163
1177
  }
1164
1178
  else {
1165
1179
  break;
1166
1180
  }
1167
1181
  }
1168
- addSection(sections, len, a.ins);
1169
- if (insert)
1182
+ addSection(sections, len, inserted < a.i ? a.ins : 0);
1183
+ if (insert && inserted < a.i)
1170
1184
  addInsert(insert, sections, a.text);
1171
- posA = end;
1172
- a.next();
1185
+ inserted = a.i;
1186
+ a.forward(a.len - left);
1173
1187
  }
1174
1188
  else if (a.done && b.done) {
1175
1189
  return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
@@ -1551,21 +1565,17 @@ class Facet {
1551
1565
  /**
1552
1566
  @internal
1553
1567
  */
1554
- compare, isStatic,
1555
- /**
1556
- @internal
1557
- */
1558
- extensions) {
1568
+ compare, isStatic, enables) {
1559
1569
  this.combine = combine;
1560
1570
  this.compareInput = compareInput;
1561
1571
  this.compare = compare;
1562
1572
  this.isStatic = isStatic;
1563
- this.extensions = extensions;
1564
1573
  /**
1565
1574
  @internal
1566
1575
  */
1567
1576
  this.id = nextID++;
1568
1577
  this.default = combine([]);
1578
+ this.extensions = typeof enables == "function" ? enables(this) : enables;
1569
1579
  }
1570
1580
  /**
1571
1581
  Define a new facet.
@@ -2706,7 +2716,7 @@ class EditorState {
2706
2716
  if (fields)
2707
2717
  for (let prop in fields) {
2708
2718
  let value = fields[prop];
2709
- if (value instanceof StateField)
2719
+ if (value instanceof StateField && this.config.address[value.id] != null)
2710
2720
  result[prop] = value.spec.toJSON(this.field(fields[prop]), this);
2711
2721
  }
2712
2722
  return result;
@@ -2723,8 +2733,10 @@ class EditorState {
2723
2733
  let fieldInit = [];
2724
2734
  if (fields)
2725
2735
  for (let prop in fields) {
2726
- let field = fields[prop], value = json[prop];
2727
- fieldInit.push(field.init(state => field.spec.fromJSON(value, state)));
2736
+ if (Object.prototype.hasOwnProperty.call(json, prop)) {
2737
+ let field = fields[prop], value = json[prop];
2738
+ fieldInit.push(field.init(state => field.spec.fromJSON(value, state)));
2739
+ }
2728
2740
  }
2729
2741
  return EditorState.create({
2730
2742
  doc: json.doc,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/state",
3
- "version": "6.0.1",
3
+ "version": "6.1.0",
4
4
  "description": "Editor state data structures for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",