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
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"devDependencies": {
"@hyperjump/json-schema": "1.6.7",
"@types/jest": "^29.5.14",
"chalk": "^5.4.1",
"concurrently": "^8.2.2",
"jest": "^29.7.0",
"lerna": "^8.0.2",
Expand Down
18 changes: 18 additions & 0 deletions packages/format/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Config } from "jest";

const config: Config = {
displayName: "@ethdebug/format",
preset: "ts-jest",
testEnvironment: "node",
moduleFileExtensions: ["ts", "js"],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
modulePathIgnorePatterns: ["<rootDir>/dist/"],
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
transform: {
'^.+\\.tsx?$': "ts-jest"
},
};

export default config;
File renamed without changes.
File renamed without changes.
9 changes: 8 additions & 1 deletion packages/format/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"prepare:yamls": "node ./bin/generate-schema-yamls.js > yamls.ts",
"prepare": "yarn prepare:yamls && tsc",
"clean": "rm -rf dist && rm yamls.ts",
"test": "node --experimental-vm-modules $(yarn bin jest)",
"watch:typescript": "tsc --watch",
"watch:schemas": "nodemon --watch ../../schemas -e 'yaml' --exec 'yarn prepare:yamls'",
"watch": "concurrently --names=tsc,schemas \"yarn watch:typescript\" \"yarn watch:schemas\""
Expand All @@ -21,8 +22,14 @@
"yaml": "^2.3.4"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
"chalk": "^4.1.0",
"concurrently": "^8.2.2",
"nodemon": "^3.0.2"
"jest": "^29.7.0",
"nodemon": "^3.0.2",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
},
"publishConfig": {
"access": "public"
Expand Down
16 changes: 8 additions & 8 deletions packages/format/src/describe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ export function describeSchema({
}

return referencesId(schema)
? describeSchemaById({ schema, pointer })
? describeSchemaById({ schema, ...(pointer ? { pointer } : {}) })
: referencesYaml(schema)
? describeSchemaByYaml({ schema, pointer })
: describeSchemaByObject({ schema, pointer });
? describeSchemaByYaml({ schema, ...(pointer ? { pointer } : {}) })
: describeSchemaByObject({ schema, ...(pointer ? { pointer } : {}) });
}

function describeSchemaById({
Expand All @@ -65,7 +65,7 @@ function describeSchemaById({

return {
id,
pointer,
...(pointer ? { pointer } : {}),
yaml,
schema,
rootSchema
Expand All @@ -86,14 +86,14 @@ function describeSchemaByYaml({
if (id) {
return {
id,
pointer,
...(pointer ? { pointer } : {}),
yaml,
schema,
rootSchema
}
} else {
return {
pointer,
...(pointer ? { pointer } : {}),
yaml,
schema,
rootSchema
Expand All @@ -116,14 +116,14 @@ function describeSchemaByObject({
if (id) {
return {
id,
pointer,
...(pointer ? { pointer } : {}),
yaml,
schema,
rootSchema
}
} else {
return {
pointer,
...(pointer ? { pointer } : {}),
yaml,
schema,
rootSchema
Expand Down
2 changes: 2 additions & 0 deletions packages/format/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from "./describe";
export { schemas, schemaIds, type Schema } from "./schemas";

export * from "./types";
37 changes: 37 additions & 0 deletions packages/format/src/types/data/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { expect, describe, it } from "@jest/globals";

import { describeSchema } from "../../describe";

import { Data } from "./index.js";

describe("type guards", () => {
const schemaGuards = [
{
schema: {
id: "schema:ethdebug/format/data/value"
},
guard: Data.isValue
},
{
schema: {
id: "schema:ethdebug/format/data/unsigned"
},
guard: Data.isUnsigned
},
{
schema: {
id: "schema:ethdebug/format/data/hex"
},
guard: Data.isHex
},
] as const;

it.each(schemaGuards)("matches its examples", ({
guard,
...describeSchemaOptions
}) => {
const { schema: { examples = [] } } = describeSchema(describeSchemaOptions);

expect(guard).toSatisfyAll(examples);
});
});
20 changes: 20 additions & 0 deletions packages/format/src/types/data/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export namespace Data {
export type Value =
| Unsigned
| Hex;

export const isValue = (value: unknown): value is Value =>
[isUnsigned, isHex].some(guard => guard(value));

export type Unsigned = number;

export const isUnsigned = (value: unknown): value is Unsigned =>
typeof value === "number" && value >= 0;

export type Hex = string;

const hexPattern = new RegExp(/^0x[0-9a-fA-F]{1,}$/);

export const isHex = (value: unknown): value is Hex =>
typeof value === "string" && hexPattern.test(value);
}
5 changes: 5 additions & 0 deletions packages/format/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./data";
export * from "./materials";
export * from "./type";
export * from "./pointer";
export * from "./program";
55 changes: 55 additions & 0 deletions packages/format/src/types/materials/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { expect, describe, it } from "@jest/globals";

import { describeSchema } from "../../describe";

import { Materials } from "./index";

describe("type guards", () => {
const schemaGuards = [
{
schema: {
id: "schema:ethdebug/format/materials/id"
},
guard: Materials.isId
},
{
schema: {
id: "schema:ethdebug/format/materials/reference"
},
guard: Materials.isReference
},
{
schema: {
id: "schema:ethdebug/format/materials/compilation"
},
guard: Materials.isCompilation
},
{
schema: {
id: "schema:ethdebug/format/materials/source"
},
guard: Materials.isSource
},
{
schema: {
id: "schema:ethdebug/format/materials/source-range"
},
guard: Materials.isSourceRange
},
] as const;

for (const { guard, ...describeSchemaOptions } of schemaGuards) {
const { schema } = describeSchemaOptions;
describe(schema.id.slice("schema:".length), () => {
it("matches its examples", () => {
const {
schema: {
examples = []
}
} = describeSchema(describeSchemaOptions);

expect(guard).toSatisfyAll(examples);
});
});
}
});
126 changes: 126 additions & 0 deletions packages/format/src/types/materials/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { Data } from "../data";

export namespace Materials {
export type Id =
| number
| string;

export const isId = (value: unknown): value is Id =>
["number", "string"].includes(typeof value);

// this and `toReference` are a bit janky to ensure Reference<X> can't
// be assigned to Reference<Y> unless X can be assigned to Y
export type Reference<O extends { id: Id; }> = OmitNever<
& OmitNever<{
[K in keyof O]-?: K extends "id" ? O[K] : never;
}>
& (
Reference.Type<O> extends string
? { type?: Reference.Type<O>; }
: { type?: string;}
)
>;

export const isReference = <O extends { id: Id; }>(
value: unknown
): value is Reference<O> =>
typeof value === "object" && !!value &&
"id" in value && isId(value.id);

export function toReference<O extends { id: Id; }>(object: O): Reference<O> {
return {
id: object.id,
...(
([
[isCompilation, "compilation"],
[isSource, "source"]
] as const)
.filter(([guard]) => guard(object))
.map(([_, type]) => ({ type }))
[0] || {}
)
} as unknown as Reference<O>;
}


type OmitNever<T> = {
[K in keyof T as T[K] extends never ? never : K]: T[K]
};


export namespace Reference {
export type Type<O extends { id: Id; }> = {
[T in keyof Types]: O extends Types[T] ? T : never;
}[keyof Types];


type Types = {
"compilation": Compilation,
"source": Source
};

}

export interface Compilation {
id: Id;
compiler: {
name: string;
version: string;
};
settings?: any;
sources: Source[];
}

export const isCompilation = (value: unknown): value is Compilation =>
typeof value === "object" && !!value &&
"id" in value && isId(value.id) &&
"compiler" in value && typeof value.compiler === "object" && !!value.compiler &&
"name" in value.compiler && typeof value.compiler.name === "string" &&
"version" in value.compiler && typeof value.compiler.version === "string" &&
"sources" in value && value.sources instanceof Array &&
value.sources.every(isSource);

export interface Source {
id: Id;
path: string;
contents: string;
encoding?: string;
language: string;
}

export const isSource = (value: unknown): value is Source =>
typeof value === "object" && !!value &&
"id" in value && isId(value.id) &&
"path" in value && typeof value.path === "string" &&
"contents" in value && typeof value.contents === "string" &&
"language" in value && typeof value.language === "string" &&
(
!("encoding" in value) || typeof value.encoding === "string"
);


export interface SourceRange {
compilation?: Reference<Compilation>;
source: Reference<Source>;
range?: {
offset: Data.Value;
length: Data.Value;
};
}

export const isSourceRange = (value: unknown): value is SourceRange =>
typeof value === "object" && !!value &&
"source" in value && isReference<Source>(value.source) &&
(
!("range" in value) ||
(
typeof value.range === "object" && !!value.range &&
"offset" in value.range && Data.isValue(value.range.offset) &&
"length" in value.range && Data.isValue(value.range.length)
)
) &&
(
!("compilation" in value) || isReference<Compilation>(value.compilation)
);

}
1 change: 1 addition & 0 deletions packages/format/src/types/pointer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Pointer, isPointer } from "./pointer";
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
/// <reference path="../../../jest.d.ts" />
import { expect, describe, it } from "@jest/globals";
import chalk from "chalk";

import { describeSchema } from "@ethdebug/format";

import { Pointer, isPointer } from "./index.js";
import { describeSchema } from "../../describe";

import { Pointer, isPointer } from "./pointer";

describe("type guards", () => {
const expressionSchema = {
Expand Down
Loading