API Reference
Exports
Section titled “Exports”The package exports didToJs, didToTs, parseDid, validateIDL,
verifyCompatibility, the deprecated verifyCompatability, and a default WASM
initializer, init, with a synchronous initSync companion.
didToJs
Section titled “didToJs”didToJs(candid: string): string
Compiles a Candid interface string into a JavaScript module string.
Parameters:
candid: The Candid interface definition string.
Returns:
- A string containing the JavaScript module source.
Output Exports: The generated JavaScript module exports:
idlFactory: AnIDL.InterfaceFactoryfunction.init: A function that returns initialization arguments.
import { didToJs } from "@ic-reactor/parser"
const js = didToJs("service:{}")// export const idlFactory ...didToTs
Section titled “didToTs”didToTs(candid: string): string
Compiles a Candid interface string into a TypeScript declaration string.
Parameters:
candid: The Candid interface definition string.
Returns:
- A string containing the TypeScript declaration source.
Output Includes:
- Imports from
@icp-sdk/core(or legacy@dfinity/agent). _SERVICEinterface defining the actor type.idlFactoryandinittype declarations.
import { didToTs } from "@ic-reactor/parser"
const ts = didToTs("service:{}")// export interface _SERVICE ...Renamed types
Section titled “Renamed types”didToTs exports each Candid type under its own name, next to the _SERVICE
interface. A type TypeScript cannot declare or refer to under its name is
renamed with _ appended, and didToJs uses the same name:
- a type named like a TypeScript type keyword:
string,number,bigint,symbol,object,any,unknown,neverorundefined; - a type named like a TypeScript type operator:
keyof,readonly,uniqueorinfer; - a type named
_SERVICEthat is not the service itself; - a type named like a JavaScript keyword, such as
class(candid_parser’s own rule).
import { didToTs } from "@ic-reactor/parser"
didToTs(`type string = record { value : text };service : { get : () -> (string) query }`)// export interface string_ { 'value' : string }// export interface _SERVICE { 'get' : ActorMethod<[], string_> }When string_ is taken by another type, the next free name (string__) is
used. A service type named _SERVICE that the service uses
(service : _SERVICE) keeps its name and is declared once, as the _SERVICE
interface.
Field names that look like numeric ids
Section titled “Field names that look like numeric ids”Candid identifies a named record field or variant tag by the hash of its name.
@icp-sdk/core reads an IDL key spelled _<digits>_ or _0x<hex digits>_,
for a number below 2^32, as that number instead, the spelling it uses for
numeric fields such as 0 : nat. So didToJs and didToTs print a field
named like that under its hash, and it is sent and read by that hash:
import { didToTs } from "@ic-reactor/parser"
didToTs(`service : { get : () -> (record { _0_ : nat; 0 : text }) query }`)// … ActorMethod<[], { _0_ : string, _4735054_ : bigint }>Use the printed key (_4735054_) for the value in calls and results.
parseDid names the field by the same key. Names that do not
match the pattern print as written. A hand-written .did that
spells a Motoko numeric field as _0_ must write it as 0, the way Motoko
prints it; spelled _0_, it is the field named _0_.
parseDid
Section titled “parseDid”parseDid(candid: string): CandidSchema
Parses a Candid interface string into a structured schema object (type declarations plus the service declaration), including any metadata tags.
Returns:
- A
CandidSchema:{ types: CandidTypeDeclaration[]; service: CandidServiceDeclaration | null }. Doc-comment metadata and validation tags are carried on the nodes — see Candid Metadata Tags. - Each record field and variant tag is named by the key
didToJsprints for it:_0_for the numeric field0, and_4735054_for a field named_0_(see Field names that look like numeric ids). Types keep their Candid names, including onedidToTsrenames.
import { parseDid } from "@ic-reactor/parser"
const schema = parseDid("service:{}")// { types: [...], service: { ... } | null }validateIDL
Section titled “validateIDL”validateIDL(candid: string): boolean
Returns true when the Candid source parses and type-checks. It never returns
false: for invalid Candid it throws the parser’s message as a string (a syntax
error, or a type error such as Unbound type identifier T), so call it inside
try / catch.
CandidAdapter.validateCandid(), which it
backs, catches that and returns false.
import { validateIDL } from "@ic-reactor/parser"
try { validateIDL("service : { greet : (text) -> (text) query }") // true} catch (message) { console.error(message) // e.g. "Unbound type identifier T"}verifyCompatibility
Section titled “verifyCompatibility”verifyCompatibility(oldDid: string, newDid: string): boolean
Returns true when newDid is a compatible upgrade of oldDid, so every
client of the old interface can keep calling the new one, and false when it
is not. Use it to guard canister upgrades against breaking interface changes.
Throws when either source does not parse or type-check, or declares no service.
import { verifyCompatibility } from "@ic-reactor/parser"
const oldDid = "service : { greet : (text) -> (text) query }"// Adding a method keeps every client of the old interface workingconst newDid = `service : { greet : (text) -> (text) query; farewell : (text) -> (text) query;}`
if (!verifyCompatibility(oldDid, newDid)) { throw new Error("The new interface breaks existing clients")}verifyCompatability (deprecated)
Section titled “verifyCompatability (deprecated)”verifyCompatability(a: string, b: string): boolean
Use verifyCompatibility(oldDid, newDid) instead. This older export returns
true when a is a compatible upgrade of b, so it takes the new interface
first, and it throws instead of returning false when the upgrade is not
compatible.
default (init)
Section titled “default (init)”init(module_or_path?): Promise<InitOutput>
Instantiates the WASM module. Required once before any other function on the
web build. A synchronous initSync(module) variant is also exported for
environments where the WASM bytes are already available.
On Node both exist for ES module imports and do nothing, because the Node build
instantiates the module when it loads. require returns only the parser
functions.
import init, { initSync } from "@ic-reactor/parser"
await init()Errors
Section titled “Errors”Invalid Candid makes a function throw the parser’s message as a string, such as
Candid parser error: Unrecognized EOF found at 11.
Some inputs make the parser itself fail, through a Rust panic or input nested or
repeated deeply enough to exhaust the stack. The function then throws an Error
whose message says the input could not be parsed, with the original
WebAssembly.RuntimeError or RangeError as its cause. Before it throws, the
parser replaces its WebAssembly instance with a new one built from the module it
already compiled, so later calls work normally and nothing is fetched again.
The web and Node builds behave this way. dist/bundler, which no export
condition selects, keeps wasm-bindgen’s generated loader and does not restart.
Module Formats
Section titled “Module Formats”The package builds for multiple targets to ensure compatibility across environments.
| Folder | Format | Resolved by |
|---|---|---|
dist/web |
ES Modules | browser, workerd and default conditions |
dist/nodejs |
ES Modules (index.mjs), CommonJS (index.js) |
node condition, for import and require |
dist/bundler |
ES Modules | Built and shipped, but not reachable via exports |
There is no ./web, ./nodejs or ./bundler subpath — the package has a
single . entry and the right build is picked by export conditions. Bundlers
resolve the browser condition to dist/web, which requires await init().