Skip to content
Open
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
8 changes: 4 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

export {Graph} from './lib/graph';
export {version} from './lib/version';
export * as json from './lib/json';
export * as alg from './lib/alg/index';
export {Graph} from './lib/graph.js';
export {version} from './lib/version.js';
export * as json from './lib/json.js';
export * as alg from './lib/alg/index.js';

export type {GraphOptions, Edge, Path, WeightFunction, EdgeFunction, Label} from './lib/types.js';
4 changes: 2 additions & 2 deletions lib/alg/bellman-ford.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from '../graph';
import type {Edge, EdgeFunction, Path, WeightFunction} from '../types';
import {Graph} from '../graph.js';
import type {Edge, EdgeFunction, Path, WeightFunction} from '../types.js';

const DEFAULT_WEIGHT_FUNC: WeightFunction = () => 1;

Expand Down
2 changes: 1 addition & 1 deletion lib/alg/components.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Graph} from '../graph';
import {Graph} from '../graph.js';

/**
* Finds all connected components in a graph and returns an array of these components.
Expand Down
4 changes: 2 additions & 2 deletions lib/alg/dfs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from '../graph';
import {reduce} from './reduce';
import {Graph} from '../graph.js';
import {reduce} from './reduce.js';

/*
* Pre- or post-order traversal on the input graph.
Expand Down
6 changes: 3 additions & 3 deletions lib/alg/dijkstra-all.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Graph} from '../graph';
import type {EdgeFunction, Path, WeightFunction} from '../types';
import {dijkstra} from './dijkstra';
import {Graph} from '../graph.js';
import type {EdgeFunction, Path, WeightFunction} from '../types.js';
import {dijkstra} from './dijkstra.js';

/**
* This function finds the shortest path from each node to every other reachable node in
Expand Down
6 changes: 3 additions & 3 deletions lib/alg/dijkstra.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Graph} from '../graph';
import {PriorityQueue} from '../data/priority-queue';
import type {Edge, EdgeFunction, Path, WeightFunction} from '../types';
import {Graph} from '../graph.js';
import {PriorityQueue} from '../data/priority-queue.js';
import type {Edge, EdgeFunction, Path, WeightFunction} from '../types.js';

const DEFAULT_WEIGHT_FUNC: WeightFunction = () => 1;

Expand Down
2 changes: 1 addition & 1 deletion lib/alg/extract-path.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {Path} from '../types';
import type {Path} from '../types.js';

interface ExtractedPath {
weight: number;
Expand Down
4 changes: 2 additions & 2 deletions lib/alg/find-cycles.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from '../graph';
import {tarjan} from './tarjan';
import {Graph} from '../graph.js';
import {tarjan} from './tarjan.js';

/**
* Given a Graph, graph, this function returns all nodes that are part of a cycle. As there
Expand Down
4 changes: 2 additions & 2 deletions lib/alg/floyd-warshall.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from '../graph';
import type {EdgeFunction, Path, WeightFunction} from '../types';
import {Graph} from '../graph.js';
import type {EdgeFunction, Path, WeightFunction} from '../types.js';

const DEFAULT_WEIGHT_FUNC: WeightFunction = () => 1;

Expand Down
26 changes: 13 additions & 13 deletions lib/alg/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export {bellmanFord} from './bellman-ford';
export {components} from './components';
export {dijkstra} from './dijkstra';
export {dijkstraAll} from './dijkstra-all';
export {findCycles} from './find-cycles';
export {floydWarshall} from './floyd-warshall';
export {isAcyclic} from './is-acyclic';
export {postorder} from './postorder';
export {preorder} from './preorder';
export {prim} from './prim';
export {shortestPaths} from './shortest-paths';
export {tarjan} from './tarjan';
export {topsort, CycleException} from './topsort';
export {bellmanFord} from './bellman-ford.js';
export {components} from './components.js';
export {dijkstra} from './dijkstra.js';
export {dijkstraAll} from './dijkstra-all.js';
export {findCycles} from './find-cycles.js';
export {floydWarshall} from './floyd-warshall.js';
export {isAcyclic} from './is-acyclic.js';
export {postorder} from './postorder.js';
export {preorder} from './preorder.js';
export {prim} from './prim.js';
export {shortestPaths} from './shortest-paths.js';
export {tarjan} from './tarjan.js';
export {topsort, CycleException} from './topsort.js';
4 changes: 2 additions & 2 deletions lib/alg/is-acyclic.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from '../graph';
import {CycleException, topsort} from './topsort';
import {Graph} from '../graph.js';
import {CycleException, topsort} from './topsort.js';

/**
* Given a Graph, graph, this function returns true if the graph has no cycles and returns false if it
Expand Down
4 changes: 2 additions & 2 deletions lib/alg/postorder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from '../graph';
import {dfs} from './dfs';
import {Graph} from '../graph.js';
import {dfs} from './dfs.js';

/**
* Performs post-order depth first traversal on the input graph. If the graph is
Expand Down
4 changes: 2 additions & 2 deletions lib/alg/preorder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from '../graph';
import {dfs} from './dfs';
import {Graph} from '../graph.js';
import {dfs} from './dfs.js';

/**
* Performs pre-order depth first traversal on the input graph. If the graph is
Expand Down
6 changes: 3 additions & 3 deletions lib/alg/prim.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Graph} from '../graph';
import {PriorityQueue} from '../data/priority-queue';
import type {Edge, WeightFunction} from '../types';
import {Graph} from '../graph.js';
import {PriorityQueue} from '../data/priority-queue.js';
import type {Edge, WeightFunction} from '../types.js';

/**
* Prim's algorithm takes a connected undirected graph and generates a minimum spanning tree. This
Expand Down
2 changes: 1 addition & 1 deletion lib/alg/reduce.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Graph} from '../graph';
import {Graph} from '../graph.js';

/*
* A helper that preforms a pre- or post-order traversal on the input graph
Expand Down
8 changes: 4 additions & 4 deletions lib/alg/shortest-paths.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {dijkstra} from './dijkstra';
import {bellmanFord} from './bellman-ford';
import {Graph} from '../graph';
import type {EdgeFunction, Path, WeightFunction} from '../types';
import {dijkstra} from './dijkstra.js';
import {bellmanFord} from './bellman-ford.js';
import {Graph} from '../graph.js';
import type {EdgeFunction, Path, WeightFunction} from '../types.js';

export function shortestPaths(
g: Graph,
Expand Down
2 changes: 1 addition & 1 deletion lib/alg/tarjan.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Graph} from '../graph';
import {Graph} from '../graph.js';

interface VisitedEntry {
onStack: boolean;
Expand Down
2 changes: 1 addition & 1 deletion lib/alg/topsort.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Graph} from '../graph';
import {Graph} from '../graph.js';

export class CycleException extends Error {
constructor(message?: string) {
Expand Down
2 changes: 1 addition & 1 deletion lib/graph.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {Edge, EdgeLabelFactory, GraphOptions, Label, NodeLabelFactory} from './types';
import type {Edge, EdgeLabelFactory, GraphOptions, Label, NodeLabelFactory} from './types.js';

const DEFAULT_EDGE_NAME = "\x00";
const GRAPH_NODE = "\x00";
Expand Down
4 changes: 2 additions & 2 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {Graph} from './graph';
export {version} from './version';
export {Graph} from './graph.js';
export {version} from './version.js';
4 changes: 2 additions & 2 deletions lib/json.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Graph} from './graph';
import type {GraphOptions, Label} from './types';
import {Graph} from './graph.js';
import type {GraphOptions, Label} from './types.js';

interface JsonGraph {
options: GraphOptions;
Expand Down
103 changes: 103 additions & 0 deletions test/dist-types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Regression test for the published type declarations (dagrejs/graphlib #238).
//
// tsconfig.build.json compiles with moduleResolution "nodenext", so the build
// itself now rejects an extensionless relative specifier in lib/** or index.ts.
// This test covers the half that a compile of this repo cannot: that a real
// dependent resolving @dagrejs/graphlib through node_modules and the package
// "exports" map gets working types out of the generated declarations. That
// wiring (package.json "exports" -> "types") can regress on its own, as #233
// showed.
//
// The failure mode has two faces, and the test catches both. With skipLibCheck
// off, tsc reports TS2834 against dist/types/index.d.ts. With it on -- the
// common default -- that error is silenced while every graphlib export quietly
// degrades to `any`; the @ts-expect-error in the consumer below is what catches
// that quieter case, since it only holds if the types resolved.
//
// Declarations are built fresh into a temp package rather than read from the
// committed dist/, so this tests the current source and leaves the working tree
// alone. The real package.json is copied in unmodified, so the "exports" map
// under test is the one that ships.

import {execFileSync} from 'child_process';
import {copyFileSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync} from 'fs';
import {tmpdir} from 'os';
import {join} from 'path';

const repoRoot = process.cwd();
// Resolved rather than hardcoded so this survives a hoisted or pnpm layout.
const tsc = require.resolve('typescript/bin/tsc');

const consumerTsconfig = {
compilerOptions: {
module: 'nodenext',
moduleResolution: 'nodenext',
target: 'es2022',
strict: true,
skipLibCheck: false,
noEmit: true,
// The consumer lives under the OS temp dir, so tsc's automatic @types
// lookup would walk up into directories we do not control and check
// whatever it found. Pin it to nothing; graphlib needs no ambient types.
types: [],
},
include: ['src'],
};

// Mirrors the #238 repro: a plain consumer calling into the public API.
const consumerSource = `import {Graph, alg, json} from '@dagrejs/graphlib';
import type {Edge} from '@dagrejs/graphlib';

const g = new Graph();
g.setEdge('a', 'b');
const edges: Edge[] = g.edges();
alg.isAcyclic(g);
json.write(g);

// If the declarations failed to resolve, Graph is \`any\`, this assignment stops
// erroring, and tsc flags the directive as unused (TS2578).
// @ts-expect-error nodes() returns string[], not number
const nodes: number = g.nodes();
`;

// tsc exits non-zero on any diagnostic, so execFileSync throws and fails the
// test; 'inherit' puts the diagnostics themselves in the jest output.
function runTsc(args: string[], cwd: string): void {
execFileSync(process.execPath, [tsc, ...args], {cwd, stdio: ['ignore', 'inherit', 'inherit']});
}

describe('dist type declarations', () => {
let tmpDir: string;
let consumerDir: string;

beforeAll(() => {
tmpDir = mkdtempSync(join(tmpdir(), 'graphlib-dist-types-'));
const packageDir = join(tmpDir, 'package');
consumerDir = join(tmpDir, 'consumer');

// A stand-in for the published package: the real package.json plus
// declarations emitted from the current source.
mkdirSync(packageDir);
copyFileSync(join(repoRoot, 'package.json'), join(packageDir, 'package.json'));
runTsc(['-p', 'tsconfig.build.json', '--outDir', join(packageDir, 'dist', 'types')], repoRoot);

// Resolve that package the way a dependent does, through node_modules
// and the "exports" map, rather than by pointing tsc at the .d.ts.
mkdirSync(join(consumerDir, 'node_modules', '@dagrejs'), {recursive: true});
mkdirSync(join(consumerDir, 'src'));
symlinkSync(packageDir, join(consumerDir, 'node_modules', '@dagrejs', 'graphlib'), 'junction');
writeFileSync(join(consumerDir, 'package.json'), JSON.stringify({name: 'consumer', private: true, type: 'module'}));
writeFileSync(join(consumerDir, 'tsconfig.json'), JSON.stringify(consumerTsconfig));
writeFileSync(join(consumerDir, 'src', 'index.ts'), consumerSource);
}, 30000);

afterAll(() => {
if (tmpDir) {
rmSync(tmpDir, {recursive: true, force: true});
}
});

it('type-check cleanly in a NodeNext consumer', () => {
runTsc(['-p', 'tsconfig.json'], consumerDir);
}, 30000);
});
2 changes: 2 additions & 0 deletions tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true,
Expand Down