near-sdk-js
Version:
High Level JavaScript SDK for building smart contracts on NEAR
93 lines (92 loc) • 3.88 kB
JavaScript
import childProcess from "child_process";
import { promisify } from "util";
import signal from "signale";
import { Project } from "ts-morph";
import chalk from "chalk";
const { Signale } = signal;
const exec = promisify(childProcess.exec);
export async function executeCommand(command, verbose = false) {
const signale = new Signale({ scope: "exec", interactive: !verbose });
if (verbose) {
signale.info(`Running command: ${command}`);
}
let stdout, stderr, code = 0;
try {
({ stdout, stderr } = await exec(command));
}
catch (error) {
({ stdout, stderr, code } = error);
}
if (code != 0) {
signale.error(`Command failed: ${command}`);
const failDueToNameConflict = stderr.match(/conflicting types for '([a-zA-Z0-9_]+)'/);
if (failDueToNameConflict && failDueToNameConflict.length > 1) {
signale.error(`'${failDueToNameConflict[1]}' is a reserved word, please use another name for contract method"`);
}
}
if (stderr && verbose) {
signale.error(`Command stderr: ${stderr}`);
}
if (verbose) {
signale.info(`Command stdout: ${stdout}`);
}
if (code != 0) {
process.exit(1);
}
return stdout.trim();
}
export async function download(url, 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.
* @param verbose - Whether to print verbose output.
**/
export async function validateContract(contractPath, verbose = false) {
const signale = new Signale({ scope: "validate-contract" });
const project = new Project();
project.addSourceFilesAtPaths(contractPath);
const sourceFile = project.getSourceFile(contractPath);
const classDeclarations = sourceFile.getClasses();
for (const classDeclaration of classDeclarations) {
const classStructure = classDeclaration.getStructure();
const { decorators, properties, name } = classStructure;
const hasNearBindgen = decorators.some(({ name }) => name === "NearBindgen");
if (hasNearBindgen) {
if (verbose) {
signale.info(`Validating ${name} class...`);
}
const constructors = classDeclaration.getConstructors();
const hasConstructor = constructors.length > 0;
const propertiesToBeInited = properties.filter(({ initializer }) => !initializer);
if (!hasConstructor && propertiesToBeInited.length === 0) {
return true;
}
if (!hasConstructor && propertiesToBeInited.length > 0) {
signale.error(chalk.redBright(`${UNINITIALIZED_PARAMETERS_ERROR} ${propertiesToBeInited
.map(({ name }) => name)
.join(", ")}`));
return false;
}
const [constructor] = constructors;
const constructorContent = constructor.getText();
if (verbose) {
signale.info("Checking for non initialized properties...");
}
const nonInitedProperties = propertiesToBeInited.reduce((properties, { name }) => {
if (constructorContent.includes(`this.${name}`)) {
return properties;
}
return [...properties, name];
}, []);
if (nonInitedProperties.length > 0) {
signale.error(chalk.redBright(`${UNINITIALIZED_PARAMETERS_ERROR} ${nonInitedProperties.join(", ")}`));
return false;
}
}
}
return true;
}