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
76 changes: 62 additions & 14 deletions .monorepolint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ const JS_PACKAGES = []; // projects that use javascript/rollup to build
const MAIN_PACKAGE = "@turf/turf";

const TAPE_PACKAGES = []; // projects that have tape tests
const NODE_TEST_PACKAGES = []; // projects that use node's native test runner
const TYPES_PACKAGES = []; // projects that have types tests
const TSTYCHE_PACKAGES = []; // projects that use tstyche for type tests.
const BENCH_PACKAGES = []; // projects that have benchmarks
const TSTYCHE_PACKAGES = []; // projects that use tstyche for type tests

// iterate all the packages and figure out what buckets everything falls into
const packagesPath = path.join(process.cwd(), "packages");
Expand All @@ -38,8 +38,16 @@ for (const pk of await fs.readdir(packagesPath)) {
JS_PACKAGES.push(name);
}

if (existsSync(path.join(pk, "test.js"))) {
TAPE_PACKAGES.push(name);
if (existsSync(path.join(packagesPath, pk, "test.ts"))) {
const testFileContents = await fs.readFile(
path.join(packagesPath, pk, "test.ts"),
"utf-8"
);
if (testFileContents.includes(`from "tape"`)) {
TAPE_PACKAGES.push(name);
} else {
NODE_TEST_PACKAGES.push(name);
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automatically differentiate if test.ts is tape or node native

}

if (existsSync(path.join(packagesPath, pk, "types.ts"))) {
Expand All @@ -51,13 +59,6 @@ for (const pk of await fs.readdir(packagesPath)) {
}
}

const TS_TAPE_PACKAGES = TAPE_PACKAGES.filter(
(pkg) => -1 !== TS_PACKAGES.indexOf(pkg)
);
const JS_TAPE_PACKAGES = TAPE_PACKAGES.filter(
(pkg) => -1 !== JS_PACKAGES.indexOf(pkg)
);

export default {
rules: [
packageOrder({
Expand Down Expand Up @@ -211,9 +212,21 @@ export default {
scripts: {
bench: "tsx bench.ts",
"test:tape": "tsx test.ts",
"test:node": REMOVE,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in case we ever migrate from node native back to tape.

},
},
includePackages: [...TS_TAPE_PACKAGES, ...JS_TAPE_PACKAGES],
includePackages: TAPE_PACKAGES,
}),

packageScript({
options: {
scripts: {
bench: "node bench.ts",
"test:node": "node --test",
"test:tape": REMOVE,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handles swapping bench from tsx execution to node as we switch to node native testing.

},
},
includePackages: NODE_TEST_PACKAGES,
}),

packageScript({
Expand Down Expand Up @@ -246,6 +259,43 @@ export default {
},
},
includePackages: [...TS_PACKAGES, ...JS_PACKAGES],
excludePackages: NODE_TEST_PACKAGES,
}),

requireDependency({
options: {
devDependencies: {
tape: "^5.9.0",
"@types/tape": "^5.8.1",
},
},
includePackages: TAPE_PACKAGES,
}),

requireDependency({
options: {
devDependencies: {
"@types/benchmark": REMOVE,
"@types/tape": REMOVE,
benchmark: REMOVE,
"load-json-file": REMOVE,
tape: REMOVE,
tsx: REMOVE,
"write-json-file": REMOVE,
},
},
includePackages: NODE_TEST_PACKAGES,
}),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we switch to node native testing and use the shared fixture runner, we get to remove a lot of dependencies in favor of the builtin tooling.


requireDependency({
options: {
devDependencies: {
"@types/benchmark": "^2.1.5",
benchmark: "^2.1.4",
},
},
includePackages: TS_PACKAGES,
excludePackages: NODE_TEST_PACKAGES,
}),

requireDependency({
Expand All @@ -254,8 +304,6 @@ export default {
tslib: "^2.8.1",
},
devDependencies: {
"@types/benchmark": "^2.1.5",
"@types/tape": "^5.8.1",
typescript: "^5.8.3",
},
},
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
"@monorepolint/config": "0.6.0-alpha.6",
"@monorepolint/core": "0.6.0-alpha.6",
"@monorepolint/rules": "0.6.0-alpha.6",
"@types/benchmark": "^2.1.5",
"@types/node": "22.15.3",
"acorn": "^8.14.1",
"benchmark": "^2.1.4",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required because of shared/benchFixtures.mts, but we get to remove it from each package.

"camelcase": "^8.0.0",
"d3-queue": "*",
"decamelize": "^6.0.0",
Expand Down
60 changes: 12 additions & 48 deletions packages/turf-center/bench.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,12 @@
import path from "path";
import { fileURLToPath } from "url";
import { glob } from "glob";
import { loadJsonFileSync } from "load-json-file";
import Benchmark from "benchmark";
import { center } from "./index.js";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const fixtures = glob
.sync(path.join(__dirname, "test", "in", "*.geojson"))
.map((input) => {
return {
name: path.parse(input).name,
geojson: loadJsonFileSync(input),
};
});

/**
* Single Process Benchmark
*
* feature-collection: 0.445ms
* imbalanced-polygon: 0.051ms
* linestring: 0.027ms
* point: 0.011ms
* polygon: 0.013ms
*/
for (const { name, geojson } of fixtures) {
console.time(name);
center(geojson);
console.timeEnd(name);
}

/**
* Benchmark Results
*
* feature-collection x 2,786,700 ops/sec ±1.50% (83 runs sampled)
* imbalanced-polygon x 1,364,145 ops/sec ±3.33% (76 runs sampled)
* linestring x 4,104,106 ops/sec ±4.16% (81 runs sampled)
* point x 4,901,692 ops/sec ±5.23% (81 runs sampled)
* polygon x 2,862,759 ops/sec ±1.14% (86 runs sampled)
*/
const suite = new Benchmark.Suite("turf-center");
for (const { name, geojson } of fixtures) {
suite.add(name, () => center(geojson));
}

suite.on("cycle", (e) => console.log(String(e.target))).run();
import { center } from "./index.ts";
import { benchFixtures } from "../../support/benchFixtures.mts";

// Benchmark Results
// feature-collection.geojson x 27,241,658 ops/sec ±0.34% (99 runs sampled)
// imbalanced-polygon.geojson x 14,679,583 ops/sec ±0.27% (98 runs sampled)
// linestring.geojson x 34,199,495 ops/sec ±0.52% (95 runs sampled)
// point.geojson x 52,230,993 ops/sec ±0.70% (96 runs sampled)
// points-with-weights.geojson x 24,802,237 ops/sec ±0.33% (100 runs sampled)
// polygon-without-weights.geojson x 18,423,881 ops/sec ±0.28% (100 runs sampled)
// polygon.geojson x 24,990,920 ops/sec ±0.45% (99 runs sampled)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hilariously this is almost exactly 10x the original speed due to hardware progression over the years.

await benchFixtures("turf-center", (input) => center(input));
4 changes: 2 additions & 2 deletions packages/turf-center/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BBox, Feature, GeoJsonProperties, Point } from "geojson";
import type { BBox, Feature, GeoJsonProperties, Point } from "geojson";
import { bbox } from "@turf/bbox";
import { point, Id, AllGeoJSON } from "@turf/helpers";
import { point, type Id, type AllGeoJSON } from "@turf/helpers";
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These type keywords are required when migrating from tsx to node native execution.


/**
* Takes a {@link Feature} or {@link FeatureCollection} and returns the absolute center point of all features.
Expand Down
13 changes: 3 additions & 10 deletions packages/turf-center/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,17 @@
"dist"
],
"scripts": {
"bench": "tsx bench.ts",
"bench": "node bench.ts",
"build": "tsup --config ../../tsup.config.ts",
"test": "pnpm run /test:.*/",
"test:tape": "tsx test.ts",
"test:node": "node --test",
"test:types": "tsc --esModuleInterop --module node16 --moduleResolution node16 --noEmit --strict types.ts"
},
"devDependencies": {
"@turf/bbox-polygon": "workspace:*",
"@turf/meta": "workspace:*",
"@types/benchmark": "^2.1.5",
"@types/tape": "^5.8.1",
"benchmark": "^2.1.4",
"load-json-file": "^7.0.1",
"tape": "^5.9.0",
"tsup": "^8.4.0",
"tsx": "^4.19.4",
"typescript": "^5.8.3",
"write-json-file": "^6.0.0"
"typescript": "^5.8.3"
},
"dependencies": {
"@turf/bbox": "workspace:*",
Expand Down
86 changes: 36 additions & 50 deletions packages/turf-center/test.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,47 @@
import test from "tape";
import { glob } from "glob";
import path from "path";
import { fileURLToPath } from "url";
import { loadJsonFileSync } from "load-json-file";
import { writeJsonFileSync } from "write-json-file";
import { bboxPolygon } from "@turf/bbox-polygon";
import { bbox } from "@turf/bbox";
import { featureEach, coordEach } from "@turf/meta";
import { lineString, featureCollection } from "@turf/helpers";
import { center } from "./index.js";
import test from "node:test";
import center from "./index.ts";
import { featureCollection, lineString } from "@turf/helpers";
import { coordEach, featureEach } from "@turf/meta";
import bboxPolygon from "@turf/bbox-polygon";
import bbox from "@turf/bbox";
import type { Geometry } from "geojson";
import { testFixtures } from "../../support/testFixtures.mts";
import assert from "assert";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
await test("center fixtures", async (t) => {
await testFixtures(t, (geojson) => {
const options = geojson.options || {};
options.properties = { "marker-symbol": "star", "marker-color": "#F00" };
const centered = center(geojson, options);

test("turf-center", (t) => {
glob
.sync(path.join(__dirname, "test", "in", "*.geojson"))
.forEach((filepath) => {
const geojson = loadJsonFileSync(filepath);
const options = geojson.options || {};
options.properties = { "marker-symbol": "star", "marker-color": "#F00" };
const centered = center(geojson, options);
// Display Results
const results = featureCollection<Geometry>([centered]);
featureEach(geojson, (feature) => results.features.push(feature));
const extent = bboxPolygon(bbox(geojson));
extent.properties = {
stroke: "#00F",
"stroke-width": 1,
"fill-opacity": 0,
};
coordEach(extent, (coord) =>
results.features.push(
lineString([coord, centered.geometry.coordinates], {
stroke: "#00F",
"stroke-width": 1,
})
)
);
results.features.push(extent);

// Display Results
const results = featureCollection([centered]);
featureEach(geojson, (feature) => results.features.push(feature));
const extent = bboxPolygon(bbox(geojson));
extent.properties = {
stroke: "#00F",
"stroke-width": 1,
"fill-opacity": 0,
};
coordEach(extent, (coord) =>
results.features.push(
lineString([coord, centered.geometry.coordinates], {
stroke: "#00F",
"stroke-width": 1,
})
)
);
results.features.push(extent);

const out = filepath.replace(
path.join("test", "in"),
path.join("test", "out")
);
if (process.env.REGEN) writeJsonFileSync(out, results);
t.deepEqual(results, loadJsonFileSync(out), path.parse(filepath).name);
});
t.end();
return results;
});
});

test("turf-center -- properties", (t) => {
test("turf-center -- properties", () => {
const line = lineString([
[0, 0],
[1, 1],
]);
const pt = center(line, { properties: { foo: "bar" } });
t.equal(pt.properties.foo, "bar", "translate properties");
t.end();
assert.strictEqual(pt.properties.foo, "bar", "translate properties");
});
27 changes: 6 additions & 21 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions support/benchFixtures.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import path from "path";
import { readdir, readFile } from "node:fs/promises";
import Benchmark from "benchmark";

export async function benchFixtures(pkgName: string, fn: (input: any) => void) {
const suite = new Benchmark.Suite(pkgName);
const fixturesPath = path.join(process.cwd(), "test", "in");
for (const file of await readdir(fixturesPath)) {
const inputPath = path.join(fixturesPath, file);
const inputData = JSON.parse(await readFile(inputPath, "utf-8"));
suite.add(file, () => fn(inputData));
}

suite.on("cycle", (e: any) => console.log(String(e.target))).run();
}
Loading
Loading