Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/green-chefs-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@onflow/flow-cadut": patch
---

Arguments for contract initialization can now be places on multiple lines
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
projects: ["<rootDir>/packages/*"],
projects: ["<rootDir>/packages/flow-cadut"],
}
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions packages/dev-test/test/interaction.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ describe("arguments - scripts", () => {
}
`
const payer = authorization()
const [txId, err] = await mutate({cadence, payer, wait: null})
console.log({txId, err})
const result = await mutate({cadence, payer, wait: null})
const err = result[1]
expect(err).toBe(null)
})

it("shall properly process Address: [UInt64] array", async () => {
Expand All @@ -74,8 +75,8 @@ describe("arguments - scripts", () => {
},
]

const [result, err] = await query({cadence, args})
console.log({result, err})
const [result] = await query({cadence, args})
expect(result).toBe("42")
})
})

Expand Down
9 changes: 5 additions & 4 deletions packages/dev-test/test/signers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ describe("signers", () => {
}
`,
})
console.log({result, err})
expect(result).toBe("42")
expect(err).toBe(null)
})

it("shall properly sign transaction", async () => {
Expand All @@ -45,8 +46,8 @@ describe("signers", () => {
keyId,
}

const [result, err] = await sendTransaction({code, payer})
console.log(result)
console.log(err)
const result = await sendTransaction({code, payer})
const err = result[0]
expect(err).toBe(null)
})
})
6 changes: 4 additions & 2 deletions packages/flow-cadut-plugin-find/tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ describe("FIND plugin", () => {
}
`
const args = ["find:shiny"]
return mapValuesToCode(code, args)
const mapped = mapValuesToCode(code, args)
expect(mapped).toBe(true)
})

it("shall resolve name.find properly", async () => {
Expand All @@ -28,6 +29,7 @@ describe("FIND plugin", () => {
}
`
const args = ["shiny.find"]
return mapValuesToCode(code, args)
const mapped = mapValuesToCode(code, args)
expect(mapped).toBe(true)
})
})
5 changes: 5 additions & 0 deletions packages/flow-cadut/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const config = {
testMatch: ["**/tests/**/*.test.[jt]s?(x)"],
}

module.exports = config
21 changes: 19 additions & 2 deletions packages/flow-cadut/src/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,17 @@ export const mapArgument = async (rawType, rawValue) => {
return fcl.arg(value, resolvedType)
}

case isBasicNumType(type): {
// Try to parse value and throw if it fails
if (value === null) {
return fcl.arg(null, resolvedType)
}
if (isNaN(parseInt(value))) {
throwTypeError("Expected proper value for integer type")
}
return fcl.arg(value.toString(), resolvedType)
}

