@codemirror/state 0.20.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/.github/workflows/dispatch.yml +1 -1
- package/CHANGELOG.md +22 -0
- package/README.md +5 -5
- package/dist/index.cjs +57 -45
- package/dist/index.d.ts +7 -14
- package/dist/index.js +57 -45
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
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
|
+
|
|
11
|
+
## 6.0.1 (2022-06-17)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Fix a problem that caused effects' `map` methods to be called with an incorrect change set when filtering changes.
|
|
16
|
+
|
|
17
|
+
## 6.0.0 (2022-06-08)
|
|
18
|
+
|
|
19
|
+
### Breaking changes
|
|
20
|
+
|
|
21
|
+
Update dependencies to 6.0.0
|
|
22
|
+
|
|
1
23
|
## 0.20.1 (2022-06-02)
|
|
2
24
|
|
|
3
25
|
### New features
|
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @codemirror/state [](https://www.npmjs.org/package/@codemirror/state)
|
|
2
2
|
|
|
3
|
-
[ [**WEBSITE**](https://codemirror.net/
|
|
3
|
+
[ [**WEBSITE**](https://codemirror.net/) | [**DOCS**](https://codemirror.net/docs/ref/#state) | [**ISSUES**](https://github.com/codemirror/dev/issues) | [**FORUM**](https://discuss.codemirror.net/c/next/) | [**CHANGELOG**](https://github.com/codemirror/state/blob/main/CHANGELOG.md) ]
|
|
4
4
|
|
|
5
5
|
This package implements the editor state data structures for the
|
|
6
|
-
[CodeMirror](https://codemirror.net/
|
|
6
|
+
[CodeMirror](https://codemirror.net/) code editor.
|
|
7
7
|
|
|
8
|
-
The [project page](https://codemirror.net/
|
|
9
|
-
number of [examples](https://codemirror.net/
|
|
10
|
-
[documentation](https://codemirror.net/
|
|
8
|
+
The [project page](https://codemirror.net/) has more information, a
|
|
9
|
+
number of [examples](https://codemirror.net/examples/) and the
|
|
10
|
+
[documentation](https://codemirror.net/docs/).
|
|
11
11
|
|
|
12
12
|
This code is released under an
|
|
13
13
|
[MIT license](https://github.com/codemirror/state/tree/main/LICENSE).
|
package/dist/index.cjs
CHANGED
|
@@ -648,10 +648,7 @@ function fromCodePoint(code) {
|
|
|
648
648
|
return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00);
|
|
649
649
|
}
|
|
650
650
|
/**
|
|
651
|
-
The
|
|
652
|
-
string. It is often useful to compare with this after calling
|
|
653
|
-
`codePointAt`, to figure out whether your character takes up 1 or
|
|
654
|
-
2 index positions.
|
|
651
|
+
The amount of positions a character takes up a JavaScript string.
|
|
655
652
|
*/
|
|
656
653
|
function codePointSize(code) { return code < 0x10000 ? 1 : 2; }
|
|
657
654
|
|
|
@@ -690,6 +687,9 @@ class ChangeDesc {
|
|
|
690
687
|
// unaffected sections, and the length of the replacement content
|
|
691
688
|
// otherwise. So an insertion would be (0, n>0), a deletion (n>0,
|
|
692
689
|
// 0), and a replacement two positive numbers.
|
|
690
|
+
/**
|
|
691
|
+
@internal
|
|
692
|
+
*/
|
|
693
693
|
constructor(
|
|
694
694
|
/**
|
|
695
695
|
@internal
|
|
@@ -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
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
b.
|
|
1143
|
-
addSection(sections,
|
|
1144
|
-
|
|
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.
|
|
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 (
|
|
1149
|
-
|
|
1150
|
-
a.
|
|
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
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
b.
|
|
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 ==
|
|
1164
|
-
|
|
1165
|
-
|
|
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
|
-
|
|
1177
|
-
a.
|
|
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.
|
|
@@ -2439,7 +2449,7 @@ function filterTransaction(tr) {
|
|
|
2439
2449
|
else {
|
|
2440
2450
|
let filtered = tr.changes.filter(result);
|
|
2441
2451
|
changes = filtered.changes;
|
|
2442
|
-
back = filtered.filtered.invertedDesc;
|
|
2452
|
+
back = filtered.filtered.mapDesc(filtered.changes).invertedDesc;
|
|
2443
2453
|
}
|
|
2444
2454
|
tr = Transaction.create(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView);
|
|
2445
2455
|
}
|
|
@@ -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
|
-
|
|
2733
|
-
|
|
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,
|
|
@@ -2791,7 +2803,7 @@ class EditorState {
|
|
|
2791
2803
|
if (i == "$")
|
|
2792
2804
|
return "$";
|
|
2793
2805
|
let n = +(i || 1);
|
|
2794
|
-
return n > insert.length ? m : insert[n - 1];
|
|
2806
|
+
return !n || n > insert.length ? m : insert[n - 1];
|
|
2795
2807
|
});
|
|
2796
2808
|
return phrase;
|
|
2797
2809
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -160,11 +160,6 @@ that doesn't store the inserted text. As such, it can't be
|
|
|
160
160
|
applied, but is cheaper to store and manipulate.
|
|
161
161
|
*/
|
|
162
162
|
declare class ChangeDesc {
|
|
163
|
-
protected constructor(
|
|
164
|
-
/**
|
|
165
|
-
@internal
|
|
166
|
-
*/
|
|
167
|
-
sections: readonly number[]);
|
|
168
163
|
/**
|
|
169
164
|
The length of the document before the change.
|
|
170
165
|
*/
|
|
@@ -510,13 +505,14 @@ declare type FacetConfig<Input, Output> = {
|
|
|
510
505
|
*/
|
|
511
506
|
static?: boolean;
|
|
512
507
|
/**
|
|
513
|
-
If given, these extension(s)
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
|
|
517
513
|
situation.)
|
|
518
514
|
*/
|
|
519
|
-
enables?: Extension;
|
|
515
|
+
enables?: Extension | ((self: Facet<Input, Output>) => Extension);
|
|
520
516
|
};
|
|
521
517
|
/**
|
|
522
518
|
A facet is a labeled value that is associated with an editor
|
|
@@ -1627,10 +1623,7 @@ respresents it (like
|
|
|
1627
1623
|
*/
|
|
1628
1624
|
declare function fromCodePoint(code: number): string;
|
|
1629
1625
|
/**
|
|
1630
|
-
The
|
|
1631
|
-
string. It is often useful to compare with this after calling
|
|
1632
|
-
`codePointAt`, to figure out whether your character takes up 1 or
|
|
1633
|
-
2 index positions.
|
|
1626
|
+
The amount of positions a character takes up a JavaScript string.
|
|
1634
1627
|
*/
|
|
1635
1628
|
declare function codePointSize(code: number): 1 | 2;
|
|
1636
1629
|
|
package/dist/index.js
CHANGED
|
@@ -644,10 +644,7 @@ function fromCodePoint(code) {
|
|
|
644
644
|
return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00);
|
|
645
645
|
}
|
|
646
646
|
/**
|
|
647
|
-
The
|
|
648
|
-
string. It is often useful to compare with this after calling
|
|
649
|
-
`codePointAt`, to figure out whether your character takes up 1 or
|
|
650
|
-
2 index positions.
|
|
647
|
+
The amount of positions a character takes up a JavaScript string.
|
|
651
648
|
*/
|
|
652
649
|
function codePointSize(code) { return code < 0x10000 ? 1 : 2; }
|
|
653
650
|
|
|
@@ -685,6 +682,9 @@ class ChangeDesc {
|
|
|
685
682
|
// unaffected sections, and the length of the replacement content
|
|
686
683
|
// otherwise. So an insertion would be (0, n>0), a deletion (n>0,
|
|
687
684
|
// 0), and a replacement two positive numbers.
|
|
685
|
+
/**
|
|
686
|
+
@internal
|
|
687
|
+
*/
|
|
688
688
|
constructor(
|
|
689
689
|
/**
|
|
690
690
|
@internal
|
|
@@ -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
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
b.
|
|
1138
|
-
addSection(sections,
|
|
1139
|
-
|
|
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.
|
|
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 (
|
|
1144
|
-
|
|
1145
|
-
a.
|
|
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
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
b.
|
|
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 ==
|
|
1159
|
-
|
|
1160
|
-
|
|
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
|
-
|
|
1172
|
-
a.
|
|
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.
|
|
@@ -2434,7 +2444,7 @@ function filterTransaction(tr) {
|
|
|
2434
2444
|
else {
|
|
2435
2445
|
let filtered = tr.changes.filter(result);
|
|
2436
2446
|
changes = filtered.changes;
|
|
2437
|
-
back = filtered.filtered.invertedDesc;
|
|
2447
|
+
back = filtered.filtered.mapDesc(filtered.changes).invertedDesc;
|
|
2438
2448
|
}
|
|
2439
2449
|
tr = Transaction.create(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView);
|
|
2440
2450
|
}
|
|
@@ -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
|
-
|
|
2727
|
-
|
|
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,
|
|
@@ -2785,7 +2797,7 @@ class EditorState {
|
|
|
2785
2797
|
if (i == "$")
|
|
2786
2798
|
return "$";
|
|
2787
2799
|
let n = +(i || 1);
|
|
2788
|
-
return n > insert.length ? m : insert[n - 1];
|
|
2800
|
+
return !n || n > insert.length ? m : insert[n - 1];
|
|
2789
2801
|
});
|
|
2790
2802
|
return phrase;
|
|
2791
2803
|
}
|