UNPKG

elliptical

Version:

Interactive natural-language interfaces

266 lines (220 loc) 7.3 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.match = match; exports.nullMatch = nullMatch; exports.beginningMatch = beginningMatch; exports.anywhereMatch = anywhereMatch; exports.fuzzyMatch = fuzzyMatch; var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _escapeStringRegexp = require('escape-string-regexp'); var _escapeStringRegexp2 = _interopRequireDefault(_escapeStringRegexp); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // returns a `words` object if its a match, else null function match(_ref) { var input = _ref.input; var text = _ref.text; var strategy = _ref.strategy; var nullInput = nullMatch({ input: input, text: text }); if (nullInput) return nullInput; var inputLower = _lodash2.default.deburr(input.toLowerCase()); var textLower = _lodash2.default.deburr(text.toLowerCase()); var beginning = beginningMatch({ input: input, text: text, inputLower: inputLower, textLower: textLower }); if (beginning) return beginning; if (strategy === 'contain' || strategy === 'fuzzy') { var anywhere = anywhereMatch({ input: input, text: text, inputLower: inputLower, textLower: textLower }); if (anywhere) return anywhere; } if (strategy === 'fuzzy') { var fuzzy = fuzzyMatch({ input: input, text: text, inputLower: inputLower, textLower: textLower }); if (fuzzy) return fuzzy; } } function nullMatch(_ref2) { var input = _ref2.input; var text = _ref2.text; if (input == null) { return { words: [{ text: text, input: false }], remaining: null, score: 1 }; } } function partialBeginningMatch(_ref3) { var input = _ref3.input; var text = _ref3.text; var inputLower = _ref3.inputLower; var textLower = _ref3.textLower; if (_lodash2.default.startsWith(inputLower, textLower)) { return { words: [{ text: text, input: true }], remaining: input.substring(text.length), score: 1 }; } } function fullBeginningMatch(_ref4) { var input = _ref4.input; var text = _ref4.text; var inputLower = _ref4.inputLower; var textLower = _ref4.textLower; if (_lodash2.default.startsWith(textLower, inputLower)) { var words = []; if (input.length > 0) { words.push({ text: text.substring(0, input.length), input: true }); } if (text.length > input.length) { words.push({ text: text.substring(input.length), input: false }); } return { words: words, remaining: null, score: 1 }; } } function beginningMatch(_ref5) { var input = _ref5.input; var text = _ref5.text; var inputLower = _ref5.inputLower; var textLower = _ref5.textLower; var partialBeginning = partialBeginningMatch({ input: input, text: text, inputLower: inputLower, textLower: textLower }); if (partialBeginning) return partialBeginning; var fullBeginning = fullBeginningMatch({ input: input, text: text, inputLower: inputLower, textLower: textLower }); if (fullBeginning) return fullBeginning; } function anywhereMatch(_ref6) { var input = _ref6.input; var text = _ref6.text; var inputLower = _ref6.inputLower; var textLower = _ref6.textLower; var index = textLower.indexOf(inputLower); if (index > -1) { var words = []; var endIndex = index + input.length; if (index > 0) { words.push({ text: text.slice(0, index), input: false }); } words.push({ text: text.slice(index, endIndex), input: true }); if (endIndex <= text.length - 1) { words.push({ text: text.slice(endIndex), input: false }); } return { words: words, remaining: null, score: 1 - index / (2 * text.length) }; } return null; } function regexSplit(text) { return _lodash2.default.map(text.split(''), _escapeStringRegexp2.default); } function acronymMatches(_ref7) { var inputLower = _ref7.inputLower; var text = _ref7.text; if (_lodash2.default.includes(text, ' ')) { var chars = regexSplit(inputLower); var fuzzyString = chars.reduce(function (a, b) { return a + '(.*(?:\\s|^))(' + b + ')'; }, '^') + '(.*)$'; var fuzzyRegex = new RegExp(fuzzyString, 'i'); var matches = text.match(fuzzyRegex); if (matches) { return { score: 0.5, matches: matches }; } } } function capitalMatches(_ref8) { var inputLower = _ref8.inputLower; var text = _ref8.text; if (/[A-Z]/.test(text)) { var chars = regexSplit(inputLower); var fuzzyString = chars.reduce(function (a, b) { var bUpper = b.toUpperCase(); return a + '([^' + bUpper + ']*)(' + bUpper + ')'; }, '^') + '(.*)$'; var fuzzyRegex = new RegExp(fuzzyString); var matches = text.match(fuzzyRegex); if (matches) { return { score: 0.4, matches: matches }; } } } function trueFuzzyMatches(_ref9) { var inputLower = _ref9.inputLower; var text = _ref9.text; var chars = regexSplit(inputLower); var fuzzyString = chars.reduce(function (a, b) { return a + '([^' + b + ']*)(' + b + ')'; }, '^') + '(.*)$'; var fuzzyRegex = new RegExp(fuzzyString, 'i'); var matches = text.match(fuzzyRegex); if (matches) { return { score: 0.3 * (1 / matches.length), matches: matches }; } } function fuzzyMatch(_ref10) { var input = _ref10.input; var text = _ref10.text; var inputLower = _ref10.inputLower; var textLower = _ref10.textLower; var _ref11 = acronymMatches({ inputLower: inputLower, text: text }) || capitalMatches({ inputLower: inputLower, text: text }) || trueFuzzyMatches({ inputLower: inputLower, text: text }) || {}; var score = _ref11.score; var matches = _ref11.matches; if (matches) { var words = []; for (var i = 1, l = matches.length; i < l; i++) { if (matches[i].length > 0) { words.push({ text: matches[i], input: i % 2 === 0 }); } } return { words: words, remaining: null, score: score }; } return null; } // export function * sort (input, items) { // let itemSet = _.map(items, item => ({item, matched: false})) // // for (let [func, score] of [[beginningMatch, 1], [anywhereMatch, 0.5]]) { // yield * sortFunction({input, itemSet, func, score}) // } // } // // function * sortFunction ({input, itemSet, func, score}) { // for (let obj of itemSet) { // if (!obj.matched) { // const words = func({input, text: obj.item.text, qualifier: obj.item.qualifier}) // if (words) { // obj.matched = true // _.forEach(words, word => word.descriptor = obj.item.descriptor) // yield {words, result: obj.item.value, score} // } // } // } // } // // escape special characters, and wrap in parens (for matching) // function regexEscape (str) { // return `(${str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/, '\\$&')})` // } // function beginningMatch ({input, text, qualifier}) { // if (_.startsWith(text.toLowerCase(), input.toLowerCase())) { // const matches = [{text: text.slice(0, input.length), input: true, qualifier}] // if (input.length < text.length) { // matches.push({text: text.slice(input.length), input: false, qualifier}) // } // return matches // } // return null // }