mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-21 05:17:43 +00:00
refactor(common/models): convert traversal.children method to return array
This commit is contained in:
parent
23ffec0c26
commit
04d74fa9fa
3 changed files with 35 additions and 28 deletions
|
|
@ -160,10 +160,12 @@ export class TrieTraversal implements LexiconTraversal {
|
|||
}
|
||||
}
|
||||
|
||||
*children(): Generator<{char: USVString, traversal: () => LexiconTraversal}> {
|
||||
children(): {char: USVString, p: number, traversal: () => LexiconTraversal}[] {
|
||||
let root = this.root;
|
||||
const totalWeight = this.totalWeight;
|
||||
|
||||
const results: {char: USVString, p: number, traversal: () => LexiconTraversal}[] = [];
|
||||
|
||||
// Sorts _just_ the current level, and only if needed.
|
||||
// We only care about sorting parts that we're actually accessing.
|
||||
sortNode(root, true);
|
||||
|
|
@ -183,21 +185,26 @@ export class TrieTraversal implements LexiconTraversal {
|
|||
let internalNode = entryNode;
|
||||
for(let lowSurrogate of internalNode.values) {
|
||||
let prefix = this.prefix + entry + lowSurrogate;
|
||||
yield {
|
||||
results.push({
|
||||
char: entry + lowSurrogate,
|
||||
p: internalNode.children[lowSurrogate].weight / totalWeight,
|
||||
traversal: function() { return new TrieTraversal(internalNode.children[lowSurrogate], prefix, totalWeight) }
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Determine how much of the 'leaf' entry has no Trie nodes, emulate them.
|
||||
// No deduplication needed. If there were multiple keys available,
|
||||
// we wouldn't be in a leaf node.
|
||||
let fullText = entryNode.entries[0].key;
|
||||
entry = entry + fullText[this.prefix.length + 1]; // The other half of the non-BMP char.
|
||||
let prefix = this.prefix + entry;
|
||||
|
||||
yield {
|
||||
const weight = entryNode.entries.reduce((best, current) => Math.max(best, current.weight), 0);
|
||||
|
||||
results.push({
|
||||
char: entry,
|
||||
p: weight / totalWeight,
|
||||
traversal: function () {return new TrieTraversal(entryNode, prefix, totalWeight)}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if(isSentinel(entry)) {
|
||||
continue;
|
||||
|
|
@ -206,34 +213,41 @@ export class TrieTraversal implements LexiconTraversal {
|
|||
continue;
|
||||
} else {
|
||||
let prefix = this.prefix + entry;
|
||||
yield {
|
||||
results.push({
|
||||
char: entry,
|
||||
p: entryNode.weight / totalWeight,
|
||||
traversal: function() { return new TrieTraversal(entryNode, prefix, totalWeight)}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return results;
|
||||
} else { // type == 'leaf'
|
||||
let prefix = this.prefix;
|
||||
|
||||
// No actual deduplication needed. If there were multiple keys available,
|
||||
// we wouldn't be in a leaf node.
|
||||
let children = root.entries.filter(function(entry) {
|
||||
return entry.key != prefix && prefix.length < entry.key.length;
|
||||
})
|
||||
});
|
||||
|
||||
for(let {key} of children) {
|
||||
let weight = children.reduce((best, current) => Math.max(current.weight, best), 0);
|
||||
|
||||
if(children.length > 0) {
|
||||
const key = children[0].content;
|
||||
let nodeKey = key[prefix.length];
|
||||
|
||||
if(isHighSurrogate(nodeKey)) {
|
||||
// Merge the other half of an SMP char in!
|
||||
nodeKey = nodeKey + key[prefix.length+1];
|
||||
}
|
||||
yield {
|
||||
results.push({
|
||||
char: nodeKey,
|
||||
p: weight / totalWeight,
|
||||
traversal: function() { return new TrieTraversal(root, prefix + nodeKey, totalWeight)}
|
||||
}
|
||||
});
|
||||
};
|
||||
return;
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,15 +174,13 @@ describe('Trie traversal abstractions', function() {
|
|||
do {
|
||||
assert.isNotEmpty(leafChildSequence);
|
||||
|
||||
let iter = curChild.traversal().children();
|
||||
let curr = iter.next();
|
||||
curChild = curr.value;
|
||||
let children = curChild.traversal().children();
|
||||
assert.equal(children.length, 1);
|
||||
curChild = children[0];
|
||||
|
||||
// Test generator behavior - there should be one child, then the 'done' state.
|
||||
assert.isDefined(curChild);
|
||||
assert.equal(curChild.char, leafChildSequence[0]);
|
||||
curr = iter.next();
|
||||
assert.isTrue(curr.done);
|
||||
|
||||
// Prepare for iteration.
|
||||
leafChildSequence.shift();
|
||||
|
|
@ -275,15 +273,13 @@ describe('Trie traversal abstractions', function() {
|
|||
do {
|
||||
assert.isNotEmpty(leafChildSequence);
|
||||
|
||||
let iter = curChild.traversal().children();
|
||||
let curr = iter.next();
|
||||
curChild = curr.value;
|
||||
let children = curChild.traversal().children();
|
||||
assert.equal(children.length, 1);
|
||||
curChild = children[0];
|
||||
|
||||
// Test generator behavior - there should be one child, then the 'done' state.
|
||||
assert.isDefined(curChild);
|
||||
assert.equal(curChild.char, leafChildSequence[0]);
|
||||
curr = iter.next();
|
||||
assert.isTrue(curr.done);
|
||||
|
||||
// Prepare for iteration.
|
||||
leafChildSequence.shift();
|
||||
|
|
@ -337,9 +333,6 @@ describe('Trie traversal abstractions', function() {
|
|||
// Just to be sure our utility function is working right.
|
||||
assert.equal(smpA + smpP + 'pl' + smpE, "𝖺𝗉pl𝖾");
|
||||
|
||||
let pKeys = ['p', smpP];
|
||||
let leafChildSequence = ['l', smpE];
|
||||
|
||||
const aNode = rootTraversal.child(smpA);
|
||||
assert.isOk(aNode);
|
||||
assert.isNotOk(rootTraversal.child('a'));
|
||||
|
|
|
|||
2
common/models/types/index.d.ts
vendored
2
common/models/types/index.d.ts
vendored
|
|
@ -67,7 +67,7 @@ declare interface LexiconTraversal {
|
|||
* - If `char` = 'e', the child represents a prefix of 'the'.
|
||||
* - Then `traversal` allows traversing the part of the lexicon prefixed by 'the'.
|
||||
*/
|
||||
children(): Generator<{char: USVString, traversal: () => LexiconTraversal}>;
|
||||
children(): {char: USVString, p: number, traversal: () => LexiconTraversal}[];
|
||||
|
||||
/**
|
||||
* Allows direct access to the traversal state that results when appending one
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue