Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
.PHONY: clean browser-tests

browser-tests: out-browser-tests/erdjs-tests-unit.js out-browser-tests/erdjs-tests-localnet.js out-browser-tests/erdjs-tests-devnet.js out-browser-tests/erdjs-tests-testnet.js out-browser-tests/erdjs-tests-mainnet.js
browser-tests: out-browser-tests/erdjs-tests-unit.js out-browser-tests/erdjs-tests-unit-min.js out-browser-tests/erdjs-tests-localnet.js out-browser-tests/erdjs-tests-devnet.js out-browser-tests/erdjs-tests-testnet.js out-browser-tests/erdjs-tests-mainnet.js

out-browser-tests/erdjs-tests-unit.js: out-tests
npx browserify $(shell find out-tests -type f -name '*.js' ! -name '*.net.spec.*') --require buffer/:buffer -o out-browser-tests/erdjs-tests-unit.js --standalone erdjs-tests -p esmify

out-browser-tests/erdjs-tests-unit-min.js: out-tests
npx browserify $(shell find out-tests -type f -name '*.js' ! -name '*.net.spec.*') --require buffer/:buffer -o out-browser-tests/erdjs-tests-unit-min.js --standalone erdjs-tests -p esmify -p tinyify

out-browser-tests/erdjs-tests-localnet.js: out-tests
npx browserify $(shell find out-tests -type f -name '*.js' ! -name '*.spec.*') $(shell find out-tests -type f -name '*.local.net.spec.js') --require buffer/:buffer -o out-browser-tests/erdjs-tests-localnet.js --standalone erdjs-tests -p esmify

Expand Down
5 changes: 5 additions & 0 deletions browser-tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
Unit tests
</button>
</li>
<li class="list-group-item">
<button class="btn btn-link" onclick="runTests('/out-browser-tests/erdjs-tests-unit-min.js')">
Unit tests (minified code)
</button>
</li>
<li class="list-group-item">
<button class="btn btn-link" onclick="runTests('/out-browser-tests/erdjs-tests-localnet.js')">
Integration tests - local testnet
Expand Down
10 changes: 0 additions & 10 deletions src/reflection.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
export function hasJavascriptConstructor(obj: Object, javascriptConstructorName: string): boolean {
return obj.constructor.name == javascriptConstructorName;
}

export function getJavascriptConstructorsNamesInHierarchy(obj: Object, filter: (prototype: any) => boolean): string[] {
let prototypes = getJavascriptPrototypesInHierarchy(obj, filter);
let constructorNames = prototypes.map(prototype => prototype.constructor.name);
return constructorNames;
}

