onflow / flow-cadut Goto Github PK
View Code? Open in Web Editor NEWNode based template generator to simplify interaction with Cadence files.
License: Apache License 2.0
Node based template generator to simplify interaction with Cadence files.
License: Apache License 2.0
Parser should have the ability to extract a list of arguments for contract initialization
For contract with following Cadence template:
pub contract Hello {
init(a: String, b: Int) {}
}
parser shall extract a list of arguments a: String, b: Int
Please fill out the template below to the best of your ability and include a label indicating which tool/service you were working with when you encountered the problem.
Using ECMAScript modules with the import
syntax/keyword doesn't work after installing the latest version of flow-cadut
(0.1.11-alpha.6).
While using the "type": "module"
settings in package.json
and trying to run this simple snippet:
import { reportMissingImports } from 'flow-cadut'
Will result in the following error:
$ yarn test
yarn run v1.22.10
$ node flow-import
internal/process/esm_loader.js:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '~/workspace/test-flow-cadut-import/node_modules/flow-cadut/dist/main.mjs' imported from ~/workspace/test-flow-cadut-import/flow-import.js
Did you mean to import flow-cadut-import/node_modules/flow-cadut/dist/main.js?
at finalizeResolution (internal/modules/esm/resolve.js:276:11)
at moduleResolve (internal/modules/esm/resolve.js:699:10)
at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:810:11)
at Loader.resolve (internal/modules/esm/loader.js:86:40)
at Loader.getModuleJob (internal/modules/esm/loader.js:230:28)
at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:56:40)
at link (internal/modules/esm/module_job.js:55:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
error Command failed with exit code 1.
Upon further investigation it looks like the package.json
of the installed flow-cadut
module has an exports/./import
of ./dist/main.mjs
:
{
"module": "./dist/main.module.js",
"exports": {
".": {
"import": "./dist/main.mjs"
}
}
}
Yet listing the contents of the dist
folder doesn't show that main.mjs
exists:
$ ls -l dist
main.js
main.js.map
main.modern.js
main.modern.js.map
main.module.js
main.module.js.map
main.umd.js
main.umd.js.map
Current Software Versions
Workaround
You can work around this problem by modify the package.json
of the installed flow-cadut
module. Change the exports/./import
to ./dist/main.js
(remove the m
from the .mjs
file extension:
{
"exports": {
".": {
"import": "./dist/main.js"
}
}
}
yarn init
and accept defaultspackage.json
to have Node treat code/modules as ECMAScript modules (i.e. add "type": "module"
){
"name": "test-flow-cadut-import",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"type": "module"
}
flow-cadut
(yarn add flow-cadut --dev
)index.js
in projects root directory:import { reportMissingImports } from 'flow-cadut'
$ node index.js
internal/process/esm_loader.js:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '~/workspace/test-flow-cadut-import/node_modules/flow-cadut/dist/main.mjs' imported from ~/workspace/test-flow-cadut-import/index.js
Did you mean to import flow-cadut-import/node_modules/flow-cadut/dist/main.js?
at finalizeResolution (internal/modules/esm/resolve.js:276:11)
at moduleResolve (internal/modules/esm/resolve.js:699:10)
at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:810:11)
at Loader.resolve (internal/modules/esm/loader.js:86:40)
at Loader.getModuleJob (internal/modules/esm/loader.js:230:28)
at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:56:40)
at link (internal/modules/esm/module_job.js:55:36) {
code: 'ERR_MODULE_NOT_FOUND'
flow-cadut
can be installed and consumed (i.e. import
) as ECMAScript modules out of the boxWorking on Dapp development for the Flow network with Cadence.
Use named exports in the index files that are generated by flow-cadut
Currently exports in flow-cadut generated code look as follows:
import scripts from "./scripts";
import transactions from "./scripts";
export default { scripts, transactions };
While there is not inherently an issue with using default exports, it is somewhat non-standard. More importantly, it does not work with IntelliSense (at least in VSCode). This makes templates more tedious to work with. I am proposing we change it to something more like the following:
import scripts from "./scripts";
import transactions from "./scripts";
export { scripts, transactions };
export default { scripts, transactions };
By using both named and default exports we can ensure backward compatibility with any applications that may still be using default exports (i.e. flow-js-testing)
Update the .hbs templates to support this form of ES exports instead.
Currently it's impossible to pass Path arguments, even though it's supported by @onflow/types
(it was recently added).
Corresponding source code for Path
type can be found here:
https://github.com/onflow/fcl-js/blob/master/packages/types/src/types.js#L539
I propose that we add some automated tests using Jest that would run in CI to the generator-test package (would be fairly straightforward).
The generator-test package currently has no automated tests and is only useful as a utility to manually test the generator after making changes.
Add file watcher to look for new files added to input folder.
We can use chokidar
- https://www.npmjs.com/package/chokidar ` - package.
User should be able to pass url to GitHub repository as input. For example, url https://github.com/onflow/flow-core-contracts/tree/feature/epochs/contracts
, shall process all the Cadence files in contracts
folder for https://github.com/onflow/flow-core-contracts
on branch feature/epochs
.
Please fill out the template below to the best of your ability and include a label indicating which tool/service you were working with when you encountered the problem.
Node 16.14.2
<what is the problem you've encountered?>
I use processFolder api with setEnv to build js script with import constract to be binding with address map, but when i import flow-cadut/generator it cant find this module ?
<what are you currently working on that this is blocking?>
Quite common case, when someone would want to create new account on server.
It will require to create authorization function and pass private key to it and then use it as signer.
The process should be much easier I think :)
Update the regex for imports to parse multiple imports from the same address in cadence code (only supports single imports currently)
Code such as the following will not work
const addressMap = {
Messages: '0xf8d6e0586b0a20c7',
OtherMessages: '0xf8d6e0586b0a20c7',
};
const code = `
import Messages, OtherMessages from 0x1
pub fun main(){}
`;
const replaced = replaceImportAddresses(code, addressMap);
console.log({ replaced });
See original issue: #73
Calling resolveArguments with an optional array of Addresses as a parameter results in the following error:
thrown: "[Address]? is not supported"
Likely applies to all arrays, not exclusively Address
Create a script/transaction that uses an optional array of addresses as a parameter
Flow-cadut must resolve these arguments properly
Linked issue onflow/flow-js-testing#163
Include an API reference of all publicly available functionality with the standard documentation format followed in the FCL docs & testing repo.
Add in use cases and examples on where to use this in the development process for maximum benefit.
In order to quickly scaffold testing environment with all the necessary parts we can implement generator, based on the one we have in Playground.
Implement a system to allow quick data fetching for specific dapps.
Something like this:
const { getView, ChainMonstersItems } from "flow-cadut/views"
const { setEnvironment } from "flow-cadut"
(async ()=>{
await setEnvironment("mainnet")
const items = await getView(ChainMonstersItems, "bjarte.find")
// items here will have a JSON structure will some specific schema
console.log({ items })
})()
Passing optional argument is currently to supported by cadut.
import { query, config } from "@onflow/fcl";
import { mapArgument } from "flow-cadut";
(async () => {
config().put("accessNode.api", "https://access-testnet.onflow.org");
const cadence = `
pub fun main(message: String?):String? {
return message
}
`;
const message = mapArgument("String?", "Hello from Cadence");
// 🪄 Ala-ca-blam!
const args = () => [message];
const rating = await query({ cadence, args });
console.log({ rating });
})();
Code above shall work properly.
It might be better if we can pass a object as the following to setting up all the contract addresses once, instead of passing it every time we invoke.
example :
const globalAddressMap= {
emulator:{
SomeContract :"some address"
},
testnet:{
SomeContract :"some address"
},
production:{
SomeContract :"some address"
}
}
cadut.setGlobalAddressMap(globalAddressMap)
and then cadut will decide to use address map network depend on environment
extractImports
sometimes reports false positive matches - for example for word "important"
<what is the problem you've encountered?>
var pkg = require('flow-cadut')
const transaction = `
transaction {
pre {}
execute{}
post{}
}
console.log(
pkg.extractContractName(transaction)
)
The code above passed in a transaction to extractContractName() method and triggers error below:
kerrywei@kerrys-mbp-2 cadut-example % node app.js
/Users/kerrywei/repos/cadut-example/node_modules/flow-cadut/dist/main.js:1
var t=require("@onflow/config"),n=require("@onflow/types"),r=require("@onflow/fcl");function e(t){if(t&&t.t)return t;var n=Object.create(null);return t&&Object.keys(t).forEach(function(r){if("default"!==r){var e=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(n,r,e.get?e:{enumerable:!0,get:function(){return t[r]}})}}),n.default=t,n}var o=e(n),c=e(r);const s={emulator:{FlowToken:"0xee82856bf20e2aa6",FungibleToken:"0x0ae53cb6e3f42a79"},testnet:{FlowToken:"0x7e60df042a9c0868",FungibleToken:"0x9a0766d93b6608b7",LockedTokens:"0x95e019a17d0e23d7",StakingProxy:"0x7aad92e5a0715d21",FUSD:"0xe223d8a629e49c68"},mainnet:{FlowToken:"0x1654653399040a61",FungibleToken:"0xf233dcee88fe0abe",LockedTokens:"0x8d0e87b65159ae63",StakingProxy:"0x62430cf28c26d095",FUSD:"0x3c5959b568896393"}},u={mainnet:"https://access-mainnet-beta.onflow.org",testnet:"https://access-testnet.onflow.org",emulator:"http://localhost:8080"},i=function(){try{return Promise.resolve(function(){try{return Promise.resolve(t.config().get("ix.env")).then(function(t){return t||"emulator"})}catch(t){return Promise.reject(t)}}()).then(function(t){return s[t]||s.emulator})}catch(t){return Promise.reject(t)}},a=t=>t.split(/\s/).map(t=>t.replace(/\s/g,"")).filter(t=>t.length>0&&"import"!==t&&"from"!==t),f=(t,n)=>{const[r,e]=n;return t[r]=e,t},l=t=>t&&0!==t.length?t.split("\n").filter(t=>t.includes("import")).map(a).reduce(f,{}):{},p=(t,n={})=>{const r=l(t),e=[];for(const t in r)!n[t]&&Object.prototype.hasOwnProperty.call(r,t)&&e.push(t);return e},m=(t=[],n="")=>{const r="Missing imports for contracts:";console.error(n?`${n} ${r}`:r,t)},d=/(\s*import\s*)([\w\d]+)(\s+from\s*)([\w\d".\\/]+)/g,x=(t,n,r=!0)=>t.replace(d,(t,e,o,c,s)=>{const u=r?o:s;return`${e}${o} from ${(n instanceof Function?n(u):n[u])||s}`}),g=t=>{const[n]=t.split("");return n.toUpperCase()+t.slice(1)},h=t=>{switch(!0){case t.indexOf("//")>=0:return"//";case t.indexOf("/")>=0:return"/";case t.indexOf("\\")>=0:return"\\";default:return""}},P=t=>t.replace(/\s+/g," "),w=t=>t.split(",").map(t=>t.replace(/\s*/g,"")).filter(t=>""!==t),y=t=>t.replace(/(\/\*[\s\S]*?\*\/)|(\/\/.*)/g,""),v=(t,n)=>{const r=y(t),e=P(r.replace(/[\n\r]/g,""));if(e){const t=new RegExp(n,"g").exec(e);if(t)return""===t[1]?[]:w(t[1])}return[]},b=t=>v(t,"(?:prepare\\s*\\(\\s*)([^\\)]*)(?:\\))"),$=t=>v(t,"(?:fun\\s+main\\s*\\(\\s*)([^\\)]*)(?:\\))"),S=t=>v(t,"(?:transaction\\s*\\(\\s*)([^\\)]*)(?:\\))"),k=t=>{const n=y(t).replace(/(resource|struct)\s+\w+\s*{[\s\S]+?}/g,""),r=/(?:access\(\w+\)|pub)\s+contract\s+(?:interface)*\s*(\w*)(\s*{[.\s\S]*init\s*\((.*?)\)[.\s\S]*})?/g.exec(n);if(r.length<2)throw new Error("Contract Error: can't find name of the contract");return{contractName:r[1],args:r[3]||""}},F=t=>{const n=y(t);if(/transaction\s*(\(\s*\))*\s*/g.test(n)){const t=b(n),r=S(n);return{type:"transaction",signers:t.length,args:r}}if(/pub\s+fun\s+main\s*/g.test(n))return{type:"script",args:$(n)};if(/\w+\s+contract\s+(\w*\s*)\w*/g.test(n)){const{contractName:t,args:r}=k(n);return{type:"contract",signers:1,args:r,contractName:t}}return{type:"unknown"}},E=t=>!t||"string"!=typeof t,T=t=>!E(t)&&(t.startsWith("Int")||t.startsWith("UInt")||t.startsWith("Word")),A=t=>{if(E(t))return!1;const n=t.replace(/\s/g,"");return n.startsWith("[")&&n.endsWith("]")},N=t=>{if(E(t))return!1;const n=t.replace(/\s/g,"");return n.startsWith("{")&&n.endsWith("}")},j=t=>A(t)||N(t);function I(t,n,r){if(!t.s){if(r instanceof O){if(!r.s)return void(r.o=I.bind(null,t,n));1&n&&(n=r.s),r=r.v}if(r&&r.then)return void r.then(I.bind(null,t,n),I.bind(null,t,2));t.s=n,t.v=r;const e=t.o;e&&e(t)}}const O=function(){function t(){}return t.prototype.then=function(n,r){const e=new t,o=this.s;if(o){const t=1&o?n:r;if(t){try{I(e,1,t(this.v))}catch(t){I(e,2,t)}return e}return this}return this.o=function(t){try{const o=t.v;1&t.s?I(e,1,n?n(o):o):r?I(e,1,r(o)):I(e,2,o)}catch(t){I(e,2,t)}},e},t}(),U={ARGUMENT:"argument"},L=function(t){try{return Promise.resolve(r.config().get("ix.plugins")).then(function(n){const r=(n||{})[t];return!!(r&&r.length>0)&&r})}catch(t){return Promise.reject(t)}};function M(t,n,r){if(!t.s){if(r instanceof _){if(!r.s)return void(r.o=M.bind(null,t,n));1&n&&(n=r.s),r=r.v}if(r&&r.then)return void r.then(M.bind(null,t,n),M.bind(null,t,2));t.s=n,t.v=r;const e=t.o;e&&e(t)}}const _=function(){function t(){}return t.prototype.then=function(n,r){const e=new t,o=this.s;if(o){const t=1&o?n:r;if(t){try{M(e,1,t(this.v))}catch(t){M(e,2,t)}return e}return this}return this.o=function(t){try{const o=t.v;1&t.s?M(e,1,n?n(o):o):r?M(e,1,r(o)):M(e,2,o)}catch(t){M(e,2,t)}},e},t}(),q=t=>t.split(/(\w+)\s*:\s*([\w{}[\]:\s?]*)/).filter(t=>""!==t).map(t=>t.replace(/\s*/g,"")),C=t=>q(t)[1],D=t=>/{(.*)}/.exec(t)[1].split(/([^:]*):(.*)/).map(t=>t.replace(/\s/g,"")).filter(t=>t),R=t=>/\[(.*)\]/.exec(t)[1].replace(/\s+/g,""),B=t=>!E(t)&&(t.includes("?")?o.Optional(o[(t=>t.slice(0,-1))(t)]):o[t]),H=t=>{if(j(t))switch(!0){case A(t):{const n=R(t);return o.Array(H(n))}case N(t):{const[n,r]=D(t),e={key:H(n),value:H(r)};return o.Dictionary(e)}default:return B(t)}return B(t)},z=function(t,n){try{return Promise.resolve(L(U.ARGUMENT)).then(function(r){function e(){let t;const n=H(s);switch(!0){case(t=>{if(E(t))return!1;let n=t.endsWith("?")?t.slice(0,-1):t;return T(n)||(t=>"String"===t)(n)||(t=>"Character"===t)(n)||(t=>"Bool"===t)(n)})(s):return c.arg(o,n);case(t=>!E(t)&&(t.startsWith("Fix64")||t.startsWith("UFix64")))(s):return null===o?c.arg(null,n):(isNaN(parseFloat(o))&&(t=>{throw new Error("Type Error: Expected proper value for fixed type")})(),c.arg(parseFloat(o).toFixed(8),n));case(t=>"Address"===t||"Address?"===t)(s):{const t=null==(p=o)?null:"0x"+(t=>null==t?null:t.replace(/^0x/,""))(p);return c.arg(t,n)}case A(s):{function r(r){return t?r:c.arg(o,n)}const e=R(s),u=function(){if(j(e))return Promise.resolve(Promise.all(o.map(function(t){try{return Promise.resolve(z(e,t)).then(function({value:t}){return t})}catch(t){return Promise.reject(t)}}))).then(function(r){return t=1,c.arg(r,n)})}();return u&&u.then?u.then(r):r(u)}case N(s):{function e(){return c.arg(p,n)}const[t,r]=D(s),p=[],m=Object.keys(o),d=(u=m,i=function(n){function e(){const n=T(t)?parseInt(c):c;p.push({key:n,value:s})}const c=m[n];let s;const u=function(){if(j(r))return Promise.resolve(z(r,o[c]).value).then(function(t){s=t});s=o[c]}();return u&&u.then?u.then(e):e()},l=-1,function t(n){try{for(;++l<u.length;)if((n=i(l))&&n.then){if(!((r=n)instanceof _&&1&r.s))return void n.then(t,f||(f=M.bind(null,a=new _,2)));n=n.v}a?M(a,1,n):a=n}catch(t){M(a||(a=new _),2,t)}var r}(),a);return d&&d.then?d.then(e):e()}default:throw`${s} is not supported`}var u,i,a,f,l,p}let o=n,s=t;const u=function(){if(r)return Promise.resolve(function(t,n){try{function r(){return{type:i,value:a}}let i=t.type,a=t.value;const f=(e=n,o=function(t){const{resolver:r}=n[t];return Promise.resolve(r(i,a)).then(function(t){i=t.type,a=t.value})},u=-1,function t(n){try{for(;++u<e.length;)if((n=o(u))&&n.then){if(!((r=n)instanceof O&&1&r.s))return void n.then(t,s||(s=I.bind(null,c=new O,2)));n=n.v}c?I(c,1,n):c=n}catch(t){I(c||(c=new O),2,t)}var r}(),c);return Promise.resolve(f&&f.then?f.then(r):r())}catch(t){return Promise.reject(t)}var e,o,c,s,u}({type:t,value:n},r)).then(function(t){o=t.value,s=t.type})}();return u&&u.then?u.then(e):e()})}catch(t){return Promise.reject(t)}},G=function(t=[],n){try{if(t.length>n.length)throw new Error("Not enough arguments");return Promise.all(n.map(function(n,r){try{return Promise.resolve(z(t[r],n)).then(function(t){var n;return(n=t).xform.asArgument(n.value),t})}catch(t){return Promise.reject(t)}}))}catch(t){return Promise.reject(t)}},W=function(t,n=[]){try{const r=F(t).args.map(C);return G(r,n)}catch(t){return Promise.reject(t)}},J=function(t,n){try{if(0===t.length)return Promise.resolve([]);const r=t[0];return Array.isArray(r)&&r.length>0&&r[r.length-1].asArgument?Promise.resolve((t=>t.reduce((t,n)=>[...t,...((t,n)=>{const r=t[t.length-1];return t.slice(0,-1).map(t=>((t,n)=>c.arg(t,n))(t,r))})(n)],[]))(t)):W(n,t)}catch(t){return Promise.reject(t)}};function K(t,n){try{var r=t()}catch(t){return n(t)}return r&&r.then?r.then(void 0,n):r}const Q=function(n,r){try{const{code:e,cadence:o,args:s,addressMap:u,limit:a,processed:f}=n,l=e||o;return Promise.resolve(i()).then(function(o){function i(){return Promise.resolve(t.config().get("ix.executionLimit")).then(function(t){if(d.push(c.limit(a||t||100)),"transaction"===r){const{proposer:t,payer:r,signers:e=[]}=n,o=0===e.length?[r]:e,s=t||r;d.push(c.payer(r)),d.push(c.proposer(s)),d.push(c.authorizations(o))}return c.send(d)})}const p={...o,...u},m=f?l:x(l,p),d="script"===r?[c.script(m)]:[c.transaction(m)],g=function(){if(s)return Promise.resolve(J(s,e)).then(function(t){d.push(c.args(t))})}();return g&&g.then?g.then(i):i()})}catch(t){return Promise.reject(t)}},V=function(t){const{raw:n=!1}=t;return Promise.resolve(K(function(){return Promise.resolve(Q(t,"script")).then(function(t){return n?[t.encodedData,null]:Promise.resolve(c.decode(t)).then(function(t){return[t,null]})})},function(t){return[null,t]}))},X=function(t){const{wait:n="seal"}=t;return Promise.resolve(K(function(){return Promise.resolve(Q(t,"transaction")).then(function(t){let r;function e(n){return r?n:[t.transactionId,null]}const o=function(){if(n){const e=(t=>{if("string"==typeof t){const n=t.toLowerCase();if(n.includes("final"))return"onceFinalized";if(n.includes("exec"))return"onceExecuted";if(n.includes("seal"))return"onceSealed"}return console.log(`⚠️ Status value "${t}" is not supported. Reverting to "onceSealed"`),"onceSealed"})(n);return Promise.resolve(c.tx(t)[e]()).then(function(n){const e={txId:t,...n};return r=1,[e,null]})}}();return o&&o.then?o.then(e):e(o)})},function(t){return[null,t]}))},Y=function(t){try{const{name:n,to:r,payer:e,proposer:o,code:c,update:s=!1,processed:u=!1,addressMap:i={}}=t,a=u?c:x(c,i),f=s?"\n transaction(name: String, code: String) {\n prepare(acct: AuthAccount){\n let decoded = code.decodeHex()\n \n acct.contracts.add(\n name: name,\n code: decoded,\n )\n }\n }\n ":"\n transaction(name: String, code: String){\n prepare(acct: AuthAccount){\n let decoded = code.decodeHex()\n \n if acct.contracts.get(name: name) == nil {\n acct.contracts.add(name: name, code: decoded)\n } else {\n acct.contracts.update__experimental(name: name, code: decoded)\n }\n }\n }\n",l=Buffer.from(a,"utf8").toString("hex");let p=r,m=r;return e&&(m=e,p=o||e),X({payer:m,proposer:p,signers:[r],code:f,args:[n,l]})}catch(t){return Promise.reject(t)}};exports.CONTRACT="contract",exports.PLUGIN_TYPES=U,exports.SCRIPT="script",exports.TRANSACTION="transaction",exports.argType=C,exports.capitalizeFirstLetter=g,exports.collapseSpaces=P,exports.deployContract=Y,exports.executeScript=V,exports.extract=v,exports.extractContractName=t=>{const n=y(t).replace(/\r\n|\n|\r/g," "),r=/\w+\s+contract\s+(?:interface)*\s*(\w*)/g.exec(n);if(r.length<2)throw new Error("Contract Error: can't find name of the contract");return r[1]},exports.extractContractParameters=k,exports.extractImports=l,exports.extractScriptArguments=$,exports.extractSigners=b,exports.extractTransactionArguments=S,exports.generateSchema=w,exports.getArrayType=R,exports.getDictionaryTypes=D,exports.getEnvironment=i,exports.getPlugins=L,exports.getSplitCharacter=h,exports.getTemplateInfo=F,exports.mapArgument=z,exports.mapArguments=G,exports.mapValuesToCode=W,exports.missingImports=p,exports.mutate=X,exports.query=V,exports.registerPlugin=function(t){try{const{type:n}=t;return Promise.resolve(r.config().get("ix.plugins")).then(function(e){const o=e||{},c=o[n]||[];return Promise.resolve(r.config().put("ix.plugins",{...o,[n]:[...c,t]})).then(function(){})})}catch(t){return Promise.reject(t)}},exports.replaceImportAddresses=x,exports.report=m,exports.reportArguments=(t,n,r="")=>{if(n>t){const e=`Incorrect number of arguments: found ${t} of ${n}`;console.error(r?`${r} ${e}`:e)}},exports.reportMissing=(t="items",n,r,e="")=>{if(r!==n){const o=`Incorrect number of ${t}: found ${n} of ${r}`;console.error(e?`${e} ${o}`:o)}},exports.reportMissingImports=(t,n,r="")=>{const e=p(t,n);e.length>0&&m(e,r)},exports.resolveArguments=J,exports.sendTransaction=X,exports.setEnvironment=function(n="emulator",r={}){try{const e=n.toLowerCase();if(!s[e])throw new Error(`Provided value "${e}" is not supported. Try "emulator", "testnet" or "mainnet". Default: "emulator"`);const{port:o,endpoint:c,limit:i}=r,a="emulator"===e&&o?`http://localhost:${o}`:u[e],f=c||a;return Promise.resolve(t.config().put("ix.env",e)).then(function(){function n(){return Promise.resolve(t.config().put("accessNode.api",f)).then(function(){})}const r=function(){if(i)return Promise.resolve(t.config().put("ix.executionLimit",i)).then(function(){})}();return r&&r.then?r.then(n):n()})}catch(t){return Promise.reject(t)}},exports.splitArgs=q,exports.trimAndSplit=(t,n,r)=>r?t.replace(n,"").split(r):t.replace(n,"").split(h(t)),exports.underscoreToCamelCase=t=>t.replace(/-/g,"_").split("_").map((t,n)=>n>0?g(t):t).join(""),exports.updateContract=function(t){try{return Y({...t,update:!0})}catch(t){return Promise.reject(t)}};
TypeError: Cannot read properties of null (reading 'length')
at Object.exports.extractContractName (/Users/kerrywei/repos/cadut-example/node_modules/flow-cadut/dist/main.js:1:11064)
at Object.<anonymous> (/Users/kerrywei/repos/cadut-example/app.js:31:9)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1147:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
Node.js v17.0.1
kerrywei@kerrys-mbp-2 cadut-example %
This is a minor issue (as we assume most people will pass in right type of transaction/script/contract), however, rather than showing "TypeError: Cannot read properties of null (reading 'length')", we can return a more explicit error type and error message
Add support for the docs site (add index.md, relevant metadata for sidebar titles, etc.)
Quite common question in community how to listen for specific events.
Create simple block query mechanism, which would listen for events fired and allow to subscribe to them.
👋🏻 Hey!
We have a cadence file where we have:
import FirstContract, SecondContract from 0xContract
pre {
self.account.address == AddressThatNeedsToBeReplaced: "Invalid"
}
Multiple imports example:
const addressMap = {
Messages: '0xf8d6e0586b0a20c7',
OtherMessages: '0xf8d6e0586b0a20c7',
};
const code = `
import Messages, OtherMessages from 0x1
pub fun main(){}
`;
const replaced = replaceImportAddresses(code, addressMap);
console.log({ replaced });
Inline instances example
const addressMap = {
Messages: '0xf8d6e0586b0a20c7',
OtherMessages: '0xf8d6e0586b0a20c7',
};
const code2 = `
import Messages from 0x1
transaction() {
pre {
self.address == Messages: "Failed" // inlined here
}
}
`;
const replaced2 = replaceImportAddresses(code2, addressMap);
console.log({ replaced2 });
Would be nice if the replaceImportAddresses
method would replace multiple imports and inline instances.
Is supporting this in on your roadmap ?
Support for passing Array of Structure to Cadence Transaction in flow-js-testing
I have a cadence transaction which needs to accept a contract structure as an argument. I was unable to find a way to pass that in flow-js-testing.
like attributes: [Contract.AttributeStruct] is an argument to my transaction
while trying to pass an array of data I am getting Error
'Rejected to value: "[Contract is not supported"'
Hey Team, I am working on flow testcases in js using flow-js-testing library. I am trying to pass AnyStruct
as an argument for my transactions and scripts but I am unable to pass it and getting some errors.
I have passed AnyStruct
as dictionary as:
transaction(data:{String:AnyStruct})
Also I have passed AnyStruct
as an argument directly as:
transaction(data:AnyStruct)
After debugging the my code and node_modules libraries, I got that flow-js-testing is using flow-cadut.
flow-cadut has a resolveArguments
method at args.js
file which resolve and validate arguments, but it doesn't seem to support AnyStruct
for now.
To solve this issue, we need to support AnyStruct
as an argument of transaction and script.
In type-checker.js
we can add a new type-checker method for AnyStruct
than we can use that method in args.js
and relevant files to support AnyStruct
. It is not complete solution but we can work on that and add support to AnyStruct
as an argument.
Let me know if it is supported already or work in progress to support it.
Thanks
For typescript user, it easier to code with typed suggestion.
Currently a list of supported environments consists of:
Each of them have predefined access node endpoint, but it doesn't allow to set it, just pick one.
It should be possible to specify endpoint and additional params via setEnvironment
method for custom environment.
Find a way to make CI tests always pass for flow-cadut-plugin-flowns and flow-cadut-plugin-find.
These tests are flakey and often fail, requiring re-running CI, etc. This is due to rate limiting and could be mitigated by potentially delaying script execution.
Run npm run test
a few times in succession and notice how some tests will fail.
CI tests always pass
👋🏻 Hello!
Noticed that some imports listed in the File System section are not exported.
Package version: "flow-cadut": "0.1.16-alpha.4",
const { sansExtension } = require('flow-cadut');
const fileName = sansExtension('log-message-and-return.cdc');
console.log({ fileName });
or
const { writeFile } = require('flow-cadut');
const script = `
pub fun main(){
log("Hello, Cadence")
}
`;
writeFile('./cadence/scripts/log.cdc', script);
Error:
const fileName = sansExtension('log-message-and-return.cdc');
^
TypeError: sansExtension is not a function
or
writeFile('./cadence/scripts/log.cdc', script);
^
TypeError: writeFile is not a function
All methods that are listed in the API docs are exported.
Maybe I'm using the wrong version, not sure. They look very promising and I'm eager to use them instead of custom scripts.
FIND - https://test.find.xyz/ - is a third-party namespace provider allowing to resolve human readable address to Flow Address.
flow-cadut
to allow to provide different resolvers for argumentsAdd a feature to support inline import instances such as the following:
pre {
self.account.address == AddressThatNeedsToBeReplaced: "Invalid"
}
This is not currently supported by flow-cadut. Code such as the following does not work
const addressMap = {
Messages: '0xf8d6e0586b0a20c7',
OtherMessages: '0xf8d6e0586b0a20c7',
};
const code2 = `
import Messages from 0x1
transaction() {
pre {
self.address == Messages: "Failed" // inlined here
}
}
`;
const replaced2 = replaceImportAddresses(code2, addressMap);
console.log({ replaced2 });
See original issue: #73
Part of the Cadut experience could be a command scaffold
which would create contracts,transactions,scripts and tests for them, based on provided name of the token.
Create basic React/Vue/Svelte/Next app around generated Cadence files.
For local development one might need copies of deployed contracts, transactions and scripts.
We can collect them and put into separate folder next to Javacript files for easier consumption.
import was failed if we won't specifiy the flowcadut packagejson {"type":"module"}, There another way to fixed that using mjs ext.
https://user-images.githubusercontent.com/40029631/167464767-8d446c01-1f7a-4cb2-b0e5-028dae352919.png
Pull #64
Allow to pass initialization arguments, when deploying a contract.
flow-generate
command should use fs.rm
instead of fs.rmdir
When running flow-generate
, fs.rmdir
deprecation warning shows as follows:
(node:6191) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead
After running flow-cadut generate function and then importing functions into a running project results in missing dependency errors from flow-cadut. I am using version 2.x of Nuxt (Vue.JS) with Typesciprt on a Macbook Pro (Catalina, although reproduced on Big Sur also).
The following error prevents my project from running:
ERROR Failed to compile with 3 errors
These dependencies were not found:
* child_process in ../node_modules/simple-git/src/lib/runners/git-executor-chain.js
* fs in ../node_modules/@kwsites/file-exists/dist/src/index.js, ../node_modules/flow-cadut/dist/index.module.js
After some discussion with @MaxStalker, it seems that the reason we're running into this could be due to the fact that the generate functions are exported in the main index entrypoint of the repo. This creates a dependency on the fs
and child_process
libs in the dep tree, which wouldn't be present in a browser environment and is likely causing the issue above.
For this project to be able to work alongside browser-based functions, users will need to explicitly reference the generate function itself instead of loading the entire lib if they want to use it. I'm working on a pull request right now to test this assumption, but hopefully others have found a more graceful workaround in the meantime so i'm posting this here.
Fix the parser regex to only match top level trasnsaction
/fun
/contract
blocks instead of potentially matching these keywords within strings
Lines 91 to 93 in 6b6e7fd
This can lead to errors if the user uses these keywords elsewhere (i.e. within a string elsewhere in code). This is connected to onflow/flow-js-testing#97
Strip the strings from the cadence code before parsing and replace with empty strings
Remove requirement for ./src/generated to exist & either generate starter folders for cadence or show a more specific error
There are two parts to this issue:
./src/generated
) should be managed fully by cadut so there should be no user requirement to manage the existence of this folder. It may be useful to include some safeguards to prevent a user from unintentionally overwriting existing non-generated files if they specify an erroneous generated folder[Error: ENOENT: no such file or directory, scandir './cadence'] {
errno: -2,
code: 'ENOENT',
syscall: 'scandir',
path: './cadence'
}
While this isn't terrible, it could be better and interrupts the developer flow slightly.
src/fixer.js
export a function, parsePath
. When paths are parsed they should have some sort of type checking such that the provided path matches the domain of the argument (i.e. if the argument type is PublicPath, it must be public domain and so forth)
Please fill out the template below to the best of your ability and include a label indicating which tool/service you were working with when you encountered the problem.
I've encountered the issue when using the flow-js-testing
framework which depends on this repo. After some digging it turns out that the regex used in extractTransactionArguments
wouldn't generate correct outputs under certain condition. (See below)
Here's my transaction snippet:
transaction(
name: String,
whole: UInt64,
fraction: UFix64,
) {
// ....
}
My tests fails with Cannot read property 'startsWith' of undefined
. Debugged with some logs, it turns out that getTemplateInfo(code)
in this line parsed out empty args. Digging further, the regex in parser may not parse out multi-line arguments.
Given multi-line arguments in transactions and scripts are common for readability, there's no harm to support this feature.
flow-js-testing
framework is depending on this module.
Parser will find 0 arguments in following - perfectly correct - code:
pub fun main ( a: Int ) {}
or
transaction ( s: String ) {
prepare ( signer: AuthAccount ) { }
}
### Solution
Fix regular expression to properly handle extra spaces
✋ Problem
If we dont specify singer in transaction . It will throw "Incorrect number of singer " error. But flow cadut has treat that prayer to be default signer
✔️ Solution
remove error log if we already specify prayers.
💡 Acceptance Criteria
no log on signer when prayer has passed.
All of the transactions generated by flow-cadut's generator are not utilizing the waitForExecution
argument for sendTransaction
, thus all default to falsy
.
This is problematic when using flow-cadut in the build process, as it is easy to drop in a boolean into respective transactions you would like to be blocking/waiting, but when using build/dist autogenerated workflows this restricts usage without manual edit of generated files - which is a nono.
The waitForExecution
parameter can be included as a parsable arg for sendTransaction
rather than a distinct member (thus can be implemented by the caller in autogen cases) or some flag for setting specific calls to be blocking by the caller would work fine too.
return (0, flow_cadut_1.sendTransaction)({ code, ...props });
This was autogenerated, and does not utilize the boolean param:
return (0, flow_cadut_1.sendTransaction)({ code, ...props }, waitForExecutionBool);
is desirable to use by code-generator usage.
This library shall have zero dependency on flow-js-testing
.
executeScript
methodsendTransaction
methoddeployContract
methodupdateContract
methodflow-js-testing
is using flow-cadut
as dependency and using it to resolve arguments passed to interactions.
Passing nested arrays - for example list: [[String]]
- will throw type error.
Allow to extract pragma comments from code template.
We have this working inside VS Code for pragma signers
and pragma arguments
.
But there is no support for other custom params users would want to use.
There are few things that are missing/incorrect in correct API doc. i.e.
https://github.com/onflow/flow-cadut/blob/main/docs/api.md#extractsignerscode -- this method is intended to be used on transactions, however the example provided supplies a script to the function and will always result in empty array returned
The SignerPair link https://github.com/onflow/flow-cadut/blob/main/docs/api.md#SignerPair is not pointing to any section (missing content)
extractContractParameters() is not documented
Perform a full audit on all documents (as the issues listed here is non-exhaustive) before promoting this tool to a wider audience
Currently there exist a number of nested NPM projects within @onflow/flow-cadut. This should be arranged like a traditional monorepo for better control and interoperability between packages. These separate packages could then be broken out into their own respective NPM registries for version control.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.