diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e5fe6aec7..c7638d1d07 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,12 +14,8 @@ # The check-basic-integration-tests-success job is designed to ensure that all jobs spun up from the matrix in the basic-integration-tests have succeeded # All Examples TODO restore when https://github.com/demergent-labs/azle/issues/1192 is resolved -# "examples/complex_types", -# "examples/func_types", # "examples/generics", -# "examples/motoko_examples/superheroes", # blocked by recursive # "examples/run_time_errors", -# "examples/tuple_types", name: Azle Tests on: @@ -74,12 +70,14 @@ jobs: "examples/candid_encoding", "examples/canister", "examples/complex_init", + "examples/complex_types", "examples/composite_queries", "examples/counter", "examples/cross_canister_calls", "examples/cycles", "examples/date", "examples/ethereum_json_rpc", + "examples/func_types", "examples/guard_functions", "examples/heartbeat", "examples/ic_api", @@ -104,6 +102,7 @@ jobs: "examples/motoko_examples/phone-book", "examples/motoko_examples/quicksort", "examples/motoko_examples/simple-to-do", + "examples/motoko_examples/superheroes", "examples/motoko_examples/threshold_ecdsa", "examples/motoko_examples/whoami", "examples/notify_raw", @@ -115,6 +114,7 @@ jobs: "examples/principal", "examples/query", "examples/randomness", + "examples/recursion", "examples/rejections", "examples/robust_imports", "examples/simple_erc20", @@ -122,6 +122,7 @@ jobs: "examples/stable_memory", "examples/stable_structures", "examples/timers", + "examples/tuple_types", "examples/update" ] END diff --git a/examples/bitcoin/src/index.did b/examples/bitcoin/src/index.did index b74fa19ac0..043bb7c09d 100644 --- a/examples/bitcoin/src/index.did +++ b/examples/bitcoin/src/index.did @@ -1,9 +1,6 @@ -type rec_14 = record {txid:vec nat8; vout:nat32}; -type rec_13 = record {height:nat32; value:nat64; outpoint:rec_14}; -type rec_12 = record {next_page:opt vec nat8; tip_height:nat32; tip_block_hash:vec nat8; utxos:vec rec_13}; service: () -> { getBalance: (text) -> (nat64); getCurrentFeePercentiles: () -> (vec nat64); - getUtxos: (text) -> (rec_12); + getUtxos: (text) -> (record {next_page:opt vec nat8; tip_height:nat32; tip_block_hash:vec nat8; utxos:vec record {height:nat32; value:nat64; outpoint:record {txid:vec nat8; vout:nat32}}}); sendTransaction: (vec nat8) -> (bool); } diff --git a/examples/canister/src/index.did b/examples/canister/src/index.did index dc020cd99a..2a6e359468 100644 --- a/examples/canister/src/index.did +++ b/examples/canister/src/index.did @@ -1,8 +1,7 @@ -type rec_0 = record {someCanister:service {query1:() -> (bool) query; update1:() -> (text) }}; service: () -> { - canisterParam: (service {query1:() -> (bool) query; update1:() -> (text) }) -> (service {query1:() -> (bool) query; update1:() -> (text) }) query; - canisterReturnType: () -> (service {query1:() -> (bool) query; update1:() -> (text) }) query; - canisterNestedReturnType: () -> (rec_0); - canisterList: (vec service {query1:() -> (bool) query; update1:() -> (text) }) -> (vec service {query1:() -> (bool) query; update1:() -> (text) }); - canisterCrossCanisterCall: (service {query1:() -> (bool) query; update1:() -> (text) }) -> (text); + canisterCrossCanisterCall: (service {query1: () -> (bool) query; update1: () -> (text);}) -> (text); + canisterList: (vec service {query1: () -> (bool) query; update1: () -> (text);}) -> (vec service {query1: () -> (bool) query; update1: () -> (text);}); + canisterNestedReturnType: () -> (record {someCanister:service {query1: () -> (bool) query; update1: () -> (text);}}); + canisterParam: (service {query1: () -> (bool) query; update1: () -> (text);}) -> (service {query1: () -> (bool) query; update1: () -> (text);}) query; + canisterReturnType: () -> (service {query1: () -> (bool) query; update1: () -> (text);}) query; } diff --git a/examples/complex_init/dfx.json b/examples/complex_init/dfx.json index 4e133518fa..d0d1e9bb68 100644 --- a/examples/complex_init/dfx.json +++ b/examples/complex_init/dfx.json @@ -2,15 +2,27 @@ "canisters": { "complex_init": { "type": "custom", - "main": "src/index.ts", + "main": "src/complex_init/index.ts", "build": "npx azle complex_init", - "candid": "src/index.did", + "candid": "src/complex_init/index.did", "wasm": ".azle/complex_init/complex_init.wasm", "gzip": true, "declarations": { "output": "test/dfx_generated/complex_init", "node_compatibility": true } + }, + "rec_init": { + "type": "custom", + "main": "src/rec_init/index.ts", + "build": "npx azle rec_init", + "candid": "src/rec_init/index.did", + "wasm": ".azle/rec_init/rec_init.wasm", + "gzip": true, + "declarations": { + "output": "test/dfx_generated/rec_init", + "node_compatibility": true + } } } } diff --git a/examples/complex_init/src/complex_init/index.did b/examples/complex_init/src/complex_init/index.did new file mode 100644 index 0000000000..fe1b700ef7 --- /dev/null +++ b/examples/complex_init/src/complex_init/index.did @@ -0,0 +1,3 @@ +service: (record {text; record {id:text}}) -> { + greetUser: () -> (text) query; +} diff --git a/examples/complex_init/src/index.ts b/examples/complex_init/src/complex_init/index.ts similarity index 100% rename from examples/complex_init/src/index.ts rename to examples/complex_init/src/complex_init/index.ts diff --git a/examples/complex_init/src/index.did b/examples/complex_init/src/index.did deleted file mode 100644 index c5e0ff4181..0000000000 --- a/examples/complex_init/src/index.did +++ /dev/null @@ -1,4 +0,0 @@ -type rec_0 = record {id:text}; -service: (record {text; rec_0}) -> { - greetUser: () -> (text) query; -} diff --git a/examples/complex_init/src/rec_init/index.did b/examples/complex_init/src/rec_init/index.did new file mode 100644 index 0000000000..b59721ecf3 --- /dev/null +++ b/examples/complex_init/src/rec_init/index.did @@ -0,0 +1,4 @@ +type rec_14 = variant {Leaf; Branch:rec_14}; +service: (rec_14) -> { + countBranches: () -> (nat) query; +} diff --git a/examples/complex_init/src/rec_init/index.ts b/examples/complex_init/src/rec_init/index.ts new file mode 100644 index 0000000000..f889a630c7 --- /dev/null +++ b/examples/complex_init/src/rec_init/index.ts @@ -0,0 +1,27 @@ +import { Canister, init, Null, query, Recursive, Variant, nat } from 'azle'; + +const Node = Recursive(() => + Variant({ + Leaf: Null, + Branch: Node + }) +); + +let tree: typeof Node = { Leaf: null }; + +export default Canister({ + init: init([Node], (node) => { + tree = node; + return undefined; + }), + countBranches: query([], nat, () => { + return countBranches(tree); + }) +}); + +function countBranches(node: typeof Node): nat { + if (node.Leaf !== undefined) { + return 1n; + } + return countBranches(node.Branch); +} diff --git a/examples/complex_init/test/pretest.ts b/examples/complex_init/test/pretest.ts index aec765eb9a..75fdf71c25 100644 --- a/examples/complex_init/test/pretest.ts +++ b/examples/complex_init/test/pretest.ts @@ -7,6 +7,10 @@ async function pretest() { stdio: 'inherit' }); + execSync(`dfx canister uninstall-code rec_init || true`, { + stdio: 'inherit' + }); + execSync( `dfx deploy complex_init --argument 'record {"Oh hello there user"; record { id = "1" }}'`, { @@ -14,9 +18,20 @@ async function pretest() { } ); + execSync( + `dfx deploy rec_init --argument 'variant {Branch = variant {Leaf}}'`, + { + stdio: 'inherit' + } + ); + execSync(`dfx generate complex_init`, { stdio: 'inherit' }); + + execSync(`dfx generate rec_init`, { + stdio: 'inherit' + }); } pretest(); diff --git a/examples/complex_init/test/test.ts b/examples/complex_init/test/test.ts index 360b581f45..a8d214f6d3 100644 --- a/examples/complex_init/test/test.ts +++ b/examples/complex_init/test/test.ts @@ -1,11 +1,21 @@ import { getCanisterId, runTests } from 'azle/test'; -import { createActor } from '../test/dfx_generated/complex_init'; -import { get_tests } from './tests'; +import { createActor as createComplexActor } from '../test/dfx_generated/complex_init'; +import { createActor as createRecActor } from '../test/dfx_generated/rec_init'; +import { get_rec_tests, get_tests } from './tests'; -const complexInitCanister = createActor(getCanisterId('complex_init'), { +const complexInitCanister = createComplexActor(getCanisterId('complex_init'), { agentOptions: { host: 'http://127.0.0.1:8000' } }); -runTests(get_tests(complexInitCanister)); +const recInitCanister = createRecActor(getCanisterId('rec_init'), { + agentOptions: { + host: 'http://127.0.0.1:8000' + } +}); + +runTests([ + ...get_tests(complexInitCanister), + ...get_rec_tests(recInitCanister) +]); diff --git a/examples/complex_init/test/tests.ts b/examples/complex_init/test/tests.ts index ccf00753b8..cf96b8917d 100644 --- a/examples/complex_init/test/tests.ts +++ b/examples/complex_init/test/tests.ts @@ -1,9 +1,10 @@ import { ActorSubclass } from '@dfinity/agent'; import { Test } from 'azle/test'; -import { _SERVICE } from './dfx_generated/complex_init/complex_init.did'; +import { _SERVICE as _COMPLEX_SERVICE } from './dfx_generated/complex_init/complex_init.did'; +import { _SERVICE as _REC_SERVICE } from './dfx_generated/rec_init/rec_init.did'; export function get_tests( - complex_init_canister: ActorSubclass<_SERVICE> + complex_init_canister: ActorSubclass<_COMPLEX_SERVICE> ): Test[] { return [ { @@ -18,3 +19,20 @@ export function get_tests( } ]; } + +export function get_rec_tests( + rec_init_canister: ActorSubclass<_REC_SERVICE> +): Test[] { + return [ + { + name: 'count branches', + test: async () => { + const result = await rec_init_canister.countBranches(); + + return { + Ok: result === 1n + }; + } + } + ]; +} diff --git a/examples/complex_types/dfx.json b/examples/complex_types/dfx.json index ac87899737..e572d2a5cb 100644 --- a/examples/complex_types/dfx.json +++ b/examples/complex_types/dfx.json @@ -5,7 +5,8 @@ "main": "src/index.ts", "build": "npx azle complex_types", "candid": "src/index.did", - "wasm": ".azle/complex_types/complex_types.wasm.gz", + "wasm": ".azle/complex_types/complex_types.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/complex_types", "node_compatibility": true diff --git a/examples/complex_types/src/candid_types.ts b/examples/complex_types/src/candid_types.ts new file mode 100644 index 0000000000..fe1f2d1469 --- /dev/null +++ b/examples/complex_types/src/candid_types.ts @@ -0,0 +1,41 @@ +import { Record, Null, text, Variant, Vec, Recursive } from 'azle'; + +export const ReactionType = Variant({ + Fire: Null, + ThumbsUp: Null, + ThumbsDown: Null +}); + +export const User = Recursive(() => + Record({ + id: text, + posts: Vec(Post), + reactions: Vec(Reaction), + threads: Vec(Thread), + username: text + }) +); + +export const Post = Recursive(() => + Record({ + id: text, + author: User, + reactions: Vec(Reaction), + text: text, + thread: Thread + }) +); + +export const Thread = Record({ + id: text, + author: User, + posts: Vec(Post), + title: text +}); + +export const Reaction = Record({ + id: text, + author: User, + post: Post, + reactionType: ReactionType +}); diff --git a/examples/complex_types/src/candid_types/post.ts b/examples/complex_types/src/candid_types/post.ts deleted file mode 100644 index 341b02421c..0000000000 --- a/examples/complex_types/src/candid_types/post.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { candid, Record, text, Vec } from 'azle'; -import { Reaction } from './reaction'; -import { Thread } from './thread'; -import { User } from './user'; - -export class Post extends Record { - @candid(text) - id: text; - - @candid(User) - author: User; - - @candid(Vec(Reaction)) - reactions: Vec; - - @candid(text) - text: text; - - @candid(Thread) - thread: Thread; -} diff --git a/examples/complex_types/src/candid_types/reaction.ts b/examples/complex_types/src/candid_types/reaction.ts deleted file mode 100644 index 57e936eefb..0000000000 --- a/examples/complex_types/src/candid_types/reaction.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { candid, Record, text } from 'azle'; -import { Post } from './post'; -import { ReactionType } from './reaction_type'; -import { User } from './user'; - -export class Reaction extends Record { - @candid(text) - id: text; - - @candid(User) - author: User; - - @candid(Post) - post: Post; - - @candid(ReactionType) - reactionType: ReactionType; -} diff --git a/examples/complex_types/src/candid_types/reaction_type.ts b/examples/complex_types/src/candid_types/reaction_type.ts deleted file mode 100644 index c44853365f..0000000000 --- a/examples/complex_types/src/candid_types/reaction_type.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { candid, Null, Variant } from 'azle'; - -export class ReactionType extends Variant { - @candid(Null) - Fire?: null; - - @candid(Null) - ThumbsUp?: null; - - @candid(Null) - ThumbsDown?: null; -} diff --git a/examples/complex_types/src/candid_types/thread.ts b/examples/complex_types/src/candid_types/thread.ts deleted file mode 100644 index 0fca81eb31..0000000000 --- a/examples/complex_types/src/candid_types/thread.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { candid, Record, text, Vec } from 'azle'; -import { Post } from './post'; -import { User } from './user'; - -export class Thread extends Record { - @candid(text) - id: text; - - @candid(User) - author: User; - - @candid(Vec(Post)) - posts: Vec; - - @candid(text) - title: text; -} diff --git a/examples/complex_types/src/candid_types/user.ts b/examples/complex_types/src/candid_types/user.ts deleted file mode 100644 index 1aaf8353fd..0000000000 --- a/examples/complex_types/src/candid_types/user.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { candid, Record, text, Vec } from 'azle'; -import { Post } from './post'; -import { Reaction } from './reaction'; -import { Thread } from './thread'; - -export class User extends Record { - @candid(text) - id: text; - - @candid(Vec(Post)) - posts: Vec; - - @candid(Vec(Reaction)) - reactions: Vec; - - @candid(Vec(Thread)) - threads: Vec; - - @candid(text) - username: text; -} diff --git a/examples/complex_types/src/index.did b/examples/complex_types/src/index.did index 8904ac346b..d75ebcf4b6 100644 --- a/examples/complex_types/src/index.did +++ b/examples/complex_types/src/index.did @@ -1,3 +1,58 @@ +type rec_441 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_441; posts:vec rec_440}; posts:vec rec_440; reactions:vec record {id:text; post:rec_440; author:rec_441; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_443 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_443; posts:vec rec_440}; posts:vec rec_440; reactions:vec record {id:text; post:rec_440; author:rec_443; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_442 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_442; posts:vec rec_440}; posts:vec rec_440; reactions:vec record {id:text; post:rec_440; author:rec_442; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_440 = record {id:text; text:text; author:rec_441; thread:record {id:text; title:text; author:rec_443; posts:vec rec_440}; reactions:vec record {id:text; post:rec_440; author:rec_442; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_485 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_485; posts:vec rec_484}; posts:vec rec_484; reactions:vec record {id:text; post:rec_484; author:rec_485; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_487 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_487; posts:vec rec_484}; posts:vec rec_484; reactions:vec record {id:text; post:rec_484; author:rec_487; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_486 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_486; posts:vec rec_484}; posts:vec rec_484; reactions:vec record {id:text; post:rec_484; author:rec_486; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_484 = record {id:text; text:text; author:rec_485; thread:record {id:text; title:text; author:rec_487; posts:vec rec_484}; reactions:vec record {id:text; post:rec_484; author:rec_486; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_483 = record {id:text; text:text; author:rec_480; thread:record {id:text; title:text; author:rec_480; posts:vec rec_483}; reactions:vec record {id:text; post:rec_483; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_481 = record {id:text; text:text; author:rec_480; thread:record {id:text; title:text; author:rec_480; posts:vec rec_481}; reactions:vec record {id:text; post:rec_481; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_482 = record {id:text; text:text; author:rec_480; thread:record {id:text; title:text; author:rec_480; posts:vec rec_482}; reactions:vec record {id:text; post:rec_482; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_480 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_480; posts:vec rec_483}; posts:vec rec_481; reactions:vec record {id:text; post:rec_482; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_547 = record {id:text; text:text; author:rec_544; thread:record {id:text; title:text; author:rec_544; posts:vec rec_547}; reactions:vec record {id:text; post:rec_547; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_545 = record {id:text; text:text; author:rec_544; thread:record {id:text; title:text; author:rec_544; posts:vec rec_545}; reactions:vec record {id:text; post:rec_545; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_546 = record {id:text; text:text; author:rec_544; thread:record {id:text; title:text; author:rec_544; posts:vec rec_546}; reactions:vec record {id:text; post:rec_546; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_544 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_544; posts:vec rec_547}; posts:vec rec_545; reactions:vec record {id:text; post:rec_546; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_549 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_549; posts:vec rec_548}; posts:vec rec_548; reactions:vec record {id:text; post:rec_548; author:rec_549; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_551 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_551; posts:vec rec_548}; posts:vec rec_548; reactions:vec record {id:text; post:rec_548; author:rec_551; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_550 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_550; posts:vec rec_548}; posts:vec rec_548; reactions:vec record {id:text; post:rec_548; author:rec_550; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_548 = record {id:text; text:text; author:rec_549; thread:record {id:text; title:text; author:rec_551; posts:vec rec_548}; reactions:vec record {id:text; post:rec_548; author:rec_550; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_603 = record {id:text; text:text; author:rec_600; thread:record {id:text; title:text; author:rec_600; posts:vec rec_603}; reactions:vec record {id:text; post:rec_603; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_601 = record {id:text; text:text; author:rec_600; thread:record {id:text; title:text; author:rec_600; posts:vec rec_601}; reactions:vec record {id:text; post:rec_601; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_602 = record {id:text; text:text; author:rec_600; thread:record {id:text; title:text; author:rec_600; posts:vec rec_602}; reactions:vec record {id:text; post:rec_602; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_600 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_600; posts:vec rec_603}; posts:vec rec_601; reactions:vec record {id:text; post:rec_602; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_457 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_457; posts:vec rec_456}; posts:vec rec_456; reactions:vec record {id:text; post:rec_456; author:rec_457; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_459 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_459; posts:vec rec_456}; posts:vec rec_456; reactions:vec record {id:text; post:rec_456; author:rec_459; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_458 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_458; posts:vec rec_456}; posts:vec rec_456; reactions:vec record {id:text; post:rec_456; author:rec_458; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_456 = record {id:text; text:text; author:rec_457; thread:record {id:text; title:text; author:rec_459; posts:vec rec_456}; reactions:vec record {id:text; post:rec_456; author:rec_458; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_517 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_517; posts:vec rec_516}; posts:vec rec_516; reactions:vec record {id:text; post:rec_516; author:rec_517; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_519 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_519; posts:vec rec_516}; posts:vec rec_516; reactions:vec record {id:text; post:rec_516; author:rec_519; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_518 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_518; posts:vec rec_516}; posts:vec rec_516; reactions:vec record {id:text; post:rec_516; author:rec_518; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_516 = record {id:text; text:text; author:rec_517; thread:record {id:text; title:text; author:rec_519; posts:vec rec_516}; reactions:vec record {id:text; post:rec_516; author:rec_518; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_515 = record {id:text; text:text; author:rec_512; thread:record {id:text; title:text; author:rec_512; posts:vec rec_515}; reactions:vec record {id:text; post:rec_515; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_513 = record {id:text; text:text; author:rec_512; thread:record {id:text; title:text; author:rec_512; posts:vec rec_513}; reactions:vec record {id:text; post:rec_513; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_514 = record {id:text; text:text; author:rec_512; thread:record {id:text; title:text; author:rec_512; posts:vec rec_514}; reactions:vec record {id:text; post:rec_514; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_512 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_512; posts:vec rec_515}; posts:vec rec_513; reactions:vec record {id:text; post:rec_514; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_579 = record {id:text; text:text; author:rec_576; thread:record {id:text; title:text; author:rec_576; posts:vec rec_579}; reactions:vec record {id:text; post:rec_579; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_577 = record {id:text; text:text; author:rec_576; thread:record {id:text; title:text; author:rec_576; posts:vec rec_577}; reactions:vec record {id:text; post:rec_577; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_578 = record {id:text; text:text; author:rec_576; thread:record {id:text; title:text; author:rec_576; posts:vec rec_578}; reactions:vec record {id:text; post:rec_578; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_576 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_576; posts:vec rec_579}; posts:vec rec_577; reactions:vec record {id:text; post:rec_578; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_581 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_581; posts:vec rec_580}; posts:vec rec_580; reactions:vec record {id:text; post:rec_580; author:rec_581; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_583 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_583; posts:vec rec_580}; posts:vec rec_580; reactions:vec record {id:text; post:rec_580; author:rec_583; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_582 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_582; posts:vec rec_580}; posts:vec rec_580; reactions:vec record {id:text; post:rec_580; author:rec_582; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_580 = record {id:text; text:text; author:rec_581; thread:record {id:text; title:text; author:rec_583; posts:vec rec_580}; reactions:vec record {id:text; post:rec_580; author:rec_582; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_619 = record {id:text; text:text; author:rec_616; thread:record {id:text; title:text; author:rec_616; posts:vec rec_619}; reactions:vec record {id:text; post:rec_619; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_617 = record {id:text; text:text; author:rec_616; thread:record {id:text; title:text; author:rec_616; posts:vec rec_617}; reactions:vec record {id:text; post:rec_617; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_618 = record {id:text; text:text; author:rec_616; thread:record {id:text; title:text; author:rec_616; posts:vec rec_618}; reactions:vec record {id:text; post:rec_618; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_616 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_616; posts:vec rec_619}; posts:vec rec_617; reactions:vec record {id:text; post:rec_618; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; service: () -> { - test: (record {id:text; username:text}) -> (text); + createPost: (text, text, text, nat32) -> (rec_440); + createReaction: (text, text, variant {Fire; ThumbsDown; ThumbsUp}, nat32) -> (record {id:text; post:rec_484; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}); + createThread: (text, text, nat32) -> (record {id:text; title:text; author:rec_544; posts:vec rec_548}); + createUser: (text, nat32) -> (rec_600); + getAllPosts: (nat32) -> (vec rec_456) query; + getAllReactions: (nat32) -> (vec record {id:text; post:rec_516; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}) query; + getAllThreads: (nat32) -> (vec record {id:text; title:text; author:rec_576; posts:vec rec_580}) query; + getAllUsers: (nat32) -> (vec rec_616) query; } diff --git a/examples/complex_types/src/index.ts b/examples/complex_types/src/index.ts index d8d2e931ec..e6fcf675f6 100644 --- a/examples/complex_types/src/index.ts +++ b/examples/complex_types/src/index.ts @@ -1,62 +1,16 @@ -import { nat32, query, Service, text, update, Vec } from 'azle'; -import { Post } from './candid_types/post'; -import { Reaction } from './candid_types/reaction'; -import { ReactionType } from './candid_types/reaction_type'; -import { Thread } from './candid_types/thread'; -import { User } from './candid_types/user'; +import { Canister } from 'azle'; import { createPost, getAllPosts } from './posts'; import { createReaction, getAllReactions } from './reactions'; import { createThread, getAllThreads } from './threads'; import { createUser, getAllUsers } from './users'; -export default class extends Service { - @update([text, text, text, nat32], Post) - createPost( - authorId: text, - text: text, - threadId: text, - joinDepth: nat32 - ): Post { - return createPost(authorId, text, threadId, joinDepth); - } - - @query([nat32], Vec(Post)) - getAllPosts(joinDepth: nat32): Vec { - return getAllPosts(joinDepth); - } - - @update([text, text, ReactionType, nat32], Reaction) - createReaction( - authorId: string, - postId: string, - reactionType: ReactionType, - joinDepth: nat32 - ): Reaction { - return createReaction(authorId, postId, reactionType, joinDepth); - } - - @query([nat32], Vec(Reaction)) - getAllReactions(joinDepth: nat32): Vec { - return getAllReactions(joinDepth); - } - - @update([text, text, nat32], Thread) - createThread(title: text, authorId: text, joinDepth: nat32): Thread { - return createThread(title, authorId, joinDepth); - } - - @query([nat32], Vec(Thread)) - getAllThreads(joinDepth: nat32): Vec { - return getAllThreads(joinDepth); - } - - @update([text, nat32], User) - createUser(username: string, joinDepth: nat32): User { - return createUser(username, joinDepth); - } - - @query([nat32], Vec(User)) - getAllUsers(joinDepth: nat32): Vec { - return getAllUsers(joinDepth); - } -} +export default Canister({ + createPost, + getAllPosts, + createReaction, + getAllReactions, + createThread, + getAllThreads, + createUser, + getAllUsers +}); diff --git a/examples/complex_types/src/posts.ts b/examples/complex_types/src/posts.ts index bb2a6dc4e6..1aae042d59 100644 --- a/examples/complex_types/src/posts.ts +++ b/examples/complex_types/src/posts.ts @@ -1,47 +1,52 @@ -import { nat32, Vec } from 'azle'; -import { Post } from './candid_types/post'; +import { nat32, query, text, update, Vec } from 'azle'; +import { Post } from './candid_types'; import { getReactionFromStateReaction } from './reactions'; import { state, StatePost, StateThread, StateUser } from './state'; import { getThreadFromStateThread } from './threads'; import { getUserFromStateUser } from './users'; -export function createPost( - authorId: string, - text: string, - threadId: string, - joinDepth: nat32 -): Post { - const id = Object.keys(state.posts).length.toString(); +export const createPost = update( + [text, text, text, nat32], + Post, + (authorId, text, threadId, joinDepth) => { + const id = Object.keys(state.posts).length.toString(); - const statePost: StatePost = { - id, - authorId, - reactionIds: [], - text, - threadId - }; - const updatedStateAuthor = getUpdatedStateAuthor(authorId, statePost.id); - const updatedStateThread = getUpdatedStateThread(threadId, statePost.id); + const statePost: StatePost = { + id, + authorId, + reactionIds: [], + text, + threadId + }; + const updatedStateAuthor = getUpdatedStateAuthor( + authorId, + statePost.id + ); + const updatedStateThread = getUpdatedStateThread( + threadId, + statePost.id + ); - state.posts[id] = statePost; - state.users[authorId] = updatedStateAuthor; - state.threads[threadId] = updatedStateThread; + state.posts[id] = statePost; + state.users[authorId] = updatedStateAuthor; + state.threads[threadId] = updatedStateThread; - const post = getPostFromStatePost(statePost, joinDepth); + const post = getPostFromStatePost(statePost, joinDepth); - return post; -} + return post; + } +); -export function getAllPosts(joinDepth: nat32): Vec { +export const getAllPosts = query([nat32], Vec(Post), (joinDepth) => { return Object.values(state.posts).map((statePost) => getPostFromStatePost(statePost, joinDepth) ); -} +}); export function getPostFromStatePost( statePost: StatePost, joinDepth: nat32 -): Post { +): typeof Post { const stateAuthor = state.users[statePost.authorId]; const author = getUserFromStateUser(stateAuthor, joinDepth); @@ -63,13 +68,13 @@ export function getPostFromStatePost( getReactionFromStateReaction(stateReaction, joinDepth - 1) ); - return Post.create({ + return { id: statePost.id, author, reactions, text: statePost.text, thread - }); + }; } } diff --git a/examples/complex_types/src/reactions.ts b/examples/complex_types/src/reactions.ts index 35e342b734..5820d501e1 100644 --- a/examples/complex_types/src/reactions.ts +++ b/examples/complex_types/src/reactions.ts @@ -1,61 +1,59 @@ -import { nat32, Vec } from 'azle'; -import { Reaction } from './candid_types/reaction'; -import { ReactionType } from './candid_types/reaction_type'; +import { nat32, query, text, update, Vec } from 'azle'; +import { Reaction, ReactionType } from './candid_types'; import { getPostFromStatePost } from './posts'; import { state, StatePost, StateReaction, StateUser } from './state'; import { getUserFromStateUser } from './users'; -export function createReaction( - authorId: string, - postId: string, - reactionType: ReactionType, - joinDepth: nat32 -): Reaction { - const id = Object.keys(state.reactions).length.toString(); +export const createReaction = update( + [text, text, ReactionType, nat32], + Reaction, + (authorId, postId, reactionType, joinDepth) => { + const id = Object.keys(state.reactions).length.toString(); - const stateReaction: StateReaction = { - id, - authorId, - postId, - reactionType - }; - const updatedStateAuthor = getUpdatedStateAuthor( - authorId, - stateReaction.id - ); - const updatedStatePost = getUpdatedStatePost(postId, stateReaction.id); + const stateReaction: StateReaction = { + id, + authorId, + postId, + reactionType + }; + const updatedStateAuthor = getUpdatedStateAuthor( + authorId, + stateReaction.id + ); + const updatedStatePost = getUpdatedStatePost(postId, stateReaction.id); - state.reactions[id] = stateReaction; - state.users[authorId] = updatedStateAuthor; - state.posts[postId] = updatedStatePost; + state.reactions[id] = stateReaction; + state.users[authorId] = updatedStateAuthor; + state.posts[postId] = updatedStatePost; - const reaction = getReactionFromStateReaction(stateReaction, joinDepth); + const reaction = getReactionFromStateReaction(stateReaction, joinDepth); - return reaction; -} + return reaction; + } +); -export function getAllReactions(joinDepth: nat32): Vec { +export const getAllReactions = query([nat32], Vec(Reaction), (joinDepth) => { return Object.values(state.reactions).map((stateReaction) => getReactionFromStateReaction(stateReaction, joinDepth) ); -} +}); export function getReactionFromStateReaction( stateReaction: StateReaction, joinDepth: nat32 -): Reaction { +): typeof Reaction { const stateAuthor = state.users[stateReaction.authorId]; const author = getUserFromStateUser(stateAuthor, joinDepth); const statePost = state.posts[stateReaction.postId]; const post = getPostFromStatePost(statePost, joinDepth); - return Reaction.create({ + return { id: stateReaction.id, author, post, reactionType: stateReaction.reactionType - }); + }; } function getUpdatedStateAuthor( diff --git a/examples/complex_types/src/threads.ts b/examples/complex_types/src/threads.ts index d070ba07a7..e4a358bed5 100644 --- a/examples/complex_types/src/threads.ts +++ b/examples/complex_types/src/threads.ts @@ -1,42 +1,45 @@ -import { nat32, Vec } from 'azle'; -import { Thread } from './candid_types/thread'; +import { nat32, query, text, update, Vec } from 'azle'; +import { Thread } from './candid_types'; import { getPostFromStatePost } from './posts'; import { state, StateThread, StateUser } from './state'; import { getUserFromStateUser } from './users'; -export function createThread( - title: string, - authorId: string, - joinDepth: nat32 -): Thread { - const id = Object.keys(state.threads).length.toString(); +export const createThread = update( + [text, text, nat32], + Thread, + (title, authorId, joinDepth) => { + const id = Object.keys(state.threads).length.toString(); - const stateThread: StateThread = { - id, - authorId, - postIds: [], - title - }; - const updatedStateAuthor = getUpdatedStateAuthor(authorId, stateThread.id); + const stateThread: StateThread = { + id, + authorId, + postIds: [], + title + }; + const updatedStateAuthor = getUpdatedStateAuthor( + authorId, + stateThread.id + ); - state.threads[id] = stateThread; - state.users[authorId] = updatedStateAuthor; + state.threads[id] = stateThread; + state.users[authorId] = updatedStateAuthor; - const thread = getThreadFromStateThread(stateThread, joinDepth); + const thread = getThreadFromStateThread(stateThread, joinDepth); - return thread; -} + return thread; + } +); -export function getAllThreads(joinDepth: nat32): Vec { +export const getAllThreads = query([nat32], Vec(Thread), (joinDepth) => { return Object.values(state.threads).map((stateThread) => getThreadFromStateThread(stateThread, joinDepth) ); -} +}); export function getThreadFromStateThread( stateThread: StateThread, joinDepth: nat32 -): Thread { +): typeof Thread { const stateAuthor = state.users[stateThread.authorId]; const author = getUserFromStateUser(stateAuthor, joinDepth); @@ -52,12 +55,12 @@ export function getThreadFromStateThread( .map((postId) => state.posts[postId]) .map((statePost) => getPostFromStatePost(statePost, joinDepth - 1)); - return Thread.create({ + return { id: stateThread.id, author, posts, title: stateThread.title - }); + }; } } diff --git a/examples/complex_types/src/users.ts b/examples/complex_types/src/users.ts index cc437169a5..4b9096c9e3 100644 --- a/examples/complex_types/src/users.ts +++ b/examples/complex_types/src/users.ts @@ -1,11 +1,11 @@ -import { nat32, Vec } from 'azle'; -import { User } from './candid_types/user'; +import { nat32, query, text, update, Vec } from 'azle'; +import { User } from './candid_types'; import { getPostFromStatePost } from './posts'; import { getReactionFromStateReaction } from './reactions'; import { state, StateUser } from './state'; import { getThreadFromStateThread } from './threads'; -export function createUser(username: string, joinDepth: nat32): User { +export const createUser = update([text, nat32], User, (username, joinDepth) => { const id = Object.keys(state.users).length.toString(); const stateUser: StateUser = { @@ -21,18 +21,18 @@ export function createUser(username: string, joinDepth: nat32): User { const user = getUserFromStateUser(stateUser, joinDepth); return user; -} +}); -export function getAllUsers(joinDepth: nat32): Vec { +export const getAllUsers = query([nat32], Vec(User), (joinDepth) => { return Object.values(state.users).map((stateUser) => getUserFromStateUser(stateUser, joinDepth) ); -} +}); export function getUserFromStateUser( stateUser: StateUser, joinDepth: nat32 -): User { +): typeof User { if (joinDepth === 0) { return { id: stateUser.id, @@ -58,12 +58,12 @@ export function getUserFromStateUser( getThreadFromStateThread(stateThread, joinDepth - 1) ); - return User.create({ + return { id: stateUser.id, posts, reactions, threads, username: stateUser.username - }); + }; } } diff --git a/examples/composite_queries/src/canister1/index.did b/examples/composite_queries/src/canister1/index.did index c62ac41a3b..c06801e6f2 100644 --- a/examples/composite_queries/src/canister1/index.did +++ b/examples/composite_queries/src/canister1/index.did @@ -1,12 +1,12 @@ service: () -> { - simpleCompositeQuery: () -> (text) query; - manualQuery: () -> (text) query; - totallyManualQuery: () -> (text) query; deepQuery: () -> (text) query; - updateQuery: () -> (text) query; - simpleQuery: () -> (text) query; - simpleUpdate: () -> (text); - incCounter: () -> (nat) query; incCanister1: () -> (nat) query; incCanister2: () -> (nat) query; + incCounter: () -> (nat) query; + manualQuery: () -> (text) query; + simpleCompositeQuery: () -> (text) query; + simpleQuery: () -> (text) query; + simpleUpdate: () -> (text); + totallyManualQuery: () -> (text) query; + updateQuery: () -> (text) query; } diff --git a/examples/composite_queries/src/canister1/index.ts b/examples/composite_queries/src/canister1/index.ts index 309cabb66c..a186c4994f 100644 --- a/examples/composite_queries/src/canister1/index.ts +++ b/examples/composite_queries/src/canister1/index.ts @@ -14,13 +14,7 @@ import Canister2 from '../canister2'; let canister2: typeof Canister2; let counter: nat = 0n; -const incCounter = query([], nat, async () => { - counter += 1n; - - return counter; -}); - -export default Canister({ +const CompQueryCanister = Canister({ init: init([], () => { canister2 = Canister2( Principal.fromText( @@ -63,17 +57,19 @@ export default Canister({ return await ic.call(canister2.deepQuery); }), // Composite query that modifies the state. Should revert after the call is done - incCounter, + incCounter: query([], nat, async () => { + counter += 1n; + + return counter; + }), // Composite query calling queries on the same canister incCanister1: query([], nat, async () => { // TODO This is not an ideal solution but will work for now - const self = Canister({ - incCounter - })(ic.id()); + const self: any = CompQueryCanister(ic.id()); counter += 1n; - const canister1AResult = await ic.call(self.incCounter); + const canister1AResult: any = await ic.call(self.incCounter); const canister1BResult = await ic.call(self.incCounter); return counter + canister1AResult + canister1BResult; @@ -88,3 +84,5 @@ export default Canister({ return counter + canister2AResult + canister2BResult; }) }); + +export default CompQueryCanister; diff --git a/examples/composite_queries/src/canister2/index.did b/examples/composite_queries/src/canister2/index.did index 779ccf764d..01f39353d7 100644 --- a/examples/composite_queries/src/canister2/index.did +++ b/examples/composite_queries/src/canister2/index.did @@ -1,7 +1,7 @@ service: () -> { + deepQuery: () -> (text) query; incCounter: () -> (nat) query; + manualQuery: () -> (text) query; simpleQuery: () -> (text) query; updateQuery: () -> (text); - manualQuery: () -> (text) query; - deepQuery: () -> (text) query; } diff --git a/examples/cross_canister_calls/src/canister1/index.did b/examples/cross_canister_calls/src/canister1/index.did index 36003a4a00..6b20dd1de2 100644 --- a/examples/cross_canister_calls/src/canister1/index.did +++ b/examples/cross_canister_calls/src/canister1/index.did @@ -1,11 +1,8 @@ -type rec_3 = record {id:text}; -type rec_4 = record {id:text; balance:nat64}; -type rec_5 = record {id:text; balance:nat64}; service: () -> { - transfer: (text, text, nat64) -> (nat64); + account: (record {id:text}) -> (opt record {id:text; balance:nat64}); + accounts: () -> (vec record {id:text; balance:nat64}); balance: (text) -> (nat64); - account: (rec_3) -> (opt rec_4); - accounts: () -> (vec rec_5); - trap: () -> (text); sendNotification: () -> (); + transfer: (text, text, nat64) -> (nat64); + trap: () -> (text); } diff --git a/examples/cross_canister_calls/src/canister2/index.did b/examples/cross_canister_calls/src/canister2/index.did index 83ffe987ef..25c20581d3 100644 --- a/examples/cross_canister_calls/src/canister2/index.did +++ b/examples/cross_canister_calls/src/canister2/index.did @@ -1,12 +1,9 @@ -type rec_0 = record {id:text}; -type rec_1 = record {id:text; balance:nat64}; -type rec_2 = record {id:text; balance:nat64}; service: () -> { - transfer: (text, text, nat64) -> (nat64); + account: (record {id:text}) -> (opt record {id:text; balance:nat64}) query; + accounts: () -> (vec record {id:text; balance:nat64}) query; balance: (text) -> (nat64) query; - account: (rec_0) -> (opt rec_1) query; - accounts: () -> (vec rec_2) query; - trap: () -> (text) query; - receiveNotification: (text) -> (); getNotification: () -> (text) query; + receiveNotification: (text) -> (); + transfer: (text, text, nat64) -> (nat64); + trap: () -> (text) query; } diff --git a/examples/ethereum_json_rpc/src/index.did b/examples/ethereum_json_rpc/src/index.did index 76ed21ee25..fbffd45803 100644 --- a/examples/ethereum_json_rpc/src/index.did +++ b/examples/ethereum_json_rpc/src/index.did @@ -1,10 +1,5 @@ -type rec_25 = record {value:text; name:text}; -type rec_24 = record {status:nat; body:vec nat8; headers:vec rec_25}; -type rec_23 = record {context:vec nat8; response:rec_24}; -type rec_27 = record {value:text; name:text}; -type rec_26 = record {status:nat; body:vec nat8; headers:vec rec_27}; service: (text) -> { ethGetBalance: (text) -> (text); ethGetBlockByNumber: (nat32) -> (text); - ethTransform: (rec_23) -> (rec_26) query; + ethTransform: (record {context:vec nat8; response:record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}}) -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}) query; } diff --git a/examples/func_types/canisters/func_types/index.did b/examples/func_types/canisters/func_types/index.did index 9fab503be8..289a4bd06a 100644 --- a/examples/func_types/canisters/func_types/index.did +++ b/examples/func_types/canisters/func_types/index.did @@ -1,50 +1,15 @@ -type ComplexFunc = func ( - record { - id : text; - complexFunc : ComplexFunc; - basicFunc : func (text) -> (text) query; - }, - variant { - Bad; - ComplexFunc : ComplexFunc; - Good; - BasicFunc : func (text) -> (text) query; - }, - ) -> (nat64); -type ManualReply = variant { Ok : func (vec nat8) -> () oneway; Err : text }; -type Reaction = variant { - Bad; - ComplexFunc : ComplexFunc; - Good; - BasicFunc : func (text) -> (text) query; -}; -type User = record { - id : text; - complexFunc : ComplexFunc; - basicFunc : func (text) -> (text) query; -}; -service : () -> { - basicFuncParam : (func (text) -> (text) query) -> ( - func (text) -> (text) query, - ) query; - basicFuncParamArray : (vec func (text) -> (text) query) -> ( - vec func (text) -> (text) query, - ) query; - basicFuncReturnType : () -> (func (text) -> (text) query) query; - basicFuncReturnTypeArray : () -> (vec func (text) -> (text) query) query; - complexFuncParam : (func (User, Reaction) -> (nat64)) -> ( - func (User, Reaction) -> (nat64), - ) query; - complexFuncReturnType : () -> (func (User, Reaction) -> (nat64)) query; - getNotifierFromNotifiersCanister : () -> (ManualReply); - getStableFunc : () -> (func (nat64, text) -> () query) query; - nullFuncParam : ( - func (opt null, vec null, null, vec vec null, vec opt null) -> ( - null, - ) query, - ) -> ( - func (opt null, vec null, null, vec vec null, vec opt null) -> ( - null, - ) query, - ) query; +type rec_26 = func (record {id:text; complexFunc:rec_26; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_26; Good; BasicFunc:func (text) -> (text) query}) -> (nat64) ; +type rec_29 = func (record {id:text; complexFunc:rec_29; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_29; Good; BasicFunc:func (text) -> (text) query}) -> (nat64) ; +type rec_34 = func (record {id:text; complexFunc:rec_34; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_34; Good; BasicFunc:func (text) -> (text) query}) -> (nat64) ; +service: () -> { + basicFuncParam: (func (text) -> (text) query) -> (func (text) -> (text) query) query; + basicFuncParamArray: (vec func (text) -> (text) query) -> (vec func (text) -> (text) query) query; + basicFuncReturnType: () -> (func (text) -> (text) query) query; + basicFuncReturnTypeArray: () -> (vec func (text) -> (text) query) query; + complexFuncParam: (rec_26) -> (rec_29) query; + complexFuncReturnType: () -> (rec_34) query; + getNotifierFromNotifiersCanister: () -> (func (vec nat8) -> () oneway) ; + getStableFunc: () -> (func (nat64, text) -> () query) query; + init: () -> () query; + nullFuncParam: (func (opt null, vec null, null, vec vec null, vec opt null) -> (null) query) -> (func (opt null, vec null, null, vec vec null, vec opt null) -> (null) query) query; } \ No newline at end of file diff --git a/examples/func_types/canisters/func_types/index.ts b/examples/func_types/canisters/func_types/index.ts index b317653fd9..01165f4b0c 100644 --- a/examples/func_types/canisters/func_types/index.ts +++ b/examples/func_types/canisters/func_types/index.ts @@ -1,4 +1,5 @@ import { + Canister, Func, init, ic, @@ -7,115 +8,98 @@ import { Principal, query, Record, - Service, StableBTreeMap, update, Variant, Vec, - candid, text, - func, Void, - Null + Null, + Recursive } from 'azle'; import Notifier, { NotifierFunc } from '../notifiers'; -@func([text], text, 'query') -class BasicFunc extends Func {} - -@func([User, Reaction], nat64, 'update') -class ComplexFunc extends Func {} - -class User extends Record { - @candid(text) - id: text; +const BasicFunc = Func([text], text, 'query'); - @candid(BasicFunc) - basicFunc: BasicFunc; +const ComplexFunc = Recursive(() => Func([User, Reaction], nat64, 'update')); - @candid(ComplexFunc) - complexFunc: ComplexFunc; -} +const User = Record({ + id: text, + basicFunc: BasicFunc, + complexFunc: ComplexFunc +}); -class Reaction extends Variant { - Good: null; - Bad: null; - BasicFunc: BasicFunc; - ComplexFunc: ComplexFunc; -} +const Reaction = Variant({ + Good: Null, + Bad: Null, + BasicFunc: BasicFunc, + ComplexFunc: ComplexFunc +}); -@func([nat64, text], Void, 'query') -class StableFunc extends Func {} +const StableFunc = Func([nat64, text], Void, 'query'); -@func( +const NullFunc = Func( [Opt(Null), Vec(Null), Null, Vec(Vec(Null)), Vec(Opt(Null))], Null, 'query' -) -class NullFunc extends Func {} +); -export default class extends Service { - stableStorage = new StableBTreeMap(text, StableFunc, 0); +let stableStorage = StableBTreeMap(text, StableFunc, 0); - @init([]) - init() { - this.stableStorage.insert( - 'stableFunc', - new StableFunc(Principal.from('aaaaa-aa'), 'start_canister') - ); - } +export default Canister({ + init: init([], () => { + stableStorage.insert('stableFunc', [ + Principal.from('aaaaa-aa'), + 'start_canister' + ]); + }), - @query([], StableFunc) - getStableFunc(): StableFunc { - const stableFuncOpt = this.stableStorage.get('stableFunc'); + getStableFunc: query([], StableFunc, () => { + const stableFuncOpt = stableStorage.get('stableFunc'); if (stableFuncOpt.length === 1) { return stableFuncOpt[0]; } - return new StableFunc(Principal.from('aaaaa-aa'), 'raw_rand'); - } + return [Principal.from('aaaaa-aa'), 'raw_rand']; + }), - @query([BasicFunc], BasicFunc) - basicFuncParam(basicFunc: BasicFunc): BasicFunc { + basicFuncParam: query([BasicFunc], BasicFunc, (basicFunc) => { return basicFunc; - } + }), - @query([NullFunc], NullFunc) - nullFuncParam(nullFunc: NullFunc): NullFunc { + nullFuncParam: query([NullFunc], NullFunc, (nullFunc) => { return nullFunc; - } + }), - @query([Vec(BasicFunc)], Vec(BasicFunc)) - basicFuncParamArray(basicFunc: Vec): Vec { - return basicFunc; - } + basicFuncParamArray: query( + [Vec(BasicFunc)], + Vec(BasicFunc), + (basicFunc) => { + return basicFunc; + } + ), - @query([], BasicFunc) - basicFuncReturnType(): BasicFunc { - return new BasicFunc(Principal.fromText('aaaaa-aa'), 'create_canister'); - } + basicFuncReturnType: query([], BasicFunc, () => { + return [Principal.fromText('aaaaa-aa'), 'create_canister']; + }), - @query([], Vec(BasicFunc)) - basicFuncReturnTypeArray(): Vec { + basicFuncReturnTypeArray: query([], Vec(BasicFunc), () => { return [ - new BasicFunc(Principal.fromText('aaaaa-aa'), 'create_canister'), - new BasicFunc(Principal.fromText('aaaaa-aa'), 'update_settings'), - new BasicFunc(Principal.fromText('aaaaa-aa'), 'install_code') + [Principal.fromText('aaaaa-aa'), 'create_canister'], + [Principal.fromText('aaaaa-aa'), 'update_settings'], + [Principal.fromText('aaaaa-aa'), 'install_code'] ]; - } + }), - @query([ComplexFunc], ComplexFunc) - complexFuncParam(complexFunc: ComplexFunc): ComplexFunc { + complexFuncParam: query([ComplexFunc], ComplexFunc, (complexFunc) => { return complexFunc; - } + }), - @query([], ComplexFunc) - complexFuncReturnType(): ComplexFunc { + complexFuncReturnType: query([], ComplexFunc, () => { return [Principal.fromText('aaaaa-aa'), 'stop_canister']; - } + }), - @update([], NotifierFunc) - async getNotifierFromNotifiersCanister(): Promise { - const notifiersCanister: Notifier = new Notifier( + getNotifierFromNotifiersCanister: update([], NotifierFunc, async () => { + const notifiersCanister = Notifier( Principal.fromText( process.env.NOTIFIERS_PRINCIPAL ?? ic.trap('process.env.NOTIFIERS_PRINCIPAL is undefined') @@ -123,5 +107,5 @@ export default class extends Service { ); return await ic.call(notifiersCanister.getNotifier); - } -} + }) +}); diff --git a/examples/func_types/canisters/notifiers/index.did b/examples/func_types/canisters/notifiers/index.did index 9ea58c8334..72c0545dc8 100644 --- a/examples/func_types/canisters/notifiers/index.did +++ b/examples/func_types/canisters/notifiers/index.did @@ -1,3 +1,3 @@ service: () -> { - getNotifier: () -> (func (vec nat8) -> () oneway) query; -} + getNotifier: () -> (func (vec nat8) -> () oneway) query; +} \ No newline at end of file diff --git a/examples/func_types/canisters/notifiers/index.ts b/examples/func_types/canisters/notifiers/index.ts index ddfc393c19..204c3135e1 100644 --- a/examples/func_types/canisters/notifiers/index.ts +++ b/examples/func_types/canisters/notifiers/index.ts @@ -1,17 +1,15 @@ -import { ic, Principal, query, blob, Func, Service, Void, func } from 'azle'; +import { Canister, ic, Principal, query, blob, Func, Void } from 'azle'; -@func([blob], Void, 'oneway') -export class NotifierFunc extends Func {} +export const NotifierFunc = Func([blob], Void, 'oneway'); -export default class extends Service { - @query([], NotifierFunc) - getNotifier(): NotifierFunc { - return new NotifierFunc( +export default Canister({ + getNotifier: query([], NotifierFunc, () => { + return [ Principal.fromText( process.env.NOTIFIERS_PRINCIPAL ?? ic.trap('process.env.NOTIFIERS_PRINCIPAL is undefined') ), 'notify' - ); - } -} + ]; + }) +}); diff --git a/examples/func_types/dfx.json b/examples/func_types/dfx.json index ea939ee18b..dcaaa7abbe 100644 --- a/examples/func_types/dfx.json +++ b/examples/func_types/dfx.json @@ -5,7 +5,8 @@ "main": "canisters/func_types/index.ts", "build": "npx azle func_types", "candid": "canisters/func_types/index.did", - "wasm": ".azle/func_types/func_types.wasm.gz", + "wasm": ".azle/func_types/func_types.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/func_types", "node_compatibility": true @@ -17,7 +18,8 @@ "main": "canisters/notifiers/index.ts", "build": "npx azle notifiers", "candid": "canisters/notifiers/index.did", - "wasm": ".azle/notifiers/notifiers.wasm.gz", + "wasm": ".azle/notifiers/notifiers.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/notifiers", "node_compatibility": true diff --git a/examples/ledger_canister/src/ledger_canister/index.did b/examples/ledger_canister/src/ledger_canister/index.did index fa9bf09b34..b782e58e0e 100644 --- a/examples/ledger_canister/src/ledger_canister/index.did +++ b/examples/ledger_canister/src/ledger_canister/index.did @@ -1,57 +1,11 @@ -type rec_116 = record {allowed_window_nanos:nat64}; -type rec_113 = record {e8s:nat64}; -type rec_112 = record {expected_fee:rec_113}; -type rec_117 = record {duplicate_of:nat64}; -type rec_115 = record {e8s:nat64}; -type rec_114 = record {balance:rec_115}; -type rec_111 = variant {TxTooOld:rec_116; BadFee:rec_112; TxDuplicate:rec_117; TxCreatedInFuture; InsufficientFunds:rec_114}; -type rec_110 = variant {Ok:nat64; Err:rec_111}; -type rec_118 = record {e8s:nat64}; -type rec_120 = record {e8s:nat64}; -type rec_119 = record {transfer_fee:rec_120}; -type rec_121 = record {start:nat64; length:nat64}; -type rec_129 = record {e8s:nat64}; -type rec_128 = record {from:vec nat8; amount:rec_129}; -type rec_127 = record {e8s:nat64}; -type rec_126 = record {to:vec nat8; amount:rec_127}; -type rec_132 = record {e8s:nat64}; -type rec_131 = record {e8s:nat64}; -type rec_130 = record {to:vec nat8; fee:rec_132; from:vec nat8; amount:rec_131}; -type rec_125 = variant {Burn:rec_128; Mint:rec_126; Transfer:rec_130}; -type rec_133 = record {timestamp_nanos:nat64}; -type rec_124 = record {memo:nat64; operation:opt rec_125; created_at_time:rec_133}; -type rec_134 = record {timestamp_nanos:nat64}; -type rec_123 = record {transaction:rec_124; timestamp:rec_134; parent_hash:opt vec nat8}; -type rec_136 = record {start:nat64; length:nat64}; -type rec_145 = record {e8s:nat64}; -type rec_144 = record {from:vec nat8; amount:rec_145}; -type rec_143 = record {e8s:nat64}; -type rec_142 = record {to:vec nat8; amount:rec_143}; -type rec_148 = record {e8s:nat64}; -type rec_147 = record {e8s:nat64}; -type rec_146 = record {to:vec nat8; fee:rec_148; from:vec nat8; amount:rec_147}; -type rec_141 = variant {Burn:rec_144; Mint:rec_142; Transfer:rec_146}; -type rec_149 = record {timestamp_nanos:nat64}; -type rec_140 = record {memo:nat64; operation:opt rec_141; created_at_time:rec_149}; -type rec_150 = record {timestamp_nanos:nat64}; -type rec_139 = record {transaction:rec_140; timestamp:rec_150; parent_hash:opt vec nat8}; -type rec_138 = record {blocks:vec rec_139}; -type rec_152 = record {requested_index:nat64; first_valid_index:nat64}; -type rec_153 = record {error_message:text; error_code:nat64}; -type rec_151 = variant {BadFirstBlockIndex:rec_152; Other:rec_153}; -type rec_137 = variant {Ok:rec_138; Err:rec_151}; -type rec_135 = record {callback:func (rec_136) -> (rec_137) query; start:nat64; length:nat64}; -type rec_122 = record {certificate:opt vec nat8; blocks:vec rec_123; chain_length:nat64; first_block_index:nat64; archived_blocks:vec rec_135}; -type rec_155 = record {canister_id:principal}; -type rec_154 = record {archives:vec rec_155}; service: () -> { - executeTransfer: (text, nat64, nat64, opt nat64) -> (rec_110); - getAccountBalance: (text) -> (rec_118); - getTransferFee: () -> (rec_119); - getBlocks: (rec_121) -> (rec_122); - getSymbol: () -> (text); - getName: () -> (text); - getDecimals: () -> (nat32); - getArchives: () -> (rec_154); + executeTransfer: (text, nat64, nat64, opt nat64) -> (variant {Ok:nat64; Err:variant {TxTooOld:record {allowed_window_nanos:nat64}; BadFee:record {expected_fee:record {e8s:nat64}}; TxDuplicate:record {duplicate_of:nat64}; TxCreatedInFuture; InsufficientFunds:record {balance:record {e8s:nat64}}}}) ; + getAccountBalance: (text) -> (record {e8s:nat64}) ; getAddressFromPrincipal: (principal) -> (text) query; + getArchives: () -> (record {archives:vec record {canister_id:principal}}) ; + getBlocks: (record {start:nat64; length:nat64}) -> (record {certificate:opt vec nat8; blocks:vec record {transaction:record {memo:nat64; operation:opt variant {Burn:record {from:vec nat8; amount:record {e8s:nat64}}; Mint:record {to:vec nat8; amount:record {e8s:nat64}}; Transfer:record {to:vec nat8; fee:record {e8s:nat64}; from:vec nat8; amount:record {e8s:nat64}}}; created_at_time:record {timestamp_nanos:nat64}}; timestamp:record {timestamp_nanos:nat64}; parent_hash:opt vec nat8}; chain_length:nat64; first_block_index:nat64; archived_blocks:vec record {callback:func (record {start:nat64; length:nat64}) -> (variant {Ok:record {blocks:vec record {transaction:record {memo:nat64; operation:opt variant {Burn:record {from:vec nat8; amount:record {e8s:nat64}}; Mint:record {to:vec nat8; amount:record {e8s:nat64}}; Transfer:record {to:vec nat8; fee:record {e8s:nat64}; from:vec nat8; amount:record {e8s:nat64}}}; created_at_time:record {timestamp_nanos:nat64}}; timestamp:record {timestamp_nanos:nat64}; parent_hash:opt vec nat8}}; Err:variant {BadFirstBlockIndex:record {requested_index:nat64; first_valid_index:nat64}; Other:record {error_message:text; error_code:nat64}}}) query; start:nat64; length:nat64}}) ; + getDecimals: () -> (nat32) ; + getName: () -> (text) ; + getSymbol: () -> (text) ; + getTransferFee: () -> (record {transfer_fee:record {e8s:nat64}}) ; } diff --git a/examples/management_canister/src/index.did b/examples/management_canister/src/index.did index dc30cc1319..1c11a82a54 100644 --- a/examples/management_canister/src/index.did +++ b/examples/management_canister/src/index.did @@ -1,21 +1,15 @@ -type rec_43 = record {canister_id:principal}; -type rec_44 = record {canister_id:principal}; -type rec_46 = variant {stopped; stopping; running}; -type rec_47 = record {freezing_threshold:nat; controllers:vec principal; memory_allocation:nat; compute_allocation:nat}; -type rec_45 = record {status:rec_46; memory_size:nat; cycles:nat; settings:rec_47; module_hash:opt vec nat8}; -type rec_48 = record {canister_id:principal}; service: () -> { - executeCreateCanister: () -> (rec_43); - executeUpdateSettings: (principal) -> (bool); + executeCreateCanister: () -> (record {canister_id:principal}); + executeDeleteCanister: (principal) -> (bool); + executeDepositCycles: (principal) -> (bool); executeInstallCode: (principal, vec nat8) -> (bool); - executeUninstallCode: (principal) -> (bool); executeStartCanister: (principal) -> (bool); executeStopCanister: (principal) -> (bool); - getCanisterStatus: (rec_44) -> (rec_45); - executeDeleteCanister: (principal) -> (bool); - executeDepositCycles: (principal) -> (bool); + executeUninstallCode: (principal) -> (bool); + executeUpdateSettings: (principal) -> (bool); + getCanisterStatus: (record {canister_id:principal}) -> (record {status:variant {stopped; stopping; running}; memory_size:nat; cycles:nat; settings:record {freezing_threshold:nat; controllers:vec principal; memory_allocation:nat; compute_allocation:nat}; module_hash:opt vec nat8}); + getCreatedCanisterId: () -> (principal) query; getRawRand: () -> (vec nat8); - provisionalCreateCanisterWithCycles: () -> (rec_48); + provisionalCreateCanisterWithCycles: () -> (record {canister_id:principal}); provisionalTopUpCanister: (principal, nat) -> (bool); - getCreatedCanisterId: () -> (principal) query; } diff --git a/examples/motoko_examples/superheroes/src/declarations/superheroes.did b/examples/motoko_examples/superheroes/src/declarations/superheroes.did index 0ecec61832..3770e592a2 100644 --- a/examples/motoko_examples/superheroes/src/declarations/superheroes.did +++ b/examples/motoko_examples/superheroes/src/declarations/superheroes.did @@ -1,13 +1,9 @@ -type Superhero = record { - "name": text; - "superpowers": opt List; -}; - -type List = record { text; opt List }; - -service: { - read: (nat32) -> (opt Superhero) query; - create: (Superhero) -> (nat32); - update: (nat32, Superhero) -> (bool); - delete_hero: (nat32) -> (bool); -} +type rec_28 = record {text; opt rec_28}; +type rec_33 = record {text; opt rec_33}; +type rec_36 = record {text; opt rec_36}; +service: () -> { + create: (record {superpowers:opt rec_28; name:text}) -> (nat32) ; + deleteHero: (nat32) -> (bool) ; + read: (nat32) -> (opt record {superpowers:opt rec_33; name:text}) query; + update: (nat32, record {superpowers:opt rec_36; name:text}) -> (bool) ; +} \ No newline at end of file diff --git a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts index fbb471d2dc..fe81f1b8a5 100644 --- a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts +++ b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts @@ -1,14 +1,18 @@ import type { Principal } from '@dfinity/principal'; import type { ActorMethod } from '@dfinity/agent'; -export type List = [string, [] | [List]]; -export interface Superhero { - superpowers: [] | [List]; - name: string; -} +export type rec_28 = [string, [] | [rec_28]]; +export type rec_33 = [string, [] | [rec_33]]; +export type rec_36 = [string, [] | [rec_36]]; export interface _SERVICE { - create: ActorMethod<[Superhero], number>; - delete_hero: ActorMethod<[number], boolean>; - read: ActorMethod<[number], [] | [Superhero]>; - update: ActorMethod<[number, Superhero], boolean>; + create: ActorMethod<[{ superpowers: [] | [rec_28]; name: string }], number>; + deleteHero: ActorMethod<[number], boolean>; + read: ActorMethod< + [number], + [] | [{ superpowers: [] | [rec_33]; name: string }] + >; + update: ActorMethod< + [number, { superpowers: [] | [rec_36]; name: string }], + boolean + >; } diff --git a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js index abff0d95de..4a110b6606 100644 --- a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js +++ b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js @@ -1,15 +1,34 @@ export const idlFactory = ({ IDL }) => { - const List = IDL.Rec(); - List.fill(IDL.Tuple(IDL.Text, IDL.Opt(List))); - const Superhero = IDL.Record({ - superpowers: IDL.Opt(List), - name: IDL.Text - }); + const rec_28 = IDL.Rec(); + const rec_33 = IDL.Rec(); + const rec_36 = IDL.Rec(); + rec_28.fill(IDL.Tuple(IDL.Text, IDL.Opt(rec_28))); + rec_33.fill(IDL.Tuple(IDL.Text, IDL.Opt(rec_33))); + rec_36.fill(IDL.Tuple(IDL.Text, IDL.Opt(rec_36))); return IDL.Service({ - create: IDL.Func([Superhero], [IDL.Nat32], []), - delete_hero: IDL.Func([IDL.Nat32], [IDL.Bool], []), - read: IDL.Func([IDL.Nat32], [IDL.Opt(Superhero)], ['query']), - update: IDL.Func([IDL.Nat32, Superhero], [IDL.Bool], []) + create: IDL.Func( + [IDL.Record({ superpowers: IDL.Opt(rec_28), name: IDL.Text })], + [IDL.Nat32], + [] + ), + deleteHero: IDL.Func([IDL.Nat32], [IDL.Bool], []), + read: IDL.Func( + [IDL.Nat32], + [ + IDL.Opt( + IDL.Record({ superpowers: IDL.Opt(rec_33), name: IDL.Text }) + ) + ], + ['query'] + ), + update: IDL.Func( + [ + IDL.Nat32, + IDL.Record({ superpowers: IDL.Opt(rec_36), name: IDL.Text }) + ], + [IDL.Bool], + [] + ) }); }; export const init = ({ IDL }) => { diff --git a/examples/motoko_examples/superheroes/src/superheroes/index.did b/examples/motoko_examples/superheroes/src/superheroes/index.did index 0ecec61832..3770e592a2 100644 --- a/examples/motoko_examples/superheroes/src/superheroes/index.did +++ b/examples/motoko_examples/superheroes/src/superheroes/index.did @@ -1,13 +1,9 @@ -type Superhero = record { - "name": text; - "superpowers": opt List; -}; - -type List = record { text; opt List }; - -service: { - read: (nat32) -> (opt Superhero) query; - create: (Superhero) -> (nat32); - update: (nat32, Superhero) -> (bool); - delete_hero: (nat32) -> (bool); -} +type rec_28 = record {text; opt rec_28}; +type rec_33 = record {text; opt rec_33}; +type rec_36 = record {text; opt rec_36}; +service: () -> { + create: (record {superpowers:opt rec_28; name:text}) -> (nat32) ; + deleteHero: (nat32) -> (bool) ; + read: (nat32) -> (opt record {superpowers:opt rec_33; name:text}) query; + update: (nat32, record {superpowers:opt rec_36; name:text}) -> (bool) ; +} \ No newline at end of file diff --git a/examples/motoko_examples/superheroes/src/superheroes/index.ts b/examples/motoko_examples/superheroes/src/superheroes/index.ts index a46342a215..1f4f20e5d9 100644 --- a/examples/motoko_examples/superheroes/src/superheroes/index.ts +++ b/examples/motoko_examples/superheroes/src/superheroes/index.ts @@ -17,10 +17,7 @@ import { export type SuperheroId = nat32; const SuperheroId = nat32; -const List = Tuple( - text, - Recursive(() => Opt(List)) -); +const List = Recursive(() => Tuple(text, Opt(List))); // The type of a superhero. const Superhero = Record({ diff --git a/examples/motoko_examples/threshold_ecdsa/src/index.did b/examples/motoko_examples/threshold_ecdsa/src/index.did index 69a1c2bb9b..74f57782b3 100644 --- a/examples/motoko_examples/threshold_ecdsa/src/index.did +++ b/examples/motoko_examples/threshold_ecdsa/src/index.did @@ -1,6 +1,4 @@ -type rec_51 = record {publicKey:vec nat8}; -type rec_52 = record {signature:vec nat8}; service: () -> { - publicKey: () -> (rec_51); - sign: (vec nat8) -> (rec_52); + publicKey: () -> (record {publicKey:vec nat8}); + sign: (vec nat8) -> (record {signature:vec nat8}); } diff --git a/examples/motoko_examples/whoami/src/index.did b/examples/motoko_examples/whoami/src/index.did index e1800ff5cf..938102e04d 100644 --- a/examples/motoko_examples/whoami/src/index.did +++ b/examples/motoko_examples/whoami/src/index.did @@ -1,7 +1,7 @@ service: (principal) -> { - installer: () -> (principal) query; argument: () -> (principal) query; - whoami: () -> (principal); id: () -> (principal); idQuick: () -> (principal) query; -} + installer: () -> (principal) query; + whoami: () -> (principal); +} \ No newline at end of file diff --git a/examples/motoko_examples/whoami/src/index.ts b/examples/motoko_examples/whoami/src/index.ts index 7d5188ee22..16387afade 100644 --- a/examples/motoko_examples/whoami/src/index.ts +++ b/examples/motoko_examples/whoami/src/index.ts @@ -5,54 +5,55 @@ import { postUpgrade, Principal, query, - update + Recursive, + update, + Void } from 'azle'; // We use the zero principal but any principal could be used. let install: Principal = Principal.fromText('aaaaa-aa'); let someone: Principal = Principal.fromText('aaaaa-aa'); -const whoami = update([], Principal, () => { - return ic.caller(); -}); +const WhoAmI = Recursive(() => + Canister({ + // Manually save the calling principal and argument for later access. + init: init([Principal], (somebody) => { + install = ic.caller(); + someone = somebody; + }), + // Manually re-save these variables after new deploys. + postUpgrade: postUpgrade([Principal], (somebody) => { + install = ic.caller(); + someone = somebody; + }), + // Return the principal identifier of the wallet canister that installed this + // canister. + installer: query([], Principal, () => { + return install; + }), + // Return the principal identifier that was provided as an installation + // argument to this canister. + argument: query([], Principal, () => { + return someone; + }), + // Return the principal identifier of the caller of this method. + whoami: update([], Principal, () => { + return ic.caller(); + }), + // Return the principal identifier of this canister. + id: update([], Principal, async () => { + const self = WhoAmI(ic.id()); -export default Canister({ - // Manually save the calling principal and argument for later access. - init: init([Principal], (somebody) => { - install = ic.caller(); - someone = somebody; - }), - // Manually re-save these variables after new deploys. - postUpgrade: postUpgrade([Principal], (somebody) => { - install = ic.caller(); - someone = somebody; - }), - // Return the principal identifier of the wallet canister that installed this - // canister. - installer: query([], Principal, () => { - return install; - }), - // Return the principal identifier that was provided as an installation - // argument to this canister. - argument: query([], Principal, () => { - return someone; - }), - // Return the principal identifier of the caller of this method. - whoami, - // Return the principal identifier of this canister. - id: update([], Principal, async () => { - // TODO This is not an ideal solution but will work for now - const self = Canister({ - whoami - })(ic.id()); - - return await ic.call(self.whoami); - }), - // Return the principal identifier of this canister via the global `ic` object. - // This is much quicker than `id()` above because it isn't making a cross- - // canister call to itself. Additionally, it can now be a `Query` which means it - // doesn't have to go through consensus. - idQuick: query([], Principal, () => { - return ic.id(); + return await ic.call(self.whoami); + }), + // Return the principal identifier of this canister via the global `ic` object. + // This is much quicker than `id()` above because it isn't making a cross- + // canister call to itself. Additionally, it can now be a `Query` which means it + // doesn't have to go through consensus. + idQuick: query([], Principal, () => { + return ic.id(); + }) }) -}); +); + +export default WhoAmI; diff --git a/examples/outgoing_http_requests/src/index.did b/examples/outgoing_http_requests/src/index.did index b329d2a5dd..bd5b328ba0 100644 --- a/examples/outgoing_http_requests/src/index.did +++ b/examples/outgoing_http_requests/src/index.did @@ -1,14 +1,5 @@ -type rec_52 = record {value:text; name:text}; -type rec_51 = record {status:nat; body:vec nat8; headers:vec rec_52}; -type rec_54 = record {value:text; name:text}; -type rec_53 = record {status:nat; body:vec nat8; headers:vec rec_54}; -type rec_57 = record {value:text; name:text}; -type rec_56 = record {status:nat; body:vec nat8; headers:vec rec_57}; -type rec_55 = record {context:vec nat8; response:rec_56}; -type rec_59 = record {value:text; name:text}; -type rec_58 = record {status:nat; body:vec nat8; headers:vec rec_59}; service: () -> { - xkcd: () -> (rec_51); - xkcdRaw: () -> (rec_53); - xkcdTransform: (rec_55) -> (rec_58) query; + xkcd: () -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}); + xkcdRaw: () -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}); + xkcdTransform: (record {context:vec nat8; response:record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}}) -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}) query; } diff --git a/examples/recursion/Cargo.lock b/examples/recursion/Cargo.lock deleted file mode 100644 index 666a952a04..0000000000 --- a/examples/recursion/Cargo.lock +++ /dev/null @@ -1,950 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base32" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" - -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" - -[[package]] -name = "binread" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" -dependencies = [ - "binread_derive", - "lazy_static", - "rustversion", -] - -[[package]] -name = "binread_derive" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" -dependencies = [ - "either", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "candid" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba9e536514a3c655568e23e36e68cbef20ee6595f641719ade03a849a13ed0ac" -dependencies = [ - "anyhow", - "binread", - "byteorder", - "candid_derive", - "codespan-reporting", - "hex", - "ic-types", - "lalrpop", - "lalrpop-util", - "leb128", - "logos", - "num-bigint", - "num-traits", - "num_enum", - "paste", - "pretty", - "serde", - "serde_bytes", - "thiserror", -] - -[[package]] -name = "candid_derive" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e02c03c4d547674a3f3f3109538fb49871fbe636216daa019f06a62faca9061" -dependencies = [ - "lazy_static", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "either" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "ic-cdk" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e471fa2e2464d4f9d676b81d33ae0d1cd190981166c53bbe4d536f13da281fc6" -dependencies = [ - "candid", - "cfg-if", - "serde", -] - -[[package]] -name = "ic-cdk-macros" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb6d2c14db28f427154a52088077419edf1848e2bbd0f527dee3150e592a0863" -dependencies = [ - "candid", - "ic-cdk", - "proc-macro2", - "quote", - "serde", - "serde_tokenstream", - "syn", -] - -[[package]] -name = "ic-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e78ec6f58886cdc252d6f912dc794211bd6bbc39ddc9dcda434b2dc16c335b3" -dependencies = [ - "base32", - "crc32fast", - "hex", - "serde", - "serde_bytes", - "sha2", - "thiserror", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "lalrpop" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" -dependencies = [ - "ascii-canvas", - "atty", - "bit-set", - "diff", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" -dependencies = [ - "regex", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "logos" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" -dependencies = [ - "logos-derive", -] - -[[package]] -name = "logos-derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" -dependencies = [ - "beef", - "fnv", - "proc-macro2", - "quote", - "regex-syntax", - "syn", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "once_cell" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "paste" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "pretty" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9940b913ee56ddd94aec2d3cd179dd47068236f42a1a6415ccf9d880ce2a61" -dependencies = [ - "arrayvec", - "typed-arena", -] - -[[package]] -name = "proc-macro-crate" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" -dependencies = [ - "thiserror", - "toml", -] - -[[package]] -name = "proc-macro2" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "rust" -version = "0.0.0" -dependencies = [ - "ic-cdk", - "ic-cdk-macros", -] - -[[package]] -name = "rustversion" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "serde" -version = "1.0.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_tokenstream" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6deb15c3a535e81438110111d90168d91721652f502abb147f31cde129f683d" -dependencies = [ - "proc-macro2", - "serde", - "syn", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer", - "cfg-if", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "string_cache" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - -[[package]] -name = "syn" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "typed-arena" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-ident" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/examples/recursion/Cargo.toml b/examples/recursion/Cargo.toml deleted file mode 100644 index 4513438de5..0000000000 --- a/examples/recursion/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[workspace] -members = [ - "canisters/rust", -] - -[profile.release] -lto = true -opt-level = 'z' -codegen-units = 1 diff --git a/examples/recursion/dfx.json b/examples/recursion/dfx.json index abc071e77c..05f3c8b1e0 100644 --- a/examples/recursion/dfx.json +++ b/examples/recursion/dfx.json @@ -2,13 +2,27 @@ "canisters": { "recursion": { "type": "custom", - "main": "src/index.ts", + "main": "src/recursion/index.ts", "build": "npx azle recursion", - "candid": "src/index.did", - "wasm": ".azle/recursion/recursion.wasm.gz", + "candid": "src/recursion/index.did", + "wasm": ".azle/recursion/recursion.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/recursion", "node_compatibility": true + }, + "env": ["MY_CANISTER_PRINCIPAL"] + }, + "recursive_canister": { + "type": "custom", + "main": "src/recursive_canister/index.ts", + "build": "npx azle recursive_canister", + "candid": "src/recursive_canister/index.did", + "wasm": ".azle/recursive_canister/recursive_canister.wasm", + "gzip": true, + "declarations": { + "output": "test/dfx_generated/recursive_canister", + "node_compatibility": true } } } diff --git a/examples/recursion/src/index.did b/examples/recursion/src/index.did deleted file mode 100644 index 5532077698..0000000000 --- a/examples/recursion/src/index.did +++ /dev/null @@ -1,23 +0,0 @@ -type rec_1 = variant {num:int8; varRec:rec_0}; -type rec_0 = record {myVar:rec_1}; -type rec_3 = variant {num:int8; varRec:rec_2}; -type rec_2 = record {myVar:rec_3}; -type rec_4 = variant {num:int8; recVariant:rec_4}; -type rec_5 = variant {num:int8; recVariant:rec_5}; -type rec_7 = variant {num:int8; varRec:rec_6}; -type rec_6 = record {myVar:rec_7}; -type rec_8 = variant {num:int8; recVariant:rec_8}; -type rec_9 = variant {num:int8; varTuple:record {rec_9; rec_9}}; -type rec_10 = variant {num:int8; varTuple:record {rec_10; rec_10}}; -type rec_11 = variant {num:int8; varTuple:record {rec_11; rec_11}}; -type rec_12 = variant {num:int8; varTuple:record {rec_12; rec_12}}; -type rec_13 = variant {num:int8; varTuple:record {rec_13; rec_13}}; -type rec_14 = variant {num:int8; varTuple:record {rec_14; rec_14}}; -service: () -> { - testRecRecordWithVariant: (rec_0) -> (rec_2) query; - testRecVariant: (rec_4) -> (rec_5) query; - testRecRecordWithVariantReturn: () -> (rec_6) query; - testRecVariantReturn: () -> (rec_8) query; - testRecTupleWithVariant: (record {rec_9; rec_10}) -> (record {rec_11; rec_12}) query; - testRecTupleWithVariantReturn: () -> (record {rec_13; rec_14}) query; -} diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did new file mode 100644 index 0000000000..0b3b6b0e80 --- /dev/null +++ b/examples/recursion/src/recursion/index.did @@ -0,0 +1,53 @@ +type rec_365 = func (rec_365) -> (rec_365) query; +type rec_368 = func (rec_368) -> (rec_368) query; +type rec_373 = func (rec_373) -> (rec_373) query; +type rec_281 = record {myOpt:opt rec_281}; +type rec_284 = record {myOpt:opt rec_284}; +type rec_329 = record {myOpt:opt rec_329}; +type rec_297 = record {myVar:variant {num:int8; varRec:rec_297}}; +type rec_300 = record {myVar:variant {num:int8; varRec:rec_300}}; +type rec_337 = record {myVar:variant {num:int8; varRec:rec_337}}; +type rec_289 = record {myVecRecords:vec rec_289}; +type rec_292 = record {myVecRecords:vec rec_292}; +type rec_333 = record {myVecRecords:vec rec_333}; +type rec_385 = service {getMessage: () -> (text) query; myQuery: (rec_385) -> (rec_385) query;}; +type rec_388 = service {getMessage: () -> (text) query; myQuery: (rec_388) -> (rec_388) query;}; +type rec_397 = service {getMessage: () -> (text) query; myQuery: (rec_397) -> (rec_397) query;}; +type rec_400 = service {getMessage: () -> (text) query; myQuery: (rec_400) -> (rec_400) query;}; +type rec_393 = service {getMessage: () -> (text) query; myQuery: (rec_393) -> (rec_393) query;}; +type rec_377 = service {myQuery: (rec_377) -> (rec_377) query;}; +type rec_380 = service {myQuery: (rec_380) -> (rec_380) query;}; +type rec_313 = record {opt rec_313; opt rec_313}; +type rec_316 = record {opt rec_316; opt rec_316}; +type rec_345 = record {opt rec_345; opt rec_345}; +type rec_353 = record {variant {num:int8; varTuple:rec_353}; variant {num:int8; varTuple:rec_353}}; +type rec_356 = record {variant {num:int8; varTuple:rec_356}; variant {num:int8; varTuple:rec_356}}; +type rec_361 = record {variant {num:int8; varTuple:rec_361}; variant {num:int8; varTuple:rec_361}}; +type rec_321 = record {vec rec_321; vec rec_321}; +type rec_324 = record {vec rec_324; vec rec_324}; +type rec_349 = record {vec rec_349; vec rec_349}; +type rec_305 = variant {num:int8; recVariant:rec_305}; +type rec_308 = variant {num:int8; recVariant:rec_308}; +type rec_341 = variant {num:int8; recVariant:rec_341}; +service: () -> { + testRecFunc: (rec_365) -> (rec_368) query; + testRecFuncReturn: () -> (rec_373) query; + testRecRecordWithOpt: (rec_281) -> (rec_284) query; + testRecRecordWithOptReturn: () -> (rec_329) query; + testRecRecordWithVariant: (rec_297) -> (rec_300) query; + testRecRecordWithVariantReturn: () -> (rec_337) query; + testRecRecordWithVec: (rec_289) -> (rec_292) query; + testRecRecordWithVecReturn: () -> (rec_333) query; + testRecService: (rec_385) -> (rec_388) query; + testRecServiceCall: (rec_397) -> (rec_400); + testRecServiceReturn: () -> (rec_393) query; + testRecServiceSimple: (rec_377) -> (rec_380) query; + testRecTupleWithOpt: (rec_313) -> (rec_316) query; + testRecTupleWithOptReturn: () -> (rec_345) query; + testRecTupleWithVariant: (rec_353) -> (rec_356) query; + testRecTupleWithVariantReturn: () -> (rec_361) query; + testRecTupleWithVec: (rec_321) -> (rec_324) query; + testRecTupleWithVecReturn: () -> (rec_349) query; + testRecVariant: (rec_305) -> (rec_308) query; + testRecVariantReturn: () -> (rec_341) query; +} diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/recursion/index.ts similarity index 52% rename from examples/recursion/src/index.ts rename to examples/recursion/src/recursion/index.ts index d840a346c1..4959221a93 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/recursion/index.ts @@ -1,51 +1,75 @@ -import { query, Service, text, Tuple, Vec, Void } from 'azle'; -import { Record, Recursive, int8, Variant, Opt } from 'azle'; +import { + Func, + ic, + None, + Principal, + query, + Canister, + Some, + Tuple, + update, + Vec, + Record, + Recursive, + int8, + Variant, + Opt +} from 'azle'; +import MyFullCanister from '../recursive_canister'; // These are the types that can be recursive // Record // Record can't be recursive by itself. It needs something to be able to terminate it. It needs to work with Variants, Opts, and Vec -// const optRecord = Record({ myOpt: Opt(Recursive(() => optRecord)) }); -// const vecRecord = Record({ myVecRecords: Vec(Recursive(() => vecRecord)) }); -const varRecord = Record({ myVar: Recursive(() => myVar) }); -// TODO I would prefer this syntax -// const varRecord = Recursive(() => Record({ myVar: myVar })); -// const vecRecord = Recursive(() => Record({ myVecRecords: Vec(vecRecord) })); -// const optRecord = Recursive(() => Record({ myOpt: Opt(optRecord) })); +const varRecord = Recursive(() => Record({ myVar: myVar })); +const vecRecord = Recursive(() => Record({ myVecRecords: Vec(vecRecord) })); +const optRecord = Recursive(() => Record({ myOpt: Opt(optRecord) })); const myVar = Variant({ num: int8, varRec: varRecord }); // Variant // Variant is the only type that can be recursive all by itself but it does need a way to end the recursion -const recVariant = Variant({ - num: int8, - recVariant: Recursive(() => recVariant) -}); +const recVariant = Recursive(() => + Variant({ num: int8, recVariant: recVariant }) +); // Tuple const optTuple = Recursive(() => Tuple(Opt(optTuple), Opt(optTuple))); -const vecTuple = Recursive(() => Vec(vecTuple)); -// const varTuple = Recursive(() => Tuple(myTupleVar, myTupleVar)); -const varTuple = Tuple( - Recursive(() => myTupleVar), - Recursive(() => myTupleVar) -); +const vecTuple = Recursive(() => Tuple(Vec(vecTuple), Vec(vecTuple))); +const varTuple = Recursive(() => Tuple(myTupleVar, myTupleVar)); const myTupleVar = Variant({ num: int8, varTuple: varTuple }); // Vec // Vec can't be recursive by itself. At the end of it all it needs to have a concrete type. // Opt // Service +const MyCanister = Recursive(() => + Canister({ + myQuery: query([MyCanister], MyCanister) + }) +); // Func +const myFunc = Recursive(() => Func([myFunc], myFunc, 'query')); -export default Service({ - // optRecord: query([optRecord], optRecord, (param) => param), - // vecRecord: query([vecRecord], vecRecord, (param) => param), +export default Canister({ + testRecRecordWithOpt: query([optRecord], optRecord, (param) => param), + testRecRecordWithVec: query([vecRecord], vecRecord, (param) => param), testRecRecordWithVariant: query([varRecord], varRecord, (param) => param), testRecVariant: query([recVariant], recVariant, (param) => param), - // optTuple: query([optTuple], optTuple, (param) => param), - // vecTuple: query([vecTuple], vecTuple, (param) => param), - // optRecordReturn: query([], optRecord, () => { - // throw ''; - // }), - // vecRecordReturn: query([], vecRecord, () => { - // throw ''; - // }), + testRecTupleWithOpt: query([optTuple], optTuple, (param) => param), + testRecTupleWithVec: query([vecTuple], vecTuple, (param) => param), + testRecRecordWithOptReturn: query([], optRecord, () => { + return { myOpt: Some({ myOpt: Some({ myOpt: None }) }) }; + }), + testRecRecordWithVecReturn: query([], vecRecord, () => { + return { + myVecRecords: [ + { myVecRecords: [{ myVecRecords: [] }] }, + { + myVecRecords: [ + { myVecRecords: [] }, + { myVecRecords: [{ myVecRecords: [] }] } + ] + }, + { myVecRecords: [] } + ] + }; + }), testRecRecordWithVariantReturn: query([], varRecord, () => { return { myVar: { @@ -58,12 +82,20 @@ export default Service({ recVariant: { recVariant: { recVariant: { num: 12 } } } }; }), - // optTupleReturn: query([], optTuple, () => { - // throw ''; - // }), - // vecTupleReturn: query([], vecTuple, () => { - // throw ''; - // }), + testRecTupleWithOptReturn: query([], optTuple, () => { + return [None, Some([None, None])]; + }), + testRecTupleWithVecReturn: query([], vecTuple, () => { + return [ + [[[], [[[], []]]]], + [ + [[], []], + [[], []], + [[], []], + [[], []] + ] + ]; + }), testRecTupleWithVariant: query([varTuple], varTuple, (param) => param), testRecTupleWithVariantReturn: query([], varTuple, () => { return [ @@ -75,7 +107,32 @@ export default Service({ }, { varTuple: [{ num: 40 }, { varTuple: [{ num: 5 }, { num: 10 }] }] } ]; - }) + }), + testRecFunc: query([myFunc], myFunc, (param) => param), + testRecFuncReturn: query([], myFunc, () => [ + Principal.fromText('aaaaa-aa'), + 'create_canister' + ]), + testRecServiceSimple: query([MyCanister], MyCanister, (param) => param), + testRecService: query([MyFullCanister], MyFullCanister, (param) => param), + testRecServiceReturn: query([], MyFullCanister, () => { + return MyFullCanister( + Principal.fromText( + process.env.MY_CANISTER_PRINCIPAL ?? + // Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? + ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') + ) + ); + }), + testRecServiceCall: update( + [MyFullCanister], + MyFullCanister, + async (myFullCanister) => { + return await ic.call(myFullCanister.myQuery, { + args: [myFullCanister] + }); + } + ) }); // Below we have a bunch of different configurations of where to put the the diff --git a/examples/recursion/src/recursive_canister/index.did b/examples/recursion/src/recursive_canister/index.did new file mode 100644 index 0000000000..c13cc9540d --- /dev/null +++ b/examples/recursion/src/recursive_canister/index.did @@ -0,0 +1,6 @@ +type rec_18 = service {getMessage: () -> (text) query; myQuery: (rec_18) -> (rec_18) query;}; +type rec_21 = service {getMessage: () -> (text) query; myQuery: (rec_21) -> (rec_21) query;}; +service: (text) -> { + getMessage: () -> (text) query; + myQuery: (rec_18) -> (rec_21) query; +} diff --git a/examples/recursion/src/recursive_canister/index.ts b/examples/recursion/src/recursive_canister/index.ts new file mode 100644 index 0000000000..dc76437737 --- /dev/null +++ b/examples/recursion/src/recursive_canister/index.ts @@ -0,0 +1,15 @@ +import { query, Canister, Recursive, text, init } from 'azle'; + +let myMessage = ''; + +const MyCanister = Recursive(() => + Canister({ + init: init([text], (message) => { + myMessage = message; + }), + myQuery: query([MyCanister], MyCanister, (param) => param), + getMessage: query([], text, () => myMessage) + }) +); + +export default MyCanister; diff --git a/examples/recursion/test/pretest.ts b/examples/recursion/test/pretest.ts index fd6c38f77a..2f2023274f 100644 --- a/examples/recursion/test/pretest.ts +++ b/examples/recursion/test/pretest.ts @@ -1,16 +1,34 @@ import { execSync } from 'child_process'; +import { getCanisterId } from 'azle/test'; async function pretest() { await new Promise((resolve) => setTimeout(resolve, 5000)); - execSync(`dfx canister uninstall-code recursion || true`, { + execSync(`dfx canister uninstall-code recursive_canister || true`, { stdio: 'inherit' }); - execSync(`dfx deploy recursion`, { + execSync(`dfx deploy recursive_canister --argument '("hello")'`, { stdio: 'inherit' }); + execSync(`dfx generate recursive_canister`, { + stdio: 'inherit' + }); + + execSync(`dfx canister uninstall-code recursion || true`, { + stdio: 'inherit' + }); + + execSync( + `MY_CANISTER_PRINCIPAL=${getCanisterId( + 'recursive_canister' + )} dfx deploy recursion`, + { + stdio: 'inherit' + } + ); + execSync(`dfx generate recursion`, { stdio: 'inherit' }); diff --git a/examples/recursion/test/test.ts b/examples/recursion/test/test.ts index e3a18cf29f..34e97ee022 100644 --- a/examples/recursion/test/test.ts +++ b/examples/recursion/test/test.ts @@ -1,6 +1,7 @@ import { getCanisterId, runTests } from 'azle/test'; import { createActor } from './dfx_generated/recursion'; -import { getTests } from './tests'; +import { createActor as createRecursiveActor } from './dfx_generated/recursive_canister'; +import { getRecursiveCanisterTests, getTests } from './tests'; const recursionCanister = createActor(getCanisterId('recursion'), { agentOptions: { @@ -8,4 +9,16 @@ const recursionCanister = createActor(getCanisterId('recursion'), { } }); -runTests(getTests(recursionCanister)); +const recursiveCanister = createRecursiveActor( + getCanisterId('recursive_canister'), + { + agentOptions: { + host: 'http://127.0.0.1:8000' + } + } +); + +runTests([ + ...getTests(recursionCanister), + ...getRecursiveCanisterTests(recursiveCanister) +]); diff --git a/examples/recursion/test/tests.ts b/examples/recursion/test/tests.ts index 148820d18d..f901177a10 100644 --- a/examples/recursion/test/tests.ts +++ b/examples/recursion/test/tests.ts @@ -1,7 +1,32 @@ -import { Test } from 'azle/test'; -import { _SERVICE, rec_1 } from './dfx_generated/recursion/recursion.did'; +import { Test, getCanisterId } from 'azle/test'; +import { + _SERVICE, + rec_313, + rec_321 +} from './dfx_generated/recursion/recursion.did'; +import { _SERVICE as _REC_SERVICE } from './dfx_generated/recursive_canister/recursive_canister.did'; import { ActorSubclass } from '@dfinity/agent'; +import { Principal } from '@dfinity/principal'; +import { execSync } from 'child_process'; +// TODO these tests should be rewritten to use @dfinity/agent once this issue is resolved: https://github.com/dfinity/agent-js/issues/702 +// TODO this issue also needs to be resolved: https://forum.dfinity.org/t/services-wont-deserialize-properly-if-functions-arent-in-alphabetical-order/20885 +export function getRecursiveCanisterTests( + recursive_canister: ActorSubclass<_REC_SERVICE> +): Test[] { + return [ + { + name: 'test recursive canister init method', + test: async () => { + const result = await recursive_canister.getMessage(); + + return { + Ok: result === 'hello' + }; + } + } + ]; +} export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { return [ { @@ -104,6 +129,163 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { }; } }, + { + name: 'recursive records with opts', + test: async () => { + const result = await recursion_canister.testRecRecordWithOpt({ + myOpt: [{ myOpt: [] }] + }); + + return { + Ok: result.myOpt[0]?.myOpt.length === 0 + }; + } + }, + { + name: 'recursive funcs', + test: async () => { + const result = await recursion_canister.testRecFunc([ + Principal.fromText('aaaaa-aa'), + 'delete_canister' + ]); + + return { + Ok: + result[0].toString() === 'aaaaa-aa' && + result[1] === 'delete_canister' + }; + } + }, + { + name: 'recursive funcs return', + test: async () => { + const result = await recursion_canister.testRecFuncReturn(); + + return { + Ok: + result[0].toString() === 'aaaaa-aa' && + result[1] === 'create_canister' + }; + } + }, + { + name: 'recursive records with vec', + test: async () => { + const input = { + myVecRecords: [ + { myVecRecords: [{ myVecRecords: [] }] }, + { + myVecRecords: [ + { myVecRecords: [] }, + { myVecRecords: [{ myVecRecords: [] }] } + ] + }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] } + ] + }; + const result = + await recursion_canister.testRecRecordWithVec(input); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with vec', + test: async () => { + const input: rec_321 = [[[[], [[[], []]]]], []]; + const result = + await recursion_canister.testRecTupleWithVec(input); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with vec return', + test: async () => { + const input = [ + [[[], [[[], []]]]], + [ + [[], []], + [[], []], + [[], []], + [[], []] + ] + ]; + const result = + await recursion_canister.testRecTupleWithVecReturn(); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with opt', + test: async () => { + const input: rec_313 = [[[[], [[[], []]]]], []]; + const result = + await recursion_canister.testRecTupleWithOpt(input); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with opt return', + test: async () => { + const input = [[], [[[], []]]]; + const result = + await recursion_canister.testRecTupleWithOptReturn(); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive records with vec return', + test: async () => { + const input = { + myVecRecords: [ + { myVecRecords: [{ myVecRecords: [] }] }, + { + myVecRecords: [ + { myVecRecords: [] }, + { myVecRecords: [{ myVecRecords: [] }] } + ] + }, + { myVecRecords: [] } + ] + }; + const result = + await recursion_canister.testRecRecordWithVecReturn(); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive records with opts return type', + test: async () => { + const result = + await recursion_canister.testRecRecordWithOptReturn(); + + return { + Ok: result.myOpt[0]?.myOpt[0]?.myOpt.length === 0 + }; + } + }, { name: 'recursive tuples with variants', test: async () => { @@ -147,6 +329,92 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { result[1].varTuple[1].varTuple[1].num === 10 }; } + }, + { + name: 'test rec service simple', + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecServiceSimple '(service "${principalId}")'` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } + }, + { + name: 'test rec service', + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecService '(service "${principalId}")'` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } + }, + { + name: 'test rec service return', + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecServiceReturn` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } + }, + { + name: 'test rec service call', + skip: true, // TODO waiting for azle.encode and azle.decode to be implemented + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecServiceCall '(service "${principalId}")'` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } } ]; } + +function deepCompare(obj1: any, obj2: any): boolean { + // Check if both objects are of type object + if (typeof obj1 !== 'object' || typeof obj2 !== 'object') { + return obj1 === obj2; + } + + // Get the keys of both objects + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + // Check if they have the same keys + if (keys1.length !== keys2.length) { + return false; + } + + // Check if each key's value is deeply equal + for (const key of keys1) { + if (!deepCompare(obj1[key], obj2[key])) { + return false; + } + } + + return true; +} diff --git a/examples/simple_user_accounts/src/index.did b/examples/simple_user_accounts/src/index.did index bfcfd23d19..1fe0dd0102 100644 --- a/examples/simple_user_accounts/src/index.did +++ b/examples/simple_user_accounts/src/index.did @@ -1,8 +1,5 @@ -type rec_0 = record {id:text; username:text}; -type rec_1 = record {id:text; username:text}; -type rec_2 = record {id:text; username:text}; service: () -> { - getUserById: (text) -> (opt rec_0) query; - getAllUsers: () -> (vec rec_1) query; - createUser: (text) -> (rec_2); + getUserById: (text) -> (opt record {id:text; username:text}) query; + getAllUsers: () -> (vec record {id:text; username:text}) query; + createUser: (text) -> (record {id:text; username:text}); } diff --git a/examples/tuple_types/dfx.json b/examples/tuple_types/dfx.json index be52556ed9..a05d8d80cc 100644 --- a/examples/tuple_types/dfx.json +++ b/examples/tuple_types/dfx.json @@ -2,10 +2,11 @@ "canisters": { "tuple_types": { "type": "custom", - "main": "src/tuple_types.ts", + "main": "src/index.ts", "build": "npx azle tuple_types", - "candid": "src/tuple_types.did", - "wasm": ".azle/tuple_types/tuple_types.wasm.gz", + "candid": "src/index.did", + "wasm": ".azle/tuple_types/tuple_types.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/tuple_types", "node_compatibility": true diff --git a/examples/tuple_types/src/index.did b/examples/tuple_types/src/index.did new file mode 100644 index 0000000000..ba4796e0e0 --- /dev/null +++ b/examples/tuple_types/src/index.did @@ -0,0 +1,36 @@ +type rec_72 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_72}; Good}; +type rec_75 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_75}; Good}; +type rec_68 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_68}; Good}; +type rec_60 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_60}; Good}; +type rec_63 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_63}; Good}; +type rec_56 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_56}; Good}; +service: () -> { + complexOneTupleInlineParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; + complexOneTupleInlineReturnType: () -> (record {record {text; nat64}}) query; + complexOneTupleParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; + complexOneTupleReturnType: () -> (record {record {text; nat64}}) query; + complexThreeTupleInlineParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_72}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_75}) query; + complexThreeTupleInlineReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_68}) query; + complexThreeTupleParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_60}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_63}) query; + complexThreeTupleReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_56}) query; + complexTwoTupleInlineParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + complexTwoTupleInlineReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + complexTwoTupleParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + complexTwoTupleReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + nestedTupleQuery: (record {record {text; record {nat8; nat8}}; int}) -> (record {record {text; record {nat8; nat8}}; int}) query; + primitiveOneTupleInlineParam: (record {text}) -> (record {text}) query; + primitiveOneTupleInlineReturnType: () -> (record {text}) query; + primitiveOneTupleParam: (record {text}) -> (record {text}) query; + primitiveOneTupleReturnType: () -> (record {text}) query; + primitiveThreeTupleInlineParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; + primitiveThreeTupleInlineReturnType: () -> (record {text; nat64; principal}) query; + primitiveThreeTupleParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; + primitiveThreeTupleReturnType: () -> (record {text; nat64; principal}) query; + primitiveTwoTupleInlineParam: (record {text; text}) -> (record {text; text}) query; + primitiveTwoTupleInlineReturnType: () -> (record {text; text}) query; + primitiveTwoTupleParam: (record {text; nat64}) -> (record {text; nat64}) query; + primitiveTwoTupleReturnType: () -> (record {text; nat64}) query; + tupleArrayParamsAndReturnType: (vec record {text; text}) -> (vec record {text; text}) query; + tupleArrayRecordField: () -> (record {headers:vec record {text; text}}) query; + tupleArrayVariantField: () -> (variant {WithHeaders:vec record {text; text}; WithoutHeaders}) query; +} \ No newline at end of file diff --git a/examples/tuple_types/src/index.ts b/examples/tuple_types/src/index.ts new file mode 100644 index 0000000000..5f7ffa2d74 --- /dev/null +++ b/examples/tuple_types/src/index.ts @@ -0,0 +1,292 @@ +import { + query, + // CallResult, + int, + nat64, + nat8, + Null, + Principal, + Record, + // Service, + // serviceUpdate, + text, + Tuple, + Variant, + Vec, + Void, + Recursive, + Canister +} from 'azle'; + +// TODO maybe we should write tests for canister and stable storage? +// TODO for now we at least know the canister compiles +// type CanisterTuple1 = Tuple<[text, nat64]>; +// type CanisterTuple2 = Tuple<[text, CanisterTuple1]>; + +// class TestCanister extends Service { +// @serviceUpdate +// test: (param: CanisterTuple1) => CallResult; +// } + +const PrimitiveOneTuple = Tuple(text); +const PrimitiveTwoTuple = Tuple(text, nat64); +const PrimitiveThreeTuple = Tuple(text, nat64, Principal); + +const User = Record({ + id: text, + primitiveTwoTuple: PrimitiveTwoTuple +}); + +const Header = Tuple(text, text); + +const StreamingCallbackType = Variant({ + WithHeaders: Vec(Header), + WithoutHeaders: Null +}); + +const Reaction = Recursive(() => + Variant({ + Good: Null, + Bad: ComplexThreeTuple + }) +); + +const ComplexOneTuple = Tuple(PrimitiveTwoTuple); +const ComplexTwoTuple = Tuple(PrimitiveTwoTuple, User); +const ComplexThreeTuple = Tuple(PrimitiveTwoTuple, User, Reaction); + +const HttpResponse = Record({ + headers: Vec(Header) +}); + +export default Canister({ + primitiveOneTupleReturnType: query([], PrimitiveOneTuple, () => { + return ['Hello']; + }), + + primitiveOneTupleParam: query( + [PrimitiveOneTuple], + PrimitiveOneTuple, + (param) => { + return param; + } + ), + + primitiveOneTupleInlineReturnType: query([], Tuple(text), () => { + return ['Greenland']; + }), + + primitiveOneTupleInlineParam: query([Tuple(text)], Tuple(text), (param) => { + return param; + }), + + primitiveTwoTupleReturnType: query([], PrimitiveTwoTuple, () => { + return ['Content-Type', 64n]; + }), + + primitiveTwoTupleParam: query( + [PrimitiveTwoTuple], + PrimitiveTwoTuple, + (param) => { + return param; + } + ), + + primitiveTwoTupleInlineReturnType: query([], Tuple(text, text), () => { + return ['Fun', 'Times']; + }), + + primitiveTwoTupleInlineParam: query( + [Tuple(text, text)], + Tuple(text, text), + (param: Tuple<[text, text]>) => { + return param; + } + ), + + primitiveThreeTupleReturnType: query([], PrimitiveThreeTuple, () => { + return [ + 'Good', + 454n, + Principal.fromText('rrkah-fqaaa-aaaaa-aaaaq-cai') + ]; + }), + + primitiveThreeTupleParam: query( + [PrimitiveThreeTuple], + PrimitiveThreeTuple, + (param) => { + return param; + } + ), + + primitiveThreeTupleInlineReturnType: query( + [], + Tuple(text, nat64, Principal), + () => { + return ['Fun', 101n, Principal.fromText('aaaaa-aa')]; + } + ), + + primitiveThreeTupleInlineParam: query( + [Tuple(text, nat64, Principal)], + Tuple(text, nat64, Principal), + (param) => { + return param; + } + ), + + complexOneTupleReturnType: query([], ComplexOneTuple, () => { + return [['Hello', 0n]]; + }), + + complexOneTupleParam: query([ComplexOneTuple], ComplexOneTuple, (param) => { + return param; + }), + + complexOneTupleInlineReturnType: query([], Tuple(PrimitiveTwoTuple), () => { + return [['Candy', 56n]]; + }), + + complexOneTupleInlineParam: query( + [Tuple(PrimitiveTwoTuple)], + Tuple(PrimitiveTwoTuple), + (param) => { + return param; + } + ), + + complexTwoTupleReturnType: query([], ComplexTwoTuple, () => { + return [ + ['Content-Type', 64n], + { + id: '0', + primitiveTwoTuple: ['Content-Type', 64n] + } + ]; + }), + + complexTwoTupleParam: query([ComplexTwoTuple], ComplexTwoTuple, (param) => { + return param; + }), + + complexTwoTupleInlineReturnType: query( + [], + Tuple(PrimitiveTwoTuple, User), + () => { + return [ + ['Content-Type', 644n], + { + id: '444', + primitiveTwoTuple: ['Content-Type', 6_422n] + } + ]; + } + ), + + complexTwoTupleInlineParam: query( + [Tuple(PrimitiveTwoTuple, User)], + Tuple(PrimitiveTwoTuple, User), + (param) => { + return param; + } + ), + + complexThreeTupleReturnType: query([], ComplexThreeTuple, () => { + return [ + ['Content-Type', 64n], + { + id: '0', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Bad: [ + ['Content-Type', 64n], + { + id: '1', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Good: null + } + ] + } + ]; + }), + + complexThreeTupleParam: query( + [ComplexThreeTuple], + ComplexThreeTuple, + (param) => { + return param; + } + ), + + complexThreeTupleInlineReturnType: query( + [], + Tuple(PrimitiveTwoTuple, User, Reaction), + () => { + return [ + ['Content-Type', 64n], + { + id: '0', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Bad: [ + ['Content-Type', 64n], + { + id: '1', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Good: null + } + ] + } + ]; + } + ), + + complexThreeTupleInlineParam: query( + [Tuple(PrimitiveTwoTuple, User, Reaction)], + Tuple(PrimitiveTwoTuple, User, Reaction), + (param) => { + return param; + } + ), + + tupleArrayParamsAndReturnType: query( + [Vec(Header)], + Vec(Header), + (headers) => { + return headers; + } + ), + + tupleArrayRecordField: query([], HttpResponse, () => { + return { + headers: [ + ['Content-Type', 'application/json'], + ['Accept-Ranges', 'bytes'] + ] + }; + }), + + tupleArrayVariantField: query([], StreamingCallbackType, () => { + return { + WithHeaders: [ + ['Content-Type', 'application/json'], + ['Accept-Ranges', 'bytes'] + ] + }; + }), + + nestedTupleQuery: query( + [Tuple(Tuple(text, Tuple(nat8, nat8)), int)], + Tuple(Tuple(text, Tuple(nat8, nat8)), int), + (param) => { + return param; + } + ) +}); diff --git a/examples/tuple_types/src/tuple_types.did b/examples/tuple_types/src/tuple_types.did deleted file mode 100644 index a15978cd8b..0000000000 --- a/examples/tuple_types/src/tuple_types.did +++ /dev/null @@ -1,57 +0,0 @@ -type rec_0 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_1 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_2 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_3 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_4 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_5 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_6 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_8 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_7 = variant {Bad:record {record {text; nat64}; rec_8; rec_7}; Good}; -type rec_9 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_11 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_10 = variant {Bad:record {record {text; nat64}; rec_11; rec_10}; Good}; -type rec_12 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_14 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_13 = variant {Bad:record {record {text; nat64}; rec_14; rec_13}; Good}; -type rec_15 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_17 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_16 = variant {Bad:record {record {text; nat64}; rec_17; rec_16}; Good}; -type rec_18 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_20 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_19 = variant {Bad:record {record {text; nat64}; rec_20; rec_19}; Good}; -type rec_21 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_23 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_22 = variant {Bad:record {record {text; nat64}; rec_23; rec_22}; Good}; -type rec_24 = record {headers:vec record {text; text}}; -type rec_25 = variant {WithHeaders:vec record {text; text}; WithoutHeaders}; -service: () -> { - primitiveOneTupleReturnType: () -> (record {text}) query; - primitiveOneTupleParam: (record {text}) -> (record {text}) query; - primitiveOneTupleInlineReturnType: () -> (record {text}) query; - primitiveOneTupleInlineParam: (record {text}) -> (record {text}) query; - primitiveTwoTupleReturnType: () -> (record {text; nat64}) query; - primitiveTwoTupleParam: (record {text; nat64}) -> (record {text; nat64}) query; - primitiveTwoTupleInlineReturnType: () -> (record {text; text}) query; - primitiveTwoTupleInlineParam: (record {text; text}) -> (record {text; text}) query; - primitiveThreeTupleReturnType: () -> (record {text; nat64; principal}) query; - primitiveThreeTupleParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; - primitiveThreeTupleInlineReturnType: () -> (record {text; nat64; principal}) query; - primitiveThreeTupleInlineParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; - complexOneTupleReturnType: () -> (record {record {text; nat64}}) query; - complexOneTupleParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; - complexOneTupleInlineReturnType: () -> (record {record {text; nat64}}) query; - complexOneTupleInlineParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; - complexTwoTupleReturnType: () -> (record {record {text; nat64}; rec_0}) query; - complexTwoTupleParam: (record {record {text; nat64}; rec_1}) -> (record {record {text; nat64}; rec_2}) query; - complexTwoTupleInlineReturnType: () -> (record {record {text; nat64}; rec_3}) query; - complexTwoTupleInlineParam: (record {record {text; nat64}; rec_4}) -> (record {record {text; nat64}; rec_5}) query; - complexThreeTupleReturnType: () -> (record {record {text; nat64}; rec_6; rec_7}) query; - complexThreeTupleParam: (record {record {text; nat64}; rec_9; rec_10}) -> (record {record {text; nat64}; rec_12; rec_13}) query; - complexThreeTupleInlineReturnType: () -> (record {record {text; nat64}; rec_15; rec_16}) query; - complexThreeTupleInlineParam: (record {record {text; nat64}; rec_18; rec_19}) -> (record {record {text; nat64}; rec_21; rec_22}) query; - tupleArrayParamsAndReturnType: (vec record {text; text}) -> (vec record {text; text}) query; - tupleArrayRecordField: () -> (rec_24) query; - tupleArrayVariantField: () -> (rec_25) query; - twoTupleWithInlineRecords: (record {record {hello:nat64}; record {goodbye:nat64}}) -> (record {record {hello:nat64}; record {goodbye:nat64}}) query; - nestedTupleQuery: (record {record {text; record {nat8; nat8}}; int}) -> (record {record {text; record {nat8; nat8}}; int}) query; -} diff --git a/examples/tuple_types/src/tuple_types.ts b/examples/tuple_types/src/tuple_types.ts deleted file mode 100644 index b146834a4a..0000000000 --- a/examples/tuple_types/src/tuple_types.ts +++ /dev/null @@ -1,319 +0,0 @@ -import { - query, - // CallResult, - int, - nat64, - nat8, - Null, - Principal, - Record, - // Service, - // serviceUpdate, - text, - Tuple, - Variant, - Vec, - Void, - candid, - principal -} from 'azle'; - -import { IDL } from '@dfinity/candid'; - -// TODO maybe we should write tests for canister and stable storage? -// TODO for now we at least know the canister compiles -// type CanisterTuple1 = Tuple<[text, nat64]>; -// type CanisterTuple2 = Tuple<[text, CanisterTuple1]>; - -// class TestCanister extends Service { -// @serviceUpdate -// test: (param: CanisterTuple1) => CallResult; -// } - -type PrimitiveOneTuple = Tuple<[text]>; -const PrimitiveOneTuple = Tuple(text); -type PrimitiveTwoTuple = Tuple<[text, nat64]>; -const PrimitiveTwoTuple = Tuple(text, nat64); -type PrimitiveThreeTuple = Tuple<[text, nat64, Principal]>; -const PrimitiveThreeTuple = Tuple(text, nat64, principal); - -class User extends Record { - @candid(text) - id: text; - - @candid(PrimitiveTwoTuple) - primitiveTwoTuple: PrimitiveTwoTuple; -} - -type Header = Tuple<[text, text]>; -const Header = Tuple(text, text); - -class StreamingCallbackType extends Variant { - @candid(Vec(Header)) - WithHeaders?: Vec
; - - @candid(Null) - WithoutHeaders?: Null; -} - -class Reaction extends Variant { - @candid(Null) - Good?: Null; - - @candid(Tuple(PrimitiveTwoTuple, User, Reaction)) - Bad?: ComplexThreeTuple; -} - -type ComplexOneTuple = Tuple<[PrimitiveTwoTuple]>; -const ComplexOneTuple = Tuple(PrimitiveTwoTuple); -type ComplexTwoTuple = Tuple<[PrimitiveTwoTuple, User]>; -const ComplexTwoTuple = Tuple(PrimitiveTwoTuple, User); -type ComplexThreeTuple = [PrimitiveTwoTuple, User, Reaction]; -const ComplexThreeTuple = Tuple(PrimitiveTwoTuple, User, Reaction); - -class HttpResponse extends Record { - @candid(Vec(Header)) - headers: Vec
; -} - -export default class { - @query([], PrimitiveOneTuple) - primitiveOneTupleReturnType(): PrimitiveOneTuple { - return ['Hello']; - } - - @query([PrimitiveOneTuple], PrimitiveOneTuple) - primitiveOneTupleParam(param: PrimitiveOneTuple): PrimitiveOneTuple { - return param; - } - - @query([], Tuple(text)) - primitiveOneTupleInlineReturnType(): Tuple<[text]> { - return ['Greenland']; - } - - @query([Tuple(text)], Tuple(text)) - primitiveOneTupleInlineParam(param: Tuple<[text]>): Tuple<[text]> { - return param; - } - - @query([], PrimitiveTwoTuple) - primitiveTwoTupleReturnType(): PrimitiveTwoTuple { - return ['Content-Type', 64n]; - } - - @query([PrimitiveTwoTuple], PrimitiveTwoTuple) - primitiveTwoTupleParam(param: PrimitiveTwoTuple): PrimitiveTwoTuple { - return param; - } - - @query([], Tuple(text, text)) - primitiveTwoTupleInlineReturnType(): Tuple<[text, text]> { - return ['Fun', 'Times']; - } - - @query([Tuple(text, text)], Tuple(text, text)) - primitiveTwoTupleInlineParam( - param: Tuple<[text, text]> - ): Tuple<[text, text]> { - return param; - } - - @query([], PrimitiveThreeTuple) - primitiveThreeTupleReturnType(): PrimitiveThreeTuple { - return [ - 'Good', - 454n, - Principal.fromText('rrkah-fqaaa-aaaaa-aaaaq-cai') - ]; - } - - @query([PrimitiveThreeTuple], PrimitiveThreeTuple) - primitiveThreeTupleParam(param: PrimitiveThreeTuple): PrimitiveThreeTuple { - return param; - } - - @query([], Tuple(text, nat64, principal)) - primitiveThreeTupleInlineReturnType(): Tuple<[text, nat64, Principal]> { - return ['Fun', 101n, Principal.fromText('aaaaa-aa')]; - } - - @query([Tuple(text, nat64, principal)], Tuple(text, nat64, principal)) - primitiveThreeTupleInlineParam( - param: Tuple<[text, nat64, Principal]> - ): Tuple<[text, nat64, Principal]> { - return param; - } - - @query([], ComplexOneTuple) - complexOneTupleReturnType(): ComplexOneTuple { - return [['Hello', 0n]]; - } - - @query([ComplexOneTuple], ComplexOneTuple) - complexOneTupleParam(param: ComplexOneTuple): ComplexOneTuple { - return param; - } - - @query([], Tuple(PrimitiveTwoTuple)) - complexOneTupleInlineReturnType(): Tuple<[PrimitiveTwoTuple]> { - return [['Candy', 56n]]; - } - - @query([Tuple(PrimitiveTwoTuple)], Tuple(PrimitiveTwoTuple)) - complexOneTupleInlineParam( - param: Tuple<[PrimitiveTwoTuple]> - ): Tuple<[PrimitiveTwoTuple]> { - return param; - } - - @query([], ComplexTwoTuple) - complexTwoTupleReturnType(): ComplexTwoTuple { - return [ - ['Content-Type', 64n], - User.create({ - id: '0', - primitiveTwoTuple: ['Content-Type', 64n] - }) - ]; - } - - @query([ComplexTwoTuple], ComplexTwoTuple) - complexTwoTupleParam(param: ComplexTwoTuple): ComplexTwoTuple { - return param; - } - - @query([], Tuple(PrimitiveTwoTuple, User)) - complexTwoTupleInlineReturnType(): Tuple<[PrimitiveTwoTuple, User]> { - return [ - ['Content-Type', 644n], - User.create({ - id: '444', - primitiveTwoTuple: ['Content-Type', 6_422n] - }) - ]; - } - - @query([Tuple(PrimitiveTwoTuple, User)], Tuple(PrimitiveTwoTuple, User)) - complexTwoTupleInlineParam( - param: Tuple<[PrimitiveTwoTuple, User]> - ): Tuple<[PrimitiveTwoTuple, User]> { - return param; - } - - @query([], ComplexThreeTuple) - complexThreeTupleReturnType(): ComplexThreeTuple { - return [ - ['Content-Type', 64n], - User.create({ - id: '0', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Bad: [ - ['Content-Type', 64n], - User.create({ - id: '1', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Good: null - }) - ] - }) - ]; - } - - @query([ComplexThreeTuple], ComplexThreeTuple) - complexThreeTupleParam(param: ComplexThreeTuple): ComplexThreeTuple { - return param; - } - - @query([], Tuple(PrimitiveTwoTuple, User, Reaction)) - complexThreeTupleInlineReturnType(): Tuple< - [PrimitiveTwoTuple, User, Reaction] - > { - return [ - ['Content-Type', 64n], - User.create({ - id: '0', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Bad: [ - ['Content-Type', 64n], - User.create({ - id: '1', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Good: null - }) - ] - }) - ]; - } - - @query( - [Tuple(PrimitiveTwoTuple, User, Reaction)], - Tuple(PrimitiveTwoTuple, User, Reaction) - ) - complexThreeTupleInlineParam( - param: Tuple<[PrimitiveTwoTuple, User, Reaction]> - ): Tuple<[PrimitiveTwoTuple, User, Reaction]> { - return param; - } - - @query([Vec(Header)], Vec(Header)) - tupleArrayParamsAndReturnType(headers: Vec
): Vec
{ - return headers; - } - - @query([], HttpResponse) - tupleArrayRecordField(): HttpResponse { - return { - headers: [ - ['Content-Type', 'application/json'], - ['Accept-Ranges', 'bytes'] - ] - }; - } - - @query([], StreamingCallbackType) - tupleArrayVariantField(): StreamingCallbackType { - return { - WithHeaders: [ - ['Content-Type', 'application/json'], - ['Accept-Ranges', 'bytes'] - ] - }; - } - - @query( - [ - Tuple( - IDL.Record({ hello: IDL.Nat64 }), - IDL.Record({ goodbye: IDL.Nat64 }) - ) - ], - Tuple( - IDL.Record({ hello: IDL.Nat64 }), - IDL.Record({ goodbye: IDL.Nat64 }) - ) - ) - twoTupleWithInlineRecords( - param: Tuple<[{ [hello: string]: nat64 }, { [goodbye: string]: nat64 }]> - ): Tuple<[{ [hello: string]: nat64 }, { [goodbye: string]: nat64 }]> { - return param; - } - - @query( - [Tuple(Tuple(text, Tuple(nat8, nat8)), int)], - Tuple(Tuple(text, Tuple(nat8, nat8)), int) - ) - nestedTupleQuery( - param: Tuple<[Tuple<[text, Tuple<[nat8, nat8]>]>, int]> - ): Tuple<[Tuple<[text, Tuple<[nat8, nat8]>]>, int]> { - return param; - } -} diff --git a/examples/tuple_types/test/tests.ts b/examples/tuple_types/test/tests.ts index d9dd74d680..b5f3a15819 100644 --- a/examples/tuple_types/test/tests.ts +++ b/examples/tuple_types/test/tests.ts @@ -466,24 +466,6 @@ export function getTests(tupleTypesCanister: ActorSubclass<_SERVICE>): Test[] { }; } }, - { - name: 'twoTupleWithInlineRecords', - test: async () => { - const result = - await tupleTypesCanister.twoTupleWithInlineRecords([ - { - hello: 0n - }, - { - goodbye: 1n - } - ]); - - return { - Ok: result[0].hello === 0n && result[1].goodbye === 1n - }; - } - }, { name: 'nested tuple test', test: async () => { @@ -491,9 +473,8 @@ export function getTests(tupleTypesCanister: ActorSubclass<_SERVICE>): Test[] { ['hello', [5, 10]], 123n ]; - const result = await tupleTypesCanister.nestedTupleQuery( - expectedResult - ); + const result = + await tupleTypesCanister.nestedTupleQuery(expectedResult); return { Ok: diff --git a/src/compiler/compile_typescript_code.ts b/src/compiler/compile_typescript_code.ts index 621a2215f9..a0fecc4104 100644 --- a/src/compiler/compile_typescript_code.ts +++ b/src/compiler/compile_typescript_code.ts @@ -35,7 +35,8 @@ export function compileTypeScriptToJavaScript( export * from './${main}'; import CanisterMethods from './${main}'; - export const canisterMethods = CanisterMethods; + export const canisterMethods = CanisterMethods(); + `; const canisterJavaScript = bundleAndTranspileJs(` diff --git a/src/compiler/generate_candid_and_canister_methods.ts b/src/compiler/generate_candid_and_canister_methods.ts index 9be7eb072a..54179f049a 100644 --- a/src/compiler/generate_candid_and_canister_methods.ts +++ b/src/compiler/generate_candid_and_canister_methods.ts @@ -1,4 +1,9 @@ import { CanisterMethods } from './utils/types'; +import { + DEFAULT_VISITOR_DATA, + DidResultToCandidString, + DidVisitor +} from '../lib_new/visitors/did_visitor'; export function generateCandidAndCanisterMethods(mainJs: string): { candid: string; @@ -29,8 +34,16 @@ export function generateCandidAndCanisterMethods(mainJs: string): { const script = new vm.Script(mainJs); script.runInContext(context); + const canisterMethods = (sandbox.exports as any).canisterMethods; + + const candidInfo = canisterMethods.getIDL([]).accept(new DidVisitor(), { + ...DEFAULT_VISITOR_DATA, + isFirstService: true, + systemFuncs: canisterMethods.getSystemFunctionIDLs() + }); + return { - candid: (sandbox.exports as any).canisterMethods.candid, - canisterMethods: (sandbox.exports as any).canisterMethods + candid: DidResultToCandidString(candidInfo), + canisterMethods: canisterMethods }; } diff --git a/src/lib_functional/candid/reference/func.ts b/src/lib_functional/candid/reference/func.ts index b798e4e6e8..d5d091214e 100644 --- a/src/lib_functional/candid/reference/func.ts +++ b/src/lib_functional/candid/reference/func.ts @@ -1,7 +1,7 @@ import { CandidType } from '..'; import { IDL } from '@dfinity/candid'; import { - processMap, + Parent, toParamIDLTypes, toReturnIDLType } from '../../../lib_new/utils'; @@ -26,10 +26,10 @@ export function Func( // const name = v4(); return { - getIDL() { + getIDL(parents: Parent[]) { return IDL.Func( - toParamIDLTypes(paramsIdls), - toReturnIDLType(returnIdl), + toParamIDLTypes(paramsIdls, parents), + toReturnIDLType(returnIdl, parents), modeToCandid[mode] ); } diff --git a/src/lib_functional/candid/reference/record.ts b/src/lib_functional/candid/reference/record.ts index b6414687c3..a3e2159d3a 100644 --- a/src/lib_functional/candid/reference/record.ts +++ b/src/lib_functional/candid/reference/record.ts @@ -18,19 +18,7 @@ export function Record< ...obj, _azleName: name, getIDL(parents: Parent[]) { - const idl = IDL.Rec(); - idl.fill( - IDL.Record( - processMap(obj as any, [ - ...parents, - { - idl: idl, - name - } - ]) - ) - ); - return idl; + return IDL.Record(processMap(obj as any, parents)); } } as any; } diff --git a/src/lib_functional/candid/reference/recursive.ts b/src/lib_functional/candid/reference/recursive.ts index c1ef810ba7..83ee4a69f3 100644 --- a/src/lib_functional/candid/reference/recursive.ts +++ b/src/lib_functional/candid/reference/recursive.ts @@ -1,7 +1,29 @@ import { v4 } from 'uuid'; +import { IDL } from '@dfinity/candid'; +import { Parent } from '../../../lib_new/utils'; -export function Recursive(idl: any) { - idl._azleRecLambda = true; - idl._azleName = v4(); - return idl; +export function Recursive any>(idlCallback: T): T { + const name = v4(); + + let result = (...args: any[]) => { + const idl = idlCallback(); + if (idl._azleIsCanister) { + return idl(...args); + } + return idl; + }; + + result._azleName = name; + result._azleIsRecursive = true; + result.getIDL = (parents: Parent[]) => { + const idl = IDL.Rec(); + let filler = idlCallback(); + if (filler._azleIsCanister) { + filler = filler(result); + } + idl.fill(filler.getIDL([...parents, { idl: idl, name }])); + return idl; + }; + + return result; } diff --git a/src/lib_functional/candid/reference/service.ts b/src/lib_functional/candid/reference/service.ts index 3e01aaa94f..e7fed94b2d 100644 --- a/src/lib_functional/candid/reference/service.ts +++ b/src/lib_functional/candid/reference/service.ts @@ -34,138 +34,16 @@ type CallableObject = { export function Canister( serviceOptions: T ): CallableObject & { _azleCandidType?: '_azleCandidType' } { - const callbacks = Object.entries(serviceOptions).reduce((acc, entry) => { - const key = entry[0]; - const value = entry[1]; - - // if (principal === undefined) { - // return { - // ...acc, - // [key]: (...args: any[]) => { - // return serviceCall( - // principal as any, - // key, - // value.paramsIdls, - // value.returnIdl - // )(...args); - // } - // }; - // } else { - return { - ...acc, - [key]: { - canisterCallback: value.callback, - crossCanisterCallback: (...args: any[]) => { - return serviceCall( - this.principal as any, - key, - value.paramsIdls, - value.returnIdl - )(...args); - } - } - }; - // } - }, {}); - - // TODO Once types have names we should deduplicate the init and post_upgrade param types - const candidTypes = Object.values(serviceOptions).reduce( - (acc: string[], canisterMethodInfo) => { - return [...acc, ...canisterMethodInfo.candidTypes]; - }, - [] - ); - - const initOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'init' - ); - const init = - initOption === undefined - ? undefined - : { - name: initOption[0] - }; - - const postUpgradeOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'postUpgrade' - ); - const postUpgrade = - postUpgradeOption === undefined - ? undefined - : { - name: postUpgradeOption[0] - }; - - const preUpgradeOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'preUpgrade' - ); - const preUpgrade = - preUpgradeOption === undefined - ? undefined - : { - name: preUpgradeOption[0] - }; - - const heartbeatOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'heartbeat' - ); - const heartbeat = - heartbeatOption === undefined - ? undefined - : { - name: heartbeatOption[0] - }; - - const inspectMessageOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'inspectMessage' - ); - const inspectMessage = - inspectMessageOption === undefined - ? undefined - : { - name: inspectMessageOption[0] - }; - - const queries = Object.entries(serviceOptions) - .filter((entry) => { - const key = entry[0]; - const value = entry[1]; - - return value.mode === 'query'; - }) - .map((entry) => { - const key = entry[0]; - const value = entry[1]; - - return { - name: key, - composite: value.async, - guard_name: createGlobalGuard(value.guard, key) - }; - }); - - const updates = Object.entries(serviceOptions) - .filter((entry) => { - const key = entry[0]; - const value = entry[1]; - - return value.mode === 'update'; - }) - .map((entry) => { - const key = entry[0]; - const value = entry[1]; - - return { - name: key, - guard_name: createGlobalGuard(value.guard, key) - }; - }); - - let returnFunction = (principal: Principal) => { + let result = (parentOrPrincipal: any) => { + const originalPrincipal = parentOrPrincipal; + const parentOrUndefined = + parentOrPrincipal !== undefined && parentOrPrincipal._isPrincipal + ? undefined + : parentOrPrincipal; const callbacks = Object.entries(serviceOptions).reduce( (acc, entry) => { const key = entry[0]; - const value = entry[1]; + const value = entry[1](parentOrUndefined); // if (principal === undefined) { // return { @@ -186,7 +64,7 @@ export function Canister( canisterCallback: value.callback, crossCanisterCallback: (...args: any[]) => { return serviceCall( - principal as any, + this.principal as any, key, value.paramsIdls, value.returnIdl @@ -199,104 +77,263 @@ export function Canister( {} ); - return { - ...callbacks, - principal - }; - }; + const initOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'init' + ); + const init = + initOption === undefined + ? undefined + : { + name: initOption[0] + }; + + const postUpgradeOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'postUpgrade' + ); + const postUpgrade = + postUpgradeOption === undefined + ? undefined + : { + name: postUpgradeOption[0] + }; + + const preUpgradeOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'preUpgrade' + ); + const preUpgrade = + preUpgradeOption === undefined + ? undefined + : { + name: preUpgradeOption[0] + }; + + const heartbeatOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'heartbeat' + ); + const heartbeat = + heartbeatOption === undefined + ? undefined + : { + name: heartbeatOption[0] + }; + + const inspectMessageOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'inspectMessage' + ); + const inspectMessage = + inspectMessageOption === undefined + ? undefined + : { + name: inspectMessageOption[0] + }; + + const queries = Object.entries(serviceOptions) + .filter((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); - returnFunction.candid = `${ - candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' - }service: (${initOption?.[1].candid ?? ''}) -> { - ${Object.entries(serviceOptions) - .filter( - ([_, value]) => value.mode === 'query' || value.mode === 'update' - ) - .map((entry) => { - return `${entry[0]}: ${entry[1].candid}`; - }) - .join('\n ')} -} -`; - - returnFunction.init = init; - returnFunction.post_upgrade = postUpgrade; - returnFunction.pre_upgrade = preUpgrade; - returnFunction.heartbeat = heartbeat; - returnFunction.inspect_message = inspectMessage; - returnFunction.queries = queries; - returnFunction.updates = updates; - returnFunction.callbacks = callbacks; - returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { - const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - - const record = Object.entries(serviceFunctionInfo).reduce( - (accumulator, [methodName, functionInfo]) => { - const paramRealIdls = toParamIDLTypes(functionInfo.paramsIdls); - const returnRealIdl = toReturnIDLType(functionInfo.returnIdl); - - const annotations = - functionInfo.mode === 'update' ? [] : ['query']; + return value.mode === 'query'; + }) + .map((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); return { - ...accumulator, - [methodName]: IDL.Func( - paramRealIdls, - returnRealIdl, - annotations - ) + name: key, + composite: value.async, + guard_name: createGlobalGuard(value.guard, key) }; - }, - {} as Record - ); + }); - return IDL.Service(record); - }; + const updates = Object.entries(serviceOptions) + .filter((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + return value.mode === 'update'; + }) + .map((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + return { + name: key, + guard_name: createGlobalGuard(value.guard, key) + }; + }); + + let returnFunction = (principal: Principal) => { + const callbacks = Object.entries(serviceOptions).reduce( + (acc, entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + // if (principal === undefined) { + // return { + // ...acc, + // [key]: (...args: any[]) => { + // return serviceCall( + // principal as any, + // key, + // value.paramsIdls, + // value.returnIdl + // )(...args); + // } + // }; + // } else { + return { + ...acc, + [key]: { + canisterCallback: value.callback, + crossCanisterCallback: (...args: any[]) => { + return serviceCall( + principal as any, + key, + value.paramsIdls, + value.returnIdl + )(...args); + } + } + }; + // } + }, + {} + ); - return returnFunction; - - // TODO loop through each key and simply grab the candid off - // TODO grab the init/post_upgrade candid as well - // return { - // candid: `${ - // candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' - // }service: () -> { - // ${Object.entries(serviceOptions) - // .map((entry) => { - // return `${entry[0]}: ${entry[1].candid}`; - // }) - // .join('\n ')} - // } - // `, - // queries, - // updates, - // callbacks, - // principal, - // ...callbacks, // TODO then we can't use any names that could collide in this object - // getIDL(parents: Parent[]): IDL.ServiceClass { - // const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - - // const record = Object.entries(serviceFunctionInfo).reduce( - // (accumulator, [methodName, functionInfo]) => { - // const paramRealIdls = toParamIDLTypes(functionInfo.paramsIdls); - // const returnRealIdl = toReturnIDLType(functionInfo.returnIdl); - - // const annotations = - // functionInfo.mode === 'update' ? [] : ['query']; - - // return { - // ...accumulator, - // [methodName]: IDL.Func( - // paramRealIdls, - // returnRealIdl, - // annotations - // ) - // }; - // }, - // {} as Record - // ); - - // return IDL.Service(record); - // } - // } as any; + return { + ...callbacks, + principal + }; + }; + + returnFunction.init = init; + returnFunction.post_upgrade = postUpgrade; + returnFunction.pre_upgrade = preUpgrade; + returnFunction.heartbeat = heartbeat; + returnFunction.inspect_message = inspectMessage; + returnFunction.queries = queries; + returnFunction.updates = updates; + returnFunction.callbacks = callbacks; + (returnFunction.getSystemFunctionIDLs = ( + parents: Parent[] + ): IDL.FuncClass[] => { + const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; + + return Object.entries(serviceFunctionInfo).reduce( + (accumulator, [_methodName, functionInfo]) => { + const mode = functionInfo(parentOrUndefined).mode; + if (mode === 'update' || mode === 'query') { + // We don't want init, post upgrade, etc showing up in the idl + return accumulator; + } + + const paramRealIdls = toParamIDLTypes( + functionInfo(parentOrUndefined).paramsIdls, + parents + ); + const returnRealIdl = toReturnIDLType( + functionInfo(parentOrUndefined).returnIdl, + parents + ); + return [ + ...accumulator, + IDL.Func(paramRealIdls, returnRealIdl, [mode]) + ]; + }, + [] as IDL.FuncClass[] + ); + }), + (returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { + const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; + + const record = Object.entries(serviceFunctionInfo).reduce( + (accumulator, [methodName, functionInfo]) => { + const paramRealIdls = toParamIDLTypes( + functionInfo(parentOrUndefined).paramsIdls, + parents + ); + const returnRealIdl = toReturnIDLType( + functionInfo(parentOrUndefined).returnIdl, + parents + ); + + const mode = functionInfo(parentOrUndefined).mode; + let annotations: string[] = []; + if (mode === 'update') { + // do nothing + } else if (mode === 'query') { + annotations = ['query']; + } else { + // We don't want init, post upgrade, etc showing up in the idl + return accumulator; + } + + return { + ...accumulator, + [methodName]: IDL.Func( + paramRealIdls, + returnRealIdl, + annotations + ) + }; + }, + {} as Record + ); + + return IDL.Service(record); + }); + + if (originalPrincipal !== undefined && originalPrincipal._isPrincipal) { + return returnFunction(originalPrincipal); + } + + return returnFunction; + + // TODO loop through each key and simply grab the candid off + // TODO grab the init/post_upgrade candid as well + // return { + // candid: `${ + // candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' + // }service: () -> { + // ${Object.entries(serviceOptions) + // .map((entry) => { + // return `${entry[0]}: ${entry[1].candid}`; + // }) + // .join('\n ')} + // } + // `, + // queries, + // updates, + // callbacks, + // principal, + // ...callbacks, // TODO then we can't use any names that could collide in this object + // getIDL(parents: Parent[]): IDL.ServiceClass { + // const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; + + // const record = Object.entries(serviceFunctionInfo).reduce( + // (accumulator, [methodName, functionInfo]) => { + // const paramRealIdls = toParamIDLTypes(functionInfo.paramsIdls); + // const returnRealIdl = toReturnIDLType(functionInfo.returnIdl); + + // const annotations = + // functionInfo.mode === 'update' ? [] : ['query']; + + // return { + // ...accumulator, + // [methodName]: IDL.Func( + // paramRealIdls, + // returnRealIdl, + // annotations + // ) + // }; + // }, + // {} as Record + // ); + + // return IDL.Service(record); + // } + // } as any; + }; + result._azleIsCanister = true; + return result; } diff --git a/src/lib_functional/candid/reference/variant.ts b/src/lib_functional/candid/reference/variant.ts index 60e8afddcb..03aa2c456e 100644 --- a/src/lib_functional/candid/reference/variant.ts +++ b/src/lib_functional/candid/reference/variant.ts @@ -19,19 +19,7 @@ export function Variant< ...obj, _azleName: name, getIDL(parents: any) { - const idl = IDL.Rec(); - idl.fill( - IDL.Variant( - processMap(obj as any, [ - ...parents, - { - idl: idl, - name - } - ]) - ) - ); - return idl; + return IDL.Variant(processMap(obj as any, parents)); } } as any; } diff --git a/src/lib_functional/canister_methods/heartbeat.ts b/src/lib_functional/canister_methods/heartbeat.ts index bc2bf0b897..2d791a4e07 100644 --- a/src/lib_functional/canister_methods/heartbeat.ts +++ b/src/lib_functional/canister_methods/heartbeat.ts @@ -1,31 +1,31 @@ -import { isAsync } from '../../lib_new/method_decorators'; +import { isAsync } from '../../lib_new/utils'; import { CanisterMethodInfo, executeMethod } from '.'; import { Void } from '../../lib_new'; export function heartbeat( callback: () => void | Promise -): CanisterMethodInfo<[], Void> { - const finalCallback = (...args: any[]) => { - executeMethod( - 'heartbeat', - undefined, - undefined, - args, - callback, - [], - Void, - false - ); - }; +): () => CanisterMethodInfo<[], Void> { + return () => { + const finalCallback = (...args: any[]) => { + executeMethod( + 'heartbeat', + undefined, + undefined, + args, + callback, + [], + Void, + false + ); + }; - return { - mode: 'heartbeat', - callback: finalCallback, - candid: '', - candidTypes: [], - paramsIdls: [], - returnIdl: Void, - async: isAsync(callback), - guard: undefined + return { + mode: 'heartbeat', + callback: finalCallback, + paramsIdls: [], + returnIdl: Void, + async: isAsync(callback), + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/index.ts b/src/lib_functional/canister_methods/index.ts index e9ad5d98ad..ecf236a735 100644 --- a/src/lib_functional/canister_methods/index.ts +++ b/src/lib_functional/canister_methods/index.ts @@ -5,6 +5,7 @@ import { DecodeVisitor, EncodeVisitor } from '../../lib_new/visitors/encode_decode'; +import { Parent } from '../../lib_new/utils'; export * from './heartbeat'; export * from './init'; @@ -14,6 +15,8 @@ export * from './pre_upgrade'; export * from './query'; export * from './update'; +export type MethodArgs = { manual?: boolean; guard?: () => void }; + export type CanisterMethodInfo, K> = { mode: | 'query' @@ -25,8 +28,6 @@ export type CanisterMethodInfo, K> = { | 'preUpgrade'; async: boolean; callback?: (...args: any) => any; - candid: string; - candidTypes: string[]; paramsIdls: any[]; returnIdl: any; guard: (() => any) | undefined; @@ -38,12 +39,12 @@ export type Callback, Return> = ( export function executeMethod( mode: CanisterMethodInfo['mode'], - paramCandid: any, - returnCandid: any, + finalParamIdls: any, + finalReturnIdl: any, args: any[], callback: any, - paramsIdls: any[], - returnIdl: any, + userMadeParamsIdls: any[], + userMadeReturnIdl: any, manual: boolean ) { if (mode === 'heartbeat') { @@ -67,11 +68,11 @@ export function executeMethod( return; } - const decoded = IDL.decode(paramCandid[0] as any, args[0]); + const decoded = IDL.decode(finalParamIdls as any, args[0]); - const myDecodedObject = paramCandid[0].map((idl: any, index: any) => { + const myDecodedObject = finalParamIdls.map((idl: any, index: any) => { return idl.accept(new DecodeVisitor(), { - js_class: paramsIdls[index], + js_class: userMadeParamsIdls[index], js_data: decoded[index] }); }); @@ -99,16 +100,14 @@ export function executeMethod( if (!manual) { // const encodeReadyResult = result === undefined ? [] : [result]; - const encodeReadyResult = returnCandid[0].map( - (idl: any) => { - return idl.accept(new EncodeVisitor(), { - js_class: returnIdl, - js_data: result - }); - } - ); + const encodeReadyResult = finalReturnIdl.map((idl: any) => { + return idl.accept(new EncodeVisitor(), { + js_class: userMadeReturnIdl, + js_data: result + }); + }); const encoded = IDL.encode( - returnCandid[0] as any, + finalReturnIdl as any, encodeReadyResult ); ic.replyRaw(new Uint8Array(encoded)); @@ -120,15 +119,15 @@ export function executeMethod( } else { if (!manual) { // const encodeReadyResult = result === undefined ? [] : [result]; - const encodeReadyResult = returnCandid[0].map((idl: any) => { + const encodeReadyResult = finalReturnIdl.map((idl: any) => { return idl.accept(new EncodeVisitor(), { - js_class: returnIdl, + js_class: userMadeReturnIdl, js_data: result }); }); const encoded = IDL.encode( - returnCandid[0] as any, + finalReturnIdl as any, encodeReadyResult ); ic.replyRaw(new Uint8Array(encoded)); @@ -137,3 +136,9 @@ export function executeMethod( console.log(`final instructions: ${ic.instructionCounter()}`); } } + +export function createParents(parent: any): Parent[] { + return parent === undefined + ? [] + : [{ idl: parent, name: parent._azleName }]; +} diff --git a/src/lib_functional/canister_methods/init.ts b/src/lib_functional/canister_methods/init.ts index 767caaa314..122be5714c 100644 --- a/src/lib_functional/canister_methods/init.ts +++ b/src/lib_functional/canister_methods/init.ts @@ -1,11 +1,7 @@ -import { - handleRecursiveParams, - handleRecursiveReturn, - newTypesToStingArr -} from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; +import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; import { CandidType, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function init< const Params extends ReadonlyArray, @@ -16,33 +12,34 @@ export function init< ? GenericCallback : never ): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn(Void as any, paramCandid[2]); + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(Void as any, parents); - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'init', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - Void, - false - ); - }; + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'init', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + Void, + false + ); + }; - return { - mode: 'init', - callback: finalCallback, - candid: paramCandid[1].join(', '), - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl: Void, - async: false, - guard: undefined + return { + mode: 'init', + callback: finalCallback, + paramsIdls: paramsIdls as any, + returnIdl: Void, + async: false, + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/inspect_message.ts b/src/lib_functional/canister_methods/inspect_message.ts index d1617ffc79..918df84c01 100644 --- a/src/lib_functional/canister_methods/inspect_message.ts +++ b/src/lib_functional/canister_methods/inspect_message.ts @@ -1,37 +1,37 @@ -import { CanisterMethodInfo, executeMethod } from '.'; -import { - Void, - handleRecursiveParams, - handleRecursiveReturn -} from '../../lib_new'; +import { CanisterMethodInfo, createParents, executeMethod } from '.'; +import { Void } from '../../lib_new'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; +import { RecursiveType } from '../candid'; export function inspectMessage( callback: () => void | Promise ): CanisterMethodInfo<[], Void> { - const paramCandid = handleRecursiveParams([]); - const returnCandid = handleRecursiveReturn(Void as any, paramCandid[2]); + return (parent: any) => { + const parents = createParents(parent); + // TODO why are we doing this handle recursive params when there are none? + const paramCandid = toParamIDLTypes([], parents); + const returnCandid = toReturnIDLType(Void as any, parents); - const finalCallback = (...args: any[]) => { - executeMethod( - 'inspectMessage', - paramCandid, - returnCandid, - args, - callback, - [], - Void, - false - ); - }; + const finalCallback = (...args: any[]) => { + executeMethod( + 'inspectMessage', + paramCandid, + returnCandid, + args, + callback, + [], + Void, + false + ); + }; - return { - mode: 'inspectMessage', - callback: finalCallback, - candid: '', - candidTypes: [], - paramsIdls: [], - returnIdl: Void, - async: false, - guard: undefined + return { + mode: 'inspectMessage', + callback: finalCallback, + paramsIdls: [], + returnIdl: Void, + async: false, + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/post_upgrade.ts b/src/lib_functional/canister_methods/post_upgrade.ts index dd54c7a2a6..35df523fac 100644 --- a/src/lib_functional/canister_methods/post_upgrade.ts +++ b/src/lib_functional/canister_methods/post_upgrade.ts @@ -1,11 +1,7 @@ -import { - handleRecursiveParams, - handleRecursiveReturn, - newTypesToStingArr -} from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; +import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; import { CandidType, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function postUpgrade< const Params extends ReadonlyArray, @@ -16,33 +12,34 @@ export function postUpgrade< ? GenericCallback : never ): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn(Void as any, paramCandid[2]); + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(Void as any, parents); - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'postUpgrade', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - Void, - false - ); - }; + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'postUpgrade', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + Void, + false + ); + }; - return { - mode: 'postUpgrade', - callback: finalCallback, - candid: paramCandid[1].join(', '), - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl: Void, - async: false, - guard: undefined + return { + mode: 'postUpgrade', + callback: finalCallback, + paramsIdls: paramsIdls as any, + returnIdl: Void, + async: false, + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/pre_upgrade.ts b/src/lib_functional/canister_methods/pre_upgrade.ts index c1a7acb4d5..8661c05b22 100644 --- a/src/lib_functional/canister_methods/pre_upgrade.ts +++ b/src/lib_functional/canister_methods/pre_upgrade.ts @@ -1,31 +1,31 @@ -import { isAsync } from '../../lib_new/method_decorators'; +import { isAsync } from '../../lib_new/utils'; import { CanisterMethodInfo, executeMethod } from '.'; import { Void } from '../../lib_new'; export function preUpgrade( callback: () => void | Promise -): CanisterMethodInfo<[], Void> { - const finalCallback = (...args: any[]) => { - executeMethod( - 'preUpgrade', - undefined, - undefined, - args, - callback, - [], - Void, - false - ); - }; +): () => CanisterMethodInfo<[], Void> { + return () => { + const finalCallback = (...args: any[]) => { + executeMethod( + 'preUpgrade', + undefined, + undefined, + args, + callback, + [], + Void, + false + ); + }; - return { - mode: 'preUpgrade', - callback: finalCallback, - candid: '', - candidTypes: [], - paramsIdls: [], - returnIdl: Void, - async: isAsync(callback), - guard: undefined + return { + mode: 'preUpgrade', + callback: finalCallback, + paramsIdls: [], + returnIdl: Void, + async: isAsync(callback), + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/query.ts b/src/lib_functional/canister_methods/query.ts index b0802bbb9d..20d9940744 100644 --- a/src/lib_functional/canister_methods/query.ts +++ b/src/lib_functional/canister_methods/query.ts @@ -1,12 +1,13 @@ +import { isAsync } from '../../lib_new/utils'; import { + Callback, + CanisterMethodInfo, MethodArgs, - handleRecursiveParams, - handleRecursiveReturn, - isAsync, - newTypesToStingArr -} from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; -import { CandidType, TypeMapping } from '../candid'; + createParents, + executeMethod +} from '.'; +import { CandidType, RecursiveType, TypeMapping } from '../candid'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function query< const Params extends ReadonlyArray, @@ -20,37 +21,35 @@ export function query< : never, methodArgs?: MethodArgs ): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn( - returnIdl as any, - paramCandid[2] - ); + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(returnIdl as any, parents); - // TODO maybe the cross canister callback should be made here? - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'query', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - returnIdl, - methodArgs?.manual ?? false - ); - }; + // TODO maybe the cross canister callback should be made here? + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'query', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + returnIdl, + methodArgs?.manual ?? false + ); + }; - return { - mode: 'query', - callback: finalCallback, - candid: `(${paramCandid[1].join(', ')}) -> (${returnCandid[1]}) query;`, - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl, - async: callback === undefined ? false : isAsync(callback), - guard: methodArgs?.guard + return { + mode: 'query', + callback: finalCallback, + paramsIdls: paramsIdls as any, + returnIdl, + async: callback === undefined ? false : isAsync(callback), + guard: methodArgs?.guard + }; }; } diff --git a/src/lib_functional/canister_methods/update.ts b/src/lib_functional/canister_methods/update.ts index 9e2046ec8c..11340a057a 100644 --- a/src/lib_functional/canister_methods/update.ts +++ b/src/lib_functional/canister_methods/update.ts @@ -1,12 +1,13 @@ +import { isAsync } from '../../lib_new/utils'; import { + Callback, + CanisterMethodInfo, MethodArgs, - handleRecursiveParams, - handleRecursiveReturn, - isAsync, - newTypesToStingArr -} from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; + createParents, + executeMethod +} from '.'; import { CandidType, TypeMapping } from '../candid'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function update< const Params extends ReadonlyArray, @@ -20,36 +21,34 @@ export function update< : never, methodArgs?: MethodArgs ): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn( - returnIdl as any, - paramCandid[2] - ); + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(returnIdl as any, parents); - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'update', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - returnIdl, - methodArgs?.manual ?? false - ); - }; + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'update', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + returnIdl, + methodArgs?.manual ?? false + ); + }; - return { - mode: 'update', - callback: finalCallback, - candid: `(${paramCandid[1].join(', ')}) -> (${returnCandid[1]});`, - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl, - async: callback === undefined ? false : isAsync(callback), - guard: methodArgs?.guard + return { + mode: 'update', + callback: finalCallback, + paramsIdls: paramsIdls as any, + returnIdl, + async: callback === undefined ? false : isAsync(callback), + guard: methodArgs?.guard + }; }; } diff --git a/src/lib_new/method_decorators.ts b/src/lib_new/method_decorators.ts index 78da74a66c..2d2d4ea3b2 100644 --- a/src/lib_new/method_decorators.ts +++ b/src/lib_new/method_decorators.ts @@ -1,393 +1,6 @@ import { ic } from './ic'; import { GuardResult, IDL } from './index'; -import { - CandidClass, - ReturnCandidClass, - toParamIDLTypes, - toReturnIDLType, - CandidTypesDefs, - CandidDef, - extractCandid -} from './utils'; -import { display } from './utils'; -import { - Service, - serviceCall, - ServiceConstructor, - serviceDecorator -} from './service'; -import { DecodeVisitor, EncodeVisitor } from './visitors/encode_decode/'; - -export type Manual = void; - -type Mode = - | 'init' - | 'postUpgrade' - | 'preUpgrade' - | 'query' - | 'update' - | 'heartbeat' - | 'inspectMessage'; - -const modeToCandid = { - query: ' query', - update: '' -}; - -// TODO add the GuardResult return type -export type MethodArgs = { manual?: boolean; guard?: () => void }; - -// Until we can figure how how to type check Funcs, Variants, and Records we are just going to have to use any here -// export function query(paramsIdls: CandidClass[], returnIdl: ReturnCandidClass) { -export function init(paramsIdls: any[]): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - return setupCanisterMethod( - target, - paramsIdls, - [], - 'init', - false, - undefined, - key, - descriptor - ); - }; -} - -// Until we can figure how how to type check Funcs, Variants, and Records we are just going to have to use any here -// export function query(paramsIdls: CandidClass[], returnIdl: ReturnCandidClass) { -export function postUpgrade(paramsIdls: any[]): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - return setupCanisterMethod( - target, - paramsIdls, - [], - 'postUpgrade', - false, - undefined, - key, - descriptor - ); - }; -} - -export function preUpgrade( - target: any, - key: string, - descriptor?: PropertyDescriptor -) { - return setupCanisterMethod( - target, - [], - [], - 'preUpgrade', - false, - undefined, - key, - descriptor - ); -} - -export function heartbeat( - target: any, - key: string, - descriptor?: PropertyDescriptor -) { - return setupCanisterMethod( - target, - [], - [], - 'heartbeat', - false, - undefined, - key, - descriptor - ); -} - -export function inspectMessage( - target: any, - key: string, - descriptor?: PropertyDescriptor -) { - return setupCanisterMethod( - target, - [], - [], - 'inspectMessage', - false, - undefined, - key, - descriptor - ); -} - -// Until we can figure how how to type check Funcs, Variants, and Records we are just going to have to use any here -// export function query(paramsIdls: CandidClass[], returnIdl: ReturnCandidClass) { -export function query( - paramsIdls: any[], - returnIdl: any, - args: MethodArgs = { manual: false } -): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - if (descriptor === undefined) { - serviceDecorator(target, key, paramsIdls, returnIdl); - } else { - return setupCanisterMethod( - target, - paramsIdls, - returnIdl, - 'query', - args.manual, - args.guard, - key, - descriptor - ); - } - }; -} - -// export function update( -// paramsIdls: CandidClass[], -// returnIdl: ReturnCandidClass -export function update( - paramsIdls: any[], - returnIdl: any, - args: MethodArgs = { manual: false } -): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - if (descriptor === undefined) { - serviceDecorator(target, key, paramsIdls, returnIdl); - } else { - return setupCanisterMethod( - target, - paramsIdls, - returnIdl, - 'update', - args.manual, - args.guard, - key, - descriptor - ); - } - }; -} - -export function newTypesToStingArr(newTypes: CandidTypesDefs): string[] { - return Object.entries(newTypes).map( - ([name, candid]) => `type ${name} = ${candid};` - ); -} - -export function handleRecursiveParams( - idls: CandidClass[] -): [IDL.Type[], CandidDef[], CandidTypesDefs] { - const paramIdls = toParamIDLTypes(idls); - const paramInfo = paramIdls.map((paramIdl) => display(paramIdl, {})); - return [paramIdls, ...extractCandid(paramInfo, {})]; -} - -export function handleRecursiveReturn( - returnIdl: ReturnCandidClass, - paramCandidTypeDefs: CandidTypesDefs -): [IDL.Type[], CandidDef[], CandidTypesDefs] { - const returnIdls = toReturnIDLType(returnIdl); - const returnInfo = returnIdls.map((returnIdl) => display(returnIdl, {})); - return [returnIdls, ...extractCandid(returnInfo, paramCandidTypeDefs)]; -} - -function setupCanisterMethod( - target: any, - paramsIdls: CandidClass[], - returnIdl: ReturnCandidClass, - mode: Mode, - manual: boolean, - guard: (() => GuardResult) | undefined, - key: string, - descriptor: PropertyDescriptor -) { - const paramCandid = handleRecursiveParams(paramsIdls); - const returnCandid = handleRecursiveReturn(returnIdl, paramCandid[2]); - - if (target.constructor._azleCanisterMethods === undefined) { - target.constructor._azleCanisterMethods = { - queries: [], - updates: [] - }; - } - - if (target.constructor._azleCandidInitParams === undefined) { - target.constructor._azleCandidInitParams = []; - } - - if (mode === 'init' || mode === 'postUpgrade') { - target.constructor._azleCandidInitParams = paramCandid[1]; - } - - if (target.constructor._azleCandidTypes === undefined) { - target.constructor._azleCandidTypes = []; - } - - target.constructor._azleCandidTypes = [ - ...target.constructor._azleCandidTypes, - ...newTypesToStingArr(returnCandid[2]) - ]; - - if (mode === 'query' || mode === 'update') { - if (target.constructor._azleCandidMethods === undefined) { - target.constructor._azleCandidMethods = []; - } - - target.constructor._azleCandidMethods.push( - `${key}: (${paramCandid[1].join(', ')}) -> (${returnCandid[1]})${ - modeToCandid[mode] - };` - ); - - if (target instanceof Service) { - addIDLForMethodToServiceConstructor( - target.constructor, - key, - paramsIdls, - returnIdl, - mode - ); - } - } - - const originalMethod = descriptor.value; - - if (mode === 'query') { - target.constructor._azleCanisterMethods.queries.push({ - name: key, - composite: isAsync(originalMethod, key), - guard_name: createGlobalGuard(guard, key) - }); - } - - if (mode === 'update') { - target.constructor._azleCanisterMethods.updates.push({ - name: key, - guard_name: createGlobalGuard(guard, key) - }); - } - - if (mode === 'heartbeat') { - target.constructor._azleCanisterMethods.heartbeat = { - name: key - }; - } - - if (mode === 'inspectMessage') { - target.constructor._azleCanisterMethods.inspect_message = { - name: key - }; - } - - if (mode === 'preUpgrade') { - target.constructor._azleCanisterMethods.pre_upgrade = { - name: key - }; - } - - // This must remain a function and not an arrow function - // in order to set the context (this) correctly - descriptor.value = function (...args: any[]) { - if (args[0] === '_AZLE_CROSS_CANISTER_CALL') { - const serviceCallInner = serviceCall(key, paramsIdls, returnIdl); - return serviceCallInner.call(this, ...args); - } - - if (mode === 'heartbeat' || mode === 'preUpgrade') { - originalMethod.call(this); - return; - } - - const decoded = IDL.decode(paramCandid[0], args[0]); - const myDecodedObject = paramCandid[0].map((idl, index) => { - return idl.accept(new DecodeVisitor(), { - js_class: paramsIdls[index], - js_data: decoded[index] - }); - }); - - const result = originalMethod.apply(this, myDecodedObject); - - if ( - mode === 'init' || - mode === 'postUpgrade' || - mode === 'inspectMessage' - ) { - return; - } - - const is_promise = - result !== undefined && - result !== null && - typeof result.then === 'function'; - - if (is_promise) { - result - .then((result) => { - // TODO this won't be accurate because we have most likely had - // TODO cross-canister calls - console.log( - `final instructions: ${ic.instructionCounter()}` - ); - - if (!manual) { - const encodeReadyResult = - result === undefined ? [] : [result]; - const encoded = IDL.encode( - returnCandid[0], - encodeReadyResult - ); - ic.replyRaw(new Uint8Array(encoded)); - } - }) - .catch((error) => { - ic.trap(error.toString()); - }); - } else { - if (!manual) { - const encodeReadyResult = returnCandid[0].map((idl) => { - return idl.accept(new EncodeVisitor(), { - js_class: returnIdl, - js_data: result - }); - }); - const encoded = IDL.encode(returnCandid[0], encodeReadyResult); - ic.replyRaw(new Uint8Array(encoded)); - } - - console.log(`final instructions: ${ic.instructionCounter()}`); - } - }; - - if (mode === 'init') { - globalThis._azleInitName = key; - } - - if (mode === 'postUpgrade') { - globalThis._azlePostUpgradeName = key; - } - - return descriptor; -} - -export function isAsync(originalFunction: any) { - if (originalFunction[Symbol.toStringTag] === 'AsyncFunction') { - return true; - } else if (originalFunction.constructor.name === 'AsyncFunction') { - return true; - } else if (originalFunction.toString().includes('async ')) { - return true; - } else { - return false; - } -} - export function createGlobalGuard( guard: (() => GuardResult) | undefined, functionName: string @@ -402,38 +15,3 @@ export function createGlobalGuard( return guardName; } - -/** - * Stores an IDL representation of the canister method into a private - * `_azleFunctionInfo` object on the provided constructor. If that property doesn't - * exist, then it will be added as a side-effect. - * - * @param constructor The class on which to store the IDL information. This - * should probably be a Service. This type should probably be tightened down. - * @param methodName The public name of the canister method - * @param paramIdls The IDLs of the parameters, coming from the `@query` and - * `@update` decorators. - * @param returnIdl The IDL of the return type, coming from the `@query` and - * `@update` decorators. - * @param mode The mode in which the method should be executed. - */ -function addIDLForMethodToServiceConstructor( - constructor: T & ServiceConstructor, - methodName: string, - paramIdls: CandidClass[], - returnIdl: ReturnCandidClass, - mode: 'query' | 'update' -): void { - if (constructor._azleFunctionInfo === undefined) { - constructor._azleFunctionInfo = {}; - } - - // TODO: Technically, there is a possibility that the method name already - // exists. We may want to handle that case. - - constructor._azleFunctionInfo[methodName] = { - mode, - paramIdls, - returnIdl - }; -} diff --git a/src/lib_new/primitives.ts b/src/lib_new/primitives.ts index fae5ebdf9b..9c9c1a240a 100644 --- a/src/lib_new/primitives.ts +++ b/src/lib_new/primitives.ts @@ -255,7 +255,7 @@ export class AzleOpt { _azleCandidType?: '_azleCandidType'; getIDL(parents: Parent[]) { - return IDL.Opt(toIDLType(this._azleType, [])); + return IDL.Opt(toIDLType(this._azleType, parents)); } } @@ -268,7 +268,7 @@ export class AzleVec { _azleCandidType?: '_azleCandidType'; getIDL(parents: Parent[]) { - return IDL.Vec(toIDLType(this._azleType, [])); + return IDL.Vec(toIDLType(this._azleType, parents)); } } diff --git a/src/lib_new/utils.ts b/src/lib_new/utils.ts index e9de3a961a..2255869811 100644 --- a/src/lib_new/utils.ts +++ b/src/lib_new/utils.ts @@ -31,86 +31,6 @@ export function extractCandid( return [paramCandid, candidTypeDefs]; } -export function display( - idl: IDL.Type, - candidTypeDefs: CandidTypesDefs -): [CandidDef, CandidTypesDefs] { - if (idl instanceof IDL.RecClass) { - // For RecClasses the definition will be the name, that name will - // reference the actual definition which will be added to the list of - // candid type defs that will get put at the top of the candid file - // Everything else will just be the normal inline candid def - const candid = extractCandid( - [display(idl.getType(), candidTypeDefs)], - candidTypeDefs - ); - return [idl.name, { ...candid[1], [idl.name]: candid[0][0] }]; - } - if (idl instanceof IDL.TupleClass) { - const fields = idl._components.map((value) => - display(value, candidTypeDefs) - ); - const candid = extractCandid(fields, candidTypeDefs); - return [`record {${candid[0].join('; ')}}`, candid[1]]; - } - if (idl instanceof IDL.OptClass) { - const candid = extractCandid( - [display(idl._type, candidTypeDefs)], - candidTypeDefs - ); - return [`opt ${candid[0]}`, candid[1]]; - } - if (idl instanceof IDL.VecClass) { - const candid = extractCandid( - [display(idl._type, candidTypeDefs)], - candidTypeDefs - ); - return [`vec ${candid[0]}`, candid[1]]; - } - if (idl instanceof IDL.RecordClass) { - const candidFields = idl._fields.map(([key, value]) => - display(value, candidTypeDefs) - ); - const candid = extractCandid(candidFields, candidTypeDefs); - const fields = idl._fields.map( - ([key, value], index) => key + ':' + candid[0][index] - ); - return [`record {${fields.join('; ')}}`, candid[1]]; - } - if (idl instanceof IDL.VariantClass) { - const candidFields = idl._fields.map(([key, value]) => - display(value, candidTypeDefs) - ); - const candid = extractCandid(candidFields, candidTypeDefs); - const fields = idl._fields.map( - ([key, value], index) => - key + (value.name === 'null' ? '' : ':' + candid[0][index]) - ); - return [`variant {${fields.join('; ')}}`, candid[1]]; - } - if (idl instanceof IDL.FuncClass) { - const argsTypes = idl.argTypes.map((value) => - display(value, candidTypeDefs) - ); - const candidArgs = extractCandid(argsTypes, candidTypeDefs); - const retsTypes = idl.retTypes.map((value) => - display(value, candidArgs[1]) - ); - const candidRets = extractCandid(retsTypes, candidArgs[1]); - const args = candidArgs[0].join(', '); - const rets = candidRets[0].join(', '); - const annon = ' ' + idl.annotations.join(' '); - return [`func (${args}) -> (${rets})${annon}`, candidRets[1]]; - } - if (idl !== undefined && !('display' in idl)) { - throw Error(`${JSON.stringify(idl)} is not a candid type`); - } - if (idl === undefined) { - throw Error('cannot convert undefined to candid'); - } - return [idl.display(), candidTypeDefs]; -} - export type Parent = { idl: IDL.RecClass; name: string; @@ -145,6 +65,7 @@ export function toIDLType(idl: CandidClass, parents: Parent[]): IDL.Type { _buildTypeTableImpl: (typeTable): void => { return parent.idl._buildTypeTableImpl(typeTable); }, + // TODO check if this is still being called. maybe by adding a throw here and see if we hit it display: () => parent.idl.name, decodeValue: (b, t) => { return parent.idl.decodeValue(b, t); @@ -168,8 +89,8 @@ export function toIDLType(idl: CandidClass, parents: Parent[]): IDL.Type { } return idl.getIDL(parents); } - if (idl._azleRecLambda) { - return toIDLType(idl(), [...parents, idl._azleName]); + if (idl._azleIsCanister) { + return toIDLType(idl(), parents); } // if (idl.display === undefined || idl.getIDL === undefined) { // throw Error(`${JSON.stringify(idl)} is not a candid type`); @@ -177,12 +98,18 @@ export function toIDLType(idl: CandidClass, parents: Parent[]): IDL.Type { return idl; } -export function toParamIDLTypes(idl: CandidClass[]): IDL.Type[] { - return idl.map((value) => toIDLType(value, [])); +export function toParamIDLTypes( + idl: CandidClass[], + parents: Parent[] = [] +): IDL.Type[] { + return idl.map((value) => toIDLType(value, parents)); } -export function toReturnIDLType(returnIdl: ReturnCandidClass): IDL.Type[] { - const idlType = toIDLType(returnIdl, []); +export function toReturnIDLType( + returnIdl: ReturnCandidClass, + parents: Parent[] = [] +): IDL.Type[] { + const idlType = toIDLType(returnIdl, parents); if (Array.isArray(idlType)) { return [...idlType]; @@ -191,6 +118,18 @@ export function toReturnIDLType(returnIdl: ReturnCandidClass): IDL.Type[] { return [idlType]; } +export function isAsync(originalFunction: any) { + if (originalFunction[Symbol.toStringTag] === 'AsyncFunction') { + return true; + } else if (originalFunction.constructor.name === 'AsyncFunction') { + return true; + } else if (originalFunction.toString().includes('async ')) { + return true; + } else { + return false; + } +} + type CandidMap = { [key: string]: any }; export function processMap(targetMap: CandidMap, parent: Parent[]): CandidMap { diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index 93b6724dfe..3207d3b59e 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -1,8 +1,45 @@ import { IDL } from '@dfinity/candid'; -type VisitorData = { usedRecClasses: IDL.RecClass[]; is_on_service: boolean }; +type VisitorData = { + usedRecClasses: IDL.RecClass[]; + isOnService: boolean; + isFirstService: boolean; + systemFuncs: IDL.FuncClass[]; +}; type VisitorResult = [CandidDef, CandidTypesDefs]; +// TODO it would be nice to have names for the rec types instead of rec_1, rec_2 etc +// TODO Once types have names we should deduplicate the init and post_upgrade param types +// TODO maybe even before we have names we should deduplicate all sorts of types +// The rust to candid converter we were using did have names, but if two things +// had the same shape they got merged into one type that had one of the names. +// That might not be the ideal situation, but it is the expected behavior in rust + +export const DEFAULT_VISITOR_DATA: VisitorData = { + usedRecClasses: [], + isOnService: false, + isFirstService: false, + systemFuncs: [] +}; + +export function DidResultToCandidString(result: VisitorResult): string { + const [candid, candidTypeDefs] = result; + const candidTypesString = newTypeToCandidString(candidTypeDefs); + return candidTypesString + candid + '\n'; +} + +function newTypeToCandidString(newTypes: CandidTypesDefs): string { + return Object.entries(newTypes).length > 0 + ? newTypesToStingArr(newTypes).join('\n') + '\n' + : ''; +} + +function newTypesToStingArr(newTypes: CandidTypesDefs): string[] { + return Object.entries(newTypes).map( + ([name, candid]) => `type ${name} = ${candid};` + ); +} + type TypeName = string; export type CandidDef = string; export type CandidTypesDefs = { [key: TypeName]: CandidDef }; @@ -21,18 +58,98 @@ export function extractCandid( return [paramCandid, candidTypeDefs]; } -class DidVisitor extends IDL.Visitor { +function hch(value: any) { + if (value._azleIsCanister) { + return value().getIDL(); + } + return value; +} + +export class DidVisitor extends IDL.Visitor { visitService(t: IDL.ServiceClass, data: VisitorData): VisitorResult { - const stuff = t._fields.map(([_name, func]) => - func.accept(this, { ...data, is_on_service: true }) + const canisterMethods = extractCandid( + t._fields.map(([_name, func]) => + func.accept(this, { + ...data, + isOnService: true, + isFirstService: false + }) + ) + ); + + const isInitFunction = (func: IDL.FuncClass) => + func.annotations.includes('init'); + const isPostUpgradeFunction = (func: IDL.FuncClass) => + func.annotations.includes('postUpgrade'); + // To get the service params we need to look at the init function + const initMethod = extractCandid( + data.systemFuncs + .filter((func) => isInitFunction(func)) + .map((initFunc) => + initFunc.accept(this, { + ...data, + isOnService: true, + isFirstService: false + }) + ) + ); + const postMethod = extractCandid( + data.systemFuncs + .filter((func) => isPostUpgradeFunction(func)) + .map((initFunc) => + initFunc.accept(this, { + ...data, + isOnService: true, + isFirstService: false + }) + ) + ); + const initMethodCandidString = initMethod[0]; + const postMethodCandidString = postMethod[0]; + function getFunctionParams( + initFuncString: string[], + postFuncString: string[] + ) { + if (initFuncString.length === 0) { + if (postFuncString.length === 0) { + return '()'; + } + const parts = postFuncString[0].split('->'); + if (parts.length >= 2) { + return parts[0].trim(); + } + } + const parts = initFuncString[0].split('->'); + if (parts.length >= 2) { + return parts[0].trim(); + } + } + const canisterParamsString = getFunctionParams( + initMethodCandidString, + postMethodCandidString ); - const candid = extractCandid(stuff); - const funcStrings = candid[0] + + const candidTypes = { + ...canisterMethods[1], + ...initMethod[1], + ...postMethod[1] + }; + + const tab = data.isFirstService ? ' ' : ''; + const func_separator = data.isFirstService ? '\n' : ' '; + + const funcStrings = canisterMethods[0] .map((value, index) => { - return `\t${t._fields[index][0]}: ${value}`; + return `${tab}${t._fields[index][0]}: ${value};`; }) - .join('\n'); - return [`service {\n${funcStrings}\n}`, candid[1]]; + .join(func_separator); + if (data.isFirstService) { + return [ + `service: ${canisterParamsString} -> {\n${funcStrings}\n}`, + candidTypes + ]; + } + return [`service {${funcStrings}}`, candidTypes]; } visitPrimitive( t: IDL.PrimitiveType, @@ -46,7 +163,7 @@ class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const fields = components.map((value) => - value.accept(this, { ...data, is_on_service: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(fields); return [`record {${candid[0].join('; ')}}`, candid[1]]; @@ -56,7 +173,7 @@ class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = ty.accept(this, { ...data, is_on_service: false }); + const candid = hch(ty).accept(this, { ...data, isOnService: false }); return [`opt ${candid[0]}`, candid[1]]; } visitVec( @@ -64,25 +181,24 @@ class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = ty.accept(this, { ...data, is_on_service: false }); + const candid = hch(ty).accept(this, { ...data, isOnService: false }); return [`vec ${candid[0]}`, candid[1]]; } visitFunc(t: IDL.FuncClass, data: VisitorData): VisitorResult { const argsTypes = t.argTypes.map((value) => - value.accept(this, { ...data, is_on_service: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candidArgs = extractCandid(argsTypes); const retsTypes = t.retTypes.map((value) => - value.accept(this, { ...data, is_on_service: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candidRets = extractCandid(retsTypes); const args = candidArgs[0].join(', '); const rets = candidRets[0].join(', '); - const annon = ' ' + t.annotations.join(' '); + const annon = + t.annotations.length === 0 ? '' : ' ' + t.annotations.join(' '); return [ - `${ - data.is_on_service ? '' : 'func ' - }(${args}) -> (${rets})${annon}`, + `${data.isOnService ? '' : 'func '}(${args}) -> (${rets})${annon}`, { ...candidArgs[1], ...candidRets[1] } ]; } @@ -97,11 +213,13 @@ class DidVisitor extends IDL.Visitor { // Everything else will just be the normal inline candid def const usedRecClasses = data.usedRecClasses; if (!usedRecClasses.includes(t)) { - const candid = t.accept(this, { + const candid = hch(ty).accept(this, { + ...data, usedRecClasses: [...usedRecClasses, t], - is_on_service: false + isOnService: false, + isFirstService: false }); - return [t.name, { ...candid[1], [t.name]: candid[0][0] }]; + return [t.name, { ...candid[1], [t.name]: candid[0] }]; } // If our list already includes this rec class then just return, we don't // need the list because we will get it when we go through the arm above @@ -113,7 +231,7 @@ class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - value.accept(this, { ...data, is_on_service: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const field_strings = fields.map( @@ -127,7 +245,7 @@ class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - value.accept(this, { ...data, is_on_service: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const fields_string = fields.map( diff --git a/src/lib_new/visitors/encode_decode/index.ts b/src/lib_new/visitors/encode_decode/index.ts index 33f3e5a842..bda98a20a3 100644 --- a/src/lib_new/visitors/encode_decode/index.ts +++ b/src/lib_new/visitors/encode_decode/index.ts @@ -22,11 +22,11 @@ export type VisitorResult = any; * is extracted into these helper methods. */ -function handleRecursiveClass(type: any) { - if (type._azleRecLambda) { - return type(); +function hch(value: any) { + if (value._azleIsCanister) { + return value().getIDL(); } - return type; + return value; } export function visitTuple( @@ -35,9 +35,9 @@ export function visitTuple( data: VisitorData ): VisitorResult { const fields = components.map((value, index) => - value.accept(visitor, { + hch(value).accept(visitor, { js_data: data.js_data[index], - js_class: handleRecursiveClass(data.js_class._azleTypes[index]) + js_class: data.js_class._azleTypes[index] }) ); return [...fields]; @@ -51,9 +51,9 @@ export function visitOpt( if (data.js_data.length === 0) { return data.js_data; } - const candid = ty.accept(visitor, { + const candid = hch(ty).accept(visitor, { js_data: data.js_data[0], - js_class: handleRecursiveClass(data.js_class._azleType) + js_class: data.js_class._azleType }); return [candid]; } @@ -67,9 +67,9 @@ export function visitVec( return data.js_data; } return data.js_data.map((array_elem: any) => { - return ty.accept(visitor, { + return hch(ty).accept(visitor, { js_data: array_elem, - js_class: handleRecursiveClass(data.js_class._azleType) + js_class: data.js_class._azleType }); }); } @@ -81,11 +81,11 @@ export function visitRecord( ): VisitorResult { const candidFields = fields.reduce((acc, [memberName, memberIdl]) => { const fieldData = data.js_data[memberName]; - const fieldClass = handleRecursiveClass(data.js_class[memberName]); + const fieldClass = data.js_class[memberName]; return { ...acc, - [memberName]: memberIdl.accept(visitor, { + [memberName]: hch(memberIdl).accept(visitor, { js_data: fieldData, js_class: fieldClass }) @@ -104,10 +104,10 @@ export function visitVariant( if ('Ok' in data.js_data) { const okField = fields[0]; const okData = data.js_data['Ok']; - const okClass = handleRecursiveClass(data.js_class._azleOk); + const okClass = data.js_class._azleOk; return Result.Ok( - okField[1].accept(visitor, { + hch(okField[1]).accept(visitor, { js_data: okData, js_class: okClass }) @@ -116,9 +116,9 @@ export function visitVariant( if ('Err' in data.js_data) { const errField = fields[0]; const errData = data.js_data['Err']; - const errClass = handleRecursiveClass(data.js_class._azleErr); + const errClass = data.js_class._azleErr; return Result.Err( - errField[1].accept(visitor, { + hch(errField[1]).accept(visitor, { js_data: errData, js_class: errClass }) @@ -127,14 +127,14 @@ export function visitVariant( } const candidFields = fields.reduce((acc, [memberName, memberIdl]) => { const fieldData = data.js_data[memberName]; - const fieldClass = handleRecursiveClass(data.js_class[memberName]); + const fieldClass = data.js_class[memberName]; if (fieldData === undefined) { // If the field data is undefined then it is not the variant that was used return acc; } return { ...acc, - [memberName]: memberIdl.accept(visitor, { + [memberName]: hch(memberIdl).accept(visitor, { js_class: fieldClass, js_data: fieldData }) @@ -149,5 +149,12 @@ export function visitRec( ty: IDL.ConstructType, data: VisitorData ): VisitorResult { - return ty.accept(visitor, data); + let js_class = data.js_class(); + if (js_class._azleIsCanister) { + js_class = js_class([]); + } + return hch(ty).accept(visitor, { + ...data, + js_class + }); }