From 5ec955d3d5a4a2b77a7f74a67268a6164bb639a3 Mon Sep 17 00:00:00 2001 From: Paul Young Date: Thu, 26 Sep 2019 14:48:57 -0700 Subject: [PATCH 1/9] IDL: update generated JS bindings Motivation for these changes are as follows: 1. The previous implementation used `require` to import a dependency instead of using the standardized ECMAScript module syntax. Some environments (including Node.js and web browsers) already support ECMAScript module syntax but know nothing about `require`. By using ECMAScript module syntax, we don't impose a particular module system on consumers, allowing them to bring in a polyfill only if necessary. 2. The previous implementation "imported" (using `require`) a module named "IDL". No such module exists; this only worked as a result of some extra setup. This approach is also inflexible in that it required hard-coding a package name, and creating a direct dependency on it. 3. The previously implementation did not export anything, making it difficult to use with a module system. Now, the module exports a function that accepts a record with an IDL field that represents the IDL module. 4. As recently discussed, "Message" was renamed to "Func". This change is now reflected in the generated JavaScript. However, due to the way we depend on the IDL module, breaking changes of this nature can now be handled at the call site if necessary. For example, if the JS bindings still used `IDL.Message`, we could do this: ```javascript import makeActorInterface from "actor.js"; const actorInterface = makeActorInterface({ IDL: { ...IDL, Message: IDL.Func, }, }); ``` --- default.nix | 13 +++++++------ src/idllib/compile_js.ml | 32 ++++++++++++++++++++------------ test/idl/ok/actor.js.ok | 12 +++++++----- test/idl/ok/cyclic.js.ok | 8 +++++--- test/idl/ok/diamond.js.ok | 7 +++++-- test/idl/ok/fields.js.ok | 8 +++++--- test/idl/ok/import.js.ok | 9 ++++++--- test/idl/ok/import1.js.ok | 6 ++++-- test/idl/ok/import3.js.ok | 14 ++++++++------ test/idl/ok/integer.js.ok | 10 ++++++---- test/idl/ok/px.js.ok | 8 +++++--- test/idl/ok/recursion.js.ok | 14 ++++++++------ test/idl/ok/test.js.ok | 21 +++++++++++---------- test/idl/ok/unicode.js.ok | 12 +++++++----- test/run.sh | 4 ++-- 15 files changed, 106 insertions(+), 72 deletions(-) diff --git a/default.nix b/default.nix index f788368a265..f78bde8bdae 100644 --- a/default.nix +++ b/default.nix @@ -36,6 +36,11 @@ let dfinity-repo = import (builtins.fetchGit { rev = "a50367859416ef7c12ca103b7fc03f5a7654f6ad"; }) { system = nixpkgs.system; }; in +let esm = builtins.fetchTarball { + sha256 = "116k10q9v0yzpng9bgdx3xrjm2kppma2db62mnbilbi66dvrvz9q"; + url = "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz"; +}; in + let real-dvm = if dvm == null then dev.dvm @@ -46,9 +51,6 @@ let real-drun = then dfinity-repo.dfinity.drun else drun; in -# Include js-client -let js-client = dev.js-dfinity-client; in - let haskellPackages = nixpkgs.haskellPackages.override { overrides = self: super: { haskell-lsp-types = self.callPackage @@ -269,11 +271,11 @@ rec { nixpkgs.getconf nixpkgs.nodejs-10_x filecheck - js-client dvm drun qc-actorscript lsp-int + esm ] ++ llvmBuildInputs; @@ -283,7 +285,7 @@ rec { export ASC=asc export AS_LD=as-ld export DIDC=didc - export JSCLIENT=${js-client} + export ESM=${esm} asc --version make parallel qc-actorscript${nixpkgs.lib.optionalString (replay != 0) @@ -553,7 +555,6 @@ rec { shellHook = llvmEnv; TOMMATHSRC = libtommath; - JSCLIENT = js-client; NIX_FONTCONFIG_FILE = users-guide.NIX_FONTCONFIG_FILE; } else null; diff --git a/src/idllib/compile_js.ml b/src/idllib/compile_js.ml index ff0f5d8ed34..ffb816b7203 100644 --- a/src/idllib/compile_js.ml +++ b/src/idllib/compile_js.ml @@ -108,7 +108,7 @@ let rec pp_typ ppf t = | OptT t -> str ppf "IDL.Opt("; pp_typ ppf t; str ppf ")"; | VariantT ts -> str ppf "IDL.Variant({"; concat ppf pp_field "," ts; str ppf "})"; | FuncT (ms, t1, t2) -> - str ppf "IDL.Message("; + str ppf "IDL.Func("; pp_fields ppf t1; kwd ppf ","; pp_fields ppf t2; @@ -175,22 +175,29 @@ let pp_actor ppf actor = (match actor.it with | ActorD (x, t) -> let x = ("actor_" ^ x.it) @@ x.at in - match t.it with - | ServT tp -> - id ppf x; space ppf (); kwd ppf "="; kwd ppf "new"; - str ppf "IDL.ActorInterface({"; - concat ppf pp_meth "," tp; - str ppf "})" - | VarT var -> id ppf x; space ppf (); kwd ppf "="; id ppf var - | _ -> assert false + (match t.it with + | ServT tp -> + id ppf x; space ppf (); kwd ppf "="; kwd ppf "new"; + str ppf "IDL.ActorInterface({"; + concat ppf pp_meth "," tp; + str ppf "});" + | VarT var -> id ppf x; space ppf (); kwd ppf "="; id ppf var; str ppf ";"; + | _ -> assert false + ); + pp_force_newline ppf (); + kwd ppf "return"; id ppf x; str ppf ";" ); pp_close_box ppf () let pp_header ppf () = pp_open_vbox ppf 0; - str ppf "const IDL = require('IDL')"; + str ppf "export default ({ IDL }) => {"; pp_close_box ppf () - + +let pp_footer ppf () = + pp_force_newline ppf (); + pp_print_string ppf "};" + let pp_prog ppf env prog = match prog.it.actor with | None -> () @@ -206,7 +213,8 @@ let pp_prog ppf env prog = TS.iter (pp_rec ppf) recs; List.iter (pp_dec ppf) env_list; pp_actor ppf actor; - pp_close_box ppf () + pp_close_box ppf (); + pp_footer ppf () let compile (scope : Typing.scope) (prog : Syntax.prog) = let buf = Buffer.create 100 in diff --git a/test/idl/ok/actor.js.ok b/test/idl/ok/actor.js.ok index 2225b3b1fd9..36fbe4a2d93 100644 --- a/test/idl/ok/actor.js.ok +++ b/test/idl/ok/actor.js.ok @@ -1,9 +1,11 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const o = IDL.Rec() -const f = IDL.Message(IDL.Obj({'0': IDL.Int8}), IDL.Obj({'0': IDL.Int8})) -const h = IDL.Message(IDL.Obj({'0': f}), IDL.Obj({'0': f})) +const f = IDL.Func(IDL.Obj({'0': IDL.Int8}), IDL.Obj({'0': IDL.Int8})) +const h = IDL.Func(IDL.Obj({'0': f}), IDL.Obj({'0': f})) const g = f o.fill(IDL.Opt(o)) const actor_g = new IDL.ActorInterface({ - 'f': IDL.Message(IDL.Obj({'0': IDL.Nat}), IDL.Obj({'0': h})), 'g': f, - 'h': g, 'o': IDL.Message(IDL.Obj({'0': o}), IDL.Obj({'0': o}))}) + 'f': IDL.Func(IDL.Obj({'0': IDL.Nat}), IDL.Obj({'0': h})), 'g': f, 'h': g, + 'o': IDL.Func(IDL.Obj({'0': o}), IDL.Obj({'0': o}))}); + return actor_g; +}; diff --git a/test/idl/ok/cyclic.js.ok b/test/idl/ok/cyclic.js.ok index f04f438c3ba..6aaa361324b 100644 --- a/test/idl/ok/cyclic.js.ok +++ b/test/idl/ok/cyclic.js.ok @@ -1,4 +1,4 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const A = IDL.Rec() const C = A const B = IDL.Opt(C) @@ -8,5 +8,7 @@ const Y = Z const X = Y const actor_S = new IDL.ActorInterface({ 'f': - IDL.Message(IDL.Obj({'0': A, '1': B, '2': C, '3': X, '4': Y, '5': Z}), - IDL.Obj({}))}) + IDL.Func(IDL.Obj({'0': A, '1': B, '2': C, '3': X, '4': Y, '5': Z}), + IDL.Obj({}))}); + return actor_S; +}; diff --git a/test/idl/ok/diamond.js.ok b/test/idl/ok/diamond.js.ok index 360efbdc716..0570db603c6 100644 --- a/test/idl/ok/diamond.js.ok +++ b/test/idl/ok/diamond.js.ok @@ -1,7 +1,10 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const t = IDL.Nat const t2 = IDL.Arr(t) const t3 = IDL.Opt(t) const t1 = IDL.Obj({'0': t2, '1': t3, '2': t}) const actor_S = new IDL.ActorInterface({ - 'f': IDL.Message(IDL.Obj({'0': t, '1': t2, '2': t3}), IDL.Obj({'0': t1}))}) + 'f': IDL.Func(IDL.Obj({'0': t, '1': t2, '2': t3}), IDL.Obj({'0': t1}))}); + + return actor_S; +}; diff --git a/test/idl/ok/fields.js.ok b/test/idl/ok/fields.js.ok index 4e2493fcfad..00c249c0f3c 100644 --- a/test/idl/ok/fields.js.ok +++ b/test/idl/ok/fields.js.ok @@ -1,4 +1,4 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const A = IDL.Obj({'0': IDL.Nat, '1': IDL.Nat, '2': IDL.Nat}) const B = IDL.Obj({'0': IDL.Arr(IDL.Nat8), '35': IDL.Arr(IDL.Nat8), '36': IDL.Nat, @@ -15,5 +15,7 @@ const nest_record = '5': IDL.Nat, '6': IDL.Nat, '7': A, '8': B, '9': C, '10': IDL.Nat}) const actor_S = new IDL.ActorInterface({ 'f': - IDL.Message(IDL.Obj({'0': A, '1': B, '2': C, '3': nest_record}), - IDL.Obj({}))}) + IDL.Func(IDL.Obj({'0': A, '1': B, '2': C, '3': nest_record}), IDL.Obj({})) + }); + return actor_S; +}; diff --git a/test/idl/ok/import.js.ok b/test/idl/ok/import.js.ok index fa9377df38d..daef8d6b5e0 100644 --- a/test/idl/ok/import.js.ok +++ b/test/idl/ok/import.js.ok @@ -1,4 +1,4 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const t = IDL.Arr(IDL.Nat8) const t1 = t const UserId = IDL.Nat @@ -13,7 +13,10 @@ const IdErr = IDL.Obj({'idErr': OpEntId}) const Inventory = IDL.Obj({'produce_id': IDL.Nat, 'quantity': IDL.Nat}) const actor_S = new IDL.ActorInterface({ 'f': - IDL.Message(IDL.Obj({'0': t, '1': t1, '2': t2}), + IDL.Func(IDL.Obj({'0': t, '1': t1, '2': t2}), IDL.Obj({'0': list, '1': IdErr})), 'getInventory': - IDL.Message(IDL.Obj({'producer_id': IDL.Nat}), IDL.Obj({'0': Inventory}))}) + IDL.Func(IDL.Obj({'producer_id': IDL.Nat}), IDL.Obj({'0': Inventory}))}); + + return actor_S; +}; diff --git a/test/idl/ok/import1.js.ok b/test/idl/ok/import1.js.ok index 23a298b9391..944ff4a8b2b 100644 --- a/test/idl/ok/import1.js.ok +++ b/test/idl/ok/import1.js.ok @@ -1,7 +1,9 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const t = IDL.Arr(IDL.Nat8) const t1 = t const UserId = IDL.Nat const t2 = UserId const actor_S = new IDL.ActorInterface({ - 'f': IDL.Message(IDL.Obj({'0': t, '1': t1, '2': t2}), IDL.Obj({}))}) + 'f': IDL.Func(IDL.Obj({'0': t, '1': t1, '2': t2}), IDL.Obj({}))}); + return actor_S; +}; diff --git a/test/idl/ok/import3.js.ok b/test/idl/ok/import3.js.ok index 517f9849fb4..46b8e726092 100644 --- a/test/idl/ok/import3.js.ok +++ b/test/idl/ok/import3.js.ok @@ -1,16 +1,16 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const B = IDL.Rec() const list = IDL.Rec() const s = IDL.Rec() const stream = IDL.Rec() const tree = IDL.Rec() -const t = IDL.Message(IDL.Obj({'server': s}), IDL.Obj({})) +const t = IDL.Func(IDL.Obj({'server': s}), IDL.Obj({})) const node = IDL.Obj({'head': IDL.Nat, 'tail': list}) list.fill(IDL.Opt(node)) stream.fill( IDL.Opt( IDL.Obj({'head': IDL.Nat, - 'next': IDL.Message(IDL.Obj({}), IDL.Obj({'0': stream}))})) + 'next': IDL.Func(IDL.Obj({}), IDL.Obj({'0': stream}))})) ) tree.fill( IDL.Variant({ @@ -21,6 +21,8 @@ B.fill(IDL.Opt(A)) s.fill( new IDL.ActorInterface({'f': t, 'g': - IDL.Message(IDL.Obj({'0': list}), - IDL.Obj({'2': stream, '1': tree, '0': B}))})) -const actor_S = s + IDL.Func(IDL.Obj({'0': list}), IDL.Obj({'2': stream, '1': tree, '0': B})) + })) +const actor_S = s; + return actor_S; +}; diff --git a/test/idl/ok/integer.js.ok b/test/idl/ok/integer.js.ok index 436f404354e..970e4d46cb8 100644 --- a/test/idl/ok/integer.js.ok +++ b/test/idl/ok/integer.js.ok @@ -1,5 +1,7 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const actor_num = new IDL.ActorInterface({ - 'f': IDL.Message(IDL.Obj({'0': IDL.Nat8}), IDL.Obj({'0': IDL.Int16})), - 'g': IDL.Message(IDL.Obj({'0': IDL.Nat64}), IDL.Obj({'0': IDL.Int64})), - 'h': IDL.Message(IDL.Obj({'0': IDL.Int8}), IDL.Obj({'0': IDL.Nat}))}) + 'f': IDL.Func(IDL.Obj({'0': IDL.Nat8}), IDL.Obj({'0': IDL.Int16})), + 'g': IDL.Func(IDL.Obj({'0': IDL.Nat64}), IDL.Obj({'0': IDL.Int64})), + 'h': IDL.Func(IDL.Obj({'0': IDL.Int8}), IDL.Obj({'0': IDL.Nat}))}); + return actor_num; +}; diff --git a/test/idl/ok/px.js.ok b/test/idl/ok/px.js.ok index 06ea8d3f87f..25173a75769 100644 --- a/test/idl/ok/px.js.ok +++ b/test/idl/ok/px.js.ok @@ -1,4 +1,4 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const UserId = IDL.Nat const RegionId = IDL.Nat const ProducerId = IDL.Nat @@ -14,5 +14,7 @@ const OpEntId = IDL.Opt(EntId) const IdErr = IDL.Obj({'idErr': OpEntId}) const actor_ProduceExchange = new IDL.ActorInterface({ 'getInventory': - IDL.Message(IDL.Obj({'producer_id': IDL.Nat, '3667444713': UserInfo}), - IDL.Obj({'0': Inventory, '1': IdErr}))}) + IDL.Func(IDL.Obj({'producer_id': IDL.Nat, '3667444713': UserInfo}), + IDL.Obj({'0': Inventory, '1': IdErr}))}); + return actor_ProduceExchange; +}; diff --git a/test/idl/ok/recursion.js.ok b/test/idl/ok/recursion.js.ok index 1b71a15819f..ca4fa31909b 100644 --- a/test/idl/ok/recursion.js.ok +++ b/test/idl/ok/recursion.js.ok @@ -1,16 +1,16 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const B = IDL.Rec() const list = IDL.Rec() const s = IDL.Rec() const stream = IDL.Rec() const tree = IDL.Rec() -const t = IDL.Message(IDL.Obj({'server': s}), IDL.Obj({})) +const t = IDL.Func(IDL.Obj({'server': s}), IDL.Obj({})) const node = IDL.Obj({'head': IDL.Nat, 'tail': list}) list.fill(IDL.Opt(node)) stream.fill( IDL.Opt( IDL.Obj({'head': IDL.Nat, - 'next': IDL.Message(IDL.Obj({}), IDL.Obj({'0': stream}))})) + 'next': IDL.Func(IDL.Obj({}), IDL.Obj({'0': stream}))})) ) tree.fill( IDL.Variant({ @@ -21,6 +21,8 @@ B.fill(IDL.Opt(A)) s.fill( new IDL.ActorInterface({'f': t, 'g': - IDL.Message(IDL.Obj({'0': list}), - IDL.Obj({'2': stream, '1': tree, '0': B}))})) -const actor_A = s + IDL.Func(IDL.Obj({'0': list}), IDL.Obj({'2': stream, '1': tree, '0': B})) + })) +const actor_A = s; + return actor_A; +}; diff --git a/test/idl/ok/test.js.ok b/test/idl/ok/test.js.ok index dc13ef34670..178c3c7ff66 100644 --- a/test/idl/ok/test.js.ok +++ b/test/idl/ok/test.js.ok @@ -1,23 +1,24 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const my_type = IDL.Nat const B = my_type const message = IDL.Obj({'25': B, '26': IDL.None, 'name': IDL.Text}) const broker = new IDL.ActorInterface({ 'find': - IDL.Message(IDL.Obj({'name': IDL.Text}), + IDL.Func(IDL.Obj({'name': IDL.Text}), IDL.Obj({ '0': - new IDL.ActorInterface({'up': IDL.Message(IDL.Obj({}), IDL.Obj({})), - 'current': IDL.Message(IDL.Obj({}), IDL.Obj({'0': IDL.Nat}))}) + new IDL.ActorInterface({'up': IDL.Func(IDL.Obj({}), IDL.Obj({})), + 'current': IDL.Func(IDL.Obj({}), IDL.Obj({'0': IDL.Nat}))}) })) }) const actor_server = new IDL.ActorInterface({ 'addUser': - IDL.Message(IDL.Obj({'name': IDL.Text, 'age': IDL.Nat8}), + IDL.Func(IDL.Obj({'name': IDL.Text, 'age': IDL.Nat8}), IDL.Obj({'id': IDL.Nat64})), - 'userName': - IDL.Message(IDL.Obj({'id': IDL.Nat64}), IDL.Obj({'0': IDL.Text})), - 'userAge': IDL.Message(IDL.Obj({'id': IDL.Nat64}), IDL.Obj({'0': IDL.Nat8})), - 'deleteUser': IDL.Message(IDL.Obj({'id': IDL.Nat64}), IDL.Obj({})), - 'f': IDL.Message(IDL.Obj({'0': message}), IDL.Obj({'0': broker}))}) + 'userName': IDL.Func(IDL.Obj({'id': IDL.Nat64}), IDL.Obj({'0': IDL.Text})), + 'userAge': IDL.Func(IDL.Obj({'id': IDL.Nat64}), IDL.Obj({'0': IDL.Nat8})), + 'deleteUser': IDL.Func(IDL.Obj({'id': IDL.Nat64}), IDL.Obj({})), + 'f': IDL.Func(IDL.Obj({'0': message}), IDL.Obj({'0': broker}))}); + return actor_server; +}; diff --git a/test/idl/ok/unicode.js.ok b/test/idl/ok/unicode.js.ok index f8f246b20ae..8c6ac0b1ec6 100644 --- a/test/idl/ok/unicode.js.ok +++ b/test/idl/ok/unicode.js.ok @@ -1,4 +1,4 @@ -const IDL = require('IDL') +export default ({ IDL }) => { const A = IDL.Obj({'': IDL.Nat, '📦🍦': IDL.Nat, '字段名': IDL.Nat, '字 段 名2': IDL.Nat}) @@ -6,7 +6,9 @@ const B = IDL.Variant({'': IDL.Unit, '空的': IDL.Unit, ' 空的 ': IDL.Unit, '1⃣️2⃣️3⃣️': IDL.Unit}) const actor_C = new IDL.ActorInterface({ - '函数名': IDL.Message(IDL.Obj({'0': A}), IDL.Obj({'0': B})), - '': IDL.Message(IDL.Obj({'0': IDL.Nat}), IDL.Obj({'0': IDL.Nat})), - '👀': IDL.Message(IDL.Obj({'0': IDL.Nat}), IDL.Obj({'0': IDL.Nat})), - '✈️ 🚗 ⛱️ ': IDL.Message(IDL.Obj({}), IDL.Obj({}))}) + '函数名': IDL.Func(IDL.Obj({'0': A}), IDL.Obj({'0': B})), + '': IDL.Func(IDL.Obj({'0': IDL.Nat}), IDL.Obj({'0': IDL.Nat})), + '👀': IDL.Func(IDL.Obj({'0': IDL.Nat}), IDL.Obj({'0': IDL.Nat})), + '✈️ 🚗 ⛱️ ': IDL.Func(IDL.Obj({}), IDL.Obj({}))}); + return actor_C; +}; diff --git a/test/run.sh b/test/run.sh index 97de087562c..490c1956b79 100755 --- a/test/run.sh +++ b/test/run.sh @@ -268,8 +268,8 @@ do if [ -e $out/$base.js ] then $ECHO -n " [node]" - export NODE_PATH=$NODE_PATH:$JSCLIENT:$JSCLIENT/src - node $out/$base.js > $out/$base.js.out 2>&1 + export NODE_PATH=$NODE_PATH:$ESM + node -r esm $out/$base.js > $out/$base.js.out 2>&1 normalize $out/$base.js.out diff_files="$diff_files $base.js.out" fi From b48281d87236581bf0726fc27dcdc83ccfa06fef Mon Sep 17 00:00:00 2001 From: Paul Young Date: Thu, 26 Sep 2019 18:32:51 -0700 Subject: [PATCH 2/9] Remove unused environment variable --- test/run.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/run.sh b/test/run.sh index 490c1956b79..faa1cb8828c 100755 --- a/test/run.sh +++ b/test/run.sh @@ -29,7 +29,6 @@ export AS_LD WASM=${WASM:-wasm} DVM_WRAPPER=$(realpath $(dirname $0)/dvm.sh) DRUN_WRAPPER=$(realpath $(dirname $0)/drun-wrapper.sh) -JSCLIENT=${JSCLIENT:-$(realpath $(dirname $0)/../../dev/experimental/js-dfinity-client)} ECHO=echo while getopts "a12si" o; do From 80e46d83b0614f442df88263c8491660f2722711 Mon Sep 17 00:00:00 2001 From: Paul Young Date: Mon, 30 Sep 2019 17:30:06 -0700 Subject: [PATCH 3/9] Test generated JS bindings against js-user-library --- default.nix | 10 ++++++++++ test/run.sh | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/default.nix b/default.nix index f78bde8bdae..d469ee5066f 100644 --- a/default.nix +++ b/default.nix @@ -36,6 +36,12 @@ let dfinity-repo = import (builtins.fetchGit { rev = "a50367859416ef7c12ca103b7fc03f5a7654f6ad"; }) { system = nixpkgs.system; }; in +let sdk = import (builtins.fetchGit { + url = "ssh://git@github.com/dfinity-lab/sdk"; + ref = "paulyoung/ts-user-library"; + rev = "42f15621bc5b228c7fd349cb52f265917d33a3a0"; +}) { system = nixpkgs.system; }; in + let esm = builtins.fetchTarball { sha256 = "116k10q9v0yzpng9bgdx3xrjm2kppma2db62mnbilbi66dvrvz9q"; url = "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz"; @@ -51,6 +57,8 @@ let real-drun = then dfinity-repo.dfinity.drun else drun; in +let js-user-library = sdk.js-user-library; in + let haskellPackages = nixpkgs.haskellPackages.override { overrides = self: super: { haskell-lsp-types = self.callPackage @@ -271,6 +279,7 @@ rec { nixpkgs.getconf nixpkgs.nodejs-10_x filecheck + js-user-library dvm drun qc-actorscript @@ -286,6 +295,7 @@ rec { export AS_LD=as-ld export DIDC=didc export ESM=${esm} + export JS_USER_LIBRARY=${js-user-library} asc --version make parallel qc-actorscript${nixpkgs.lib.optionalString (replay != 0) diff --git a/test/run.sh b/test/run.sh index faa1cb8828c..b2e16d34b43 100755 --- a/test/run.sh +++ b/test/run.sh @@ -268,9 +268,17 @@ do then $ECHO -n " [node]" export NODE_PATH=$NODE_PATH:$ESM + node -r esm $out/$base.js > $out/$base.js.out 2>&1 normalize $out/$base.js.out diff_files="$diff_files $base.js.out" + + node -r esm -e \ + "import actorInterface from './$out/$base.js'; + import { makeActor, makeHttpAgent } from '$JS_USER_LIBRARY'; + const httpAgent = makeHttpAgent({ canisterId: 1 }); + const actor = makeActor(actorInterface)(httpAgent); + assert(Object.entries(actor).length > 0);" fi fi fi From 079eb4d14b4e32553ce457af6a1013c40c04cb88 Mon Sep 17 00:00:00 2001 From: Paul Young Date: Tue, 1 Oct 2019 17:13:45 -0700 Subject: [PATCH 4/9] Don't run Node.js tests on empty gemerated files --- default.nix | 1 + test/run.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/default.nix b/default.nix index d469ee5066f..9a1611c6150 100644 --- a/default.nix +++ b/default.nix @@ -285,6 +285,7 @@ rec { qc-actorscript lsp-int esm + nixpkgs.gnugrep ] ++ llvmBuildInputs; diff --git a/test/run.sh b/test/run.sh index b2e16d34b43..d156f05d787 100755 --- a/test/run.sh +++ b/test/run.sh @@ -264,7 +264,8 @@ do normalize $out/$base.js.out diff_files="$diff_files $base.js.out $base.js" - if [ -e $out/$base.js ] + # Proceed only if the file is not empty & doesn't just contain whitespace + if [[ ! -z $(grep '[^[:space:]]' $out/$base.js) ]]; then $ECHO -n " [node]" export NODE_PATH=$NODE_PATH:$ESM From 3ad267b41fc47e1c39911ab296165ca3b3e461bd Mon Sep 17 00:00:00 2001 From: Paul Young Date: Thu, 3 Oct 2019 13:09:04 -0700 Subject: [PATCH 5/9] Make esm & js-user-library available in nix-shell To allow for running the tests in a nix shell with make: ```sh $ cd actorscript $ nix-shell $ cd src $ make asc && make didc $ cd ../test/idl $ make ``` --- default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/default.nix b/default.nix index 9a1611c6150..20b48c9b6c2 100644 --- a/default.nix +++ b/default.nix @@ -565,6 +565,8 @@ rec { )); shellHook = llvmEnv; + ESM=esm; + JS_USER_LIBRARY=js-user-library; TOMMATHSRC = libtommath; NIX_FONTCONFIG_FILE = users-guide.NIX_FONTCONFIG_FILE; } else null; From 1dff1b1adccafcad57548f8f42c4e884ee2a797c Mon Sep 17 00:00:00 2001 From: Paul Young Date: Thu, 10 Oct 2019 12:36:24 -0700 Subject: [PATCH 6/9] Revert "Don't run Node.js tests on empty gemerated files" This reverts commit 079eb4d14b4e32553ce457af6a1013c40c04cb88. --- default.nix | 1 - test/run.sh | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/default.nix b/default.nix index 2cd9d39b422..d5e1d099368 100644 --- a/default.nix +++ b/default.nix @@ -285,7 +285,6 @@ rec { qc-actorscript lsp-int esm - nixpkgs.gnugrep ] ++ llvmBuildInputs; diff --git a/test/run.sh b/test/run.sh index d0cd97f163a..edab391f9ae 100755 --- a/test/run.sh +++ b/test/run.sh @@ -270,8 +270,7 @@ do normalize $out/$base.js.out diff_files="$diff_files $base.js.out $base.js" - # Proceed only if the file is not empty & doesn't just contain whitespace - if [[ ! -z $(grep '[^[:space:]]' $out/$base.js) ]]; + if [ -e $out/$base.js ] then $ECHO -n " [node]" export NODE_PATH=$NODE_PATH:$ESM From d70424da679bcd6f30c99723dcc5acd6719f8d78 Mon Sep 17 00:00:00 2001 From: Paul Young Date: Mon, 14 Oct 2019 13:09:28 -0700 Subject: [PATCH 7/9] Ensure recursive data exports an ActorInterface --- src/idllib/compile_js.ml | 3 ++- test/idl/ok/import3.js.ok | 2 +- test/idl/ok/recursion.js.ok | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/idllib/compile_js.ml b/src/idllib/compile_js.ml index ffb816b7203..1e9f3037aa5 100644 --- a/src/idllib/compile_js.ml +++ b/src/idllib/compile_js.ml @@ -181,7 +181,8 @@ let pp_actor ppf actor = str ppf "IDL.ActorInterface({"; concat ppf pp_meth "," tp; str ppf "});" - | VarT var -> id ppf x; space ppf (); kwd ppf "="; id ppf var; str ppf ";"; + | VarT var -> + id ppf x; space ppf (); kwd ppf "="; id ppf (var.it ^ ".__typ;"); | _ -> assert false ); pp_force_newline ppf (); diff --git a/test/idl/ok/import3.js.ok b/test/idl/ok/import3.js.ok index 46b8e726092..fbd7f269d06 100644 --- a/test/idl/ok/import3.js.ok +++ b/test/idl/ok/import3.js.ok @@ -23,6 +23,6 @@ s.fill( 'g': IDL.Func(IDL.Obj({'0': list}), IDL.Obj({'2': stream, '1': tree, '0': B})) })) -const actor_S = s; +const actor_S = s.__typ; return actor_S; }; diff --git a/test/idl/ok/recursion.js.ok b/test/idl/ok/recursion.js.ok index ca4fa31909b..5d828a96773 100644 --- a/test/idl/ok/recursion.js.ok +++ b/test/idl/ok/recursion.js.ok @@ -23,6 +23,6 @@ s.fill( 'g': IDL.Func(IDL.Obj({'0': list}), IDL.Obj({'2': stream, '1': tree, '0': B})) })) -const actor_A = s; +const actor_A = s.__typ; return actor_A; }; From 2ab7a8cb28a149814c41496957a782b9546b7a5b Mon Sep 17 00:00:00 2001 From: Paul Young Date: Mon, 14 Oct 2019 13:13:10 -0700 Subject: [PATCH 8/9] fixup: Ensure recursive data exports an ActorInterface --- src/idllib/compile_js.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idllib/compile_js.ml b/src/idllib/compile_js.ml index 1e9f3037aa5..4b8bc7020d7 100644 --- a/src/idllib/compile_js.ml +++ b/src/idllib/compile_js.ml @@ -182,7 +182,7 @@ let pp_actor ppf actor = concat ppf pp_meth "," tp; str ppf "});" | VarT var -> - id ppf x; space ppf (); kwd ppf "="; id ppf (var.it ^ ".__typ;"); + id ppf x; space ppf (); kwd ppf "="; str ppf (var.it ^ ".__typ;"); | _ -> assert false ); pp_force_newline ppf (); From e91b6456baa03c75fad576c0be5fe59144f84b6d Mon Sep 17 00:00:00 2001 From: chenyan-dfinity Date: Mon, 14 Oct 2019 13:35:57 -0700 Subject: [PATCH 9/9] add .__typ for recursive types only --- src/idllib/compile_js.ml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/idllib/compile_js.ml b/src/idllib/compile_js.ml index 4b8bc7020d7..1e159436d64 100644 --- a/src/idllib/compile_js.ml +++ b/src/idllib/compile_js.ml @@ -169,7 +169,7 @@ let pp_rec ppf x = pp_close_box ppf (); pp_print_cut ppf () -let pp_actor ppf actor = +let pp_actor ppf actor recs = pp_open_hovbox ppf 1; kwd ppf "const"; (match actor.it with @@ -182,7 +182,11 @@ let pp_actor ppf actor = concat ppf pp_meth "," tp; str ppf "});" | VarT var -> - id ppf x; space ppf (); kwd ppf "="; str ppf (var.it ^ ".__typ;"); + id ppf x; space ppf (); kwd ppf "="; + if TS.mem var.it recs then + str ppf (var.it ^ ".__typ;") + else + str ppf var.it; | _ -> assert false ); pp_force_newline ppf (); @@ -213,7 +217,7 @@ let pp_prog ppf env prog = pp_open_vbox ppf 0; TS.iter (pp_rec ppf) recs; List.iter (pp_dec ppf) env_list; - pp_actor ppf actor; + pp_actor ppf actor recs; pp_close_box ppf (); pp_footer ppf ()