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
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ If you like, you can also run Mocha in watch mode for a specific file, so that u
TZ=America/Los_Angeles yarn tsx node_modules/.bin/mocha --watch test/marks/bar-test.js
```

The tests import `replot`, which package.json maps to `src/index.js`, a file that exists only as the TypeScript source `src/index.ts`; tsx resolves that, which is why Mocha has to run through it here, as it does in `yarn test:mocha`.
The tests import `@dave-hillier/replot`, which the `paths` in tsconfig.json map to the TypeScript source `src/replot.ts`; tsx resolves that, which is why Mocha has to run through it here, as it does in `yarn test:mocha`.

### Snapshot tests

Snapshot tests live in `test/plots` and are registered in [`test/plots/index.ts`](./test/plots/index.ts); see [`test/plots/aapl-bollinger.ts`](./test/plots/aapl-bollinger.ts) for example. Unlike unit tests which only test individual methods, snapshot tests actually visualize data—they’re more representative of how we expect people will use Replot. Snapshot tests can also serve as examples of how to use the Replot API, though note that some of the examples intentionally test edge case of the API and may not embody best practices. Each snapshot test defines a plot by exporting a default async function. For example, here’s a line chart using BLS unemployment data:
Snapshot tests live in `test/plots` and are registered in [`test/plots/registry.ts`](./test/plots/registry.ts); see [`test/plots/aapl-bollinger.ts`](./test/plots/aapl-bollinger.ts) for example. Unlike unit tests which only test individual methods, snapshot tests actually visualize data—they’re more representative of how we expect people will use Replot. Snapshot tests can also serve as examples of how to use the Replot API, though note that some of the examples intentionally test edge case of the API and may not embody best practices. Each snapshot test defines a plot by exporting a default async function. For example, here’s a line chart using BLS unemployment data:

```ts
import * as Plot from "@dave-hillier/replot";
Expand All @@ -91,7 +91,7 @@ export async function lineUnemployment() {

When a snapshot test is run, its output is compared against the SVG or HTML snapshot saved in the `test/output` folder. This makes it easier to review the effect of code changes and to catch unintended changes. Snapshot tests must have deterministic, reproducible behavior; they should not depend on live data, external servers, the current time, the weather, etc. To use randomness in a test, use a seeded random number generator such as [d3.randomLcg](https://d3js.org/d3-random#randomLcg).

To add a new snapshot test, create a new JavaScript file in the `test/plots` folder using the pattern shown above. Then export your snapshot test function from [`test/plots/index.ts`](./test/plots/index.ts). For example:
To add a new snapshot test, create a new JavaScript file in the `test/plots` folder using the pattern shown above. Then export your snapshot test function from [`test/plots/registry.ts`](./test/plots/registry.ts). For example:

```js
export * from "./moby-dick.ts";
Expand Down
2 changes: 1 addition & 1 deletion bundle.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {version} from "./package.json";
export * from "./src/index.ts";
export * from "./src/replot.ts";
2 changes: 1 addition & 1 deletion docs/data/api.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export default {
project.addSourceFilesAtPaths("src/**/*.d.ts");
const allMethods: {name: string; comment: string; href: string}[] = [];
const allOptions: {name: string; context: {name: string; href: string}}[] = [];
const index = project.getSourceFile("src/index.d.ts")!;
const index = project.getSourceFile("src/replot.d.ts")!;
for (const [name, declarations] of index.getExportedDeclarations()) {
if (isInternalMethod(name) || isUndocumentedImperative(name)) continue;
for (const declaration of declarations) {
Expand Down
2 changes: 1 addition & 1 deletion docs/vite.docs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default defineConfig({
resolve: {
alias: {
"@dave-hillier/replot/react": path.resolve(__dirname, "../src/react/api.tsx"),
"@dave-hillier/replot": path.resolve(__dirname, "../src/index.js")
"@dave-hillier/replot": path.resolve(__dirname, "../src/replot.js")
},
dedupe: ["react", "react-dom"]
},
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
},
"license": "ISC",
"type": "module",
"main": "dist/esm/index.js",
"module": "dist/esm/index.js",
"main": "dist/esm/replot.js",
"module": "dist/esm/replot.js",
"jsdelivr": "dist/replot.umd.min.js",
"unpkg": "dist/replot.umd.min.js",
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"types": "./dist/types/replot.d.ts",
"umd": "./dist/replot.umd.min.js",
"default": "./dist/esm/index.js"
"default": "./dist/esm/replot.js"
},
"./react": {
"types": "./dist/types/react/api.d.ts",
"default": "./dist/esm/react/api.js"
},
"./package.json": "./package.json"
},
"types": "dist/types/index.d.ts",
"types": "dist/types/replot.d.ts",
"keywords": [
"react",
"charts",
Expand Down Expand Up @@ -71,7 +71,7 @@
"parity": "tsx scripts/parity.ts"
},
"sideEffects": [
"./dist/esm/index.js"
"./dist/esm/replot.js"
],
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
Expand Down
6 changes: 0 additions & 6 deletions scripts/copy-declarations.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
const source = join(root, "src");
const target = join(root, "dist", "types");

// src/react/index.d.ts is a stub that re-exports "./index.js" (the sibling
// index.tsx). Copying it would clobber the real generated entry point with a
// self-referential export.
const skip = new Set([join("react", "index.d.ts")]);

async function* declarations(dir) {
for (const entry of await readdir(dir, {withFileTypes: true})) {
const path = join(dir, entry.name);
Expand All @@ -30,7 +25,6 @@ async function* declarations(dir) {
let count = 0;
for await (const path of declarations(source)) {
const name = relative(source, path);
if (skip.has(name)) continue;
const destination = join(target, name);
await mkdir(dirname(destination), {recursive: true});
await copyFile(path, destination);
Expand Down
2 changes: 1 addition & 1 deletion src/channel.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {InternSet, rollups} from "d3";
import {ascendingDefined, descendingDefined} from "./defined.js";
import {first, isColor, isEvery, isIterable, isOpacity, labelof, map, maybeValue, range, valueof} from "./options.js";
import {registry} from "./scales/index.js";
import {registry} from "./scales/registry.js";
import {isSymbol, maybeSymbol} from "./symbol.js";
import {maybeReduce} from "./transforms/group.js";

Expand Down
2 changes: 1 addition & 1 deletion src/plot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {dataify, lengthof, map, yes, maybeIntervalTransform} from "./options.js"
import {createProjection, getGeometryChannels, hasProjection, xyProjection} from "./projection.js";
import {createScales, createScaleFunctions, autoScaleRange, exposeScales} from "./scales.js";
import {innerDimensions, outerDimensions} from "./scales.js";
import {isPosition, registry as scaleRegistry} from "./scales/index.js";
import {isPosition, registry as scaleRegistry} from "./scales/registry.js";
import {maybeClassName} from "./style.js";
import {initializer} from "./transforms/basic.js";
import {consumeWarnings, warn} from "./warnings.js";
Expand Down
4 changes: 2 additions & 2 deletions src/react/interactions/pointerUpstream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import * as pointer from "../../interactions/pointer.js";
//
// They are deliberately NOT declared in src/interactions/pointer.d.ts. That
// file is upstream's, so a future re-sync of it should be a zero-hunk diff;
// and src/index.d.ts does `export * from "./interactions/pointer.js"`, so a
// and src/replot.d.ts does `export * from "./interactions/pointer.js"`, so a
// declaration there would advertise these internals as part of the package's
// public type surface even though src/index.ts exports only pointer, pointerX
// public type surface even though src/replot.ts exports only pointer, pointerX
// and pointerY at runtime. Upstream keeps such internals undeclared — which is
// why src/marks/tip.ts reaches anchorX/anchorY through an @ts-expect-error.
interface PointerInternals {
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/scales.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
coerceDates
} from "./options.js";
import {orderof} from "./order.js";
import {registry, color, position, radius, opacity, symbol, length} from "./scales/index.js";
import {registry, color, position, radius, opacity, symbol, length} from "./scales/registry.js";
import {
createScaleLinear,
createScaleSqrt,
Expand Down
2 changes: 1 addition & 1 deletion src/scales/diverging.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import {negative, positive} from "../defined.js";
import {arrayify} from "../options.js";
import {warn} from "../warnings.js";
import {color, registry} from "./index.js";
import {color, registry} from "./registry.js";
import {flip, inferDomain, interpolatePiecewise, maybeInterpolator} from "./quantitative.js";
import {quantitativeScheme} from "./schemes.js";

Expand Down
2 changes: 1 addition & 1 deletion src/scales/ordinal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {scaleBand, scaleOrdinal, scalePoint, scaleImplicit} from "d3";
import {ascendingDefined} from "../defined.js";
import {isNoneish, map, maybeRangeInterval} from "../options.js";
import {maybeSymbol} from "../symbol.js";
import {registry, color, opacity, position, symbol} from "./index.js";
import {registry, color, opacity, position, symbol} from "./registry.js";
import {maybeBooleanRange, ordinalScheme, quantitativeScheme} from "./schemes.js";

// This denotes an implicitly ordinal color scale: the scale type was not set,
Expand Down
2 changes: 1 addition & 1 deletion src/scales/quantitative.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
import {finite, negative, positive} from "../defined.js";
import {arrayify, constant, maybeNiceInterval, maybeRangeInterval, slice} from "../options.js";
import {orderof} from "../order.js";
import {color, length, opacity, radius, registry, hasNumericRange} from "./index.js";
import {color, length, opacity, radius, registry, hasNumericRange} from "./registry.js";
import {ordinalRange, quantitativeScheme} from "./schemes.js";

export const flip = (i) => (t) => i(1 - t);
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion test/aspect-ratio-empty-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from "assert";
import {warns} from "./assert.js";
import it from "./jsdom.js";
import * as Plot from "../src/index.js";
import * as Plot from "../src/replot.js";

describe("aspectRatio with empty data", () => {
// Upstream computes a NaN height here and writes it to the <svg>
Expand Down
2 changes: 1 addition & 1 deletion test/mark-title-child-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// nothing at all, and a frame title — having no group — lands on the <svg>.
import assert from "assert";
import it from "./jsdom.js";
import * as Plot from "../src/index.ts";
import * as Plot from "../src/replot.ts";

// Every <title> under `root` must be a child of `parent`.
function assertTitlesAreChildrenOf(root, parent, what) {
Expand Down
2 changes: 1 addition & 1 deletion test/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ReactDOM from "react-dom/client";
import {act} from "react";
import assert from "./assert.js";
import it from "./jsdom.js";
import * as plots from "./plots/index.ts"; // TODO index.js
import * as plots from "./plots/registry.ts";

// Detect if a value is a React element
function isReactElement(value) {
Expand Down
2 changes: 1 addition & 1 deletion test/plots/dot-sort.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as Plot from "../../src/index.js";
import * as Plot from "../../src/replot.js";
import {html} from "htl";

export async function dotSort() {
Expand Down
2 changes: 1 addition & 1 deletion test/plots/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
}
</style>
<script type="module">
import * as tests from "./index.ts";
import * as tests from "./registry.ts";
import {createRoot} from "react-dom/client";

function isReactElement(value) {
Expand Down
2 changes: 1 addition & 1 deletion test/plots/offset.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {plot, axisX, axisY, rect, bin} from "../../src/index.js";
import {plot, axisX, axisY, rect, bin} from "../../src/replot.js";
import {setOffset} from "../../src/style.js";
import * as d3 from "d3";

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion test/plots/viewof.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {Replot} from "../../src/react/api.js";
// onValue> prop reports those same value changes and ordinary state carries
// them to the textarea, so nothing reaches for a DOM handle.
//
// Deliberately NOT listed in ./index.ts: that module's exports are each run as
// Deliberately NOT listed in ./registry.ts: that module's exports are each run as
// a test plot, and this one is a component.
export function PointerViewof({title, children}: {title?: string; children: ReactNode}) {
const [value, setValue] = useState<unknown>(null);
Expand Down
2 changes: 1 addition & 1 deletion test/raster-render-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import assert from "assert";
import {createCanvas, loadImage} from "canvas";
import jsdomit from "./jsdom.js";
import * as Plot from "../src/index.ts";
import * as Plot from "../src/replot.ts";

// The 1×1 canvas a colour converter reads is not exposed by any snapshot, so
// these tests observe the canvas API itself: the counts and arguments the mark
Expand Down
2 changes: 1 addition & 1 deletion test/react-geo-null-data-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from "react";
import ReactDOM from "react-dom/client";
import {act} from "react";
import jsdomit from "./jsdom.js";
import * as Plot from "../src/index.ts";
import * as Plot from "../src/replot.ts";
import {Replot as PlotComponent, Geo} from "../src/react/api.js";

async function renderSvg(node) {
Expand Down
2 changes: 1 addition & 1 deletion test/react-null-data-marks-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import React from "react";
import ReactDOM from "react-dom/client";
import {act} from "react";
import jsdomit from "./jsdom.js";
import * as Plot from "../src/index.ts";
import * as Plot from "../src/replot.ts";
import {
Replot as PlotComponent,
Arrow,
Expand Down
2 changes: 1 addition & 1 deletion test/valueof-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assert from "node:assert";
import * as Arrow from "apache-arrow";
import {valueof} from "../src/index.js";
import {valueof} from "../src/replot.js";

describe("valueof(data, value, type)", () => {
it("allows data to be an Arrow Table", () => {
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"baseUrl": "./src",
"jsx": "react-jsx",
"paths": {
"@dave-hillier/replot": ["./index.ts"],
"@dave-hillier/replot": ["./replot.ts"],
"@dave-hillier/replot/react": ["./react/api.tsx"],
"react": ["../node_modules/@types/react"],
"react/jsx-runtime": ["../node_modules/@types/react/jsx-runtime"],
Expand Down
2 changes: 1 addition & 1 deletion vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default defineConfig({
publicDir: path.resolve("./test"),
resolve: {
alias: {
"@dave-hillier/replot": path.resolve("./src/index.ts")
"@dave-hillier/replot": path.resolve("./src/replot.ts")
}
},
server: {
Expand Down
Loading