Skip to content

Commit

Permalink
Parser contract arguments (#21)
Browse files Browse the repository at this point in the history
* Add methods for extracting contract arguments

* Export new methods

* Update CHANGELOG

* Bump version
  • Loading branch information
Maksim Daunarovich authored Sep 22, 2021
1 parent 7c1eb4a commit 44b9432
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### 0.1.9 - 2021-09-23
- Add parser logic for extracting contract arguments

### 0.1.8 - 2021-09-22
- Fixed parser issue, when extra spaces are present in argument definition

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "flow-cadut",
"version": "0.1.8",
"version": "0.1.9-alpha.1",
"description": "Flow Cadence Template Utilities",
"author": "Maksim Daunarovich",
"license": "Apache-2.0",
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export {
extractScriptArguments,
extractTransactionArguments,
extractContractName,
extractContractParameters,
getTemplateInfo,
generateSchema,
CONTRACT,
TRANSACTION,
SCRIPT,
Expand Down
35 changes: 27 additions & 8 deletions src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,24 @@ export const TRANSACTION = "transaction";
export const SCRIPT = "script";
export const UNKNOWN = "unknown";

export const generateSchema = (argsDefinition) =>
argsDefinition
.split(",")
.map((item) => item.replace(/\s*/g, ""))
.filter((item) => item !== "");

export const extract = (code, keyWord) => {
const target = collapseSpaces(code.replace(/[\n\r]/g, ""))
const target = collapseSpaces(code.replace(/[\n\r]/g, ""));

if (target) {
const regexp = new RegExp(keyWord, "g")
const regexp = new RegExp(keyWord, "g");
const match = regexp.exec(target);

if (match) {
if (match[1] === "") {
return [];
}
return match[1]
.split(",")
.map((item) => item.replace(/\s*/g, ""))
.filter(item => item !== "")
return generateSchema(match[1])
}
}
return [];
Expand Down Expand Up @@ -68,6 +70,23 @@ export const extractContractName = (code) => {
return matches[1];
};

export const extractContractParameters = (code) => {
const complexMatcher = /(resource|struct)\s+\w+\s*{[\s\S]+?}/g;
const contractNameMatcher =
/\w+\s+contract\s+(?:interface)*\s*(\w*)(\s*{[.\s\S]*init\s*\((.*?)\)[.\s\S]*})?/g;
const clean = code.replace(complexMatcher, "");
const matches = contractNameMatcher.exec(clean);

if (matches.length < 2) {
throw new Error("Contract Error: can't find name of the contract");
}

return {
contractName: matches[1],
args: matches[3] || "",
};
};

export const getTemplateInfo = (code) => {
const contractMatcher = /\w+\s+contract\s+(\w*\s*)\w*/g;
const transactionMatcher = /transaction\s*(\(\s*\))*\s*/g;
Expand All @@ -93,11 +112,11 @@ export const getTemplateInfo = (code) => {

if (contractMatcher.test(code)) {
// TODO: implement extraction from `init` method
const contractName = extractContractName(code);
const { contractName, args } = extractContractParameters(code);
return {
type: CONTRACT,
signers: 1,
args: [],
args,
contractName,
};
}
Expand Down
113 changes: 111 additions & 2 deletions tests/parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TRANSACTION,
extractTransactionArguments,
extractScriptArguments,
extractContractParameters,
} from "../src/parser";

describe("parser", () => {
Expand Down Expand Up @@ -111,6 +112,114 @@ describe("extract contract name", () => {
});
});

describe("extract contract parameters", () => {
test("no init method in code", () => {
const contractName = "Hello";
const input = `
pub contract ${contractName} {
// no init method here either
}
`;
const output = extractContractParameters(input);
expect(output.contractName).toBe(contractName);
expect(output.args).toBe("");
});

test("no init method in code - interface", () => {
const contractName = "Hello";
const input = `
pub contract interface ${contractName} {
// no init method here either
}
`;
const output = extractContractParameters(input);
expect(output.contractName).toBe(contractName);
expect(output.args).toBe("");
});

test("with init method in code - no arguments", () => {
const contractName = "Hello";
const input = `
pub contract interface ${contractName} {
// init method here
init(){}
}
`;
const output = extractContractParameters(input);
expect(output.contractName).toBe(contractName);
expect(output.args).toBe("");
});

test("with init method in code - single argument", () => {
const contractName = "Hello";
const args = "a: String";
const input = `
pub contract interface ${contractName} {
// init method here
init(${args}){}
}
`;
const output = extractContractParameters(input);
expect(output.contractName).toBe(contractName);
expect(output.args).toBe(args);
});

test("with init method in code - multiple argument", () => {
const contractName = "Hello";
const args = "a: String, b: {String: String}";
const input = `
pub contract interface ${contractName} {
// init method here
init(${args}){}
}
`;
const output = extractContractParameters(input);
expect(output.contractName).toBe(contractName);
expect(output.args).toBe(args);
});

test("init method on resource", () => {
const contractName = "Hello";
const input = `
pub contract interface ${contractName} {
// init method on resource
resource Token{
pub let balance: UInt
init(balance: UInt){
self.balance = balance
}
}
}
`;
const output = extractContractParameters(input);
expect(output.contractName).toBe(contractName);
expect(output.args).toBe("");
});

test("init method on resource - contract init before resource", () => {
const contractName = "Hello";
const args = "a: String, b: {String: String}";
const input = `
pub contract interface ${contractName} {
init(${args}){
// contract initialization here
}
// init method on resource
resource Token{
pub let balance: UInt
init(balance: UInt){
self.balance = balance
}
}
}
`;
const output = extractContractParameters(input);
expect(output.contractName).toBe(contractName);
expect(output.args).toBe(args);
});
});

describe("template type checker", () => {
test("is contract - script", () => {
const input = `
Expand Down Expand Up @@ -176,7 +285,7 @@ describe("template type checker", () => {
});
});

describe("spaces in definitions", ()=>{
describe("spaces in definitions", () => {
test("spaces in definition - transaction", () => {
const input = `
transaction ( code: String ) {
Expand Down Expand Up @@ -211,7 +320,7 @@ describe("spaces in definitions", ()=>{
expect(type).toBe(SCRIPT);
expect(args.length).toBe(1);
});
})
});

describe("interaction signatures", () => {
test("multi line transaction signature - no arguments", async () => {
Expand Down

0 comments on commit 44b9432

Please sign in to comment.