UNPKG

@discoveryjs/discovery

Version:

Frontend framework for rapid data (JSON) analysis, shareable serverless reports and dashboards

93 lines (92 loc) 2.86 kB
const lastQuerySuggestionsStat = /* @__PURE__ */ new WeakMap(); const typeOrder = ["variable", "property", "value", "assertion", "method"]; const sortByType = (a, b) => typeOrder.indexOf(a.type) - typeOrder.indexOf(b.type); const suggestionValueFilter = (pattern) => { const patternLowerCased = pattern.toLowerCase(); return (value) => value !== pattern && // 2022-04-08 // v8: includes() is 20-30% slower than indexOf() !== -1 // Firefox & Safari approximate the same (typeof value === "string" ? value : String(value)).toLowerCase().indexOf(patternLowerCased) !== -1; }; function stringifyValue(value, text) { if (typeof value !== "string") { return String(value); } value = JSON.stringify(value); if (text[0] !== "'") { return value; } return `'${value.slice(1, -1).replace( /\\.|'/g, (m) => m === '\\"' ? '"' : m === "'" ? "\\'" : m )}'`; } function isSameSuggestions(api, pos1, pos2) { if (pos1 === pos2) { return true; } const ranges1 = api.stat(pos1) || []; const ranges2 = api.stat(pos2) || []; if (ranges1.length !== ranges2.length) { return false; } for (let i = 0; i < ranges1.length; i++) { const range1 = ranges1[i]; const range2 = ranges2[i]; for (const key of Object.keys(range1)) { if (range1[key] !== range2[key]) { return false; } } } return true; } export function querySuggestions(host, query, offset, data, context) { try { let stat = lastQuerySuggestionsStat.get(host); if (!stat || stat.query !== query || stat.data !== data || stat.context !== context) { const options = { tolerant: true, stat: true }; lastQuerySuggestionsStat.set(host, stat = { query, data, context, offset: -1, suggestions: null, api: null }); stat.api = host.queryFnFromString(query, options)(data, context); } if (stat.api === null) { return null; } if (stat.offset !== -1 && isSameSuggestions(stat.api, stat.offset, offset)) { return stat.suggestions; } const suggestionsByType = stat.api.suggestion(stat.offset = offset, { sort: true, filter: suggestionValueFilter, limit: 50 }); if (suggestionsByType) { stat.suggestions = []; for (const entry of suggestionsByType.sort(sortByType)) { stat.suggestions.push(...entry.suggestions.map((value) => ({ type: entry.type, from: entry.from, to: entry.to, text: entry.text, value: entry.type === "value" ? stringifyValue(value, entry.text) : value }))); } } else { stat.suggestions = null; } return stat.suggestions; } catch (e) { host.logger.error("Error while attempting to retrieve suggestions for the query:", e.message); return null; } }