Git Product home page Git Product logo

flow-cadut's Introduction

Flow Cadence Template Utilities

Flow Cadut supports Cadence interaction by wrapping template files in Javascript.

Flow Cadut (Flow Cadence Utilities) contains two core packages:

  1. Flow Cadence Utilities (@onflow/flow-cadut)
  2. Flow Cadence Template Generator (@onflow/flow-cadut-generator)

Flow Cadence Utilites: Flow Cadut

The Flow Cadence Utilities (@onflow/flow-cadut) package is the API responsible for parsing cadence templates, mapping arguments/imports to these templates, and interacting with the chain. It is the set of runtime utilities which are used behind the scenes by the JavaScript template files generated by @onflow/flow-cadut-generator.

For more information, see the README file.

You can find a list of available methods with examples at API Documentation

Flow Cadence Template Generator: Flow Cadut Generator

The Flow Cadence Template Generator (@onflow/flow-cadut-generator) is responsible for parsing Cadence (.cdc) template files and translating them to easy-to-use JavaScript (.js) files. The Cadence Template Generator, takes either path to a local folder or url to a Github repository and generates JavaScript files which wrap the Cadence code and facilitate sending the templated interactions to the Flow network.

Usage

Installation

In order to install the Flow Cadence Template Generator CLI, run the following command to add it to your project's devDependencies:

npm install -D @onflow/flow-cadut-generator

Note that any generated code will require @onflow/flow-cadut as a dependency which can be installed by running the following command in your project root:

npm install @onflow/flow-cadut

CLI options

flow-generate [input] [output]

Generate corresponding JavaScript files from a cadence input folder

Options:
      --help        Show help                                          [boolean]
      --version     Show version number                                [boolean]
  -i, --input       Cadence input directory or Github repository URL
                                                 [string] [default: "./cadence"]
  -o, --output      Javascript output directory
                                           [string] [default: "./src/generated"]
  -b, --branch      Git branch to use if git repository used as input   [string]
  -d, --dependency  Dependency to use in generated templates
                                        [string] [default: "@onflow/flow-cadut"]
  -w, --watch       Whether to run the generator as a standalone build or in
                    watch mode                        [boolean] [default: false]

Local Folder

# long flags
npx flow-generate --input ./cadence --output ./src/generated

# short flags
npx flow-generate -i ./cadence -o ./src/generated

# no flags
npx flow-generate ./cadence ./src/generated

GitHub Repository

For GitHub repositories you can specify branch you want to pull with --branch or -b flags. If you omit it, then generator will default to master/main branch.

# long flags
npx flow-generate --input https://github.com/onflow/flow-core-contracts --branch feature/epochs --output ./src/generated

# short flags
npx flow-generate -i https://github.com/onflow/flow-core-contracts -b feature/epochs -o ./src/generated

# positional arguments
npx flow-generate https://github.com/onflow/flow-core-contracts ./src/generated -b feature/epochs

# positional arguments, main branch
npx flow-generate https://github.com/onflow/flow-core-contracts ./src/generated

Process Single Folder (recursively)

You can also paste full path to specific folder that you want to process. For example:

npx flow-generate https://github.com/onflow/flow-core-contracts/tree/master/contracts ./src/generated

In this specific case, generator would assume that you want to process contracts folder in the root of repository.

For a slightly more complex case - using Git Flow approach for example - please, specify branch name, so generator can extract folder name properly.

npx flow-generate https://github.com/onflow/flow-core-contracts/tree/feature/epochs/transactions/flowToken ./src/generated -b feature/epochs

flow-cadut's People

Contributors

10thfloor avatar caosbad avatar codingone21 avatar dependabot[bot] avatar github-actions[bot] avatar hotrungnhan avatar jciruolo avatar jribbink avatar louisguitton avatar maxstalker avatar nialexsan avatar sisyphussmiling avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flow-cadut's Issues

Flow-cadut-generator throws non-specifc errors when generated or cadence folders are missing

Instructions

Remove requirement for ./src/generated to exist & either generate starter folders for cadence or show a more specific error

Issue To Be Solved

There are two parts to this issue:

  1. The generated folder (i.e. ./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
  2. The cadence folder should either be generated by flow-cadut if it does not exist (generate according folders for scripts/transactions/contracts for ease of use) -- I like this solution best. The other option is to at least show a more specific error as this error is not currently caught and simply shows as
[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.

Rate limiting on testnet/mainnet makes flowns/find CI tests flakey

Instructions

Find a way to make CI tests always pass for flow-cadut-plugin-flowns and flow-cadut-plugin-find.

Problem

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.

Steps to Reproduce

Run npm run test a few times in succession and notice how some tests will fail.

Acceptance Criteria

CI tests always pass

Documentation improvement

Issue To Be Solved

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

Suggestion

Perform a full audit on all documents (as the issues listed here is non-exhaustive) before promoting this tool to a wider audience

Implement waitForExecution as transaction arg or flag during generation somehow

Issue To Be Solved

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.

(Optional): Suggest A Solution

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.

Example

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.

Convert to monorepo

Instructions

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.

Parser couldn't parse out multi-line arguments correctly

Instructions

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.

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)

Steps to Reproduce

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.

Acceptance Criteria

Given multi-line arguments in transactions and scripts are common for readability, there's no harm to support this feature.

Context

flow-js-testing framework is depending on this module.

Optional array of Addresses as a parameter does not work

Problem

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

Steps to Reproduce

Create a script/transaction that uses an optional array of addresses as a parameter

Acceptance Criteria

Flow-cadut must resolve these arguments properly

Context

Linked issue onflow/flow-js-testing#163

Create testing scaffold generator

In order to quickly scaffold testing environment with all the necessary parts we can implement generator, based on the one we have in Playground.

Flow-cadut-generator shows deprecation warning for fs.rmdir

Instructions

flow-generate command should use fs.rm instead of fs.rmdir

Issue To Be Solved

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

Add domain checking to paths

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)

Add API reference & examples documentation

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.

Extra spaces in arguments definition break extractor

Problem

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

Implement Views

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 })
})()

Parser regex matches unintended expressions

Instructions

Fix the parser regex to only match top level trasnsaction/fun/contract blocks instead of potentially matching these keywords within strings

flow-cadut/src/parser.js

Lines 91 to 93 in 6b6e7fd

const contractMatcher = /\w+\s+contract\s+(\w*\s*)\w*/g;
const transactionMatcher = /transaction\s*(\(\s*\))*\s*/g;
const scriptMatcher = /pub\s+fun\s+main\s*/g;

Problem

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

Solution

Strip the strings from the cadence code before parsing and replace with empty strings

`replaceImportAddresses` doesn't replace all instances (multiple imports / inline instances)

Problem

๐Ÿ‘‹๐Ÿป Hey!

We have a cadence file where we have:

  • multiple imports: import FirstContract, SecondContract from 0xContract
  • inline instances:
      pre {
          self.account.address == AddressThatNeedsToBeReplaced: "Invalid"
      }

Steps to Reproduce

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 });

Acceptance Criteria

Would be nice if the replaceImportAddresses method would replace multiple imports and inline instances.

Is supporting this in on your roadmap ?

cadut generate api : global address map

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

Nested arrays arguments conversion is incorrect

Instructions

flow-js-testing is using flow-cadut as dependency and using it to resolve arguments passed to interactions.

Problem

Passing nested arrays - for example list: [[String]] - will throw type error.

Add support for arguments of Path type

โœ‹ Problem

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

โœ”๏ธ Solution

  • add resolver for Path type
  • add tests to cover this use case

๐Ÿ’ก Acceptance Criteria

  • it should be possible to pass Path arguments
  • new tests added and passing for all basic cases

Add support for optionals

Problem

Passing optional argument is currently to supported by cadut.

Steps to Reproduce

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.

ESM bundle can't be imported (e.g. `import { ... } from 'flow-cadut'`)

Instructions

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.

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

  • Node: v14.15.4
  • yarn: 1.22.10

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"
    }
  }
}

Steps to Reproduce

  • Create and change to new workspace directory
  • Run yarn init and accept defaults
  • Modify package.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"
}
  • Install flow-cadut (yarn add flow-cadut --dev)
  • Create and add the following contents to index.js in projects root directory:
import { reportMissingImports } from 'flow-cadut'
  • Execute/run the script file with Node and observe the errors:
$ 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'

Acceptance Criteria

  • Latest version of flow-cadut can be installed and consumed (i.e. import) as ECMAScript modules out of the box

Context

Working on Dapp development for the Flow network with Cadence.

Support for passing Array of Structure to Cadence Transaction in flow-js-testing

Instructions

Support for passing Array of Structure to Cadence Transaction in flow-js-testing

Issue To Be Solved

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"'

Extract pragma comments from template

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.

Add support of AnyStruct type as arguments

Support for AnyStruct as arg in transactions and scripts

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})

than I got following error:
image

Also I have passed AnyStruct as an argument directly as:
transaction(data:AnyStruct)

than I got this error:
image

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.

Issue To Be Solved

To solve this issue, we need to support AnyStruct as an argument of transaction and script.

Suggest A Solution

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

Generated output fails to import due to missing dependency errors

Instructions

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).

Problem

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

Steps to Reproduce

  • Run the generate function from a local folder of cdc files
  • Import any of the generated files from flow-cadut
  • See error in runtime / build logs

Acceptance Criteria

  • Projects can successfully load generated functions from flow-cadut generated output at runtime

Context

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.

Extract arguments from contract initializer

Problem

Parser should have the ability to extract a list of arguments for contract initialization

Solution

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

Incorrect number of singer Log

โœ‹ 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.

Allow to specify private key to sendTransaction

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 :)

Better error type & message when there extractXXX() method is passed in a string that is not recognized

Problem

<what is the problem you've encountered?>

Steps to Reproduce

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 % 

Suggestion

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

Create simple event listener

Description

Quite common question in community how to listen for specific events.

Solution

Create simple block query mechanism, which would listen for events fired and allow to subscribe to them.

Remove flow-js-testing dependency

This library shall have zero dependency on flow-js-testing.

  • - move arguments resolver
  • - implement executeScript method
  • - implement sendTransaction method
  • - implement deployContract method
  • - implement updateContract method

`replaceImportAddresses` does not work with multiple imports

Instructions

Update the regex for imports to parse multiple imports from the same address in cadence code (only supports single imports currently)

Problem

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 });

Context

See original issue: #73

Collect cadence files during code generation

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.

Can find module js ?

Instructions

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

Problem

<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 ?

Steps to Reproduce

image

Acceptance Criteria

Context

<what are you currently working on that this is blocking?>

Use named exports for flow-cadut generated index files

Instructions

Use named exports in the index files that are generated by flow-cadut

Issue To Be Solved

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)

(Optional): Suggest A Solution

Update the .hbs templates to support this form of ES exports instead.

not all methods listed in the API are exported from the `index` file, mainly "file system" ones

Problem

๐Ÿ‘‹๐Ÿป Hello!

Noticed that some imports listed in the File System section are not exported.

Package version: "flow-cadut": "0.1.16-alpha.4",

Steps to Reproduce

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

Acceptance Criteria

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.

Make automated test suite for generator-test

Instructions

I propose that we add some automated tests using Jest that would run in CI to the generator-test package (would be fairly straightforward).

Issue To Be Solved

The generator-test package currently has no automated tests and is only useful as a utility to manually test the generator after making changes.

Allow to specify custom environment

Currently a list of supported environments consists of:

  • mainnet
  • testnet
  • emulator

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.

`replaceImportAddresses` does not work with inline import instances

Instructions

Add a feature to support inline import instances such as the following:

  pre {
      self.account.address == AddressThatNeedsToBeReplaced: "Invalid"
  }

Problem

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 });

Context

See original issue: #73

Add support for GitHub repository import

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.

Add FIND address resolver

Issue To Be Solved

FIND - https://test.find.xyz/ - is a third-party namespace provider allowing to resolve human readable address to Flow Address.

Solution

  • Add plugin system to flow-cadut to allow to provide different resolvers for arguments
  • Create plugin for FIND namespace provider

Create Scaffold generator

Idea

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.

Bonus Points

Create basic React/Vue/Svelte/Next app around generated Cadence files.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.