on master help sign in
search: use Levenshtein distance algorithm
17bc14aMatilde Park
components/Search.js+4−1
@@ -5,6 +5,7 @@ import debounce from "lodash.debounce";
5import Downshift from "downshift";
5import Downshift from "downshift";
6import ob from "urbit-ob";
6import ob from "urbit-ob";
7import Sigil from "../components/Sigil";
7import Sigil from "../components/Sigil";
8+import levenSort from "leven-sort";
8
9
9class Search extends Component {
10class Search extends Component {
10 constructor(props) {
11 constructor(props) {
@@ -24,11 +25,12 @@ class Search extends Component {
24 }
25 }
25
26
26 glossarySearch(query) {
27 glossarySearch(query) {
27− return glossary.filter((entry) => {
28+ const entries = glossary.filter((entry) => {
28 return (
29 return (
29 entry.name.includes(query.toLowerCase()) || entry.symbol.includes(query)
30 entry.name.includes(query.toLowerCase()) || entry.symbol.includes(query)
30 );
31 );
31 });
32 });
33+ return levenSort(entries, query, ["symbol"]);
32 }
34 }
33
35
34 patpSearch(query) {
36 patpSearch(query) {
@@ -57,6 +59,7 @@ class Search extends Component {
57 fetch(this.searchEndpoint(query))
59 fetch(this.searchEndpoint(query))
58 .then((res) => res.json())
60 .then((res) => res.json())
59 .then((res) => {
61 .then((res) => {
62+ console.log(res);
60 // Wrap results in an object which will tell React what component to use to render results.
63 // Wrap results in an object which will tell React what component to use to render results.
61 const results = res.results.map((item) => ({
64 const results = res.results.map((item) => ({
62 type: "RESULT",
65 type: "RESULT",
package-lock.json+30
@@ -24,6 +24,7 @@
24 "gray-matter": "^4.0.3",
24 "gray-matter": "^4.0.3",
25 "html-entities": "^2.3.2",
25 "html-entities": "^2.3.2",
26 "html-react-parser": "^1.4.14",
26 "html-react-parser": "^1.4.14",
27+ "leven-sort": "^3.0.0",
27 "lodash.debounce": "^4.0.8",
28 "lodash.debounce": "^4.0.8",
28 "lodash.omit": "^4.5.0",
29 "lodash.omit": "^4.5.0",
29 "luxon": "^2.0.2",
30 "luxon": "^2.0.2",
@@ -1776,6 +1777,22 @@
1776 "graceful-fs": "^4.1.11"
1777 "graceful-fs": "^4.1.11"
1777 }
1778 }
1778 },
1779 },
1780+ "node_modules/leven": {
1781+ "version": "3.1.0",
1782+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
1783+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
1784+ "engines": {
1785+ "node": ">=6"
1786+ }
1787+ },
1788+ "node_modules/leven-sort": {
1789+ "version": "3.0.0",
1790+ "resolved": "https://registry.npmjs.org/leven-sort/-/leven-sort-3.0.0.tgz",
1791+ "integrity": "sha512-dw+6CDkFAbmXiAv/bU2IQKEJzgdXUYnc2Z4FipY9gOt+tdUUiP1R1Jn8S05aORllj5NLcKyx6zwIz+M3ygCohA==",
1792+ "dependencies": {
1793+ "leven": "^3.1.0"
1794+ }
1795+ },
1779 "node_modules/lilconfig": {
1796 "node_modules/lilconfig": {
1780 "version": "2.0.5",
1797 "version": "2.0.5",
1781 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
1798 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
@@ -4593,6 +4610,19 @@
4593 "graceful-fs": "^4.1.11"
4610 "graceful-fs": "^4.1.11"
4594 }
4611 }
4595 },
4612 },
4613+ "leven": {
4614+ "version": "3.1.0",
4615+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
4616+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="
4617+ },
4618+ "leven-sort": {
4619+ "version": "3.0.0",
4620+ "resolved": "https://registry.npmjs.org/leven-sort/-/leven-sort-3.0.0.tgz",
4621+ "integrity": "sha512-dw+6CDkFAbmXiAv/bU2IQKEJzgdXUYnc2Z4FipY9gOt+tdUUiP1R1Jn8S05aORllj5NLcKyx6zwIz+M3ygCohA==",
4622+ "requires": {
4623+ "leven": "^3.1.0"
4624+ }
4625+ },
4596 "lilconfig": {
4626 "lilconfig": {
4597 "version": "2.0.5",
4627 "version": "2.0.5",
4598 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
4628 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
package.json+1
@@ -33,6 +33,7 @@
33 "gray-matter": "^4.0.3",
33 "gray-matter": "^4.0.3",
34 "html-entities": "^2.3.2",
34 "html-entities": "^2.3.2",
35 "html-react-parser": "^1.4.14",
35 "html-react-parser": "^1.4.14",
36+ "leven-sort": "^3.0.0",
36 "lodash.debounce": "^4.0.8",
37 "lodash.debounce": "^4.0.8",
37 "lodash.omit": "^4.5.0",
38 "lodash.omit": "^4.5.0",
38 "luxon": "^2.0.2",
39 "luxon": "^2.0.2",
pages/api/search.js+5−2
@@ -1,12 +1,15 @@
1import { index } from "../../cache/data";
1import { index } from "../../cache/data";
2+const levenSort = require("leven-sort");
2
3
3export default (req, res) => {
4export default (req, res) => {
4 const results = index.filter(
5 const results = index.filter(
5 (e) =>
6 (e) =>
6 e.title?.toLowerCase().includes(req.query.q.toLowerCase()) ||
7 e.title?.toLowerCase().includes(req.query.q.toLowerCase()) ||
7− e?.slug.includes(req.query.q.toLowerCase())
8+ e?.slug.includes(req.query.q.toLowerCase()) ||
9+ e?.parent.toLowerCase().includes(req.query.q.toLowerCase())
8 );
10 );
11+ const sorted = levenSort(results, req.q, ["title", "slug", "parent"]);
9 res.statusCode = 200;
12 res.statusCode = 200;
10 res.setHeader("Content-Type", "application/json");
13 res.setHeader("Content-Type", "application/json");
11− res.end(JSON.stringify({ results }));
14+ res.end(JSON.stringify({ results: sorted }));
12};
15};