UNPKG

typedoc

Version:

Create api documentation for TypeScript projects.

85 lines (84 loc) 2.86 kB
import { DefaultMap } from "./map.js"; /** Count the number of times `search` appears in `text` */ export function countMatches(text, search) { let count = 0; let last = 0; for (;;) { const index = text.indexOf(search, last); if (index === -1) { break; } else { last = index + 1; ++count; } } return count; } export function dedent(text) { const lines = text.split(/\r?\n/); while (lines.length && lines[0].search(/\S/) === -1) { lines.shift(); } while (lines.length && lines[lines.length - 1].search(/\S/) === -1) { lines.pop(); } const minIndent = lines.reduce((indent, line) => line.length ? Math.min(indent, line.search(/\S/)) : indent, Infinity); return lines.map((line) => line.substring(minIndent)).join("\n"); } // Based on https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows // Slightly modified for improved match results for options export function editDistance(s, t) { if (s.length < t.length) return editDistance(t, s); let v0 = Array.from({ length: t.length + 1 }, (_, i) => i); let v1 = Array.from({ length: t.length + 1 }, () => 0); for (let i = 0; i < s.length; i++) { v1[0] = i + 1; for (let j = 0; j < s.length; j++) { const deletionCost = v0[j + 1] + 1; const insertionCost = v1[j] + 1; let substitutionCost; if (s[i] === t[j]) { substitutionCost = v0[j]; } else if (s[i]?.toUpperCase() === t[j]?.toUpperCase()) { substitutionCost = v0[j] + 1; } else { substitutionCost = v0[j] + 3; } v1[j + 1] = Math.min(deletionCost, insertionCost, substitutionCost); } [v0, v1] = [v1, v0]; } return v0[t.length]; } export function getSimilarValues(values, compareTo) { const results = new DefaultMap(() => []); let lowest = Infinity; for (const name of values) { const distance = editDistance(compareTo, name); lowest = Math.min(lowest, distance); results.get(distance).push(name); } // Experimenting a bit, it seems an edit distance of 3 is roughly the // right metric for relevant "similar" results without showing obviously wrong suggestions return results .get(lowest) .concat(results.get(lowest + 1), results.get(lowest + 2)); } // From MDN export function escapeRegExp(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } const htmlEscapes = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;", }; export function escapeHtml(html) { return html.replace(/[&<>'"]/g, (c) => htmlEscapes[c]); }