-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: constructor validation on build #226
Changes from 16 commits
18e9386
6d1d9bf
fd356cc
1c4938e
eb7730e
a457a44
4badd6f
125086e
f7d1b7d
8e1943b
8460a91
1aec5c9
df50b2d
72d21d0
81b48bc
1c9eedd
a2806e6
c558746
7e0eb28
80306f8
f48b632
391212a
664d178
50c6e59
5025f8e
e57364d
bfc09a6
fc0fb95
64a3c6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Project } from "ts-morph"; | ||
import path from "path"; | ||
import chalk from "chalk"; | ||
|
||
const validateContract = async (contractPath) => { | ||
const project = new Project(); | ||
project.addSourceFilesAtPaths(contractPath); | ||
const baseFileName = path.parse(contractPath).base; | ||
const contractClassFile = project.getSourceFile(contractPath); | ||
const contractClasses = contractClassFile.getClasses(baseFileName); | ||
for (const contractClass of contractClasses) { | ||
const classStructure = contractClass.getStructure(); | ||
const { decorators, properties } = classStructure; | ||
const hasBindgen = decorators.find( | ||
(decorator) => decorator.name === "NearBindgen" | ||
); | ||
if (hasBindgen) { | ||
const constructors = contractClass.getConstructors(); | ||
const hasConstructor = constructors.length > 0; | ||
const propertiesToBeInited = properties.filter((p) => !p.initializer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does it work with JS contracts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not work for JS contracts due to the absence of parameter declaration. |
||
// reson: examples/clean-state.js | ||
volovyks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!hasConstructor && propertiesToBeInited.length === 0) { | ||
return true; | ||
} | ||
if (!hasConstructor && propertiesToBeInited.length > 0) { | ||
console.log( | ||
chalk.redBright( | ||
`Ops, constructor isnt initialized, after initialization include ${propertiesToBeInited | ||
volovyks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.map((p) => p.name) | ||
.join(", ")} in constructor` | ||
) | ||
); | ||
process.exit(2); | ||
} | ||
const constructor = constructors[0]; | ||
const constructorContent = constructor.getText(); | ||
const nonInitedProperties = []; | ||
for (const property of propertiesToBeInited) { | ||
if (!constructorContent.includes(`this.${property.name} =`)) { | ||
nonInitedProperties.push(property.name); | ||
} | ||
} | ||
if (nonInitedProperties.length > 0) { | ||
console.log( | ||
chalk.redBright( | ||
`Ops, please initialise ${nonInitedProperties.join( | ||
", " | ||
)} in constructor` | ||
) | ||
); | ||
process.exit(2); | ||
} | ||
} | ||
} | ||
}; | ||
|
||
export default validateContract; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import test from "ava"; | ||
import { execSync } from "child_process"; | ||
|
||
test("should build, constructor is correctly initialized", async (t) => { | ||
let result = null; | ||
try { | ||
result = execSync( | ||
volovyks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"near-sdk-js build src/constructor-validation/version-1.ts build/constructor-validation/version-1.wasm" | ||
).toString(); | ||
} catch (e) { | ||
result = e; | ||
} | ||
t.not(result.status, 2); | ||
volovyks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
|
||
test("should throw error, name isnt inited", async (t) => { | ||
let result = null; | ||
try { | ||
result = execSync( | ||
"near-sdk-js build src/constructor-validation/version-2.ts build/constructor-validation/version-2.wasm" | ||
).toString(); | ||
} catch (e) { | ||
result = e; | ||
} | ||
|
||
t.is(result.status, 2); | ||
}); | ||
|
||
test("should throw error, construcor is empty", async (t) => { | ||
let result = null; | ||
try { | ||
volovyks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
result = execSync( | ||
"near-sdk-js build src/constructor-validation/version-3.ts build/constructor-validation/version-3.wasm" | ||
).toString(); | ||
} catch (e) { | ||
result = e; | ||
} | ||
|
||
t.is(result.status, 2); | ||
}); | ||
|
||
test("should throw error, construcor isnt declared", async (t) => { | ||
volovyks marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be great to compare error text here. Can we do that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think result.stdout / result.stderr records the error text There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The validation error is overridden with another top-level error. Added const for now. |
||
let result = null; | ||
try { | ||
result = execSync( | ||
"near-sdk-js build src/constructor-validation/version-4.ts build/constructor-validation/version-4.wasm" | ||
).toString(); | ||
} catch (e) { | ||
result = e; | ||
} | ||
|
||
t.is(result.status, 2); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { NearBindgen, LookupMap, call } from "near-sdk-js"; | ||
|
||
@NearBindgen({}) | ||
export class ConstructorValidation { | ||
map: LookupMap<string>; | ||
name: string; | ||
constructor() { | ||
this.map = new LookupMap<string>("a"); | ||
this.name = ""; | ||
} | ||
|
||
@call({}) | ||
get() { | ||
return { status: "ok" }; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { NearBindgen, LookupMap } from "near-sdk-js"; | ||
|
||
@NearBindgen({}) | ||
export class ConstructorValidation { | ||
map: LookupMap<string>; | ||
name: string; | ||
constructor() { | ||
this.map = new LookupMap<string>("a"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { NearBindgen, LookupMap } from "near-sdk-js"; | ||
|
||
@NearBindgen({}) | ||
export class ConstructorValidation { | ||
map: LookupMap<string>; | ||
name: string; | ||
constructor() { | ||
// | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { NearBindgen, LookupMap } from "near-sdk-js"; | ||
volovyks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
@NearBindgen({}) | ||
export class ConstructorValidation { | ||
map: LookupMap<string>; | ||
name: string; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice step! All existing contracts can pass the validation