{"id":19306708,"url":"https://github.com/drashland/moogle","last_synced_at":"2025-07-27T14:45:13.012Z","repository":{"id":37011838,"uuid":"348502242","full_name":"drashland/moogle","owner":"drashland","description":"An easy way to \"Google\" your \"Map\" using search terms. Works in Node, Deno, and the browser.","archived":false,"fork":false,"pushed_at":"2024-05-02T00:33:37.000Z","size":75,"stargazers_count":3,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-01T08:07:24.160Z","etag":null,"topics":["browser","deno","javscript","node","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drashland.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-16T21:54:19.000Z","updated_at":"2023-02-04T13:20:58.000Z","dependencies_parsed_at":"2023-12-22T03:08:19.502Z","dependency_job_id":"ec80effa-acf3-44ad-8236-b0dbf502732d","html_url":"https://github.com/drashland/moogle","commit_stats":{"total_commits":68,"total_committers":6,"mean_commits":"11.333333333333334","dds":0.5735294117647058,"last_synced_commit":"473a793e7259f81eb4b441084b886fc448eceb73"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/drashland/moogle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drashland%2Fmoogle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drashland%2Fmoogle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drashland%2Fmoogle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drashland%2Fmoogle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drashland","download_url":"https://codeload.github.com/drashland/moogle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drashland%2Fmoogle/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267372487,"owners_count":24076781,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","deno","javscript","node","typescript"],"created_at":"2024-11-10T00:07:42.395Z","updated_at":"2025-07-27T14:45:12.965Z","avatar_url":"https://github.com/drashland.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003c!--\u003cimg height=\"200\" src=\"./logo.svg\" alt=\"Moogle logo\"\u003e--\u003e\n  \u003ch1 align=\"center\"\u003eMoogle\u003c/h1\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003eAn easy way to \"Google\" your \"Map\" using search terms.\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/drashland/moogle/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/release/drashland/moogle.svg?color=bright_green\u0026label=latest\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/drashland/moogle/actions\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/workflow/status/drashland/moogle/Main?label=ci\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://discord.gg/SgejNXq\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/chat-on%20discord-blue\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://twitter.com/drash_land\"\u003e\n    \u003cimg src=\"https://img.shields.io/twitter/url?label=%40drash_land\u0026style=social\u0026url=https%3A%2F%2Ftwitter.com%2Fdrash_land\"\u003e\n  \u003c/a\u003e\n  \u003c!-- \u003ca href=\"https://rb.gy/vxmeed\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Tutorials-YouTube-red\"\u003e\n  \u003c/a\u003e --\u003e\n\u003c/p\u003e\n\n---\n\n## Quickstart\n\nMoogle works in Node, Deno, and in the browser. Follow the appropriate\nquickstart guide below to get started quickly. We have quickstart guides for:\n\n- Node - JavaScript\n- Node - TypeScript\n- Deno - JavaScript\n- Deno - TypeScript\n- Browser\n\n### Quickstart: Node - JavaScript\n\n1. Initialize your project as a Node project.\n\n   ```shell\n   $ npm init -y\n   ```\n\n   _Note: `-y` skips all of the prompts._\n\n2. Install Moogle.\n\n   ```\n   $ npm install @drashland/moogle\n   ```\n\n3. Create your `app.js` file.\n\n   ```javascript\n   const { Moogle } = require(\"@drashland/moogle\");\n   const service = new Moogle();\n   service.addItem([\"hello\"], \"world\");\n\n   console.log(service.search(\"hel\"));\n   ```\n\n4. Run your `app.js` file.\n\n   ```shell\n   $ node app.js\n   ```\n\n   You should see the following output:\n\n   ```\n   Map(1) {\n     0 =\u003e { id: 0, item: 'world', searchTerm: 'hello', searchInput: 'hel' }\n   }\n   ```\n\n### Quickstart: Node - TypeScript\n\n1. Initialize your project as a Node project.\n\n   ```shell\n   $ npm init -y\n   ```\n\n   _Note: `-y` skips all of the prompts._\n\n2. Install Moogle, TypeScript, and `ts-node`.\n\n   ```\n   $ npm install @drashland/moogle\n   $ npm install typescript\n   $ npm install --global ts-node\n   ```\n\n3. Create your `app.ts` file.\n\n   ```typescript\n   import { Moogle } from \"@drashland/moogle\";\n   const serviceWithoutTypes = new Moogle();\n   // Or use the following syntax to specify a type (in this case, it's a string)\n   // const serviceWithTypes = new Moogle\u003cstring\u003e();\n   serviceWithoutTypes.addItem([\"hello\"], \"world\");\n\n   console.log(serviceWithoutTypes.search(\"hel\"));\n   ```\n\n4. Run your `app.ts` file.\n\n   ```shell\n   $ ts-node app.ts\n   ```\n\n   You should see the following output:\n\n   ```\n   Map(1) {\n     0 =\u003e { id: 0, item: 'world', searchTerm: 'hello', searchInput: 'hel' }\n   }\n   ```\n\n### Quickstart: Deno - JavaScript\n\n1. Create your `app.js` file.\n\n   ```javascript\n   import { Moogle } from \"https://unpkg.com/@drashland/moogle@1.0.0/lib/esm/Moogle.js\";\n   const service = new Moogle();\n   service.addItem([\"hello\"], \"world\");\n\n   console.log(service.search(\"hel\"));\n   ```\n\n2. Run your `app.js` file.\n\n   ```shell\n   $ deno run app.js\n   ```\n\n   You should see the following output:\n\n   ```\n   Map(1) {\n     0 =\u003e { id: 0, item: 'world', searchTerm: 'hello', searchInput: 'hel' }\n   }\n   ```\n\n### Quickstart: Deno - TypeScript\n\n1. Create your `app.ts` file.\n\n   ```typescript\n   import { Moogle } from \"https://deno.land/x/moogle@v1.0.0/mod.ts\";\n   const serviceWithoutTypes = new Moogle();\n   // Or use the following syntax to specify a type (in this case, it's a string)\n   // const serviceWithTypes = new Moogle\u003cstring\u003e();\n   serviceWithoutTypes.addItem([\"hello\"], \"world\");\n\n   console.log(serviceWithoutTypes.search(\"hel\"));\n   ```\n\n2. Run your `app.ts` file.\n\n   ```shell\n   $ deno run app.ts\n   ```\n\n   You should see the following output:\n\n   ```\n   Map(1) {\n     0 =\u003e { id: 0, item: 'world', searchTerm: 'hello', searchInput: 'hel' }\n   }\n   ```\n\n### Quickstart: Browser\n\n1. Create your `index.html` file.\n\n   ```html\n   \u003c!doctype html\u003e\n   \u003chtml\u003e\n     \u003chead\u003e\n       \u003ctitle\u003eMoogle\u003c/title\u003e\n     \u003c/head\u003e\n     \u003cbody\u003e\n       \u003cp\u003eOpen up your console to see Moogle working.\u003c/p\u003e\n       \u003cscript type=\"module\"\u003e\n         import { Moogle } from \"https://unpkg.com/@drashland/moogle@1.0.0/lib/esm/Moogle.js\";\n         const service = new Moogle();\n         service.addItem([\"hello\"], \"world\");\n\n         console.log(service.search(\"hel\"));\n       \u003c/script\u003e\n     \u003c/body\u003e\n   \u003c/html\u003e\n   ```\n\n2. Open your `index.html` file so that it opens up in your browser and open up\n   the console to see Moogle working.\n\n## Advanced Tutorial: Creating A Search Form\n\nIn this tutorial, you will create a search form where you can type in search\ninputs into a search field and see the results in a results field.\n\n1. Create your `index.html` file with the search and results fields. _Note: This\n   file uses Tailwind CSS to make the UI look better._\n\n   ```html\n   \u003c!doctype html\u003e\n   \u003chtml class=\"w-full h-full\"\u003e\n\n     \u003chead\u003e\n       \u003ctitle\u003eMoogle\u003c/title\u003e\n       \u003clink href=\"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css\" rel=\"stylesheet\"\u003e\n     \u003c/head\u003e\n\n     \u003cbody class=\"p-10 w-full h-full\"\u003e\n       \u003ch1 class=\"mb-5 text-2xl\"\u003eMoogle\u003c/h1\u003e\n       \u003cdiv class=\"mb-10 w-full\"\u003e\n         \u003cp class=\"mb-2\"\u003eSearch\u003c/p\u003e\n         \u003cinput\n           class=\"search border-solid border-2 mb-2 w-full p-2\"\n           type=\"text\"\n           placeholder=\"Search for something\"\n         \u003e\n         \u003cp class=\"italic\"\u003eTry the following searches: one, two, red, blue, fish, sh, ish, ue, ed\u003c/p\u003e\n       \u003c/div\u003e\n       \u003cdiv class=\"w-full\"\u003e\n         \u003cp class=\"mb-2\"\u003eResults\u003c/p\u003e\n         \u003ctextarea\n           class=\"results font-mono text-xs border-solid border-2 p-2 w-full\"\n           rows=\"15\"\n         \u003e[]\u003c/textarea\u003e\n       \u003c/div\u003e\n     \u003c/body\u003e\n   \u003c/html\u003e\n   ```\n2. Add the following script before the closing `\u003c/body\u003e` tag.\n   ```html\n   \u003cscript type=\"module\"\u003e\n     import { Moogle } from \"https://unpkg.com/@drashland/moogle@1.0.0/lib/esm/Moogle.js\";\n\n     // Set up Moogle and add some items you can search for\n     const service = new Moogle();\n     service.addItem([\"one fish\", \"one\", \"fish\"], \"ONE_FISH\");\n     service.addItem([\"two fish\", \"two\", \"fish\"], \"TWO_FISH\");\n     service.addItem([\"red fish\", \"red\", \"fish\"], \"RED_FISH\");\n     service.addItem([\"blue fish\", \"blue\", \"fish\"], \"BLUE_FISH\");\n\n     // Set up event handlers for the DOM\n     const searchElement = document.querySelector(\".search\");\n     searchElement.addEventListener(\"keyup\", search);\n\n     /**\n      * Search for an item in Moogle's lookup table.\n      */\n     function search() {\n       let results = [];\n       const searchInput = searchElement.value.trim();\n\n       if (searchInput == \"\") {\n         return setResults(results);\n       }\n\n       const resultsFromService = service.search(searchInput);\n\n       resultsFromService.forEach((item) =\u003e {\n         results.push(item);\n       });\n\n       setResults(results);\n     }\n\n     /**\n      * Set the given results in the results textarea DOM element.\n      */\n     function setResults(results) {\n       const resultsElement = document.querySelector(\".results\");\n       resultsElement.value = JSON.stringify(results, null, 4);\n     }\n   \u003c/script\u003e\n   ```\n   This script will set up Moogle, add items to Moogle's lookup table so that\n   you can search for them, and set up event handlers in the DOM so that the\n   search field and results field work as expected.\n\n3. Open up the `index.html` to load it in your browser.\n\n4. Enter some search terms in the search field element and see the results you\n   get in the results element.\n\n## Why Use Moogle?\n\nEveryone likes `Array`, but they come with a problem. If you want to find an\nitem in an array and you don't know the index of that item, then you have to\niterate over the entire array to find the item. This is slow.\n\nTo make the process faster, you can use `Map`. You can quickly find an item in a\n`Map` if you know the key to the item. However, if you only know a bit of the\nkey, then the process of finding that item is just like the array -- you have to\niterate over the entire map to find your item.\n\nSo... introducing Moogle! Moogle takes `Maps` to another level -- making them\nsearchable and blazing fast!\n\n## How It Works\n\n### At a high level\n\nWhen you instantiate the `Moogle` class, it sets up an index, a lookup table,\nand a cache table. From there, you add items to your index and lookup table\nusing `addItem()`. On initial lookups, Moogle will search the lookup table. On\nsubsequent lookups (using the same search terms), Moogle will use the cache\ntable -- making subsequent searches faster. The index is where Moogle stores\nassociations between search terms and items in the lookup table.\n\nWhen you add items via `addItem()`, you are providing the function with two\narguments: (1) an array of search terms and (2) the item associated with the\nsearch terms. This makes it so that you can search for the item using the search\nterms (or parts of the search terms if you do not know the full search terms).\n\n### At a low level\n\nLet us say you have instantiated Moogle via `const m = new Moogle()`. If you\ncall `m.addItem([\"hello\", \"world\"], \"world\");`, Moogle will take the array of\nsearch terms and assign them an ID in the index like so:\n\n```\n// This is what the index looks like as of now\n[\"hello\", [0]]\n[\"world\", [0]]\n```\n\nAfter that, Moogle will take the ID it used for the search terms and assign it\nto the item like so:\n\n```\n// This is what the lookup table looks like as of now\n[0, \"world\"]\n```\n\nThese associations mean you can search for the following strings ...\n\n```\nh\nhe\nhel\nhell\nhello\nw\nwo\nwor\nworl\nworld\n```\n\n... and they will all match `[\"hello\", [0]]` or `[\"world\", [0]]` in the index.\n\nThe assigned ID comes into play when the actual search in Moogle happens. Say\nyou have searched for `hel`. Moogle will match `hel` to `[\"hello\", [0]]` in the\nindex. It will then take the ID associated with the search term and match it to\nan item in the lookup table using `lookupTable.get(0)`. In this case, the\n`.get()` call will be matched to `[0, \"world\"]` in the lookup table. So what you\nget back is a search result in the following schema:\n\n```typescript\nMap {\n  0 =\u003e {\n    id: 0,\n    item: \"world\",\n    searchInput: \"hel\",\n    searchTerm: \"hello\"\n  }\n}\n```\n\nIn short, Moogle takes the search term, uses the ID associated with that search\nterm in a `.get()` call on the lookup table, and returns the item associated\nwith the ID -- all without having to iterate through the entire lookup table in\ncase it has millions of items. This is why Moogle is quick.\n\nAgain, each search is cached, so subsequent searches of the same search terms\nare faster than the first search.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrashland%2Fmoogle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrashland%2Fmoogle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrashland%2Fmoogle/lists"}