From 8ad60756528a31ae07788e7e7db5e74e88a5e0d1 Mon Sep 17 00:00:00 2001 From: James Beard Date: Thu, 5 Feb 2026 20:43:33 +1100 Subject: [PATCH] Introduced tstyche for type checking and to guard against unintentional API changes. For example, a test like this would have caught #3006 --- .monorepolint.config.mjs | 23 ++++++++++++ packages/turf-line-offset/package.json | 3 +- packages/turf-line-offset/test/types.tst.ts | 37 +++++++++++++++++++ packages/turf-line-offset/types.ts | 23 ------------ pnpm-lock.yaml | 39 +++++++++++++++------ 5 files changed, 90 insertions(+), 35 deletions(-) create mode 100644 packages/turf-line-offset/test/types.tst.ts delete mode 100644 packages/turf-line-offset/types.ts diff --git a/.monorepolint.config.mjs b/.monorepolint.config.mjs index 58617304cd..515e891174 100644 --- a/.monorepolint.config.mjs +++ b/.monorepolint.config.mjs @@ -17,6 +17,7 @@ const MAIN_PACKAGE = "@turf/turf"; const TAPE_PACKAGES = []; // projects that have tape tests 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 // iterate all the packages and figure out what buckets everything falls into @@ -39,6 +40,10 @@ glob.sync(path.join(__dirname, "packages", "turf-*")).forEach((pk) => { if (fs.existsSync(path.join(pk, "types.ts"))) { TYPES_PACKAGES.push(name); } + + if (fs.existsSync(path.join(pk, "test/types.tst.ts"))) { + TSTYCHE_PACKAGES.push(name); + } }); const TS_TAPE_PACKAGES = TAPE_PACKAGES.filter( @@ -216,6 +221,15 @@ export default { includePackages: TYPES_PACKAGES, }), + packageScript({ + options: { + scripts: { + "test:types": "tstyche", + }, + }, + includePackages: TSTYCHE_PACKAGES, + }), + requireDependency({ options: { devDependencies: { @@ -242,6 +256,15 @@ export default { includePackages: TS_PACKAGES, }), + requireDependency({ + options: { + devDependencies: { + tstyche: "^6.2.0", + }, + }, + includePackages: TSTYCHE_PACKAGES, + }), + requireDependency({ options: { dependencies: { diff --git a/packages/turf-line-offset/package.json b/packages/turf-line-offset/package.json index 831723ea7e..b0b1ba1b02 100644 --- a/packages/turf-line-offset/package.json +++ b/packages/turf-line-offset/package.json @@ -54,7 +54,7 @@ "docs": "tsx ../../scripts/generate-readmes.ts", "test": "pnpm run /test:.*/", "test:tape": "tsx test.ts", - "test:types": "tsc --esModuleInterop --module node16 --moduleResolution node16 --noEmit --strict types.ts" + "test:types": "tstyche" }, "devDependencies": { "@turf/truncate": "workspace:*", @@ -63,6 +63,7 @@ "benchmark": "^2.1.4", "load-json-file": "^7.0.1", "tape": "^5.9.0", + "tstyche": "^6.2.0", "tsup": "^8.4.0", "tsx": "^4.19.4", "typescript": "^5.8.3", diff --git a/packages/turf-line-offset/test/types.tst.ts b/packages/turf-line-offset/test/types.tst.ts new file mode 100644 index 0000000000..ed7e779df3 --- /dev/null +++ b/packages/turf-line-offset/test/types.tst.ts @@ -0,0 +1,37 @@ +import { lineOffset } from "../index.js"; +import { lineString, multiLineString } from "@turf/helpers"; +import type { Feature, LineString, MultiLineString } from "geojson"; + +import { expect } from "tstyche"; + +const line = lineString([ + [0, 0], + [10, 10], +]); +const multiLine = multiLineString([ + [ + [0, 0], + [10, 10], + ], + [ + [5, 5], + [15, 15], + ], +]); + +/** + * If the syntax below starts generating errors it's possible you've narrowed + * the input arguments which is likely to be a breaking change. + */ +expect(lineOffset).type.toBeCallableWith(line, 50); +expect(lineOffset).type.toBeCallableWith(line.geometry, 50); +expect(lineOffset).type.toBeCallableWith(multiLine, 50); +expect(lineOffset).type.toBeCallableWith(multiLine.geometry, 50); +expect(lineOffset).type.toBeCallableWith(line, 50, { units: "miles" }); + +/** + * If the sytax in this section starts generating errors, it's possible you've + * broadened the return type which is likely to be a breaking change. + */ +expect(lineOffset(line, 50)).type.toBe>(); +expect(lineOffset(multiLine, 50)).type.toBe>(); diff --git a/packages/turf-line-offset/types.ts b/packages/turf-line-offset/types.ts deleted file mode 100644 index 43789bcaa3..0000000000 --- a/packages/turf-line-offset/types.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { lineOffset } from "./index.js"; -import { lineString, multiLineString } from "@turf/helpers"; - -const line = lineString([ - [0, 0], - [10, 10], -]); -const multiLine = multiLineString([ - [ - [0, 0], - [10, 10], - ], - [ - [5, 5], - [15, 15], - ], -]); - -lineOffset(line, 50); -lineOffset(line.geometry, 50); -lineOffset(multiLine, 50); -lineOffset(multiLine.geometry, 50); -lineOffset(line, 50, { units: "miles" }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08b02ad069..c2f3ab8297 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,7 +31,7 @@ importers: version: 22.15.3 acorn: specifier: ^8.14.1 - version: 8.14.1 + version: 8.15.0 camelcase: specifier: ^8.0.0 version: 8.0.0 @@ -3748,6 +3748,9 @@ importers: tape: specifier: ^5.9.0 version: 5.9.0 + tstyche: + specifier: ^6.2.0 + version: 6.2.0(typescript@5.8.3) tsup: specifier: ^8.4.0 version: 8.4.0(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1) @@ -9174,11 +9177,13 @@ packages: glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@11.1.0: resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@13.0.0: @@ -9187,16 +9192,17 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} engines: {node: '>=16 || 14 >=14.17'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals-docs@2.4.1: resolution: {integrity: sha512-qpPnUKkWnz8NESjrCvnlGklsgiQzlq+rcCxoG5uNQ+dNA7cFMCmn231slLAwS2N/PlkzZ3COL8CcS10jXmLHqg==} @@ -11185,6 +11191,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -11460,6 +11467,16 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tstyche@6.2.0: + resolution: {integrity: sha512-WBiB6fGGsmQCFFRGwYaKq528pCLJ0CUUdrIdUm2rnVJ1Ineskbrv9uQADWsD3uHndEV/Hesdx1Gj8PdkBahxlQ==} + engines: {node: '>=22.12'} + hasBin: true + peerDependencies: + typescript: '>=5.4' + peerDependenciesMeta: + typescript: + optional: true + tsup@8.4.0: resolution: {integrity: sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==} engines: {node: '>=18'} @@ -13801,17 +13818,13 @@ snapshots: abbrev@3.0.1: {} - acorn-jsx@5.3.2(acorn@8.14.1): - dependencies: - acorn: 8.14.1 - acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn-walk@8.3.4: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 acorn@8.14.1: {} @@ -14857,8 +14870,8 @@ snapshots: espree@10.3.0: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.0 espree@10.4.0: @@ -17834,7 +17847,7 @@ snapshots: terser@5.26.0: dependencies: '@jridgewell/source-map': 0.3.5 - acorn: 8.14.1 + acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -17915,6 +17928,10 @@ snapshots: tslib@2.8.1: {} + tstyche@6.2.0(typescript@5.8.3): + optionalDependencies: + typescript: 5.8.3 + tsup@8.4.0(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.3)