All files suggestion.ts

38.78% Statements 19/49
14.29% Branches 2/14
55.56% Functions 5/9
48.65% Lines 18/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101  4x                         4x 43x 43x   43x 43x     4x       4x       4x 2x 2x   2x     4x                               4x                                                                             4x 45x 53x         4x  
import { Word, SuggestedPattern } from './types'
import { isWord } from './typegaurds'
 
/**
 * <p align="center"> 
 *   <img src="https://web.archive.org/web/20090729035015/http://www.geocities.com/pskashyap/floppy.gif">
 *   <img src="https://web.archive.org/web/20090729035015/http://www.geocities.com/pskashyap/floppy.gif">
 *   <img src="https://web.archive.org/web/20090729035015/http://www.geocities.com/pskashyap/floppy.gif">
 * </p>
 *
 * A `Suggestion` represents a single result matching the input provided to [[Scope.suggest|suggest]].
 * It consists of a sequence of [[Suggestion.tokens|tokens]] which form a suggested pattern.
 * 
 */
export class Suggestion {
    public rank: number = 0
    private _simplified: Word[] = []
 
    constructor(public tokens: SuggestedPattern) {
        this._simplify()
    }
 
    get simplified(): Word[] {
        return this._simplified
    }
 
    get length(): number {
        return this.tokens.length
    }
 
    public concat(suggestion: Suggestion): Suggestion {
        this.tokens = this.tokens.concat(suggestion.tokens)
        this._simplify()
 
        return this
    }
 
    public splice(offset: number, tokens: Word[]): Suggestion {
        if (offset === -1) offset = this.tokens.length
        this.tokens = [...this.tokens.slice(0, offset), ...tokens, ...this.tokens.slice(offset)]
        this._simplify()
 
        return this
    }
 
    /**
     * Given a sequence of offset tokens and a range, `n`, to resolve, this method
     * will resolve the next `n` contiguous lookups which occur after the provided
     * offset tokens. If the last token in the offset tokens is a substring of the
     * token at that offset in this suggestion, then no further resolution will occur.
     * This is mean to only resolve sequences of contiguous lookups occuring directly
     * after the final offset token if the final offset token completes a word suggestion.
     */
    public resolveLookups(offsetTokens: Word[], n: number): Suggestion[] {
        const offset = offsetTokens.length
 
        if (n === 0) return [this]
 
        if (this.tokens.length < offset) return [this]
 
        // does the final offset token equal the word at that index in the suggestion?
        // if not, do not proceed.
        if (offsetTokens[offset - 1] !== this.tokens[offset - 1]) return [this]
 
        // if the next token is a word (and not a lookup), do not proceed.
        if (isWord(this.tokens[offset])) return [this]
 
        // okay, the next token is a lookup
 
        let suggestions: Suggestion[] = []
 
        // iterate over each context of a lookup token.
        for (const context of Object.values(this.tokens[offset])[0]) {
            for (const suggestion of context.completePattern([])) {
                // splice the new suggestion with the pre-existing suggestion
                // (effectively expanding the next lookup)
                suggestion
                    .splice(0, offsetTokens)
                    .splice(-1, this.tokens.slice(offset + 1))
 
                // is the next token a word? if so, resolve
                if (isWord(suggestion.tokens[offset])) {
                    suggestions = suggestions.concat(suggestion.resolveLookups(suggestion.tokens.slice(0, offset + 1), n - 1))
                } else {
                    suggestions = suggestions.concat(suggestion.resolveLookups(offsetTokens, n))
                }
            }
        }
 
        return suggestions
    }
 
    private _simplify() {
        this._simplified = this.tokens.map(t => {
            return isWord(t)
                ? t
                : `[${Object.keys(t)[0]}]` // TODO make delimeters configurable
        })
    }
}