Types refactoring
parent
edc8f4eb6a
commit
beb5c408d1
|
@ -37,7 +37,7 @@
|
||||||
"@babel/preset-env": "^7.0.0-beta.32",
|
"@babel/preset-env": "^7.0.0-beta.32",
|
||||||
"@babel/preset-flow": "^7.0.0-beta.32",
|
"@babel/preset-flow": "^7.0.0-beta.32",
|
||||||
"@babel/register": "^7.0.0-beta.32",
|
"@babel/register": "^7.0.0-beta.32",
|
||||||
"flow-bin": "^0.59.0",
|
"flow-bin": "^0.60.0",
|
||||||
"jasmine": "^2.8.0",
|
"jasmine": "^2.8.0",
|
||||||
"mocha": "^4.0.1",
|
"mocha": "^4.0.1",
|
||||||
"nyc": "^11.3.0"
|
"nyc": "^11.3.0"
|
||||||
|
|
|
@ -20,6 +20,8 @@ import type {
|
||||||
MaybeType, NumberType, StringType, BooleanType, LiteralType, ReferenceType,
|
MaybeType, NumberType, StringType, BooleanType, LiteralType, ReferenceType,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
|
import * as t from './types';
|
||||||
|
|
||||||
import {extractPragmas} from './pragmas';
|
import {extractPragmas} from './pragmas';
|
||||||
|
|
||||||
import {invariant} from './utils';
|
import {invariant} from './utils';
|
||||||
|
@ -54,18 +56,16 @@ function processInterfaceDeclaration(ctx: Context, node: InterfaceDeclaration) {
|
||||||
|
|
||||||
invariant(type.id);
|
invariant(type.id);
|
||||||
|
|
||||||
parts.push({
|
const reference = t.createReference(t.clone(type.id));
|
||||||
kind: 'reference',
|
|
||||||
to: type.id.slice(),
|
parts.push(reference);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parts.push(type);
|
parts.push(type);
|
||||||
|
|
||||||
ctx.define(name, {
|
const intersection = t.createIntersection(parts);
|
||||||
kind: 'intersection',
|
|
||||||
parts,
|
ctx.define(name, intersection);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: type params.
|
// TODO: type params.
|
||||||
|
@ -87,27 +87,22 @@ function processClassDeclaration(ctx: Context, node: ClassDeclaration) {
|
||||||
|
|
||||||
invariant(base.id);
|
invariant(base.id);
|
||||||
|
|
||||||
const baseRef = {
|
const baseRef = t.createReference(t.clone(base.id));
|
||||||
kind: 'reference',
|
const intersection = t.createIntersection([baseRef, type]);
|
||||||
to: base.id.slice(),
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.define(name, {
|
ctx.define(name, intersection);
|
||||||
kind: 'intersection',
|
|
||||||
parts: [baseRef, type],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeType(ctx: Context, node: FlowTypeAnnotation): ?Type {
|
function makeType(ctx: Context, node: FlowTypeAnnotation): ?Type {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'NullLiteralTypeAnnotation':
|
case 'NullLiteralTypeAnnotation':
|
||||||
return {kind: 'literal', value: null};
|
return t.createLiteral(null);
|
||||||
case 'BooleanTypeAnnotation':
|
case 'BooleanTypeAnnotation':
|
||||||
return {kind: 'boolean'};
|
return t.createBoolean();
|
||||||
case 'NumberTypeAnnotation':
|
case 'NumberTypeAnnotation':
|
||||||
return {kind: 'number', repr: 'f64'};
|
return t.createNumber('f64');
|
||||||
case 'StringTypeAnnotation':
|
case 'StringTypeAnnotation':
|
||||||
return {kind: 'string'};
|
return t.createString();
|
||||||
case 'TypeAnnotation':
|
case 'TypeAnnotation':
|
||||||
return makeType(ctx, node.typeAnnotation);
|
return makeType(ctx, node.typeAnnotation);
|
||||||
case 'NullableTypeAnnotation':
|
case 'NullableTypeAnnotation':
|
||||||
|
@ -123,13 +118,13 @@ function makeType(ctx: Context, node: FlowTypeAnnotation): ?Type {
|
||||||
case 'IntersectionTypeAnnotation':
|
case 'IntersectionTypeAnnotation':
|
||||||
return makeIntersection(ctx, node);
|
return makeIntersection(ctx, node);
|
||||||
case 'StringLiteralTypeAnnotation':
|
case 'StringLiteralTypeAnnotation':
|
||||||
return {kind: 'literal', value: node.value};
|
return t.createLiteral(node.value);
|
||||||
case 'GenericTypeAnnotation':
|
case 'GenericTypeAnnotation':
|
||||||
return makeReference(ctx, node);
|
return makeReference(ctx, node);
|
||||||
case 'AnyTypeAnnotation':
|
case 'AnyTypeAnnotation':
|
||||||
return {kind: 'any'};
|
return t.createAny();
|
||||||
case 'MixedTypeAnnotation':
|
case 'MixedTypeAnnotation':
|
||||||
return {kind: 'mixed'};
|
return t.createMixed();
|
||||||
case 'FunctionTypeAnnotation':
|
case 'FunctionTypeAnnotation':
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
|
@ -144,10 +139,7 @@ function makeMaybe(ctx: Context, node: NullableTypeAnnotation): ?MaybeType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return t.createMaybe(type);
|
||||||
kind: 'maybe',
|
|
||||||
value: type,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeComplexType(ctx: Context, node: ObjectTypeAnnotation): Type {
|
function makeComplexType(ctx: Context, node: ObjectTypeAnnotation): Type {
|
||||||
|
@ -168,10 +160,7 @@ function makeComplexType(ctx: Context, node: ObjectTypeAnnotation): Type {
|
||||||
|
|
||||||
const parts = record.fields.length > 0 ? [record, ...maps] : maps;
|
const parts = record.fields.length > 0 ? [record, ...maps] : maps;
|
||||||
|
|
||||||
return {
|
return t.createIntersection(parts);
|
||||||
kind: 'intersection',
|
|
||||||
parts,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRecord<T: ObjectTypeProperty | ClassProperty>(ctx: Context, nodes: T[]): RecordType {
|
function makeRecord<T: ObjectTypeProperty | ClassProperty>(ctx: Context, nodes: T[]): RecordType {
|
||||||
|
@ -180,10 +169,7 @@ function makeRecord<T: ObjectTypeProperty | ClassProperty>(ctx: Context, nodes:
|
||||||
.filter()
|
.filter()
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
return {
|
return t.createRecord(fields);
|
||||||
kind: 'record',
|
|
||||||
fields,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Field {
|
function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Field {
|
||||||
|
@ -238,11 +224,7 @@ function makeMap(ctx: Context, node: ObjectTypeIndexer): ?MapType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return t.createMap(keys, values);
|
||||||
kind: 'map',
|
|
||||||
keys,
|
|
||||||
values,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeArrayType(ctx: Context, node: ArrayTypeAnnotation): ?ArrayType {
|
function makeArrayType(ctx: Context, node: ArrayTypeAnnotation): ?ArrayType {
|
||||||
|
@ -252,10 +234,7 @@ function makeArrayType(ctx: Context, node: ArrayTypeAnnotation): ?ArrayType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return t.createArray(items);
|
||||||
kind: 'array',
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeTupleType(ctx: Context, node: TupleTypeAnnotation): ?TupleType {
|
function makeTupleType(ctx: Context, node: TupleTypeAnnotation): ?TupleType {
|
||||||
|
@ -266,10 +245,7 @@ function makeTupleType(ctx: Context, node: TupleTypeAnnotation): ?TupleType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return t.createTuple(items);
|
||||||
kind: 'tuple',
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeUnionType(ctx: Context, node: UnionTypeAnnotation): ?Type {
|
function makeUnionType(ctx: Context, node: UnionTypeAnnotation): ?Type {
|
||||||
|
@ -286,10 +262,7 @@ function makeUnionType(ctx: Context, node: UnionTypeAnnotation): ?Type {
|
||||||
return variants[0];
|
return variants[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return t.createUnion(variants);
|
||||||
kind: 'union',
|
|
||||||
variants,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeIntersection(ctx: Context, node: IntersectionTypeAnnotation): ?Type {
|
function makeIntersection(ctx: Context, node: IntersectionTypeAnnotation): ?Type {
|
||||||
|
@ -307,10 +280,7 @@ function makeIntersection(ctx: Context, node: IntersectionTypeAnnotation): ?Type
|
||||||
return parts[0];
|
return parts[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return t.createIntersection(parts);
|
||||||
kind: 'intersection',
|
|
||||||
parts,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeReference(ctx: Context, node: GenericTypeAnnotation): ?Type {
|
function makeReference(ctx: Context, node: GenericTypeAnnotation): ?Type {
|
||||||
|
@ -324,10 +294,7 @@ function makeReference(ctx: Context, node: GenericTypeAnnotation): ?Type {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return t.createReference(t.clone(type.id));
|
||||||
kind: 'reference',
|
|
||||||
to: type.id.slice(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -1,35 +1,26 @@
|
||||||
import wu from 'wu';
|
import wu from 'wu';
|
||||||
|
|
||||||
import {invariant, clone} from './utils';
|
import {invariant} from './utils';
|
||||||
import type {Type, TypeId} from './types';
|
import type {Type, TypeId} from './types';
|
||||||
|
import * as t from './types';
|
||||||
|
|
||||||
function object(params: (?Type)[]): ?Type {
|
function object(params: (?Type)[]): ?Type {
|
||||||
invariant(params.length === 0);
|
invariant(params.length === 0);
|
||||||
|
|
||||||
return {
|
return t.createMap(t.createMixed(), t.createMixed());
|
||||||
kind: 'map',
|
|
||||||
keys: {kind: 'mixed'},
|
|
||||||
values: {kind: 'mixed'},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buffer(params: (?Type)[]): ?Type {
|
function buffer(params: (?Type)[]): ?Type {
|
||||||
invariant(params.length === 0);
|
invariant(params.length === 0);
|
||||||
|
|
||||||
return {
|
return t.createReference(['Buffer']);
|
||||||
kind: 'reference',
|
|
||||||
to: ['Buffer'],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function array(params: (?Type)[]): ?Type {
|
function array(params: (?Type)[]): ?Type {
|
||||||
invariant(params.length === 1);
|
invariant(params.length === 1);
|
||||||
invariant(params[0]);
|
invariant(params[0]);
|
||||||
|
|
||||||
return {
|
return t.createArray(t.clone(params[0]));
|
||||||
kind: 'array',
|
|
||||||
items: params[0],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function elemType(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
function elemType(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
@ -51,7 +42,7 @@ function elemType(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
const field = wu(record.fields).find(field => field.name === key.value);
|
const field = wu(record.fields).find(field => field.name === key.value);
|
||||||
|
|
||||||
// TODO: what about removing "id"?
|
// TODO: what about removing "id"?
|
||||||
return field ? clone(field.value) : null;
|
return field ? t.clone(field.value) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stripMaybe(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
function stripMaybe(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
@ -65,10 +56,10 @@ function stripMaybe(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
|
||||||
// TODO: support for unions and nested maybe.
|
// TODO: support for unions and nested maybe.
|
||||||
if (maybe.kind !== 'maybe') {
|
if (maybe.kind !== 'maybe') {
|
||||||
return clone(ref);
|
return t.clone(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
return clone(maybe.value);
|
return t.clone(maybe.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function shape(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
function shape(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
@ -83,14 +74,14 @@ function shape(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
invariant(record.kind === 'record');
|
invariant(record.kind === 'record');
|
||||||
|
|
||||||
const fields = wu(record.fields)
|
const fields = wu(record.fields)
|
||||||
.map(clone)
|
.map(field => ({
|
||||||
.tap(field => field.required = false)
|
name: field.name,
|
||||||
|
value: t.clone(field.value),
|
||||||
|
required: false,
|
||||||
|
}))
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
return {
|
return t.createRecord(fields);
|
||||||
kind: 'record',
|
|
||||||
fields,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function unwrap(params: (?Type)[]): ?Type {
|
function unwrap(params: (?Type)[]): ?Type {
|
||||||
|
@ -98,7 +89,7 @@ function unwrap(params: (?Type)[]): ?Type {
|
||||||
|
|
||||||
const [type] = params;
|
const [type] = params;
|
||||||
|
|
||||||
return type ? clone(type) : null;
|
return type ? t.clone(type) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function keys(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
function keys(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
@ -114,15 +105,12 @@ function keys(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
|
||||||
const variants = wu(record.fields)
|
const variants = wu(record.fields)
|
||||||
.pluck('name')
|
.pluck('name')
|
||||||
.map(name => ({kind: 'literal', value: name}))
|
.map(t.createLiteral)
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
// TODO: empty records.
|
// TODO: empty records.
|
||||||
|
|
||||||
return {
|
return t.createUnion(variants);
|
||||||
kind: 'union',
|
|
||||||
variants,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function values(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
function values(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
@ -138,16 +126,13 @@ function values(params: (?Type)[], resolve: TypeId => Type): ?Type {
|
||||||
|
|
||||||
const variants = wu(record.fields)
|
const variants = wu(record.fields)
|
||||||
.pluck('value')
|
.pluck('value')
|
||||||
.map(clone)
|
.map(t.clone)
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
// TODO: empty records.
|
// TODO: empty records.
|
||||||
// TODO: dedup values.
|
// TODO: dedup values.
|
||||||
|
|
||||||
return {
|
return t.createUnion(variants);
|
||||||
kind: 'union',
|
|
||||||
variants,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {invariant} from './utils';
|
import {invariant} from './utils';
|
||||||
|
|
||||||
import type {Type} from './types';
|
import type {Type} from './types';
|
||||||
|
import * as t from './types';
|
||||||
|
|
||||||
export type Pragma =
|
export type Pragma =
|
||||||
| TypePragma;
|
| TypePragma;
|
||||||
|
@ -21,15 +22,10 @@ export function extractPragmas(text: string): Pragma[] {
|
||||||
|
|
||||||
invariant(['i32', 'i64', 'u32', 'u64', 'f32', 'f64'].includes(repr));
|
invariant(['i32', 'i64', 'u32', 'u64', 'f32', 'f64'].includes(repr));
|
||||||
|
|
||||||
const pragma = {
|
pragmas.push({
|
||||||
kind: 'type',
|
kind: 'type',
|
||||||
value: {
|
value: t.createNumber(repr),
|
||||||
kind: 'number',
|
});
|
||||||
repr,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pragmas.push(pragma);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pragmas;
|
return pragmas;
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default function* traverse(node: Node): Generator<Node, void, boolean> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
const subNode = (node: Object)[key];
|
const subNode = (node: $FlowFixMe)[key];
|
||||||
|
|
||||||
if (subNode instanceof Array) {
|
if (subNode instanceof Array) {
|
||||||
for (const node of subNode) {
|
for (const node of subNode) {
|
||||||
|
|
70
src/types.js
70
src/types.js
|
@ -92,3 +92,73 @@ export type ReferenceType = BaseType & {
|
||||||
kind: 'reference',
|
kind: 'reference',
|
||||||
to: TypeId,
|
to: TypeId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createRecord = (fields: *): RecordType => ({kind: 'record', fields});
|
||||||
|
export const createArray = (items: *): ArrayType => ({kind: 'array', items});
|
||||||
|
export const createTuple = (items: *): TupleType => ({kind: 'tuple', items});
|
||||||
|
export const createMap = (keys: *, values: *): MapType => ({kind: 'map', keys, values});
|
||||||
|
export const createUnion = (variants: *): UnionType => ({kind: 'union', variants});
|
||||||
|
export const createIntersection = (parts: *): IntersectionType => ({kind: 'intersection', parts});
|
||||||
|
export const createMaybe = (value: *): MaybeType => ({kind: 'maybe', value});
|
||||||
|
export const createNumber = (repr: *): NumberType => ({kind: 'number', repr});
|
||||||
|
export const createString = (): StringType => ({kind: 'string'});
|
||||||
|
export const createBoolean = (): BooleanType => ({kind: 'boolean'});
|
||||||
|
export const createLiteral = (value: *): LiteralType => ({kind: 'literal', value});
|
||||||
|
export const createAny = () => ({kind: 'any'});
|
||||||
|
export const createMixed = () => ({kind: 'mixed'});
|
||||||
|
export const createReference = (to: *) => ({kind: 'reference', to});
|
||||||
|
|
||||||
|
declare function clone(Type): Type;
|
||||||
|
declare function clone(TypeId): TypeId;
|
||||||
|
declare function clone(?Type): ?Type;
|
||||||
|
export function clone(type: ?Type | TypeId): ?Type | TypeId {
|
||||||
|
if (!type) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type instanceof Array) {
|
||||||
|
return type.slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloneType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cloneType(type: Type): Type {
|
||||||
|
switch (type.kind) {
|
||||||
|
case 'record':
|
||||||
|
const fields = type.fields.map(field => ({
|
||||||
|
name: field.name,
|
||||||
|
value: clone(field.value),
|
||||||
|
required: field.required,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return createRecord(fields);
|
||||||
|
case 'array':
|
||||||
|
return createArray(clone(type.items));
|
||||||
|
case 'tuple':
|
||||||
|
return createTuple(type.items.map(clone));
|
||||||
|
case 'map':
|
||||||
|
return createMap(clone(type.keys), clone(type.values));
|
||||||
|
case 'union':
|
||||||
|
return createUnion(type.variants.map(clone));
|
||||||
|
case 'intersection':
|
||||||
|
return createIntersection(type.parts.map(clone));
|
||||||
|
case 'maybe':
|
||||||
|
return createMaybe(clone(type.value));
|
||||||
|
case 'number':
|
||||||
|
return createNumber(type.repr);
|
||||||
|
case 'string':
|
||||||
|
return createString();
|
||||||
|
case 'boolean':
|
||||||
|
return createBoolean();
|
||||||
|
case 'literal':
|
||||||
|
return createLiteral(type.value);
|
||||||
|
case 'any':
|
||||||
|
return createAny();
|
||||||
|
case 'mixed':
|
||||||
|
return createMixed();
|
||||||
|
case 'reference':
|
||||||
|
default:
|
||||||
|
return createReference(type.to.slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
19
src/utils.js
19
src/utils.js
|
@ -9,22 +9,3 @@ export function last<T>(list: T[]): T {
|
||||||
|
|
||||||
return list[list.length - 1];
|
return list[list.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clone<T>(that: T): T {
|
|
||||||
if (that == null || typeof that !== 'object') {
|
|
||||||
return that;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (that instanceof Array) {
|
|
||||||
return that.map(clone);
|
|
||||||
}
|
|
||||||
|
|
||||||
const obj = {};
|
|
||||||
|
|
||||||
for (const key in that) {
|
|
||||||
obj[key] = clone(that[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: we skip complex objects.
|
|
||||||
return (obj: $FlowFixMe);
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import wu from 'wu';
|
||||||
import collect from '../src';
|
import collect from '../src';
|
||||||
|
|
||||||
function run(title) {
|
function run(title) {
|
||||||
let actual, expected: any;
|
let actual, expected: $FlowFixMe;
|
||||||
|
|
||||||
// Run the collector only if the suite will be checked.
|
// Run the collector only if the suite will be checked.
|
||||||
before(() => {
|
before(() => {
|
||||||
|
|
Loading…
Reference in New Issue