{"id":16636686,"url":"https://github.com/justinwilaby/spellchecker-wasm","last_synced_at":"2026-04-04T04:36:34.034Z","repository":{"id":36557528,"uuid":"228220638","full_name":"justinwilaby/spellchecker-wasm","owner":"justinwilaby","description":"SpellcheckerWasm is an extrememly fast spellchecker for WebAssembly based on SymSpell ","archived":false,"fork":false,"pushed_at":"2023-01-06T22:28:40.000Z","size":6936,"stargazers_count":58,"open_issues_count":24,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-11T22:34:06.852Z","etag":null,"topics":["levenshtein","levenshtein-distance","rust","spell-check","spellcheck","spellchecker","spelling","spelling-correction","symspell","webassembly"],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/justinwilaby.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}},"created_at":"2019-12-15T17:07:20.000Z","updated_at":"2025-03-09T20:54:19.000Z","dependencies_parsed_at":"2023-01-17T02:45:42.929Z","dependency_job_id":null,"html_url":"https://github.com/justinwilaby/spellchecker-wasm","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinwilaby%2Fspellchecker-wasm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinwilaby%2Fspellchecker-wasm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinwilaby%2Fspellchecker-wasm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinwilaby%2Fspellchecker-wasm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/justinwilaby","download_url":"https://codeload.github.com/justinwilaby/spellchecker-wasm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243830953,"owners_count":20354854,"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","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":["levenshtein","levenshtein-distance","rust","spell-check","spellcheck","spellchecker","spelling","spelling-correction","symspell","webassembly"],"created_at":"2024-10-12T06:22:30.548Z","updated_at":"2026-04-04T04:36:34.008Z","avatar_url":"https://github.com/justinwilaby.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spellchecker + WebAssembly\n*When you absolutely, positively have to have the fastest spellchecker in the room, accept no substitutes.*\n\n[![Build Status](https://travis-ci.org/justinwilaby/spellchecker-wasm.svg?branch=master)](https://travis-ci.org/justinwilaby/spellchecker-wasm)\n[![Coverage Status](https://coveralls.io/repos/github/justinwilaby/spellchecker-wasm/badge.svg?branch=master)](https://coveralls.io/github/justinwilaby/spellchecker-wasm?branch=master)\n\n* **Fast** - Based on [SymSpell](https://github.com/wolfgarbe/symspell) v6.6 with bigram support.\n* **Plug and play** - Ready to go out of the box (batteries included).\n\nSpellcheck-wasm is an extremely fast spellchecker for [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) complete with\ntooling for leveraging Worker threads to guarantee lightning fast processing of a single word or very large documents *without* the use\nof native Node plugins. Sub-millisecond benchmarks bring **near native speeds** to spellchecking in Node.\n\nSpellcheck-wasm uses a zero dependency [Rust](https://www.rust-lang.org/en-US/) port of the extremely popular [SymSpell](https://github.com/wolfgarbe/symspell)\nengine with several optimizations for WebAssembly.\n\n|               |            |\n|---------------|-----------:|\n| Electron      |      ✓     |\n| Node          |      ✓     |\n| Browsers      |      ✓     |\n| Workers       |      ✓     |\n| Cli           |      ✓     |\n\n## Installation\n```bash\nnpm i -s spellchecker-wasm\n```\n## As an interactive CLI\n```bash\nnpm i -g spellchecker-wasm\n```\nThen use `spellcheck` to enter interactive mode. For supported arguments, run `spellcheck --help`.\n\n## Usage in Electron\n```js\n// Within the preload script of your BrowserWindow instance\nconst { webFrame } = require('electron');\nconst { SpellcheckerWasm }  = require('spellchecker-wasm');\n\nconst wasmPath = require.resolve('spellchecker-wasm/lib/spellcheck-wasm.wasm');\nconst dictionaryLocation = require.resolve('spellchecker-wasm/lib/frequency_dictionary_en_82_765.txt');\nconst spellchecker = new SpellcheckerWasm();\n\nspellchecker.prepareSpellchecker(wasmPath, dictionaryLocation)\n    .then(() =\u003e {\n        let suggestions;\n        spellchecker.resultsHandler = results =\u003e {\n            suggestions = results;\n        };\n\n        webFrame.setSpellCheckProvider('en-US', {\n            spellCheck(words, callback) {\n                const misspelledWords = [];\n                words.forEach(word =\u003e {\n                    spellchecker.checkSpelling(word); // synchronous\n                    if (suggestions.length) {\n                        misspelledWords.push(word);\n                    }\n                });\n                callback(misspelledWords);\n            }\n        })\n    })\n```\n\n## Usage in Node\n```typescript\nimport { SpellcheckerWasm } from 'spellchecker-wasm';\nconst wasmPath = require.resolve('spellchecker-wasm/lib/spellchecker-wasm.wasm');\nconst dictionaryLocation = require.resolve('spellchecker-wasm/lib/frequency_dictionary_en_82_765.txt');\n// Optional bigram support for compound lookups - add only when needed\nconst bigramLocation = require.resolve('spellchecker-wasm/lib/frequency_bigramdictionary_en_243_342.txt');\n\nconst spellchecker = new SpellcheckerWasm(resultHandler);\nspellChecker.prepareSpellchecker(wasmPath, dictionaryLocation, bigramLocation)\n    .then(() =\u003e {\n        ['tiss', 'gves', 'practiclly', 'instent', 'relevent', 'resuts'].forEach(word =\u003e spellchecker.checkSpelling(word));\n        spellchecker.checkSpellingCompound('tiss cheks th entir sentance')\n    });\n\nfunction resultHandler(results) {\n    // Results are given in the same order they are sent.\n    // The most relevant results are order lower in the results index.\n    process.stdout.write(results.map(r =\u003e r.term));\n}\n```\n\n## Usage as a Node Worker\n```typescript\nconst { SpellcheckerWasm } = require('../lib/nodejs/SpellcheckerWasm.js');\n\nconst wasmPath = require.resolve('spellchecker-wasm/lib/spellchecker-wasm.wasm');\nconst dictionaryLocation = require.resolve('spellchecker-wasm/lib/frequency_dictionary_en_82_765.txt');\n// Optional bigram support for compound lookups - add only when needed\nconst bigramLocation = require.resolve('spellchecker-wasm/lib/frequency_bigramdictionary_en_243_342.txt');\n\nlet resultHandler = (results) =\u003e {process.stdout.write(results.map(r =\u003e r.term) + '\\n');};\nlet spellcheckerWasm = new SpellcheckerWasm(resultHandler);\nspellcheckerWasm.prepareSpellchecker(wasmPath, dictionaryLocation, bigramLocation)\n    .then(() =\u003e {\n        process.stdout.write('Ready\\n');\n        process.stdin.on('data', data =\u003e {\n            spellcheckerWasm.checkSpelling('' + data);\n        });\n    })\n    .catch((e) =\u003e {\n        process.stdout.write(`Error initializing the SpellChecker\\n${e}\\n`);\n    });\n```\n## Usage in the Browser\n```js\nimport { SpellcheckerWasm } from 'spellchecker-wasm/lib/browser/index.js';\n\nlet resultHandler = (results) =\u003e console.log(\"Results : \", results.map(result =\u003e result.term));\n\nasync function initializeSpellchecker() {\n    const wasm = await fetch('spellchecker-wasm/lib/spellchecker-wasm.wasm');\n    const dictionary = await fetch('spellchecker-wasm/lib/frequency_dictionary_en_82_765.txt');\n    const bigramLocation = await fetch('spellchecker-wasm/lib/frequency_bigramdictionary_en_243_342.txt'); // Optional\n\n    const spellchecker = new SpellcheckerWasm(resultHandler);\n    await spellchecker.prepareSpellchecker(wasm, dictionary, bigramLocation);\n    return spellchecker;\n}\n\ninitializeSpellchecker().then(spellchecker =\u003e {\n    ['tiss', 'gves', 'practiclly', 'instent', 'relevent', 'resuts'].forEach(word =\u003e spellchecker.checkSpelling(word));\n    spellchecker.checkSpellingCompound('tiss cheks th entir sentance');\n});\n```\n## Common use cases\n### Differentiating between a correct word and a word with no suggestions\nBy default, the spellchecker will return no results for both 'there' and 'thereeeee'. \nThe former is correct and so will not produce suggestions. The latter word is obviously a mistake, \nbut its distance from any word in the dictionary is greater than the maxEditDistance.\n\nTo distinguish between the two, one can use the `includeUnknown` option :\n```js\nlet lastResults;\nconst resultsHandler = results =\u003e {\n    lastResults = results;\n};\n\nspellchecker.checkSpelling('there');\n// lastResults.length === 0\n\nspellchecker.checkSpelling('thereeeee');\n// lastResults.length === 0\n\nspellchecker.checkSpelling('thereeeee', {\n    includeUnknown: true,\n    maxEditDistance: 2,\n    verbosity: 2,\n    includeSelf: false\n});\n// lastResults.length === 1\n```\n### Allowing for deeper word searches\nGiven that the default `maxEditDistance`, which controls up to which edit distance words from the dictionary should be treated as suggestions, is 2, words such as `cofvvvfee` will not return suggestions.\n\nThis can be remedied as follows:\n```js\nlet lastResults;\nconst resultsHandler = results =\u003e {\n    lastResults = results;\n};\n\nspellchecker.checkSpelling('cofvvvfee');\n// lastResults.length === 0\n\nspellchecker.checkSpelling('cofvvvfee', {\n    includeUnknown: false,\n    maxEditDistance: 4,\n    verbosity: 1,\n    includeSelf: false\n});\n// lastResults.length === 1, lastResults[0] --\u003e 'coffee'\n```\n*Caveat* : the `maxEditDistance` parameter that is passed to `checkSpelling` must be less-than-or-equal to the `dictionaryEditDistance` parameter of `prepareSpellchecker`. E.g. : \n```js\n// BAD!\nawait spellchecker.prepareSpellchecker(wasmPath, dictionaryLocation); // Default value of dictionaryEditDistance is 2\nlet lastResults;\nconst resultsHandler = results =\u003e {\n    lastResults = results;\n};\nspellchecker.checkSpelling('cofvvvfee', {\n    includeUnknown: false,\n    maxEditDistance: 4,\n    verbosity: 1,\n    includeSelf: false\n});\n// ERROR!\n```\n\n```js\n// Good\nawait spellchecker.prepareSpellchecker(wasmPath, dictionaryLocation, null, {countThreshold: 2, dictionaryEditDistance: 4});\nlet lastResults;\nconst resultsHandler = results =\u003e {\n    lastResults = results;\n};\nspellchecker.checkSpelling('cofvvvfee', {\n    includeUnknown: false,\n    maxEditDistance: 4,\n    verbosity: 1,\n    includeSelf: false\n});\n// lastResults.length === 1\n```\n### Controlling the amount and ordering of returned suggestions\nThe `verbosity` parameter to `checkSpelling` can be used to tweak the amount of suggestions returned. Its supported values are :\n```js\nverbosity:\n    0: (top) returns only the suggestion with the highest term frequency of the suggestions of smallest edit distance found,\n    1: (closest) returns all suggestions of smallest edit distance found, suggestions ordered by term frequency,\n    2: (all) returns all suggestions within maxEditDistance, suggestions ordered by edit distance, then by term frequency,\n\n```\n\n## Building from source\n### Prerequisites\n\nThis project requires rust v1.30+ since it contains the `wasm32-unknown-unknown` target out of the box.\n\nInstall rust:\n```bash\ncurl https://sh.rustup.rs -sSf | sh\n```\nInstall the stable compiler and switch to it.\n```bash\nrustup install stable\nrustup default stable\n```\nInstall the wasm32-unknown-unknown target.\n```bash\nrustup target add wasm32-unknown-unknown --toolchain stable\n```\nInstall [node with npm](https://nodejs.org/en/) then run the following command from the project root.\n```bash\nnpm install\n```\nInstall the wasm-bindgen-cli tool\n```bash\ncargo install wasm-bindgen-cli\n```\nThe project can now be built using:\n```bash\nnpm run build\n```\nThe artifacts from the build will be located in the `/libs` directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustinwilaby%2Fspellchecker-wasm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjustinwilaby%2Fspellchecker-wasm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustinwilaby%2Fspellchecker-wasm/lists"}