{"id":21166482,"url":"https://github.com/eyereasoner/eye-js","last_synced_at":"2026-04-15T03:04:05.988Z","repository":{"id":65085417,"uuid":"581706557","full_name":"eyereasoner/eye-js","owner":"eyereasoner","description":"A distribution of EYE reasoner in the JavaScript ecosystem using Webassembly.","archived":false,"fork":false,"pushed_at":"2025-01-06T17:26:53.000Z","size":429200,"stargazers_count":40,"open_issues_count":23,"forks_count":5,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-06T17:30:56.394Z","etag":null,"topics":["javascript","owl","proof","rdf","reasoner","semantic","solid","surfaces","typescript","web","webassembly"],"latest_commit_sha":null,"homepage":"https://eyereasoner.github.io/eye-js/example/","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/eyereasoner.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-24T02:45:51.000Z","updated_at":"2025-01-06T17:26:57.000Z","dependencies_parsed_at":"2023-12-26T02:44:33.886Z","dependency_job_id":"39deb794-9609-4c0d-b0c9-65ff0b51f890","html_url":"https://github.com/eyereasoner/eye-js","commit_stats":{"total_commits":836,"total_committers":7,"mean_commits":"119.42857142857143","dds":0.4569377990430622,"last_synced_commit":"15033666ded3254b6bdbceff00a65c1256c2918b"},"previous_names":[],"tags_count":740,"template":false,"template_full_name":"jeswr/template-typescript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eyereasoner%2Feye-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eyereasoner%2Feye-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eyereasoner%2Feye-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eyereasoner%2Feye-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eyereasoner","download_url":"https://codeload.github.com/eyereasoner/eye-js/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247430868,"owners_count":20937874,"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":["javascript","owl","proof","rdf","reasoner","semantic","solid","surfaces","typescript","web","webassembly"],"created_at":"2024-11-20T14:50:29.836Z","updated_at":"2026-03-12T03:06:13.506Z","avatar_url":"https://github.com/eyereasoner.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EYE JS\nDistributing the [EYE](https://github.com/eyereasoner/eye) reasoner for browser and node using WebAssembly.\n\n[![GitHub license](https://img.shields.io/github/license/eyereasoner/eye-js.svg)](https://github.com/eyereasoner/eye-js/blob/master/LICENSE)\n[![npm version](https://img.shields.io/npm/v/eyereasoner.svg)](https://www.npmjs.com/package/eyereasoner)\n[![build](https://img.shields.io/github/actions/workflow/status/eyereasoner/eye-js/nodejs.yml?branch=main)](https://github.com/eyereasoner/eye-js/tree/main/)\n[![Dependabot](https://badgen.net/badge/Dependabot/enabled/green?icon=dependabot)](https://dependabot.com/)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n[![bundlephobia](https://img.shields.io/bundlephobia/min/eyereasoner.svg)](https://www.npmjs.com/package/eyereasoner)\n[![DOI](https://zenodo.org/badge/581706557.svg)](https://zenodo.org/doi/10.5281/zenodo.12211023)\n\n## Usage\n\nThe simplest way to use this package is to use the `n3reasoner` to execute a query over a dataset and get the results. The input `data` should include the data and any inference rules that you wish to apply to the dataset; the optional `query` should match the pattern of data you wish the engine to return; if left undefined, all new inferred facts will be returned. For example:\n\n```ts\nimport { n3reasoner } from 'eyereasoner';\n\nexport const queryString = `\n@prefix : \u003chttp://example.org/socrates#\u003e.\n\n{:Socrates a ?WHAT} =\u003e {:Socrates a ?WHAT}.\n`;\n\nexport const dataString = `\n@prefix rdfs: \u003chttp://www.w3.org/2000/01/rdf-schema#\u003e.\n@prefix : \u003chttp://example.org/socrates#\u003e.\n\n:Socrates a :Human.\n:Human rdfs:subClassOf :Mortal.\n\n{?A rdfs:subClassOf ?B. ?S a ?A} =\u003e {?S a ?B}.\n`;\n\n// The result of the query (as a string)\nconst resultString = await n3reasoner(dataString, queryString);\n\n// All inferred data\nconst resultString = await n3reasoner(dataString);\n```\n\n*Note:* One can also supply an array of `dataString`s rather than a single `dataString` if one has multiple input data files.\n\nThe `n3reasoner` accepts both `string`s (formatted in Notation3 syntax) and `quad`s as input. The output will be of the same type as the input `data`. This means that we can use `n3reasoner` with RDF/JS quads as follows:\n\n```ts\nimport { Parser } from 'n3';\n\nconst parser = new Parser({ format: 'text/n3' });\nexport const queryQuads = parser.parse(queryString);\nexport const dataQuads = parser.parse(dataString);\n\n// The result of the query (as an array of quads)\nconst resultQuads = await n3reasoner(dataQuads, queryQuads);\n```\n\n### Options\n\nThe `n3reasoner` function allows one to optionally pass along a set of options\n\n```ts\nimport { n3reasoner } from 'eyereasoner';\n\nconst data = `\n@prefix : \u003curn:example.org:\u003e .\n:Alice a :Person .\n{ ?S a :Person } =\u003e { ?S a :Human } .\n`;\n\nconst result = await n3reasoner(data, undefined, {\n  output: 'derivations',\n  outputType: 'string'\n});\n```\n\nThe `options` parameter can be used to configure the reasoning process. The following options are available:\n- `output`: What to output with implicit queries.\n    - `derivations`: output only new derived triples, a.k.a `--pass-only-new` (default)\n    - `deductive_closure`: output deductive closure, a.k.a `--pass`\n    - `deductive_closure_plus_rules`: output deductive closure plus rules, a.k.a `--pass-all`\n    - `grounded_deductive_closure_plus_rules`: ground the rules and output deductive closure plus rules, a.k.a `--pass-all-ground`\n    - `none`: provides no `-pass-*` arguments to eye, often used when doing RDF Surface reasoning\n- `outputType`: The type of output (if different from the input)\n    - `string`: output as string\n    - `quads`: output as array of RDF/JS Quads\n\n## Advanced usage\n\nTo have more granular control one can also use this module as follows\n\n```ts\nimport { SwiplEye, queryOnce } from 'eyereasoner';\n\nconst query = `\n@prefix : \u003chttp://example.org/socrates#\u003e.\n\n{:Socrates a ?WHAT} =\u003e {:Socrates a ?WHAT}.\n`\n\nconst data = `\n@prefix rdfs: \u003chttp://www.w3.org/2000/01/rdf-schema#\u003e.\n@prefix : \u003chttp://example.org/socrates#\u003e.\n\n:Socrates a :Human.\n:Human rdfs:subClassOf :Mortal.\n\n{?A rdfs:subClassOf ?B. ?S a ?A} =\u003e {?S a ?B}.\n`\n\nasync function main() {\n  // Instantiate a new SWIPL module and log any results it produces to the console\n  const Module = await SwiplEye({ print: (str: string) =\u003e { console.log(str) }, arguments: ['-q'] });\n\n  // Load the the strings data and query as files data.n3 and query.n3 into the module\n  Module.FS.writeFile('data.n3', data);\n  Module.FS.writeFile('query.n3', query);\n\n  // Execute main(['--nope', '--quiet', './data.n3', '--query', './query.n3']).\n  queryOnce(Module, 'main', ['--nope', '--quiet', './data.n3', '--query', './query.n3']);\n}\n\nmain();\n```\n\n## Selecting the `SWIPL` module\n\nThe `SWIPL` module exported from this library is a build that inlines WebAssembly and data strings in order to be\nisomorphic across browser and node without requiring any bundlers. Some users may wish to have more fine-grained control\nover their SWIPL module; for instance in order to load the `.wasm` file separately for performance. In these cases\nsee the `SWIPL` modules exported by [npm swipl wasm](https://github.com/rla/npm-swipl-wasm/).\n\nAn example usage of the node-specific swipl-wasm build is as follows:\n```ts\nimport { loadEyeImage, queryOnce } from 'eyereasoner';\nimport SWIPL from 'swipl-wasm/dist/swipl-node';\n\nasync function main() {\n  const SwiplEye = loadEyeImage(SWIPL);\n\n  // Instantiate a new SWIPL module and log any results it produces to the console\n  const Module = await SwiplEye({ print: (str: string) =\u003e { console.log(str) }, arguments: ['-q'] });\n\n  // Load the the strings data and query as files data.n3 and query.n3 into the module\n  Module.FS.writeFile('data.n3', data);\n  Module.FS.writeFile('query.n3', query);\n\n  // Execute main(['--nope', '--quiet', './data.n3', '--query', './query.n3']).\n  queryOnce(Module, 'main', ['--nope', '--quiet', './data.n3', '--query', './query.n3']);\n}\n\nmain();\n```\n\n## CLI Usage\n\nThis package also exposes a CLI interface for using the reasoner. It can be used via `npx`\n\n```bash\n# Run the command using the latest version of eyereasoner on npm\nnpx eyereasoner --nope --quiet ./socrates.n3 --query ./socrates-query.n3\n```\n\nor by globally installing `eyereasoner`\n\n```bash\n# Gloablly install eyereasoner\nnpm i -g eyereasoner\n# Run a command with eyereasoner\neyereasoner --nope --quiet ./socrates.n3 --query ./socrates-query.n3\n```\n\n## Browser Builds\n\nFor convenience we provide deploy bundled versions of the eyereasoner on github pages which can be directly used in an HTML document as shown in [this example](https://github.com/eyereasoner/eye-js/tree/main/examples/prebuilt/index.html) which is also [deployed on github pages](https://eyereasoner.github.io/eye-js/example/index.html).\n\nThere is a bundled version for each release - which can be found at the url:\n\u003cp align=center\u003e\nhttps://eyereasoner.github.io/eye-js/vMajor/vMinor/vPatch/index.js\n\nfor instance v2.3.14 has the url https://eyereasoner.github.io/eye-js/2/3/14/index.js. We also have shortcuts for:\n - the latest version https://eyereasoner.github.io/eye-js/latest/index.js,\n - the latest of each major version https://eyereasoner.github.io/eye-js/vMajor/latest/index.js, and\n - the latest of each minor version https://eyereasoner.github.io/eye-js/vMajor/vMinor/latest/index.js\n\nAvailable versions can be browsed at https://github.com/eyereasoner/eye-js/tree/pages.\n\nGithub also serves these files with a `gzip` content encoding which compresses the script to ~1.4MB when being served.\n\n![](./github-transfer.png)\n\n### Serving Files\n\nWhen self-hosting the bundled files, ensure your server includes `charset=utf-8` in the `Content-Type` header for JavaScript files:\n\n```\nContent-Type: text/javascript; charset=utf-8\n```\n\nWithout the charset, WASM streaming instantiation may fail in headless browsers with errors like:\n- Firefox: `CompileError: wasm validation error: at offset 642: byte size mismatch in type section`\n- Chromium: `CompileError: WebAssembly.instantiate(): section was shorter than expected size`\n\nMost static file servers (e.g., `express.static()`) set this automatically, but custom streaming handlers using `createReadStream().pipe(res)` may not.\n\n### Dynamic imports\n\nWe also distribute bundles that can be dynamically imported on github pages; for example\n```ts\nconst { eyereasoner } = await import('https://eyereasoner.github.io/eye-js/2/latest/dynamic-import.js');\n\n// Instantiate a new SWIPL module and log any results it produces to the console\nconst Module = await eyereasoner.SwiplEye({ print: (str) =\u003e { console.log(str) }, arguments: ['-q'] });\n\n// Load the the strings data and query as files data.n3 and query.n3 into the module\nModule.FS.writeFile('data.n3', data);\nModule.FS.writeFile('query.n3', query);\n\n// Execute main(['--nope', '--quiet', './data.n3', '--query', './query.n3']).\neyereasoner.queryOnce(Module, 'main', ['--nope', '--quiet', './data.n3', '--query', './query.n3']);\n```\n## Using with Webpack\n\nWhen bundling `eyereasoner` with Webpack for the browser, the underlying Emscripten-generated code may import Node.js built-in modules using the `node:` scheme (e.g. `node:fs`, `node:crypto`). Webpack does not handle the `node:` scheme by default and will produce errors like:\n\n```\nModule build failed: UnhandledSchemeError: Reading from \"node:fs\" is not handled by plugins (Unhandled scheme).\n```\n\nTo fix this, add the following to your `webpack.config.js`:\n\n```js\nconst { NormalModuleReplacementPlugin } = require('webpack');\n\nmodule.exports = {\n  // ...your existing config\n  resolve: {\n    fallback: {\n      path: false,\n      fs: false,\n      crypto: false,\n      perf_hooks: false,\n    },\n  },\n  plugins: [\n    new NormalModuleReplacementPlugin(/^node:/, (resource) =\u003e {\n      resource.request = resource.request.replace(/^node:/, '');\n    }),\n  ],\n};\n```\n\nThe `NormalModuleReplacementPlugin` strips the `node:` prefix so that the imports are resolved by the `resolve.fallback` entries, which map them to `false` (i.e. empty modules) since they are not needed in the browser.\n\n## Examples\n\nWe provide some examples of using `eyereasoner`:\n - Using as an npm package and bundling using webpack ([`./examples/rollup`](https://github.com/eyereasoner/eye-js/tree/main/examples/rollup)).\n - Using a prebuilt version of `eyereasoner` ([`./examples/prebuilt`](https://github.com/eyereasoner/eye-js/tree/main/examples/prebuilt)) - this example is [deployed on github pages](https://eyereasoner.github.io/eye-js/example/index.html).\n\n## Performance\n\nWe use [benchmark.js](https://benchmarkjs.com/) to collect the performance results of some basic operations. Those results are published [here](https://eyereasoner.github.io/eye-js/dev/bench/).\n\n## Experimental `linguareasoner`\n\nWe have experimental support for RDF Lingua using the `linguareasoner`; similarly to `n3reasoner` it can be used with both string and quad input/output. For instance:\n\n```ts\nimport { linguareasoner } from 'eyereasoner';\n\nconst result = await linguareasoner(`\n# ------------------\n# Socrates Inference\n# ------------------\n#\n# Infer that Socrates is mortal.\n\n@prefix rdfs: \u003chttp://www.w3.org/2000/01/rdf-schema#\u003e.\n@prefix log: \u003chttp://www.w3.org/2000/10/swap/log#\u003e.\n@prefix var: \u003chttp://www.w3.org/2000/10/swap/var#\u003e.\n@prefix : \u003chttp://example.org/socrates#\u003e.\n\n# facts\n:Socrates a :Human.\n:Human rdfs:subClassOf :Mortal.\n\n# rdfs subclass\n_:ng1 log:implies _:ng2.\n\n_:ng1 {\n    var:A rdfs:subClassOf var:B.\n    var:S a var:A.\n}\n\n_:ng2 {\n    var:S a var:B.\n}\n\n# query\n_:ng3 log:query _:ng3.\n\n_:ng3 {\n    var:S a :Mortal.\n}`)\n```\n\n## Cite\n\nIf you are using or extending eye-js as part of a scientific publication, we would appreciate a citation of our [zenodo artefact](https://zenodo.org/doi/10.5281/zenodo.12211023).\n\n## License\n©2022–present\n[Jesse Wright](https://github.com/jeswr),\n[Jos De Roo](https://github.com/josd/),\n[MIT License](https://github.com/eyereasoner/eye-js/blob/master/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feyereasoner%2Feye-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feyereasoner%2Feye-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feyereasoner%2Feye-js/lists"}