mirror of https://github.com/embarklabs/embark.git
106 lines
3.2 KiB
TypeScript
106 lines
3.2 KiB
TypeScript
import Ajv from "ajv";
|
|
import { Logger } /* supplied by @types/embark in packages/embark-typings */ from "embark";
|
|
import { __ } from "embark-i18n";
|
|
import { schema } from "./schema";
|
|
const fs = require("fs");
|
|
|
|
const ajv = new Ajv();
|
|
const scaffoldingSchema = ajv.compile(schema);
|
|
|
|
interface Properties {
|
|
[propertyName: string]: string;
|
|
}
|
|
|
|
interface Data {
|
|
[contractName: string]: Properties;
|
|
}
|
|
|
|
const ASSOCIATIONS = ["belongsTo", "hasMany"];
|
|
const IPFS = ["ipfsText", "ipfsImage"];
|
|
|
|
export class SmartContractsRecipe {
|
|
public data: Data;
|
|
constructor(private readonly logger: Logger,
|
|
private readonly contractOrFile: string,
|
|
private readonly fields: string[],
|
|
) {
|
|
if (fs.existsSync(contractOrFile)) {
|
|
this.data = fs.readJSONSync(contractOrFile);
|
|
} else {
|
|
this.data = this.build();
|
|
}
|
|
}
|
|
|
|
public standardAttributes(contractName: string): Properties {
|
|
return Object.keys(this.data[contractName]).reduce((acc: Properties, propertyName: string) => {
|
|
const type = this.data[contractName][propertyName];
|
|
if (!ASSOCIATIONS.includes(type) && !IPFS.includes(type)) {
|
|
acc[propertyName] = type;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
public ipfsAttributes(contractName: string): Properties {
|
|
return Object.keys(this.data[contractName]).reduce((acc: Properties, propertyName: string) => {
|
|
const type = this.data[contractName][propertyName];
|
|
if (IPFS.includes(type)) {
|
|
acc[propertyName] = type;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
public associationAttributes(contractName: string): Properties {
|
|
return Object.keys(this.data[contractName]).reduce((acc: Properties, propertyName: string) => {
|
|
const type = this.data[contractName][propertyName];
|
|
if (ASSOCIATIONS.includes(type)) {
|
|
acc[propertyName] = type;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
public validate() {
|
|
if (!scaffoldingSchema(this.data)) {
|
|
this.logger.error(__("The scaffolding schema is not valid:"));
|
|
this.logger.error(ajv.errorsText(scaffoldingSchema.errors));
|
|
process.exit(1);
|
|
}
|
|
|
|
const contractNames = Object.keys(this.data);
|
|
contractNames.forEach((contractName) => {
|
|
if (contractName[0] !== contractName[0].toUpperCase()) {
|
|
this.logger.error(__(`${contractName} must be capitalized.`));
|
|
process.exit(1);
|
|
}
|
|
Object.keys(this.associationAttributes(contractName)).forEach((associationName) => {
|
|
if (associationName === contractName) {
|
|
this.logger.error(__(`${contractName} is referring to himself.`));
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!contractNames.includes(associationName)) {
|
|
this.logger.error(__(`${contractName} not found. Please make sure it is in the description.`));
|
|
process.exit(1);
|
|
}
|
|
|
|
if (Object.keys(this.data[associationName]).includes(contractName)) {
|
|
this.logger.error(__(`${associationName} has a cyclic dependencies with ${contractName}.`));
|
|
process.exit(1);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
private build() {
|
|
return {
|
|
[this.contractOrFile]: this.fields.reduce((acc: Properties, property) => {
|
|
const [name, value] = property.split(":");
|
|
acc[name] = value;
|
|
return acc;
|
|
}, {}),
|
|
};
|
|
}
|
|
}
|