{"id":13566935,"url":"https://github.com/guregu/trealla-js","last_synced_at":"2025-04-11T23:23:49.783Z","repository":{"id":59272414,"uuid":"530832699","full_name":"guregu/trealla-js","owner":"guregu","description":"Trealla Prolog for the web","archived":false,"fork":false,"pushed_at":"2025-04-11T01:09:48.000Z","size":598,"stargazers_count":48,"open_issues_count":15,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-11T02:27:10.046Z","etag":null,"topics":["javascript","logic-programming","prolog","webassembly"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/trealla","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/guregu.png","metadata":{"funding":{"github":"guregu"},"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":"2022-08-30T21:10:31.000Z","updated_at":"2025-04-11T01:09:52.000Z","dependencies_parsed_at":"2023-10-15T07:14:40.486Z","dependency_job_id":"efa70ec4-5921-4d15-823a-bc4a88ea204c","html_url":"https://github.com/guregu/trealla-js","commit_stats":{"total_commits":126,"total_committers":1,"mean_commits":126.0,"dds":0.0,"last_synced_commit":"6b3f1817fb4d9a022619efad22bd9b4743434379"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Ftrealla-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Ftrealla-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Ftrealla-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Ftrealla-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guregu","download_url":"https://codeload.github.com/guregu/trealla-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248329824,"owners_count":21085611,"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","logic-programming","prolog","webassembly"],"created_at":"2024-08-01T13:02:19.936Z","updated_at":"2025-04-11T23:23:49.775Z","avatar_url":"https://github.com/guregu.png","language":"TypeScript","funding_links":["https://github.com/sponsors/guregu"],"categories":["TypeScript"],"sub_categories":[],"readme":"# trealla-js\r\n\r\n~~Javascript~~ TypeScript bindings for [Trealla Prolog](https://github.com/trealla-prolog/trealla).\r\n\r\nTrealla is a quick and lean ISO Prolog interpreter.\r\n\r\nTrealla is built targeting [WASI](https://wasi.dev/) and should be useful for both browsers and serverless runtimes.\r\n\r\n**Demo**: https://php.energy/trealla.html\r\n\r\n**Status**: beta!\r\n\r\n## Get\r\n\r\ntrealla-js embeds the Trealla WASM binary. Simply import the module, load it, and you're good to go.\r\n\r\n### JS Modules\r\n\r\nYou can import Trealla directly from a CDN that supports ECMAScript Modules.\r\n\r\nFor now, it's best to pin a version as in: `https://esm.sh/trealla@X.Y.Z`.\r\n\r\n```js\r\nimport { load, Prolog } from 'https://esm.sh/trealla';\r\nimport { load, Prolog } from 'https://esm.run/trealla';\r\nimport { load, Prolog } from 'https://unpkg.com/trealla';\r\nimport { load, Prolog } from 'https://cdn.skypack.dev/trealla';\r\n```\r\n\r\n### NPM\r\n\r\nThis package is [available on NPM](https://www.npmjs.com/package/trealla) as `trealla`.\r\n\r\n```bash\r\nnpm install trealla\r\n```\r\n\r\n```js\r\nimport { load, Prolog } from 'trealla';\r\n```\r\n\r\n## Example\r\n\r\n### Javascript to Prolog\r\n\r\n```html\r\n\u003c!-- Make sure to use type=\"module\" for inline scripts. --\u003e\r\n\u003cscript type=\"module\"\u003e\r\n\r\nimport { Prolog, load, atom } from 'https://esm.sh/trealla';\r\n\r\n// Load the runtime.\r\n// This is requred before construction of any interpreters.\r\nawait load();\r\n\r\n// Create a new Prolog interpreter\r\n// Each interpreter is independent and persistent\r\nconst pl = new Prolog();\r\n\r\n// Queries are async generators.\r\n// You can run multiple queries against the same interpreter simultaneously.\r\nconst query = pl.query('between(2, 10, X), Y is X^2, format(\"(~w,~w)~n\", [X, Y]).');\r\nfor await (const answer of query) {\r\n  console.log(answer);\r\n}\r\n\r\n// Use the bind option to easily bind variables.\r\n// You can bind strings as-is.\r\n// Atoms can be quickly constructed with the atom template tag.\r\n// See: Term type.\r\nconst greeting = await pl.queryOnce('format(\"hello ~a\", [X])', {bind: {X: atom`world`}});\r\nconsole.log(greeting.stdout); // \"hello world\"\r\nconsole.log(greeting.answer.X); // Atom { functor: \"world\" }\r\n\r\n\u003c/script\u003e\r\n```\r\n\r\n```javascript\r\n{\r\n  \"status\": \"success\",\r\n  \"answer\": {\"X\": 2, \"Y\": 4},\r\n  \"stdout\": \"(2,4)\\n\"\r\n}\r\n// ...\r\n```\r\n\r\n### Prolog to Javascript\r\n\r\nExperimental. With great power comes great responsibility 🤠\r\n\r\n#### Writing a Prolog predicate in Javascript 🆕\r\n\r\nYou can implement Prolog predicates using Javascript.\r\n\r\nThis is useful for taking advantage of browser functionality, or utilizing JS's async runtime.\r\n\r\n```typescript\r\n// Native predicates are fully type-safe :-)\r\nexport type PredicateFunction\u003cG extends Goal\u003e =\r\n\t(pl: Prolog, subq: Ptr\u003csubquery_t\u003e, goal: G, ctrl: Ctrl) =\u003e\r\n\t\tContinuation\u003cG\u003e | Promise\u003cContinuation\u003cG\u003e\u003e | AsyncIterable\u003cContinuation\u003cG\u003e\u003e;\r\nexport type Continuation\u003cG extends Goal\u003e = G | boolean;\r\nexport type Goal = Atom | Compound\u003cstring, [Term, ...Term[]]\u003e;\r\n```\r\n\r\nCreate a new Predicate with `new Predicate(...)` and register it with `pl.register(...)`.\r\n\r\nThe return value of all predicates is a \"continuation\" that is either:\r\n- A goal that will be unified with the call\r\n- Boolean `true` to succeed unconditionally\r\n- Boolean `false` to fail unconditionally\r\n\r\nThrowing a Prolog term will cause `throw/1` to be called by the guest.\r\nThrowing a non-Term will become `throw(error(system_error(js_exception, \"details...\"), foo/N))`.\r\n\r\n```typescript\r\n// Example of between/3 implemented in JS\r\nexport const betwixt_3 = new Predicate\u003cCompound\u003c\"betwixt\", [number, number, number | Variable]\u003e\u003e(\r\n    \"betwixt\", 3,\r\n    async function*(_pl, _subquery, goal) {\r\n        const [min, max, n] = goal.args;\r\n        if (!isNumber(min))\r\n            throw type_error(\"number\", min, goal.pi);\r\n        if (!isNumber(max))\r\n            throw type_error(\"number\", max, goal.pi);\r\n\r\n        for (let i = isNumber(n) ? n : min; i \u003c= max; i++) {\r\n            goal.args[2] = i;\r\n            if (i == max)\r\n                return goal;\r\n            yield goal;\r\n        }\r\n    });\r\n\r\nawait pl.register(betwixt_3, /* optional module name */);\r\n```\r\n\r\nThe fanciest predicate function is an async generator, in which you can use `yield` to create choice points, and `return` as a kind of internal cut.\r\n\r\nYou can also use regular async functions (i.e. functions that return a `Promise`) or plain functions.\r\n\r\nThe Prolog interpreter will automatically yield to the host when calling a native predicate backed by an async function or generator.\r\n\r\n#### Evaluating JS code from Prolog\r\n\r\n**NOTE**: work in progress, see `examples/{hostcall,yield}.mjs`\r\n\r\nThe JS host will evaluate the expression you give it ~~and marshal it to JSON~~.\r\nYou can use `js_eval/2` to grab the result.\r\n\r\n```prolog\r\ngreet :-\r\n  js_eval(\"return prompt('Name?');\", Name),\r\n  format(\"Greetings, ~s.\", [Name]).\r\n\r\nhere(URL) :-\r\n  js_eval(\"return new trealla.Atom(location.href);\", URL).\r\n% URL = 'https://php.energy/trealla.html'\r\n```\r\n\r\nIf your evaluated code returns a promise, Prolog will yield to the host to evaluate the promise.\r\nHopefully this should be transparent to the user.\r\n\r\n```prolog\r\n?- js_eval(\"return fetch('http://example.com').then(x =\u003e x.text());\", Src).\r\n   Src = \"\u003chtml\u003e\u003chead\u003e\u003ctitle\u003eExample page...\"\r\n```\r\n\r\nFunction signature of eval:\r\n```typescript\r\nfunction eval(pl: Prolog, subq: Ptr\u003csubquery_t\u003e, goal: Goal, trealla: {...LIBRARY_BINDINGS}) {\r\n  /* your code here */\r\n  // return someTerm;\r\n}\r\n```\r\n\r\nThe `trealla` argument provides bindings to the library's constructors for terms.\r\n\r\n### Caveats\r\n\r\nMultiple queries can be run concurrently. If you'd like to kill a query early, use the `return()` method on the generator returned from `query()`.\r\nThis is not necessary if you iterate through until it is finished.\r\n\r\n### Output format\r\n\r\nYou can change the output format with the `format` option in queries.\r\n\r\nThe format is `\"json\"` by default which goes through `library(js)` and returns JSON-friendly Javascript objects (see: type `Term`).\r\n\r\n### `\"prolog\"` format\r\n\r\nYou can get pure text output with the `\"prolog\"` format.\r\nThe output is the same as Trealla's regular toplevel, but full terms (with a dot) are printed.\r\n\r\n```javascript\r\nfor await (const answer of pl.query(`dif(A, B) ; dif(C, D).`, {format: \"prolog\"})) {\r\n  console.log(answer);\r\n};\r\n// \"dif(A,B).\"\r\n// \"dif(C,D).\"\r\n```\r\n\r\n### Automatic yielding\r\n\r\nBy default, the interpreter will yield every 20ms to let the UI thread catch up.\r\nThis prevents long-running queries from freezing the browser, but incurs a small (~20%) overhead.\r\nYou can disable this behavior by setting the query option `autoyield` to `0`.\r\n\r\n### Virtual Filesystem\r\n\r\nEach Prolog interpreter instance has its own virtual filesystem you can read and write to.\r\nFor details, check out the [wasmer-js docs for `MemFS`](https://github.com/wasmerio/wasmer-js/tree/1184d7acbb77d424003b701278d2580107c50918?tab=readme-ov-file#typescript-api).\r\nAlthough we don't use wasmer-js anymore, the same API is still provided.\r\n\r\n```js\r\nconst pl = new Prolog();\r\n// create a file in the virtual filesystem\r\npl.fs.open(\"/greeting.pl\", { write: true, create: true }).writeString(`\r\n  :- module(greeting, [hello/1]).\r\n  hello(world).\r\n  hello(世界).\r\n`);\r\n\r\n// consult file\r\nawait pl.consult(\"/greeting.pl\");\r\n\r\n// use the file we added\r\nconst query = pl.query(\"use_module(greeting), hello(X)\");\r\nfor await (const answer of query) {\r\n  console.log(answer); // X = world, X = 世界\r\n}\r\n```\r\n\r\n### Template strings\r\n\r\nThe `prolog` string template literal is an easy way to escape terms.\r\nEach `${value}` will be interpreted as a Prolog term.\r\n\r\n```typescript\r\nimport { prolog, Variable } from \"trealla\";\r\nconst result = await pl.queryOnce(\r\n\tprolog`atom_chars(${new Variable(\"X\")}, ${\"Hello!\"}).`,\r\n);\r\nconsole.log(result.answer); // { X: Atom('Hello!') }\r\n```\r\n\r\n## Javascript API\r\nApproaching stability.\r\n\r\n```typescript\r\ndeclare module 'trealla' {\r\n  /** Call this first to load the runtime.\r\n    Must be called before any interpreters are constructed. */\r\n  function load(): Promise\u003cvoid\u003e;\r\n\r\n  /** Prolog interpreter.\r\n    Each interpreter is independent, having its own knowledgebase and virtual filesystem.\r\n    Multiple queries can be run against one interpreter simultaneously. */\r\n  class Prolog {\r\n    constructor(options?: PrologOptions);\r\n\r\n    /** Run a query. This is an asynchronous generator function.\r\n      Use a `for await` loop to easily iterate through results.\r\n      Exiting the loop will automatically destroy the query and reclaim memory.\r\n      If manually iterating with `next()`, call the `return()` method of the generator to kill it early.\r\n      Runtimes that support finalizers will make a best effort attempt to kill live but garbage-collected queries. */\r\n    public query\u003cT = Answer\u003e(goal: string, options?: QueryOptions): AsyncGenerator\u003cT, void, void\u003e;\r\n    /** Runs a query and returns a single solution, ignoring others. */\r\n    public queryOnce\u003cT = Answer\u003e(goal: string, options?: QueryOptions): Promise\u003cT\u003e;\r\n\r\n    /** Consult (load) a Prolog file with the given filename. */\r\n    public consult(filename: string): Promise\u003cvoid\u003e;\r\n    /** Consult (load) a Prolog file with the given text content. */\r\n    public consultText(text: string | Uint8Array): Promise\u003cvoid\u003e;\r\n\r\n    /** Use fs to manipulate the virtual filesystem. */\r\n    public readonly fs: FS;\r\n  }\r\n\r\n  interface PrologOptions {\r\n    /** Library files path (default: \"/library\")\r\n      This is to set the search path for use_module(library(...)). */\r\n    library?: string;\r\n    /** Environment variables.\r\n      Accessible with the predicate getenv/2. */\r\n    env?: Record\u003cstring, string\u003e;\r\n    /** Quiet mode. Disables warnings printed to stderr if true. */\r\n    quiet?: boolean;\r\n    /** Manually specify module instead of the default. */\r\n    module?: WebAssembly.Module;\r\n  }\r\n\r\n  interface QueryOptions {\r\n    /** Mapping of variables to bind in the query. */\r\n    bind?: Substitution;\r\n    /** Prolog program text to evaluate before the query. */\r\n    program?: string | Uint8Array;\r\n    /** Answer format. This changes the return type of the query generator.\r\n      `\"json\"` (default) returns Javascript objects.\r\n      `\"prolog\"` returns the standard Prolog toplevel output as strings.\r\n      You can add custom formats to the global `FORMATS` object.\r\n      You can also pass in a `Toplevel` object directly. */\r\n    format?: keyof typeof FORMATS | Toplevel\u003cany, any\u003e;\r\n    /** Encoding options for \"json\" or custom formats. */\r\n    encode?: EncodingOptions;\r\n    /** Automatic yield interval in milliseconds. Default is 20ms. */\r\n    autoyield?: number;\r\n  }\r\n\r\n  type EncodingOptions = JSONEncodingOptions | PrologEncodingOptions | Record\u003cstring, unknown\u003e;\r\n\r\n  interface JSONEncodingOptions {\r\n    /** Encoding for Prolog atoms. Default is \"object\". */\r\n    atoms?: \"string\" | \"object\";\r\n    /** Encoding for Prolog strings. Default is \"string\". */\r\n    strings?: \"string\" | \"list\";\r\n   \t/** Encoding for Prolog integers. Default is \"fit\", which uses bigints if outside of the safe integer range. */\r\n   \tintegers?: \"fit\" | \"bigint\" | \"number\";\r\n\r\n    /** Functor for compounds of arity 1 to be converted to booleans.\r\n      For example, `\"{}\"` to turn the Prolog term `{true}` into true ala Tau,\r\n      or `\"@\"` for SWI-ish behavior that uses `@(true)`. */\r\n    booleans?: string;\r\n    /** Functor for compounds of arity 1 to be converted to null.\r\n      For example, `\"{}\"` to turn the Prolog term `{null}` into null`. */\r\n    nulls?: string;\r\n    /** Functor for compounds of arity 1 to be converted to undefined.\r\n      For example, `\"{}\"` to turn the Prolog term `{undefined}` into undefined`. */\r\n    undefineds?: string;\r\n  }\r\n\r\n  interface PrologEncodingOptions {\r\n    /** Include the fullstop \".\" in results. */\r\n    /** True by default. */\r\n    dot?: boolean;\r\n  }\r\n\r\n  /** Answer for the \"json\" format. */\r\n  interface Answer {\r\n    status: \"success\" | \"failure\" | \"error\";\r\n    answer?: Substitution;\r\n    error?: Term;\r\n    /** Standard output text (`user_output` stream in Prolog) */\r\n    stdout?: string;\r\n    /** Standard error text (`user_error` stream in Prolog) */\r\n    stderr?: string;\r\n  }\r\n\r\n  /** Mapping of variable name → Term substitutions. */\r\n  type Substitution = Record\u003cstring, Term\u003e;\r\n\r\n  /** Prolog term.\r\n    Default encoding (in order of priority):\r\n    string(X)   → string\r\n    is_list(X)  → List\r\n    atom(X)     → Atom\r\n    compound(X) → Compound\r\n    integer(X)  → BigInt if necessary\r\n    rational(X) → Rational\r\n    number(X)   → number\r\n    var(X)      → Variable\r\n  */\r\n  type Term = Atom | Compound | Variable | List | string | number | bigint | Rational;\r\n\r\n  type List = Term[];\r\n\r\n  class Atom {\r\n    constructor(functor: string);\r\n    functor: string;\r\n    /** Predicate indicator (example: `\"foo/0\"`) */\r\n    readonly pi: string;\r\n    toProlog(): string;\r\n  }\r\n\r\n  /** String template literal for making atoms: atom`foo` = 'foo'. */\r\n  function atom([functor]): Atom;\r\n\r\n  class Compound {\r\n    constructor(functor: string, args: List);\r\n    functor: string;\r\n    args: List;\r\n    /** Predicate indicator (in `\"foo/N\"` format) */\r\n    readonly pi: string;\r\n    toProlog(): string;\r\n  }\r\n\r\n  class Variable {\r\n    constructor(name: string, attr: List);\r\n    /** Variable name. */\r\n    var: string;\r\n    /** Residual goals. */\r\n    attr?: List;\r\n    toProlog(): string;\r\n  }\r\n\r\n  type Numeric = number | bigint;\r\n\r\n  class Rational {\r\n    constructor(numerator: Numeric, denominator: Numeric);\r\n    numerator: Numeric;\r\n    denominator: Numeric;\r\n    toProlog(): string;\r\n  }\r\n\r\n  /** Convert Term objects to their Prolog text representation. */\r\n  function toProlog(object: Term): string;\r\n\r\n  /** Parse JSON representations of terms. */\r\n  function fromJSON(json: string, options?: JSONEncodingOptions): Term;\r\n\r\n  /** Convert Term objects to JSON text. */\r\n  function toJSON(term: Term, indent?: string): string;\r\n\r\n  const FORMATS: {\r\n    json: Toplevel\u003cAnswer, JSONEncodingOptions\u003e,\r\n    prolog: Toplevel\u003cstring, PrologEncodingOptions\u003e,\r\n    // add your own!\r\n    // [name: string]: Toplevel\u003cany, any\u003e\r\n  };\r\n\r\n  interface Toplevel\u003cT, Options\u003e {\r\n    /** Prepare query string, returns goal to execute. */\r\n    query(pl: Prolog, goal: string, bind?: Substitution, options?: Options): string;\r\n    /** Parse stdout and return an answer. */\r\n    parse(pl: Prolog, status: boolean, stdout: Uint8Array, stderr: Uint8Array, options?: Options): T;\r\n    /** Yield simple truth value, when output is blank.\r\n      For queries such as `true.` and `1=2.`.\r\n      Return null to bail early and yield no values. */\r\n    truth(pl: Prolog, status: boolean, stderr: Uint8Array, options?: Options): T | null;\r\n  }\r\n}\r\n```\r\n\r\n\r\n# Predicate reference\r\n\r\ntrealla-js includes [all libraries bundled with Trealla](https://github.com/guregu/trealla/tree/main/library).\r\nImport a library module with the `use_module(library(Name))` directive or predicate.\r\n\r\nThe predicates described below are imported by default.\r\n\r\n## Specialized built-ins\r\n\r\nThese predicates are Trealla built-ins specialized for a Javascript execution environment.\r\n\r\n### crypto_data_hash/3\r\n\r\nHashes the given string and options. Calls into the global [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest) object.\r\n\r\n```prolog\r\n%! crypto_data_hash(+Data, -Hash, +Options) is det.\r\n%  Unifies Hash with a hashed hex string representation of Data, which is a string.\r\n%  Options is a list of options:\r\n%  - algorithm(Algorithm): Algorithm is an atom representing the hash algorithm to use.\r\n%    One of: sha256 (default), sha386, sha512, sha1 (insecure).\r\ncrypto_data_hash(Data, Hash, Options).\r\n```\r\n\r\nThis will only work in secure contexts (i.e. over HTTPS) in browsers. Node users may need to set the global crypto object.\r\n\r\n```js\r\nimport crypto from \"node:crypto\";\r\nglobalThis.crypto = crypto;\r\n```\r\n\r\n### sleep/1\r\n\r\nSleeps for the given amount of seconds. This yields to the host, unblocking the main thread for the duration.\r\n\r\n```prolog\r\n%! sleep(+N) is det.\r\n%  Sleep for N seconds. N is an integer.\r\nsleep(Seconds).\r\n```\r\n\r\n## library(wasm_js)\r\n\r\nModule `library(wasm_js)` provides predicates for calling into the host.\r\n\r\n### http_consult/1\r\n\r\nLoad Prolog code from URL.\r\n\r\n```prolog\r\n%! http_consult(+URL) is det.\r\n%  Downloads Prolog code from URL, which must be a string, and consults it.\r\nhttp_consult(URL).\r\n```\r\n\r\n### http_fetch/3\r\n\r\nFetch content from a URL.\r\n\r\n```prolog\r\n%! http_fetch(+URL, +Options, -Content) is det.\r\n%  Fetch URL (string) and unify the result with Content.\r\n%  This is a friendly wrapper around Javascript's fetch API.\r\n%  Options is a list of options:\r\n%  - as(string): Content will be unified with the text of the result as a string\r\n%  - as(json): Content will be parsed as JSON and unified with a JSON term\r\n%  - headers([\"key\"-\"value\", ...]): HTTP headers to send\r\n%  - body(Cs): body to send (Cs is string)\r\nhttp_fetch(URL, Options, Content).\r\n```\r\n\r\n### js_eval_json/2\r\n\r\nEvaluate a string of Javascript code. Code is evaluated using [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function) and only has access to the global envrionment.\r\n\r\n```prolog\r\n%! js_eval_json(+Code, -JSON) is det.\r\n%  Evaluate Code, which must be a string of valid Javascript code.\r\n%  Returning a promise will cause the query to yield to the host. The host will await the promise and resume the query.\r\n%  Return values are encoded to JSON and returned as a JSON term (see pseudojson:json_value/2).\r\njs_eval_json(Code, JSON).\r\n```\r\n\r\n### js_eval/2\r\n\r\nLow-level predicate for evaluating JS code.\r\n\r\n```prolog\r\n%! js_eval(+Code, -Cs) is det.\r\n%  Low-level predicate that functions the same as js_eval_json/2 but without the JSON decoding.\r\n%  Returning a Uint8Array in your JS code will bypass the host's default JSON encoding.\r\n%  Combined with this, you can customize the host-\u003eguest API.\r\njs_eval(Code, Cs).\r\n```\r\n\r\n## library(pseudojson)\r\n\r\nModule `library(pseudojson)` is preloaded. It provides very fast predicates for encoding and decoding JSON.\r\nIts One Crazy Trick is using regular Prolog terms such as `{\"foo\":\"bar\"}` for reading/writing.\r\nThis means that it accepts invalid JSON that is a valid Prolog term.\r\n\r\nThe predicate `json_value/2` converts between the same representation of JSON values as `library(json)`, to ensure future compatibility.\r\nYou are free to use `library(json)` which provides a JSON DCG that properly validates (but is slow for certain inputs).\r\n\r\n### json_chars/2\r\n\r\nEncoding and decoding of JSON strings.\r\n\r\n```prolog\r\n%! json_chars(?JSON, ?Cs) is det.\r\n%  JSON is a Prolog term representing the JSON.\r\n%  Cs is a JSON string.\r\njson_chars(JSON, Cs).\r\n```\r\n\r\n### json_value/2\r\n\r\nRelates JSON terms and friendlier Value terms that are compatible with `library(json)`.\r\n\r\n- strings: `string(\"abc\")`\r\n- numbers: `number(123)`\r\n- booleans: `boolean(true)`\r\n- objects: `pairs([string(\"key\")-Value, ...])`\r\n- arrays: `list([...])`\r\n\r\n```prolog\r\n%! json_value(?JSON, ?Value) is det.\r\n%  Unifies JSON and Value with their library(pseudojson) and library(json) counterparts.\r\n%  Can be used to convert between JSON terms and friendlier Value terms.\r\njson_value(JSON, Value).\r\n```\r\n\r\n## Implementation Details\r\n\r\nCurrently uses the WASM build from [guregu/trealla](https://github.com/guregu/trealla).\r\nJSON output goes through the [`wasm`](https://github.com/guregu/trealla/blob/main/library/wasm.pl) module.\r\n\r\n### Development\r\n\r\nMake sure you can build Trealla.\r\n\r\n```bash\r\n# install deps\r\nnpm install\r\n# build wasm\r\nnpm run compile\r\n# build js\r\nnpm run build\r\n# (build and) run tests\r\nnpm run test\r\n```\r\n\r\n## See Also\r\n\r\n- [trealla-prolog/go](https://github.com/trealla-prolog/go) is Trealla for Go.\r\n- [Tau Prolog](http://www.tau-prolog.org/) is a pure Javascript Prolog.\r\n- [SWI Prolog](https://swi-prolog.discourse.group/t/swi-prolog-in-the-browser-using-wasm/5650) has a WASM implementation using Emscripten.\r\n- [Ciao](https://github.com/ciao-lang/ciaowasm) has a WASM implementation using Emscripten.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguregu%2Ftrealla-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguregu%2Ftrealla-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguregu%2Ftrealla-js/lists"}