{"id":36542830,"url":"https://github.com/deniskyashif/ssfst","last_synced_at":"2026-01-12T05:49:36.460Z","repository":{"id":21844211,"uuid":"94203198","full_name":"deniskyashif/ssfst","owner":"deniskyashif","description":"Rewrite text in linear time.","archived":false,"fork":false,"pushed_at":"2023-03-04T02:39:17.000Z","size":282,"stargazers_count":81,"open_issues_count":4,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-11-27T10:46:20.332Z","etag":null,"topics":["finite-state-machine","nlp","rewriting","search-replace","transducers"],"latest_commit_sha":null,"homepage":"https://npm.runkit.com/ssfst","language":"JavaScript","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/deniskyashif.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":"2017-06-13T10:56:19.000Z","updated_at":"2024-08-20T05:04:25.000Z","dependencies_parsed_at":"2023-02-17T11:45:28.995Z","dependency_job_id":null,"html_url":"https://github.com/deniskyashif/ssfst","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/deniskyashif/ssfst","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deniskyashif%2Fssfst","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deniskyashif%2Fssfst/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deniskyashif%2Fssfst/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deniskyashif%2Fssfst/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deniskyashif","download_url":"https://codeload.github.com/deniskyashif/ssfst/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deniskyashif%2Fssfst/sbom","scorecard":{"id":334110,"data":{"date":"2025-08-11","repo":{"name":"github.com/deniskyashif/ssfst","commit":"801813e53e7b30047ab18e254431034e5c5a1337"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 1/21 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"15 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T04:17:37.037Z","repository_id":21844211,"created_at":"2025-08-18T04:17:37.037Z","updated_at":"2025-08-18T04:17:37.037Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28335331,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T00:36:25.062Z","status":"online","status_checked_at":"2026-01-12T02:00:08.677Z","response_time":98,"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":["finite-state-machine","nlp","rewriting","search-replace","transducers"],"created_at":"2026-01-12T05:49:36.358Z","updated_at":"2026-01-12T05:49:36.449Z","avatar_url":"https://github.com/deniskyashif.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Subsequential Finite State Transducer\n\n[![Build Status](https://api.travis-ci.org/deniskyashif/ssfst.svg?branch=master)](https://travis-ci.org/deniskyashif/ssfst)\n[![Coverage Status](https://coveralls.io/repos/github/deniskyashif/ssfst/badge.svg?branch=master)](https://coveralls.io/github/deniskyashif/ssfst?branch=master)\n[![Code Climate](https://codeclimate.com/github/deniskyashif/ssfst/badges/gpa.svg)](https://codeclimate.com/github/deniskyashif/ssfst)\n[![Dependencies](https://img.shields.io/badge/dependencies-none-green.svg)](https://www.npmjs.com/package/ssfst)\n\nGiven an input text, produces a new text by applying a fixed set of rewrite rules. The algorithm builds a minimal subsequential transducer and uses the \"leftmost largest match\" replacement strategy with skips. No overlap between the replaced parts is possible. The time needed to compute the transducer is **linear** in the size of the input dictionary. For any  text `t` of length `|t|` the time it takes to perform a rewrite is also **linear** `O(|t|+|t'|)` where `t'` denotes the resulting output string.  \nCheck out the [Online Sandbox](https://npm.runkit.com/ssfst).\n\n## Usage\n\n```sh\nnpm i --save ssfst\n```\n\n## Example: Text Rewriting\n\n```js\nconst ssfst = require('ssfst');\n\nconst spellingCorrector = ssfst.init([\n    { input: 'acheive', output: 'achieve'},\n    { input: 'arguement', output: 'argument'},\n    { input: 'independant', output: 'independent'},\n    { input: 'posession', output: 'possession'},\n    { input: 'mercy less', output: 'merciless' }\n]);\n\nspellingCorrector.process('independant'); // =\u003e \"independent\"\nspellingCorrector.process('mercy less arguement'); // =\u003e \"merciless argument\"\nspellingCorrector.process('they acheived a lot'); // =\u003e \"they achieved a lot\"\n```\n\nThe `init` factory function takes a collection of pairs and returns a transducer. The transducer can be initialized by any iterable object.\n\n```js\nfunction* dictGen() {\n    yield { input: 'dog', output: '\u003ca href=\"https://en.wikipedia.org/wiki/Dog\"\u003edog\u003c/a\u003e' };\n    yield { input: 'fox', output: '\u003ca href=\"https://en.wikipedia.org/wiki/Fox\"\u003efox\u003c/a\u003e' };\n}\n\nconst transducer = ssfst.init(dictGen());\ntransducer.process('The quick brown fox jumped over the lazy dog.');\n/* =\u003e The quick brown \u003ca href=\"https://en.wikipedia.org/wiki/Fox\"\u003efox\u003c/a\u003e jumped over the lazy \u003ca href=\"https://en.wikipedia.org/wiki/Dog\"\u003edog\u003c/a\u003e. */\n```\n\n## Working with large datasets\n\nLoading the full rewrite dictionary in memory is not optimal when working with large datasets. In this case we want to build the transducer by adding the entries asynchronously one at a time. This is achieved by using an async iterable.\n\nFor example, if our dataset is stored in a file, we can read its contents one line at a time.\n\n```txt\nBerlin,Germany\nBuenos Aires,Argentina\nLondon,United Kingdom\nSofia,Bulgaria\nTokyo,Japan\n```\n\nThis is the dictionary text file. Each line contains an entry and its input and output values are separated by a comma. We implement a generator function which reads it asynchronously line by line and yields an object which is consumed by the initialization of the transducer.\n\n```js\nconst fs = require('fs');\nconst readline = require('readline');\nconst ssfst = require('ssfst');\n\nasync function* readLinesGenAsync() {\n    const lineReader = readline.createInterface({\n        input: fs.createReadStream(__dirname + '/capitals.txt')\n    });\n\n    for await (const line of lineReader) {\n        const [input, output] = line.split(',');\n        yield { input, output };\n    }\n}\n```\n\nWe pass the async iterable to the `initAsync` factory function.\n\n```js\nconst transducer = await ssfst.initAsync(readLinesGenAsync());\n```\n\n## Example: Key-Value Store\n\nThe subsequential transducer can also be used to efficiently store key-value pairs.\n\n```js\nconst val = transducer.process('Sofia'); // =\u003e Bulgaria\nconst invalid = transducer.process('Unknown Key'); // =\u003e Unknown Key\n```\n\nIf there's no value for a given key, it will return the key itself, which simply reduces to processing a text without applying any rewrite rules.\n\n## Use with TypeScript\n\n```ts\nimport * as ssfst from 'ssfst';\n```\n\n## Run Locally\n\n```sh\ngit clone https://github.com/deniskyashif/ssfst.git\ncd ssfst\nnpm i\n```\n\nSample implementations can be found in [examples/](https://github.com/deniskyashif/ssfst/tree/master/examples).\n\n## Run the Tests\n\n```sh\nnpm t\n```\n\n## References\n\nThis implementation follows the construction presented in [\"Efficient Dictionary-Based Text Rewriting using Subsequential Transducers\" by S. Mihov, K. Schulz](https://dl.acm.org/doi/abs/10.1017/S1351324905004092)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeniskyashif%2Fssfst","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeniskyashif%2Fssfst","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeniskyashif%2Fssfst/lists"}