export function getJavascriptPrototypesInHierarchy(obj: Object, filter: (prototype: any) => boolean): Object[] {
let prototypes: Object[] = [];
let prototype: any = Object.getPrototypeOf(obj);
Expand Down
12 changes: 6 additions & 6 deletions src/smartcontracts/argSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,18 @@ export class ArgSerializer {
function readValue(type: Type): TypedValue {
// TODO: Use matchers.

if (type.hasJavascriptConstructor(OptionalType.name)) {
if (type.hasExactClass(OptionalType.ClassName)) {
let typedValue = readValue(type.getFirstTypeParameter());
return new OptionalValue(type, typedValue);
} else if (type.hasJavascriptConstructor(VariadicType.name)) {
} else if (type.hasExactClass(VariadicType.ClassName)) {
let typedValues = [];

while (!hasReachedTheEnd()) {
typedValues.push(readValue(type.getFirstTypeParameter()));
}

return new VariadicValue(type, typedValues);
} else if (type.hasJavascriptConstructor(CompositeType.name)) {
} else if (type.hasExactClass(CompositeType.ClassName)) {
let typedValues = [];

for (const typeParameter of type.getTypeParameters()) {
Expand Down Expand Up @@ -132,17 +132,17 @@ export class ArgSerializer {
function handleValue(value: TypedValue): void {
// TODO: Use matchers.

if (value.hasJavascriptConstructor(OptionalValue.name)) {
if (value.hasExactClass(OptionalValue.ClassName)) {
let valueAsOptional = <OptionalValue>value;
if (valueAsOptional.isSet()) {
handleValue(valueAsOptional.getTypedValue());
}
} else if (value.hasJavascriptConstructor(VariadicValue.name)) {
} else if (value.hasExactClass(VariadicValue.ClassName)) {
let valueAsVariadic = <VariadicValue>value;
for (const item of valueAsVariadic.getItems()) {
handleValue(item);
}
} else if (value.hasJavascriptConstructor(CompositeValue.name)) {
} else if (value.hasExactClass(CompositeValue.ClassName)) {
let valueAsComposite = <CompositeValue>value;
for (const item of valueAsComposite.getItems()) {
handleValue(item);
Expand Down
4 changes: 2 additions & 2 deletions src/smartcontracts/typesystem/abiRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ export class AbiRegistry {
return names.map((name) => this.getInterface(name));
}
getStruct(name: string): StructType {
let result = this.customTypes.find((e) => e.getName() == name && e.hasJavascriptConstructor(StructType.name));
let result = this.customTypes.find((e) => e.getName() == name && e.hasExactClass(StructType.ClassName));
guardValueIsSetWithMessage(`struct [${name}] not found`, result);
return <StructType>result!;
}
getStructs(names: string[]): StructType[] {
return names.map((name) => this.getStruct(name));
}
getEnum(name: string): EnumType {
let result = this.customTypes.find((e) => e.getName() == name && e.hasJavascriptConstructor(EnumType.name));
let result = this.customTypes.find((e) => e.getName() == name && e.hasExactClass(EnumType.ClassName));
guardValueIsSetWithMessage(`enum [${name}] not found`, result);
return <EnumType>result!;
}
Expand Down
11 changes: 11 additions & 0 deletions src/smartcontracts/typesystem/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,33 @@ import { Address } from "../../address";
import { PrimitiveType, PrimitiveValue } from "./types";

export class AddressType extends PrimitiveType {
static ClassName = "AddressType";

constructor() {
super("Address");
}

getClassName(): string {
return AddressType.ClassName;
}
}

/**
* An address fed to or fetched from a Smart Contract contract, as an immutable abstraction.
*/
export class AddressValue extends PrimitiveValue {
static ClassName = "AddressValue";
private readonly value: Address;

constructor(value: Address) {
super(new AddressType());
this.value = value;
}

getClassName(): string {
return AddressValue.ClassName;
}

/**
* Returns whether two objects have the same value.
*
Expand Down
15 changes: 13 additions & 2 deletions src/smartcontracts/typesystem/algebraic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,29 @@ import { NullType, Type, TypeCardinality, TypedValue } from "./types";
* An optional is an algebraic type. It holds zero or one values.
*/
export class OptionalType extends Type {
static ClassName = "OptionalType";

constructor(typeParameter: Type) {
super("Optional", [typeParameter], TypeCardinality.variable(1));
}

getClassName(): string {
return OptionalType.ClassName;
}

isAssignableFrom(type: Type): boolean {
if (!(type.hasJavascriptConstructor(OptionalType.name))) {
if (!(type.hasExactClass(OptionalType.ClassName))) {
return false;
}

let invariantTypeParameters = this.getFirstTypeParameter().equals(type.getFirstTypeParameter());
let fakeCovarianceToNull = type.getFirstTypeParameter().hasJavascriptConstructor(NullType.name);
let fakeCovarianceToNull = type.getFirstTypeParameter().hasExactClass(NullType.ClassName);
return invariantTypeParameters || fakeCovarianceToNull;
}
}

export class OptionalValue extends TypedValue {
static ClassName = "OptionalValue";
private readonly value: TypedValue | null;

constructor(type: OptionalType, value: TypedValue | null = null) {
Expand All @@ -31,6 +38,10 @@ export class OptionalValue extends TypedValue {
this.value = value;
}

getClassName(): string {
return OptionalValue.ClassName;
}

/**
* Creates an OptionalValue, as not provided (missing).
*/
Expand Down
11 changes: 11 additions & 0 deletions src/smartcontracts/typesystem/boolean.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import { PrimitiveType, PrimitiveValue } from "./types";

export class BooleanType extends PrimitiveType {
static ClassName = "BooleanType";

constructor() {
super("bool");
}

getClassName(): string {
return BooleanType.ClassName;
}
}

/**
* A boolean value fed to or fetched from a Smart Contract contract, as an immutable abstraction.
*/
export class BooleanValue extends PrimitiveValue {
static ClassName = "BooleanValue";
private readonly value: boolean;

constructor(value: boolean) {
super(new BooleanType());
this.value = value;
}

getClassName(): string {
return BooleanValue.ClassName;
}

/**
* Returns whether two objects have the same value.
*
Expand Down
12 changes: 11 additions & 1 deletion src/smartcontracts/typesystem/bytes.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
import * as errors from "../../errors";
import { PrimitiveType, PrimitiveValue } from "./types";

export class BytesType extends PrimitiveType {
static ClassName = "BytesType";

constructor() {
super("bytes");
}

getClassName(): string {
return BytesType.ClassName;
}
}

export class BytesValue extends PrimitiveValue {
static ClassName = "BytesValue";
private readonly value: Buffer;

constructor(value: Buffer) {
super(new BytesType());
this.value = value;
}

getClassName(): string {
return BytesValue.ClassName;
}

/**
* Creates a BytesValue from a utf-8 string.
*/
Expand Down
11 changes: 11 additions & 0 deletions src/smartcontracts/typesystem/composite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ import { guardLength } from "../../utils";
import { Type, TypeCardinality, TypedValue } from "./types";

export class CompositeType extends Type {
static ClassName = "CompositeType";

constructor(...typeParameters: Type[]) {
super("Composite", typeParameters, TypeCardinality.variable(typeParameters.length));
}

getClassName(): string {
return CompositeType.ClassName;
}
}

export class CompositeValue extends TypedValue {
static ClassName = "CompositeValue";
private readonly items: TypedValue[];

constructor(type: CompositeType, items: TypedValue[]) {
Expand All @@ -20,6 +27,10 @@ export class CompositeValue extends TypedValue {
this.items = items;
}

getClassName(): string {
return CompositeValue.ClassName;
}

static fromItems(...items: TypedValue[]): CompositeValue {
let typeParameters = items.map(value => value.getType());
let type = new CompositeType(...typeParameters);
Expand Down
10 changes: 10 additions & 0 deletions src/smartcontracts/typesystem/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import { CustomType, TypedValue } from "./types";
const SimpleEnumMaxDiscriminant = 256;

export class EnumType extends CustomType {
static ClassName = "EnumType";
readonly variants: EnumVariantDefinition[] = [];

constructor(name: string, variants: EnumVariantDefinition[]) {
super(name);
this.variants = variants;
}

getClassName(): string {
return EnumType.ClassName;
}

static fromJSON(json: { name: string; variants: any[] }): EnumType {
let variants = (json.variants || []).map((variant) => EnumVariantDefinition.fromJSON(variant));
return new EnumType(json.name, variants);
Expand Down Expand Up @@ -58,6 +63,7 @@ export class EnumVariantDefinition {
}

export class EnumValue extends TypedValue {
static ClassName = "EnumValue";
readonly name: string;
readonly discriminant: number;
private readonly fields: Field[] = [];
Expand All @@ -74,6 +80,10 @@ export class EnumValue extends TypedValue {
Fields.checkTyping(this.fields, definitions);
}

getClassName(): string {
return EnumValue.ClassName;
}

/**
* Utility (named constructor) to create a simple (i.e. without fields) enum value.
*/
Expand Down
26 changes: 24 additions & 2 deletions src/smartcontracts/typesystem/generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,43 @@ import { Type, TypedValue, NullType, TypePlaceholder } from "./types";

// TODO: Move to a new file, "genericOption.ts"
export class OptionType extends Type {
static ClassName = "OptionType";

constructor(typeParameter: Type) {
super("Option", [typeParameter]);
}

getClassName(): string {
return OptionType.ClassName;
}

isAssignableFrom(type: Type): boolean {
if (!(type.hasJavascriptConstructor(OptionType.name))) {
if (!(type.hasExactClass(OptionType.ClassName))) {
return false;
}

let invariantTypeParameters = this.getFirstTypeParameter().equals(type.getFirstTypeParameter());
let fakeCovarianceToNull = type.getFirstTypeParameter().hasJavascriptConstructor(NullType.name);
let fakeCovarianceToNull = type.getFirstTypeParameter().hasExactClass(NullType.ClassName);
return invariantTypeParameters || fakeCovarianceToNull;
}
}

// TODO: Move to a new file, "genericList.ts"
export class ListType extends Type {
static ClassName = "ListType";

constructor(typeParameter: Type) {
super("List", [typeParameter]);
}

getClassName(): string {
return ListType.ClassName;
}
}

// TODO: Move to a new file, "genericOption.ts"
export class OptionValue extends TypedValue {
static ClassName = "OptionValue";
private readonly value: TypedValue | null;

constructor(type: OptionType, value: TypedValue | null = null) {
Expand All @@ -38,6 +51,10 @@ export class OptionValue extends TypedValue {
this.value = value;
}

getClassName(): string {
return OptionValue.ClassName;
}

/**
* Creates an OptionValue, as a missing option argument.
*/
Expand Down Expand Up @@ -80,6 +97,7 @@ export class OptionValue extends TypedValue {
// TODO: Rename to ListValue, for consistency (though the term is slighly unfortunate).
// Question for review: or not?
export class List extends TypedValue {
static ClassName = "List";
private readonly backingCollection: CollectionOfTypedValues;

/**
Expand All @@ -95,6 +113,10 @@ export class List extends TypedValue {
this.backingCollection = new CollectionOfTypedValues(items);
}

getClassName(): string {
return List.ClassName;
}

static fromItems(items: TypedValue[]): List {
if (items.length == 0) {
return new List(new TypePlaceholder(), []);
Expand Down
Loading