Skip to content

Commit 0eca025

Browse files
committed
Changeset: Use a generator to implement OpIter
1 parent a4aec00 commit 0eca025

File tree

1 file changed

+27
-17
lines changed

1 file changed

+27
-17
lines changed

src/static/js/Changeset.js

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,28 @@ exports.oldLen = (cs) => exports.unpack(cs).oldLen;
180180
*/
181181
exports.newLen = (cs) => exports.unpack(cs).newLen;
182182

183+
/**
184+
* Parses a string of serialized changeset operations.
185+
*
186+
* @param {string} ops - Serialized changeset operations.
187+
* @yields {Op}
188+
* @returns {Generator<Op>}
189+
*/
190+
const deserializeOps = function* (ops) {
191+
// TODO: Migrate to String.prototype.matchAll() once there is enough browser support.
192+
const regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([-+=])([0-9a-z]+)|(.)/g;
193+
let match;
194+
while ((match = regex.exec(ops)) != null) {
195+
if (match[5] === '$') return; // Start of the insert operation character bank.
196+
if (match[5] != null) error(`invalid operation: ${ops.slice(regex.lastIndex - 1)}`);
197+
const op = new Op(match[3]);
198+
op.lines = exports.parseNum(match[2] || '0');
199+
op.chars = exports.parseNum(match[4]);
200+
op.attribs = match[1];
201+
yield op;
202+
}
203+
};
204+
183205
/**
184206
* Iterator over a changeset's operations.
185207
*
@@ -190,24 +212,15 @@ class OpIter {
190212
* @param {string} ops - String encoding the change operations to iterate over.
191213
*/
192214
constructor(ops) {
193-
this._ops = ops;
194-
this._regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([-+=])([0-9a-z]+)|(.)/g;
195-
this._nextMatch = this._nextRegexMatch();
196-
}
197-
198-
_nextRegexMatch() {
199-
const match = this._regex.exec(this._ops);
200-
if (!match) return null;
201-
if (match[5] === '$') return null; // Start of the insert operation character bank.
202-
if (match[5] != null) error(`invalid operation: ${this._ops.slice(this._regex.lastIndex - 1)}`);
203-
return match;
215+
this._gen = deserializeOps(ops);
216+
this._next = this._gen.next();
204217
}
205218

206219
/**
207220
* @returns {boolean} Whether there are any remaining operations.
208221
*/
209222
hasNext() {
210-
return this._nextMatch && !!this._nextMatch[0];
223+
return !this._next.done;
211224
}
212225

213226
/**
@@ -221,11 +234,8 @@ class OpIter {
221234
*/
222235
next(opOut = new Op()) {
223236
if (this.hasNext()) {
224-
opOut.attribs = this._nextMatch[1];
225-
opOut.lines = exports.parseNum(this._nextMatch[2] || '0');
226-
opOut.opcode = this._nextMatch[3];
227-
opOut.chars = exports.parseNum(this._nextMatch[4]);
228-
this._nextMatch = this._nextRegexMatch();
237+
copyOp(this._next.value, opOut);
238+
this._next = this._gen.next();
229239
} else {
230240
clearOp(opOut);
231241
}

0 commit comments

Comments
 (0)