case isFixedNumType(type): {
// Try to parse value and throw if it fails
if (value === null) {
Expand Down Expand Up @@ -196,8 +207,14 @@ export const mapArgument = async (rawType, rawValue) => {
return fcl.arg(mappedValue, resolvedType)
}

const result = fcl.arg(value, resolvedType)
return result
if (isBasicNumType(arrayType) || isFixedNumType(arrayType)) {
return fcl.arg(
value.map(item => (isNaN(item) ? item : item.toString())),
resolvedType
)
}

return fcl.arg(value, resolvedType)
}

case isDictionary(type): {
Expand Down
61 changes: 41 additions & 20 deletions packages/flow-cadut/src/imports.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,32 @@
=== REGEXP_IMPORT explanation ===
Matches import line in cadence code and is used for extracting address & list of contracts imported

/ => start of regexp
import\s+ => should have keyword import followed by one or more spaces

((([\w\d]+)(\s*,\s*))*[\w\d]+) => >>MATCH[1]<< matcher group for imported contracts (one or more comma separated words including digits)
/ => start of regexp
^ => Matches the start of the string.
\s* => Matches zero or more whitespace characters.
import\s+ => Matches the word "import" followed by one or more whitespace characters.
("?([\w\d]+\s*,\s*)*(?!from\b)[\w\d]+"?) => Matches a list of one or more variable names separated by commas,
with each variable name optionally surrounded by quotes (?"), and optional
whitespace characters in between ([\w\d]+\s*,\s*)*. The negative lookahead
assertion (?!from\b) ensures that the word "from" is not part of a
variable name. The entire list of variable names is optionally surrounded
by quotes as well (?").
\s* => Matches zero or more whitespace characters.
(?:from)? => Matches the word "from" if it appears, but does not capture it.
\s* => Matches zero or more whitespace characters.
([\w\d".\/]+)? => Matches the target path, which is a sequence of one or more
alphanumeric characters, quotes ("), periods (.), forward slashes (/),
or double quotes (").
$ => Matches the end of the string.
/ => end of regexp

([\w\d]+\s*,\s*)* => match comma-separated contracts
[\w\d]+ => match individual contract name (one or more word or digit)
\s*,\s* => match trailing comma with any amount of space separation

[\w\d]+ => match last contract name (mustn't have trailing comma, so separate from previous matcher)

\s+from\s+ => keyword from with one or more leading and following space characters
([\w\d".\\/]+) => >>MATCH[3]<< one or more word, digit, "" or / character for address or file import notation
/ => end of regexp
*/
export const REGEXP_IMPORT =
/import\s+(([\w\d]+\s*,\s*)*[\w\d]+)\s+from\s*([\w\d".\\/]+)/g
/\s*import\s+("?([\w\d]+\s*,\s*)*(?!from\b)[\w\d]+"?)\s*(?:from)?\s*([\w\d"./]+)?$/gm

/*
=== REGEXP_IMPORT_CONTRACT ===
Used to separate individual contract names from comma/space separarated list of contracts
Used to separate individual contract names from comma/space separated list of contracts

/ => start of regexp
([\w\d]+) => >>MATCH[1]<< match individual contract name (one or more word or digit)
Expand All @@ -58,7 +63,8 @@ export const extractImports = code => {
return {}
}

return [...code.matchAll(REGEXP_IMPORT)].reduce((contracts, match) => {
const lines = [...code.matchAll(REGEXP_IMPORT)]
return lines.reduce((contracts, match) => {
const contractsStr = match[1],
address = match[3]

Expand Down Expand Up @@ -117,30 +123,45 @@ export const reportMissingImports = (code, addressMap, prefix = "") => {
/**
* Returns Cadence template code with replaced import addresses
* @param {string} code - Cadence template code.
* @param {{string:string}} [addressMap={}] - name/address map or function to use as lookup table
* @param {{[key:string]:string}} [addressMap={}] - name/address map or function to use as lookup table
* for addresses in import statements.
* @param byName - lag to indicate whether we shall use names of the contracts.
* @returns {*}
*/
export const replaceImportAddresses = (code, addressMap, byName = true) => {
const EMPTY = "empty"
return code.replace(REGEXP_IMPORT, importLine => {
const contracts = extractImports(importLine)

const contractMap = Object.keys(contracts).reduce((map, contract) => {
const address = contracts[contract]

const key = byName ? contract : address
const newAddress =
addressMap instanceof Function ? addressMap(key) : addressMap[key]

// If the address is not inside addressMap we shall not alter import statement
const validAddress = newAddress || address
map[validAddress] = (map[validAddress] ?? []).concat(contract)
let validAddress = newAddress || address

if (!newAddress || contract === "Crypto") {
validAddress = EMPTY
}

if (!map[validAddress]) {
map[validAddress] = []
}

map[validAddress] = map[validAddress].concat(contract)
return map
}, {})

return Object.keys(contractMap)
.reduce((res, addr) => {
const contractsStr = contractMap[addr].join(", ")
return res.concat(`import ${contractsStr} from ${addr}`)
if (addr === EMPTY) {
return res.concat(`import ${contractsStr}`)
}
return res.concat(`import ${contractsStr} from ${addr} `)
}, [])
.join("\n")
})
Expand Down
2 changes: 1 addition & 1 deletion packages/flow-cadut/src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const extractContractName = code => {
export const extractContractParameters = code => {
const complexMatcher = /(resource|struct)\s+\w+\s*{[\s\S]+?}/g
const contractNameMatcher =
/(?:access\(\w+\)|pub)\s+contract\s+(?:interface)*\s*(\w*)[:\s\w]*(\s*{[.\s\S]*init\s*\((.*?)\)[.\s\S]*})?/g
/(?:access\(\w+\)|pub)\s+contract\s+(?:interface)*\s*(\w*)[:\s\w]*(\s*{[.\s\S]*init\s*\(([.\s\S\r\n]*)\)[.\s\S]*})?/g

const noComments = stripComments(code)
const noComplex = noComments.replace(complexMatcher, "")
Expand Down
18 changes: 15 additions & 3 deletions packages/flow-cadut/tests/args.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "../src/args"
import {toFixedValue, withPrefix} from "../src/fixer"
import {getTemplateInfo} from "../src"
import {isBasicNumType} from "../src/type-checker"

describe("argument types", () => {
test("Basic Type", async () => {
Expand Down Expand Up @@ -77,10 +78,21 @@ describe("type resolvers", () => {
for (let i = 0; i < cases.length; i++) {
const {type, argInput} = cases[i]
const output = resolveType(type)
const asArgument = output.asArgument(argInput)

let value = argInput
if (isBasicNumType(type)) {
value = value.toString()
}
const asArgument = output.asArgument(value)

/*eslint-disable*/
expect(asArgument.type).toBe(type)
expect(asArgument.value.toString()).toBe(argInput.toString())
if (isBasicNumType(asArgument.type)) {
expect(asArgument.value).toBe(argInput.toString())
} else {
expect(asArgument.value).toBe(argInput)
}
/*eslint-enable*/
}
})
test("simple array = [String]", () => {
Expand Down Expand Up @@ -398,7 +410,7 @@ describe("mapValuesToCode", () => {
expect(first.xform.label).toBe("Array")
expect(first.value[0].length).toBe(values[0][0].length)
for (let i = 0; i < values[0][0].length; i++) {
expect(first.value[0][i]).toBe(values[0][0][i])
expect(first.value[0][i]).toBe(values[0][0][i].toString())
}
})
})
Expand Down
15 changes: 11 additions & 4 deletions packages/flow-cadut/tests/example.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
missingImports,
report,
replaceImportAddresses,
} from "../src/imports"
} from "../src"

// arguments
import {
Expand All @@ -15,7 +15,7 @@ import {
argType,
getDictionaryTypes,
getArrayType,
} from "../src/args"
} from "../src"

// parser
import {
Expand All @@ -27,10 +27,10 @@ import {
extractScriptArguments,
extractTransactionArguments,
extractContractName,
} from "../src/parser"
} from "../src"

// Interactions
import {setEnvironment, getEnvironment} from "../src/env"
import {setEnvironment, getEnvironment} from "../src"

describe("documentation examples", function () {
// Imports
Expand Down Expand Up @@ -70,8 +70,13 @@ describe("documentation examples", function () {
})

it("should report to console", function () {
console.error = jest.fn()
const list = ["Message", "Log"]
report(list)
expect(console.error.mock.calls[0].length).toBe(2)
expect(console.error.mock.calls[0][0].includes("Missing imports")).toBe(
true
)
})

it("should replace import addresses", function () {
Expand Down Expand Up @@ -318,6 +323,7 @@ describe("documentation examples", function () {
expect(complexType).toBe("{String:String}")
})

/* eslint-disable */
// Generator
// This block is commented out for CI to work properly
/*
Expand All @@ -333,6 +339,7 @@ describe("documentation examples", function () {
await processGitRepo(url, output);
});
*/
/* eslint-enable */

// Interactions
it("should throw error for unknown network", async function () {
Expand Down
Loading