Skip to content
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

Merged
merged 29 commits into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
18e9386
fix: constructor validation on build
osalkanovic Sep 16, 2022
6d1d9bf
Update unordered-map.js
osalkanovic Sep 16, 2022
fd356cc
feat: constructor checker
osalkanovic Oct 9, 2022
1c4938e
feat: constructor validation
osalkanovic Oct 9, 2022
eb7730e
Merge branch 'fix/constructor-validation' of github.com:osalkanovic/n…
osalkanovic Oct 9, 2022
a457a44
Merge branch 'develop' of github.com:osalkanovic/near-sdk-js into fix…
osalkanovic Oct 9, 2022
4badd6f
fix: resolve conflicts
osalkanovic Oct 9, 2022
125086e
fix: resolve conflicts
osalkanovic Oct 9, 2022
f7d1b7d
fix: code cleaning
osalkanovic Oct 9, 2022
8e1943b
fix: code cleaning
osalkanovic Oct 9, 2022
8460a91
fix: code cleaning
osalkanovic Oct 9, 2022
1aec5c9
fix: lint
osalkanovic Oct 9, 2022
df50b2d
fix: tests
osalkanovic Oct 9, 2022
72d21d0
fix: empty state contract
osalkanovic Oct 9, 2022
81b48bc
fix: update contract valdiation to handle clean-state example
osalkanovic Oct 9, 2022
1c9eedd
linter fix
volovyks Oct 11, 2022
a2806e6
Merge branch 'develop' into fix/constructor-validation
volovyks Oct 12, 2022
c558746
merge conflicts fixed
volovyks Oct 24, 2022
7e0eb28
constructor validation moved to utils
volovyks Oct 24, 2022
80306f8
constructor test contracts renamed, typos fixed
volovyks Oct 24, 2022
f48b632
redandunt comment deleted
volovyks Oct 24, 2022
391212a
Error messages changed
volovyks Oct 24, 2022
664d178
log comments added to contract validation
volovyks Oct 24, 2022
50c6e59
yarn build
volovyks Oct 24, 2022
5025f8e
cli/cli.js deleted
volovyks Oct 24, 2022
e57364d
contract validation added to the main pipeline
volovyks Oct 25, 2022
bfc09a6
contract validation rewrittent with TS
volovyks Oct 25, 2022
fc0fb95
signal used in contract validation, tests rewritten
volovyks Oct 25, 2022
64a3c6e
contract validation doc added
volovyks Oct 25, 2022
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
3 changes: 2 additions & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@types/lodash-es": "^4.17.6",
"ava": "^4.2.0",
"near-workspaces": "3.2.1",
"typescript": "^4.7.4"
"typescript": "^4.7.4",
"npm-run-all": "^4.1.5"
}
}
1,434 changes: 927 additions & 507 deletions examples/yarn.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion lib/cli/cli.js

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

5 changes: 5 additions & 0 deletions lib/cli/utils.d.ts

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

44 changes: 44 additions & 0 deletions lib/cli/utils.js

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
"@types/eslint": "^8.4.6",
"@types/node": "^17.0.38",
"@types/rollup": "^0.54.0",
"chalk": "^5.1.0",
"ts-morph": "^16.0.0",
"@types/signale": "^1.4.4",
"@typescript-eslint/eslint-plugin": "^5.37.0",
"@typescript-eslint/parser": "^5.37.0",
Expand Down
5 changes: 4 additions & 1 deletion src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { rollup } from "rollup";
import { Command } from "commander";
import signal from "signale";

import { executeCommand } from "./utils.js";
import { executeCommand, validateContract } from "./utils.js";

const { Signale } = signal;
const PROJECT_DIR = process.cwd();
Expand Down Expand Up @@ -66,6 +66,9 @@ export async function buildCom(
signale.await(`Creating ${TARGET_DIR} directory...`);
await executeCommand(`mkdir -p ${TARGET_DIR}`, verbose);

signal.await(`Validatig ${source} contract...`);
await validateContract(source);

signale.await(`Creating ${source} file with Rollup...`);
await createJsFileWithRullup(source, ROLLUP_TARGET, verbose);

Expand Down
48 changes: 48 additions & 0 deletions src/cli/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import childProcess from "child_process";
import { promisify } from "util";
import signal from "signale"
import { ClassDeclaration, ClassDeclarationStructure, ConstructorDeclaration, OptionalKind, Project, PropertyDeclarationStructure, SourceFile } from "ts-morph";
import chalk from "chalk";
import signale from "signale";

const {Signale} = signal;

Expand Down Expand Up @@ -37,3 +40,48 @@ export async function executeCommand(
export async function download(url: string, verbose = false) {
await executeCommand(`curl -LOf ${url}`, verbose);
}

const UNINITIALIZED_PARAMETERS_ERROR = "All parameters must be initialized in the constructor. Uninitialized parameters:";

/**
* Validates the contract by checking that all parameters are initialized in the constructor. Works only for contracts written in TypeScript.
* @param contractPath Path to the contract.
**/
export async function validateContract(contractPath: string): Promise<boolean> {
const project: Project = new Project();
project.addSourceFilesAtPaths(contractPath);
const sourceFile: SourceFile = project.getSourceFile(contractPath);
const classDeclarations: ClassDeclaration[] = sourceFile.getClasses();
for (const classDeclaration of classDeclarations) {
const classStructure: ClassDeclarationStructure = classDeclaration.getStructure();
const { decorators, properties } = classStructure;
const hasNearBindgen: boolean = decorators.find(
(decorator) => decorator.name === "NearBindgen"
) ? true : false;
if (hasNearBindgen) {
const constructors: ConstructorDeclaration[] = classDeclaration.getConstructors();
const hasConstructor = constructors.length > 0;
const propertiesToBeInited: OptionalKind<PropertyDeclarationStructure>[] = properties.filter((p) => !p.initializer);
if (!hasConstructor && propertiesToBeInited.length === 0) {
return true;
}
if (!hasConstructor && propertiesToBeInited.length > 0) {
signale.error(chalk.redBright(`${UNINITIALIZED_PARAMETERS_ERROR} ${propertiesToBeInited.map((p) => p.name)}`));
process.exit(1);
}
const constructor: ConstructorDeclaration = constructors[0];
const constructorContent: string = constructor.getText();
const nonInitedProperties: string[] = [];
for (const property of propertiesToBeInited) {
if (!constructorContent.includes(`this.${property.name}`)) {
nonInitedProperties.push(property.name);
}
}
if (nonInitedProperties.length > 0) {
signale.error(chalk.redBright(`${UNINITIALIZED_PARAMETERS_ERROR} ${nonInitedProperties.join(", ")}`));
process.exit(1);
}
}
}
return true;
}
39 changes: 39 additions & 0 deletions tests/__tests__/constructor_validation.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import test from "ava";
import { execSync } from "child_process";

const BUILD_FAILURE_ERROR_CODE = 1;

test("should not throw error, constructor is correctly initialized", async (t) => {
t.notThrows(() => {
execSync(
"near-sdk-js build src/constructor-validation/all-parameters-set-in-constructor.ts build/all-parameters-set-in-constructor.wasm"
);
});
});

test("should throw error, name is not inited", async (t) => {
const error = t.throws(() => {
execSync(
"near-sdk-js build src/constructor-validation/1-parameter-not-set-in-constructor.ts build/1-parameter-not-set-in-constructor.wasm"
);
});
t.is(error.status, BUILD_FAILURE_ERROR_CODE);
});

test("should throw error, construcor is empty", async (t) => {
const error = t.throws(() => {
execSync(
"near-sdk-js build src/constructor-validation/no-parameters-set-in-constructor.ts build/no-parameters-set-in-constructor.wasm"
);
});
t.is(error.status, BUILD_FAILURE_ERROR_CODE);
});

test("should throw error, construcor is not declared", async (t) => {
const error = t.throws(() => {
execSync(
"near-sdk-js build src/constructor-validation/no-constructor.ts build/no-constructor.wasm"
);
});
t.is(error.status, BUILD_FAILURE_ERROR_CODE);
});
4 changes: 3 additions & 1 deletion tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@
"test:bigint-serialization": "ava __tests__/test-bigint-serialization.ava.js",
"test:date-serialization": "ava __tests__/test-date-serialization.ava.js",
"test:serialization": "ava __tests__/test-serialization.ava.js",
"test:constructor-validation": "ava __tests__/constructor_validation.ava.js",
"test:middlewares": "ava __tests__/test-middlewares.ava.js"
},
"author": "Near Inc <hello@nearprotocol.com>",
"license": "Apache-2.0",
"devDependencies": {
"ava": "^4.2.0",
"near-workspaces": "3.2.1",
"typescript": "^4.7.4"
"typescript": "^4.7.4",
"npm-run-all": "^4.1.5"
}
}
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,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" };
}
}
7 changes: 7 additions & 0 deletions tests/src/constructor-validation/no-constructor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { NearBindgen, LookupMap } from "near-sdk-js";

@NearBindgen({})
export class ConstructorValidation {
map: LookupMap<string>;
name: string;
}
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() {
//
}
}
Loading