diff --git a/.monorepolint.config.mjs b/.monorepolint.config.mjs index 369c23faf..53ee29a6f 100644 --- a/.monorepolint.config.mjs +++ b/.monorepolint.config.mjs @@ -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"); @@ -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); + } } if (existsSync(path.join(packagesPath, pk, "types.ts"))) { @@ -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({ @@ -211,9 +212,21 @@ export default { scripts: { bench: "tsx bench.ts", "test:tape": "tsx test.ts", + "test:node": REMOVE, }, }, - includePackages: [...TS_TAPE_PACKAGES, ...JS_TAPE_PACKAGES], + includePackages: TAPE_PACKAGES, + }), + + packageScript({ + options: { + scripts: { + bench: "node bench.ts", + "test:node": "node --test", + "test:tape": REMOVE, + }, + }, + includePackages: NODE_TEST_PACKAGES, }), packageScript({ @@ -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, + }), + + requireDependency({ + options: { + devDependencies: { + "@types/benchmark": "^2.1.5", + benchmark: "^2.1.4", + }, + }, + includePackages: TS_PACKAGES, + excludePackages: NODE_TEST_PACKAGES, }), requireDependency({ @@ -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", }, }, diff --git a/package.json b/package.json index a339ee93c..649d7d512 100644 --- a/package.json +++ b/package.json @@ -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", "camelcase": "^8.0.0", "d3-queue": "*", "decamelize": "^6.0.0", diff --git a/packages/turf-center/bench.ts b/packages/turf-center/bench.ts index aed38d199..a9abd3f42 100644 --- a/packages/turf-center/bench.ts +++ b/packages/turf-center/bench.ts @@ -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) +await benchFixtures("turf-center", (input) => center(input)); diff --git a/packages/turf-center/index.ts b/packages/turf-center/index.ts index f23c8697c..7b3bd7e05 100644 --- a/packages/turf-center/index.ts +++ b/packages/turf-center/index.ts @@ -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"; /** * Takes a {@link Feature} or {@link FeatureCollection} and returns the absolute center point of all features. diff --git a/packages/turf-center/package.json b/packages/turf-center/package.json index cf4594088..10cc9ff88 100644 --- a/packages/turf-center/package.json +++ b/packages/turf-center/package.json @@ -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:*", diff --git a/packages/turf-center/test.ts b/packages/turf-center/test.ts index 2896523e4..42d8d6201 100644 --- a/packages/turf-center/test.ts +++ b/packages/turf-center/test.ts @@ -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([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"); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f18631ed4..0429d8f03 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,12 +26,18 @@ importers: '@monorepolint/rules': specifier: 0.6.0-alpha.6 version: 0.6.0-alpha.6 + '@types/benchmark': + specifier: ^2.1.5 + version: 2.1.5 '@types/node': specifier: 22.15.3 version: 22.15.3 acorn: specifier: ^8.14.1 version: 8.15.0 + benchmark: + specifier: ^2.1.4 + version: 2.1.4 camelcase: specifier: ^8.0.0 version: 8.0.0 @@ -1641,33 +1647,12 @@ importers: '@turf/meta': specifier: workspace:* version: link:../turf-meta - '@types/benchmark': - specifier: ^2.1.5 - version: 2.1.5 - '@types/tape': - specifier: ^5.8.1 - version: 5.8.1 - benchmark: - specifier: ^2.1.4 - version: 2.1.4 - load-json-file: - specifier: ^7.0.1 - version: 7.0.1 - tape: - specifier: ^5.9.0 - version: 5.9.0 tsup: specifier: ^8.4.0 version: 8.4.0(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.2) - tsx: - specifier: ^4.19.4 - version: 4.19.4 typescript: specifier: ^5.8.3 version: 5.8.3 - write-json-file: - specifier: ^6.0.0 - version: 6.0.0 packages/turf-center-mean: dependencies: diff --git a/support/benchFixtures.mts b/support/benchFixtures.mts new file mode 100644 index 000000000..b111054a5 --- /dev/null +++ b/support/benchFixtures.mts @@ -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(); +} diff --git a/support/testFixtures.mts b/support/testFixtures.mts new file mode 100644 index 000000000..f568cfd84 --- /dev/null +++ b/support/testFixtures.mts @@ -0,0 +1,26 @@ +import assert from "node:assert"; +import { readdir, readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; +import type { TestContext } from "node:test"; + +export async function testFixtures(t: TestContext, fn: (input: any) => any) { + const dirs = { + in: path.join(process.cwd(), "test", "in"), + out: path.join(process.cwd(), "test", "out"), + }; + + for (const file of await readdir(dirs.in)) { + await t.test(file, async () => { + const inputPath = path.join(dirs.in, file); + const outputPath = path.join(dirs.out, file); + const inputData = JSON.parse(await readFile(inputPath, "utf-8")); + const result = fn(inputData); + if (process.env.REGEN) { + await writeFile(outputPath, JSON.stringify(result, null, 2)); + } else { + const expected = JSON.parse(await readFile(outputPath, "utf-8")); + assert.deepStrictEqual(result, expected); + } + }); + } +} diff --git a/tsconfig.shared.json b/tsconfig.shared.json index 81cb45d27..68fcbf085 100644 --- a/tsconfig.shared.json +++ b/tsconfig.shared.json @@ -8,6 +8,7 @@ "moduleResolution": "node16", "importHelpers": true, "skipLibCheck": true, - "erasableSyntaxOnly": true + "erasableSyntaxOnly": true, + "rewriteRelativeImportExtensions": true } }