Skip to content

Commit

Permalink
switch to tsd to check types
Browse files Browse the repository at this point in the history
Fix errors that arose as a result
  • Loading branch information
erikbrinkman committed Jun 13, 2021
1 parent ff06883 commit 59fd705
Show file tree
Hide file tree
Showing 22 changed files with 678 additions and 224 deletions.
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@
]
},
"scripts": {
"format": "prettier --write {src,test,types}/**/*.ts {,.}*.json && import-sort --write {src,test,types}/**/*.ts",
"lint": "prettier --check {src,test,types}/**/*.ts {,.}*.json && tsc --noEmit && eslint {src,test,types}/**/*.ts",
"fix": "eslint --fix {src,test,types}/**/*.ts",
"build": "tsc -p tsconfig.build.json && esbuild dist/index.js --bundle --minify --external:fs --external:child_process --global-name=d3 --banner:js=\"$(preamble)\nvar d3 = Object.assign(d3 || {}, (() => {\" --footer:js='return d3; })())' --outfile=bundle/d3-dag.iife.min.js && esbuild dist/index.js --bundle --minify --format=cjs --platform=node --banner:js=\"$(preamble)\" --outfile=bundle/d3-dag.cjs.min.js && esbuild dist/index.js --bundle --minify --format=esm --external:fs --external:child_process --banner:js=\"$(preamble)\" --outfile=bundle/d3-dag.esm.min.js",
"test": "tsc -p tsconfig.test.json && jest --coverage && yarn lint",
"prepare": "yarn jest --clear-cache && yarn test && yarn build",
"prettier": "prettier {src,test,test-d,types}/**/*.ts {,.}*.json",
"format": "yarn prettier --write && import-sort --write {src,test,test-d,types}/**/*.ts",
"lint": "yarn prettier --check && eslint {src,test,test-d,types}/**/*.ts",
"build": "rm -rf dist && tsc -p tsconfig.build.json",
"bundle": "rm -rf bundle && esbuild dist/index.js --bundle --minify --external:fs --external:child_process --global-name=d3 --banner:js=\"$(preamble)\nvar d3 = Object.assign(d3 || {}, (() => {\" --footer:js='return d3; })())' --outfile=bundle/d3-dag.iife.min.js && esbuild dist/index.js --bundle --minify --format=cjs --platform=node --banner:js=\"$(preamble)\" --outfile=bundle/d3-dag.cjs.min.js && esbuild dist/index.js --bundle --minify --format=esm --external:fs --external:child_process --banner:js=\"$(preamble)\" --outfile=bundle/d3-dag.esm.min.js",
"test": "tsc && jest --coverage && yarn build && tsd && yarn lint",
"prepare": "jest --clear-cache && yarn test && yarn build && yarn bundle",
"todo": "grep -rI --color TODO src test types",
"docs": "typedoc --out docs --excludeInternal --media resources src && touch docs/.nojekyll"
"docs": "rm -rf docs && typedoc --out docs --excludeInternal --media resources src && touch docs/.nojekyll"
},
"dependencies": {
"d3-array": "^3.0.1",
Expand All @@ -67,6 +68,7 @@
"jest": "^27.0.4",
"package-preamble": "^0.1.0",
"prettier": "^2.3.1",
"tsd": "^0.17.0",
"typedoc": "^0.20.36",
"typescript": "^4.3.2"
}
Expand Down
4 changes: 3 additions & 1 deletion src/dag/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class LayoutChildLink<NodeDatum, LinkDatum> {
/**
* The concrete class backing the {@link Link} interface.
*/
class LayoutLink<NodeDatum, LinkDatum> {
class LayoutLink<NodeDatum, LinkDatum>
implements DagLink<NodeDatum, LinkDatum>
{
constructor(
readonly source: DagNode<NodeDatum, LinkDatum>,
readonly target: DagNode<NodeDatum, LinkDatum>,
Expand Down
3 changes: 3 additions & 0 deletions src/dag/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export interface DagLink<NodeDatum = unknown, LinkDatum = unknown> {
/** */
export interface Dag<NodeDatum = unknown, LinkDatum = unknown>
extends Iterable<DagNode<NodeDatum, LinkDatum>> {
// XXX this is unused, but necessary for typescript to typecheck
__typing_sentinel__?: NodeDatum;

/** */
iroots(): FluentIterable<DagNode<NodeDatum, LinkDatum>>;

Expand Down
28 changes: 12 additions & 16 deletions src/sugiyama/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,16 @@ type SNSDagNode<Op extends SugiNodeSizeAccessor> = SugiDataDagNode<
Parameters<Op>[0]["data"]
>;

type OpsNodeDatum<Ops extends Operators> = NodeDatum<
LDagNode<Ops["layering"]>
> &
NodeDatum<OpDagNode<Ops["decross"]>> &
NodeDatum<OpDagNode<Ops["coord"]>> &
NodeDatum<SNSDagNode<Ops["sugiNodeSize"]>>;
type OpsLinkDatum<Ops extends Operators> = LinkDatum<
LDagNode<Ops["layering"]>
> &
LinkDatum<OpDagNode<Ops["decross"]>> &
LinkDatum<OpDagNode<Ops["coord"]>> &
LinkDatum<SNSDagNode<Ops["sugiNodeSize"]>>;
type OpsDag<Ops extends Operators> = Dag<
NodeDatum<LDagNode<Ops["layering"]>> &
NodeDatum<OpDagNode<Ops["decross"]>> &
NodeDatum<OpDagNode<Ops["coord"]>> &
NodeDatum<SNSDagNode<Ops["sugiNodeSize"]>>,
LinkDatum<LDagNode<Ops["layering"]>> &
LinkDatum<OpDagNode<Ops["decross"]>> &
LinkDatum<OpDagNode<Ops["coord"]>> &
LinkDatum<SNSDagNode<Ops["sugiNodeSize"]>>
>;

/**
* The operator used to layout a {@link Dag} using the sugiyama method.
Expand All @@ -117,7 +115,7 @@ export interface SugiyamaOperator<Ops extends Operators = Operators> {
* DAG nodes will have added properties from {@link SugiyamaNode}. In addition,
* each link will have points reset and assigned.
*/
(dag: Dag<OpsNodeDatum<Ops>, OpsLinkDatum<Ops>>): SugiyamaInfo;
(dag: OpsDag<Ops>): SugiyamaInfo;

/**
* Set the {@link LayeringOperator}. See {@link "sugiyama/layering/index" |
Expand Down Expand Up @@ -213,9 +211,7 @@ function buildOperator<Ops extends Operators>(
size: readonly [number, number] | null;
}
): SugiyamaOperator<Ops> {
function sugiyama(
dag: Dag<OpsNodeDatum<Ops>, OpsLinkDatum<Ops>>
): SugiyamaInfo {
function sugiyama(dag: OpsDag<Ops>): SugiyamaInfo {
// compute layers
options.layering(dag);

Expand Down
4 changes: 0 additions & 4 deletions src/sugiyama/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ export type SugiNode<NodeDatum = unknown, LinkDatum = unknown> = DagNode<
SugiData<NodeDatum, LinkDatum>,
undefined
>;
export type SugiDag<NodeDatum = unknown, LinkDatum = unknown> = Dag<
SugiData<NodeDatum, LinkDatum>,
undefined
>;

export type SugiDataDagNode<S extends SugiData> = S extends {
node: DagNode;
Expand Down
53 changes: 53 additions & 0 deletions test-d/dag/connect.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ConnectDatum, IdOperator, connect } from "../../src/dag/create";
import { expectAssignable, expectNotAssignable, expectType } from "tsd";

import { Dag } from "../../src/dag";

// initial types
interface Init {
[0]: string;
[1]: string;
}

const init = connect();
expectAssignable<(inp: Init[]) => Dag<ConnectDatum, Init>>(init);
expectNotAssignable<(inp: unknown[]) => Dag<ConnectDatum, unknown>>(init);

// subtypes are preserved
interface Extra extends Init {
extra: true;
}
declare const extraArray: Extra[];
expectType<Dag<ConnectDatum, Extra>>(init(extraArray));

// link data narrows appropriately
interface MyTargetId extends IdOperator<{ target: string }> {
target: true;
}
interface Intermediate {
[0]: string;
target: string;
}
declare const myTargetId: MyTargetId;
const targetId = init.targetId(myTargetId);
expectAssignable<(inp: Intermediate[]) => Dag<ConnectDatum, Intermediate>>(
targetId
);
expectNotAssignable<(inp: Init[]) => Dag<ConnectDatum, Init>>(targetId);
expectType<MyTargetId>(targetId.targetId());

interface MySourceId extends IdOperator<{ source: string }> {
source: true;
}
interface Complex {
source: string;
target: string;
}
declare const mySourceId: MySourceId;
const sourceId = targetId.sourceId(mySourceId);
expectAssignable<(inp: Complex[]) => Dag<ConnectDatum, Complex>>(sourceId);
expectNotAssignable<(inp: Intermediate[]) => Dag<ConnectDatum, Intermediate>>(
sourceId
);
expectType<MyTargetId>(sourceId.targetId());
expectType<MySourceId>(sourceId.sourceId());
45 changes: 45 additions & 0 deletions test-d/dag/hierarchy.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
ChildrenDataOperator,
ChildrenOperator,
hierarchy
} from "../../src/dag/create";
import { expectAssignable, expectNotAssignable, expectType } from "tsd";

import { Dag } from "../../src/dag";

// initial types
interface Init {
children?: readonly Init[] | undefined;
}

const init = hierarchy();
expectAssignable<(...inp: Init[]) => Dag<Init, undefined>>(init);
expectNotAssignable<(...inp: unknown[]) => Dag<unknown, unknown>>(init);

// data narrows appropriately
interface MyChildrenData
extends ChildrenDataOperator<{ node: true }, { link: true }> {
myChildrenData: true;
}
declare const myChildrenData: MyChildrenData;
const childrenData = init.childrenData(myChildrenData);
expectAssignable<
(...inp: { node: true }[]) => Dag<{ node: true }, { link: true }>
>(childrenData);
expectNotAssignable<(...inp: Init[]) => Dag<Init, undefined>>(childrenData);
expectType<MyChildrenData>(childrenData.children().wrapped);
expectType<MyChildrenData>(childrenData.childrenData());

interface MyChildren extends ChildrenOperator<{ id: string }> {
myChildren: true;
}
declare const myChildren: MyChildren;
const children = childrenData.children(myChildren);
expectAssignable<(...inp: { id: string }[]) => Dag<{ id: string }, undefined>>(
children
);
expectNotAssignable<
(...inp: { node: true }[]) => Dag<{ node: true }, { link: true }>
>(children);
expectType<MyChildren>(children.children());
expectType<MyChildren>(children.childrenData().wrapped);
72 changes: 72 additions & 0 deletions test-d/dag/stratify.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
IdOperator,
ParentDataOperator,
ParentIdsOperator,
stratify
} from "../../src/dag/create";
import { expectAssignable, expectNotAssignable, expectType } from "tsd";

import { Dag } from "../../src/dag";

// initial types
interface Init {
id: string;
parentIds: string[];
}

const init = stratify();
expectAssignable<(inp: Init[]) => Dag<Init, undefined>>(init);
expectNotAssignable<(inp: unknown[]) => Dag<unknown, unknown>>(init);

// subtypes are preserved
interface Extra extends Init {
extra: true;
}
declare const extraArray: Extra[];
expectType<Dag<Extra, undefined>>(init(extraArray));

// data narrows appropriately
interface MyParentIds extends ParentIdsOperator<{ pids: string[] }> {
myParentIds: true;
}
interface Pids {
id: string;
pids: string[];
}
declare const myParentIds: MyParentIds;
const parentIds = init.parentIds(myParentIds);
expectAssignable<(inp: Pids[]) => Dag<Pids, undefined>>(parentIds);
expectNotAssignable<(inp: Init[]) => Dag<Init, undefined>>(parentIds);
expectType<MyParentIds>(parentIds.parentIds());
expectType<MyParentIds>(parentIds.parentData().wrapped);

interface MyId extends IdOperator<{ myid: string }> {
id: true;
}
interface Ids {
myid: string;
pids: string[];
}
declare const myId: MyId;
const id = parentIds.id(myId);
expectAssignable<(inp: Ids[]) => Dag<Ids, undefined>>(id);
expectNotAssignable<(inp: Pids[]) => Dag<Pids, undefined>>(id);
expectType<MyParentIds>(id.parentIds());
expectType<MyParentIds>(id.parentData().wrapped);
expectType<MyId>(id.id());

interface MyParentData
extends ParentDataOperator<{ node: true }, { link: true }> {
myParentData: true;
}
interface Data {
myid: string;
node: true;
}
declare const myParentData: MyParentData;
const parentData = id.parentData(myParentData);
expectAssignable<(inp: Data[]) => Dag<Data, { link: true }>>(parentData);
expectNotAssignable<(inp: Ids[]) => Dag<Ids, undefined>>(parentData);
expectType<MyParentData>(parentData.parentIds().wrapped);
expectType<MyParentData>(parentData.parentData());
expectType<MyId>(parentData.id());
19 changes: 19 additions & 0 deletions test-d/sugiyama/decross/two-layer.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expectAssignable, expectNotAssignable, expectType } from "tsd";

import { SugiNode } from "../../../src/sugiyama/utils";
import { TwolayerOperator } from "../../../src/sugiyama/twolayer";
import { twoLayer } from "../../../src/sugiyama/decross/two-layer";

const init = twoLayer();
expectAssignable<(inp: SugiNode[][]) => void>(init);

interface MyTwolayer extends TwolayerOperator<{ node: true }, { link: true }> {
myTwoLayer: true;
}
declare const myTwolayer: MyTwolayer;
const custom = init.order(myTwolayer);
expectAssignable<(inp: SugiNode<{ node: true }, { link: true }>[][]) => void>(
custom
);
expectNotAssignable<(inp: SugiNode[][]) => void>(custom);
expectType<MyTwolayer>(custom.order());
33 changes: 33 additions & 0 deletions test-d/sugiyama/layering/simplex.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { GroupAccessor, RankAccessor } from "../../../src/sugiyama/layering";
import { expectAssignable, expectNotAssignable, expectType } from "tsd";

import { Dag } from "../../../src/dag";
import { simplex } from "../../../src/sugiyama/layering/simplex";

const init = simplex();
expectAssignable<(inp: Dag) => void>(init);

interface MyRank extends RankAccessor<{ rank: number }, { link: true }> {
myRank: true;
}
declare const myRank: MyRank;
const rank = init.rank(myRank);
expectAssignable<(inp: Dag<{ rank: number }, { link: true }>) => void>(rank);
expectNotAssignable<(inp: Dag) => void>(rank);
expectType<MyRank>(rank.rank());

interface MyGroup extends GroupAccessor<{ group: string }, { info: string }> {
myGroup: true;
}
declare const myGroup: MyGroup;
const group = rank.group(myGroup);
expectAssignable<
(
inp: Dag<{ rank: number; group: string }, { link: true; info: string }>
) => void
>(group);
expectNotAssignable<(inp: Dag<{ rank: number }, { link: true }>) => void>(
group
);
expectType<MyRank>(group.rank());
expectType<MyGroup>(group.group());
Loading

0 comments on commit 59fd705

Please sign in to comment.