From 047c5f5656bf45ddb907bc4d759e927014996973 Mon Sep 17 00:00:00 2001 From: James Beard Date: Tue, 23 Jul 2024 19:48:30 +1000 Subject: [PATCH] Converted turf-transform-scale to Typescript (#2652) Converted turf-transform-scale to Typescript. Avoiding in house type AllGeoJSON. Some refactoring to accomodate stricter typing where existing code was potentially vulnerable at runtime. turf-distance README was out of date so regenerating that too. --- packages/turf-distance/README.md | 22 ++- packages/turf-transform-scale/README.md | 30 ++-- packages/turf-transform-scale/bench.ts | 28 ++- packages/turf-transform-scale/index.d.ts | 16 -- packages/turf-transform-scale/index.js | 149 ---------------- packages/turf-transform-scale/index.ts | 195 +++++++++++++++++++++ packages/turf-transform-scale/package.json | 5 +- packages/turf-transform-scale/test.ts | 58 +++++- pnpm-lock.yaml | 9 + 9 files changed, 306 insertions(+), 206 deletions(-) delete mode 100644 packages/turf-transform-scale/index.d.ts delete mode 100644 packages/turf-transform-scale/index.js create mode 100644 packages/turf-transform-scale/index.ts diff --git a/packages/turf-distance/README.md b/packages/turf-distance/README.md index 79342a31b5..8698f12f13 100644 --- a/packages/turf-distance/README.md +++ b/packages/turf-distance/README.md @@ -4,16 +4,16 @@ ## distance -Calculates the distance between two [points][1] in degrees, radians, miles, or kilometers. +Calculates the distance between two [coordinates][1] in degrees, radians, miles, or kilometers. This uses the [Haversine formula][2] to account for global curvature. ### Parameters -* `from` **([Coord][3] | [Point][4])** origin point or coordinate -* `to` **([Coord][3] | [Point][4])** destination point or coordinate -* `options` **[Object][5]** Optional parameters (optional, default `{}`) +* `from` **[Coord][3]** origin coordinate +* `to` **[Coord][3]** destination coordinate +* `options` **[Object][4]** Optional parameters (optional, default `{}`) - * `options.units` **[string][6]** can be degrees, radians, miles, or kilometers (optional, default `'kilometers'`) + * `options.units` **[string][5]** can be degrees, radians, miles, or kilometers (optional, default `'kilometers'`) ### Examples @@ -30,21 +30,19 @@ from.properties.distance = distance; to.properties.distance = distance; ``` -Returns **[number][7]** distance between the two points +Returns **[number][6]** distance between the two coordinates -[1]: https://tools.ietf.org/html/rfc7946#section-3.1.2 +[1]: https://tools.ietf.org/html/rfc7946#section-3.1.1 [2]: http://en.wikipedia.org/wiki/Haversine_formula [3]: https://tools.ietf.org/html/rfc7946#section-3.1.1 -[4]: https://tools.ietf.org/html/rfc7946#section-3.1.2 +[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object -[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object +[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String -[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - -[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number +[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number diff --git a/packages/turf-transform-scale/README.md b/packages/turf-transform-scale/README.md index 8578cd2345..7c2d7f0deb 100644 --- a/packages/turf-transform-scale/README.md +++ b/packages/turf-transform-scale/README.md @@ -4,38 +4,40 @@ ## transformScale -Scale a GeoJSON from a given point by a factor of scaling (ex: factor=2 would make the GeoJSON 200% larger). -If a FeatureCollection is provided, the origin point will be calculated based on each individual Feature. +Scale GeoJSON objects from a given point by a scaling factor e.g. factor=2 +would make each object 200% larger. +If a FeatureCollection is provided, the origin point will be calculated +based on each individual feature *unless* an exact ### Parameters -* `geojson` **[GeoJSON][1]** GeoJSON to be scaled -* `factor` **[number][2]** of scaling, positive values greater than 0. Numbers between 0 and 1 will shrink the geojson, numbers greater than 1 will expand it, a factor of 1 will not change the geojson. -* `options` **[Object][3]** Optional parameters (optional, default `{}`) +* `geojson` **([GeoJSON][1] | [GeometryCollection][2])** objects to be scaled +* `factor` **[number][3]** of scaling, positive values greater than 0. Numbers between 0 and 1 will shrink the geojson, numbers greater than 1 will expand it, a factor of 1 will not change the geojson. +* `options` **[Object][4]** Optional parameters (optional, default `{}`) - * `options.origin` **([string][4] | [Coord][5])** Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid) (optional, default `'centroid'`) - * `options.mutate` **[boolean][6]** allows GeoJSON input to be mutated (significant performance increase if true) (optional, default `false`) + * `options.origin` **(Corners | [Coord][5])** Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid) (optional, default `'centroid'`) + * `options.mutate` **[boolean][6]** allows GeoJSON input to be mutated (significant performance improvement if true) (optional, default `false`) ### Examples ```javascript -var poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]); -var scaledPoly = turf.transformScale(poly, 3); +const poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]); +const scaledPoly = turf.transformScale(poly, 3); //addToMap -var addToMap = [poly, scaledPoly]; +const addToMap = [poly, scaledPoly]; scaledPoly.properties = {stroke: '#F00', 'stroke-width': 4}; ``` -Returns **[GeoJSON][1]** scaled GeoJSON +Returns **([GeoJSON][1] | [GeometryCollection][2])** scaled GeoJSON [1]: https://tools.ietf.org/html/rfc7946#section-3 -[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number +[2]: https://tools.ietf.org/html/rfc7946#section-3.1.8 -[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object +[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number -[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String +[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object [5]: https://tools.ietf.org/html/rfc7946#section-3.1.1 diff --git a/packages/turf-transform-scale/bench.ts b/packages/turf-transform-scale/bench.ts index 9e29fe2f03..602a056b03 100644 --- a/packages/turf-transform-scale/bench.ts +++ b/packages/turf-transform-scale/bench.ts @@ -1,8 +1,10 @@ +import { Feature, FeatureCollection } from "geojson"; import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import { loadJsonFileSync } from "load-json-file"; -import Benchmark from "benchmark"; +import Benchmark, { Event } from "benchmark"; +import { Coord, Corners } from "@turf/helpers"; import { transformScale as scale } from "./index.js"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -11,7 +13,9 @@ const directory = path.join(__dirname, "test", "in") + path.sep; const fixtures = fs.readdirSync(directory).map((filename) => { return { name: path.parse(filename).name, - geojson: loadJsonFileSync(directory + filename), + geojson: loadJsonFileSync(directory + filename) as + | FeatureCollection + | Feature, }; }); @@ -31,7 +35,14 @@ const fixtures = fs.readdirSync(directory).map((filename) => { * z-scaling: 0.237ms */ for (const { name, geojson } of fixtures) { - const { factor, origin } = geojson.properties || {}; + let factor: number = 2, + origin: Coord | Corners = "centroid"; + if (geojson.type === "Feature") { + // Override any test options specified in the feature's properties. + factor = geojson.properties?.factor ?? factor; + origin = geojson.properties?.origin ?? origin; + } + console.time(name); scale(geojson, factor || 2, { origin, mutate: true }); console.timeEnd(name); @@ -54,8 +65,15 @@ for (const { name, geojson } of fixtures) { */ const suite = new Benchmark.Suite("turf-transform-scale"); for (const { name, geojson } of fixtures) { - const { factor, origin } = geojson.properties || {}; + let factor: number = 2, + origin: Coord | Corners = "centroid"; + if (geojson.type === "Feature") { + // Override any test options specified in the feature's properties. + factor = geojson.properties?.factor ?? factor; + origin = geojson.properties?.origin ?? origin; + } + suite.add(name, () => scale(geojson, factor || 2, { origin })); } -suite.on("cycle", (e) => console.log(String(e.target))).run(); +suite.on("cycle", (e: Event) => console.log(String(e.target))).run(); diff --git a/packages/turf-transform-scale/index.d.ts b/packages/turf-transform-scale/index.d.ts deleted file mode 100644 index 371668a7d3..0000000000 --- a/packages/turf-transform-scale/index.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Corners, Coord, AllGeoJSON } from "@turf/helpers"; - -/** - * http://turfjs.org/docs/#transformscale - */ -declare function transformScale( - geojson: T, - factor: number, - options?: { - origin?: Corners | Coord; - mutate?: boolean; - } -): T; - -export { transformScale }; -export default transformScale; diff --git a/packages/turf-transform-scale/index.js b/packages/turf-transform-scale/index.js deleted file mode 100644 index cce16ec249..0000000000 --- a/packages/turf-transform-scale/index.js +++ /dev/null @@ -1,149 +0,0 @@ -import { clone } from "@turf/clone"; -import { center } from "@turf/center"; -import { centroid } from "@turf/centroid"; -import { bbox as turfBBox } from "@turf/bbox"; -import { rhumbBearing } from "@turf/rhumb-bearing"; -import { rhumbDistance } from "@turf/rhumb-distance"; -import { rhumbDestination } from "@turf/rhumb-destination"; -import { coordEach, featureEach } from "@turf/meta"; -import { point, isObject } from "@turf/helpers"; -import { getCoord, getCoords, getType } from "@turf/invariant"; - -/** - * Scale a GeoJSON from a given point by a factor of scaling (ex: factor=2 would make the GeoJSON 200% larger). - * If a FeatureCollection is provided, the origin point will be calculated based on each individual Feature. - * - * @name transformScale - * @param {GeoJSON} geojson GeoJSON to be scaled - * @param {number} factor of scaling, positive values greater than 0. Numbers between 0 and 1 will shrink the geojson, numbers greater than 1 will expand it, a factor of 1 will not change the geojson. - * @param {Object} [options={}] Optional parameters - * @param {string|Coord} [options.origin='centroid'] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid) - * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true) - * @returns {GeoJSON} scaled GeoJSON - * @example - * var poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]); - * var scaledPoly = turf.transformScale(poly, 3); - * - * //addToMap - * var addToMap = [poly, scaledPoly]; - * scaledPoly.properties = {stroke: '#F00', 'stroke-width': 4}; - */ -function transformScale(geojson, factor, options) { - // Optional parameters - options = options || {}; - if (!isObject(options)) throw new Error("options is invalid"); - var origin = options.origin; - var mutate = options.mutate; - - // Input validation - if (!geojson) throw new Error("geojson required"); - if (typeof factor !== "number" || factor <= 0) - throw new Error("invalid factor"); - var originIsPoint = Array.isArray(origin) || typeof origin === "object"; - - // Clone geojson to avoid side effects - if (mutate !== true) geojson = clone(geojson); - - // Scale each Feature separately - if (geojson.type === "FeatureCollection" && !originIsPoint) { - featureEach(geojson, function (feature, index) { - geojson.features[index] = scale(feature, factor, origin); - }); - return geojson; - } - // Scale Feature/Geometry - return scale(geojson, factor, origin); -} - -/** - * Scale Feature/Geometry - * - * @private - * @param {Feature|Geometry} feature GeoJSON Feature/Geometry - * @param {number} factor of scaling, positive or negative values greater than 0 - * @param {string|Coord} [origin="centroid"] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid) - * @returns {Feature|Geometry} scaled GeoJSON Feature/Geometry - */ -function scale(feature, factor, origin) { - // Default params - var isPoint = getType(feature) === "Point"; - origin = defineOrigin(feature, origin); - - // Shortcut no-scaling - if (factor === 1 || isPoint) return feature; - - // Scale each coordinate - coordEach(feature, function (coord) { - var originalDistance = rhumbDistance(origin, coord); - var bearing = rhumbBearing(origin, coord); - var newDistance = originalDistance * factor; - var newCoord = getCoords(rhumbDestination(origin, newDistance, bearing)); - coord[0] = newCoord[0]; - coord[1] = newCoord[1]; - if (coord.length === 3) coord[2] *= factor; - }); - - delete feature.bbox; - - return feature; -} - -/** - * Define Origin - * - * @private - * @param {GeoJSON} geojson GeoJSON - * @param {string|Coord} origin sw/se/nw/ne/center/centroid - * @returns {Feature} Point origin - */ -function defineOrigin(geojson, origin) { - // Default params - if (origin === undefined || origin === null) origin = "centroid"; - - // Input Coord - if (Array.isArray(origin) || typeof origin === "object") - return getCoord(origin); - - // Define BBox - var bbox = geojson.bbox - ? geojson.bbox - : turfBBox(geojson, { recalculate: true }); - var west = bbox[0]; - var south = bbox[1]; - var east = bbox[2]; - var north = bbox[3]; - - switch (origin) { - case "sw": - case "southwest": - case "westsouth": - case "bottomleft": - return point([west, south]); - case "se": - case "southeast": - case "eastsouth": - case "bottomright": - return point([east, south]); - case "nw": - case "northwest": - case "westnorth": - case "topleft": - return point([west, north]); - case "ne": - case "northeast": - case "eastnorth": - case "topright": - return point([east, north]); - case "center": - return center(geojson); - case undefined: - case null: - case "centroid": - return centroid(geojson); - default: - throw new Error("invalid origin"); - } -} - -export { transformScale }; -export default transformScale; diff --git a/packages/turf-transform-scale/index.ts b/packages/turf-transform-scale/index.ts new file mode 100644 index 0000000000..7a09eb05a9 --- /dev/null +++ b/packages/turf-transform-scale/index.ts @@ -0,0 +1,195 @@ +import { Corners, Coord } from "@turf/helpers"; +import { FeatureCollection, GeoJSON, GeometryCollection } from "geojson"; +import { clone } from "@turf/clone"; +import { center } from "@turf/center"; +import { centroid } from "@turf/centroid"; +import { bbox as turfBBox } from "@turf/bbox"; +import { rhumbBearing } from "@turf/rhumb-bearing"; +import { rhumbDistance } from "@turf/rhumb-distance"; +import { rhumbDestination } from "@turf/rhumb-destination"; +import { coordEach, featureEach } from "@turf/meta"; +import { point, isObject } from "@turf/helpers"; +import { getCoord, getCoords, getType } from "@turf/invariant"; + +/** + * Scale GeoJSON objects from a given point by a scaling factor e.g. factor=2 + * would make each object 200% larger. + * If a FeatureCollection is provided, the origin point will be calculated + * based on each individual feature _unless_ an exact + * + * @name transformScale + * @param {GeoJSON|GeometryCollection} geojson objects to be scaled + * @param {number} factor of scaling, positive values greater than 0. Numbers between 0 and 1 will shrink the geojson, numbers greater than 1 will expand it, a factor of 1 will not change the geojson. + * @param {Object} [options={}] Optional parameters + * @param {Corners|Coord} [options.origin='centroid'] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid) + * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance improvement if true) + * @returns {GeoJSON|GeometryCollection} scaled GeoJSON + * @example + * const poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]); + * const scaledPoly = turf.transformScale(poly, 3); + * + * //addToMap + * const addToMap = [poly, scaledPoly]; + * scaledPoly.properties = {stroke: '#F00', 'stroke-width': 4}; + */ +function transformScale( + geojson: T, + factor: number, + options?: { + origin?: Corners | Coord; + mutate?: boolean; + } +): T { + // Optional parameters + options = options || {}; + if (!isObject(options)) throw new Error("options is invalid"); + const origin = options.origin || "centroid"; + const mutate = options.mutate || false; + + // Input validation + if (!geojson) throw new Error("geojson required"); + if (typeof factor !== "number" || factor <= 0) + throw new Error("invalid factor"); + const originIsPoint = Array.isArray(origin) || typeof origin === "object"; + + // Clone geojson to avoid side effects + if (mutate !== true) geojson = clone(geojson); + + // Scale each Feature separately if a feature collection AND the user didn't + // pass a single explicit point to scale the whole collection from. + if (geojson.type === "FeatureCollection" && !originIsPoint) { + featureEach(geojson, function (feature, index) { + // The type guard above is not recognised in the callback so we have to + // cast to accept responsibility. + (geojson as FeatureCollection).features[index] = scale( + feature, + factor, + origin + ); + }); + return geojson; + } + // Scale Feature/Geometry + return scale(geojson, factor, origin); +} + +/** + * Scale Feature/Geometry + * + * @private + * @param {GeoJSON|GeometryCollection} feature feature or geometry collection to scale + * @param {number} factor of scaling, positive or negative values greater than 0 + * @param {Corners|Coord} [origin="centroid"] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid) + * @returns {GeoJSON|GeometryCollection} scaled GeoJSON Feature/Geometry + */ +function scale( + feature: T, + factor: number, + origin: Corners | Coord +): T { + // Default params + const isPoint = getType(feature) === "Point"; + // Work with a Coord equivalent of the origin from here on. + const originCoord: Coord = defineOrigin(feature, origin); + + // Shortcut no-scaling + if (factor === 1 || isPoint) return feature; + + // Scale each coordinate + coordEach(feature, function (coord) { + const originalDistance = rhumbDistance(originCoord, coord); + const bearing = rhumbBearing(originCoord, coord); + const newDistance = originalDistance * factor; + const newCoord = getCoords( + rhumbDestination(originCoord, newDistance, bearing) + ); + coord[0] = newCoord[0]; + coord[1] = newCoord[1]; + if (coord.length === 3) coord[2] *= factor; + }); + + delete feature.bbox; + + return feature; +} + +/** + * Define Origin + * + * @private + * @param {GeoJSON|GeometryCollection} geojson GeoJSON + * @param {Corners|Coord} origin sw/se/nw/ne/center/centroid + * @returns {Feature} Point origin + */ +function defineOrigin( + geojson: GeoJSON | GeometryCollection, + origin: Corners | Coord +): Coord { + // Default params + if (origin === undefined || origin === null) origin = "centroid"; + + // Input Coord + if (Array.isArray(origin) || typeof origin === "object") + return getCoord(origin); + + // Define BBox + const bbox = geojson.bbox + ? geojson.bbox + : turfBBox(geojson, { recompute: true }); + const west = bbox[0]; + const south = bbox[1]; + const east = bbox[2]; + const north = bbox[3]; + + // Having to disable eslint below for lines which fail the no-fallthrough + // rule, though only because of the ts-expect-error rules. Once we remove + // southeast, bottomright, rightbottom, etc we should be able to remove all + // these supressions. + /* eslint-disable no-fallthrough */ + switch (origin) { + case "sw": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "southwest": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "westsouth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "bottomleft": + return point([west, south]); + case "se": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "southeast": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "eastsouth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "bottomright": + return point([east, south]); + case "nw": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "northwest": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "westnorth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "topleft": + return point([west, north]); + case "ne": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "northeast": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "eastnorth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt + case "topright": + return point([east, north]); + case "center": + return center(geojson); + case undefined: + case null: + case "centroid": + return centroid(geojson); + default: + throw new Error("invalid origin"); + } + /* eslint-enable no-fallthrough */ +} + +export { transformScale }; +export default transformScale; diff --git a/packages/turf-transform-scale/package.json b/packages/turf-transform-scale/package.json index c3b4f3b406..2133675063 100644 --- a/packages/turf-transform-scale/package.json +++ b/packages/turf-transform-scale/package.json @@ -71,6 +71,7 @@ "tape": "^5.7.2", "tsup": "^8.0.1", "tsx": "^4.6.2", + "typescript": "^5.2.2", "write-json-file": "^5.0.0" }, "dependencies": { @@ -83,6 +84,8 @@ "@turf/meta": "workspace:^", "@turf/rhumb-bearing": "workspace:^", "@turf/rhumb-destination": "workspace:^", - "@turf/rhumb-distance": "workspace:^" + "@turf/rhumb-distance": "workspace:^", + "@types/geojson": "7946.0.8", + "tslib": "^2.6.2" } } diff --git a/packages/turf-transform-scale/test.ts b/packages/turf-transform-scale/test.ts index c442ffe067..5e361a388a 100644 --- a/packages/turf-transform-scale/test.ts +++ b/packages/turf-transform-scale/test.ts @@ -1,3 +1,4 @@ +import { BBox, Feature, FeatureCollection } from "geojson"; import fs from "fs"; import test from "tape"; import path from "path"; @@ -17,6 +18,8 @@ import { lineString, geometryCollection, featureCollection, + Coord, + Corners, } from "@turf/helpers"; import { transformScale as scale } from "./index.js"; @@ -31,14 +34,23 @@ const fixtures = fs.readdirSync(directories.in).map((filename) => { return { filename, name: path.parse(filename).name, - geojson: loadJsonFileSync(directories.in + filename), + geojson: loadJsonFileSync(directories.in + filename) as + | FeatureCollection + | Feature, }; }); test("scale", (t) => { for (const { filename, name, geojson } of fixtures) { - let { factor, origin, mutate } = geojson.properties || {}; - factor = factor || 2; + let factor: number = 2, + origin: Coord | Corners = "centroid", + mutate = false; + if (geojson.type === "Feature") { + // Override any test options specified in the feature's properties. + factor = geojson.properties?.factor ?? factor; + origin = geojson.properties?.origin ?? origin; + mutate = geojson.properties?.mutate ?? mutate; + } const scaled = scale(geojson, factor, { origin: origin, @@ -68,10 +80,14 @@ test("scale -- throws", (t) => { [12, 15], ]); + // @ts-expect-error testing JS runtime for mis-typed option t.throws(() => scale(null, 1.5), /geojson required/); + // @ts-expect-error testing JS runtime for mis-typed option t.throws(() => scale(line, null), /invalid factor/); t.throws(() => scale(line, 0), /invalid factor/); + // @ts-expect-error testing JS runtime for mis-typed option t.throws(() => scale(line, 1.5, { origin: "foobar" }), /invalid origin/); + // @ts-expect-error testing JS runtime for mis-typed option t.throws(() => scale(line, 1.5, { origin: 2 }), /invalid origin/); t.end(); @@ -82,7 +98,7 @@ test("scale -- additional params", (t) => { [10, 10], [12, 15], ]); - const bbox = [-180, -90, 180, 90]; + const bbox: BBox = [-180, -90, 180, 90]; t.assert(scale(line, 1.5, { origin: "sw" })); t.assert(scale(line, 1.5, { origin: "se" })); @@ -90,6 +106,7 @@ test("scale -- additional params", (t) => { t.assert(scale(line, 1.5, { origin: "ne" })); t.assert(scale(line, 1.5, { origin: "center" })); t.assert(scale(line, 1.5, { origin: "centroid" })); + // @ts-expect-error testing JS runtime for mis-typed option t.assert(scale(line, 1.5, { origin: null })); line.bbox = bbox; t.assert(scale(line, 1.5)); @@ -122,7 +139,8 @@ test("scale -- mutated input", (t) => { ); scale(line, 1.5, { origin: "centroid", mutate: false }); t.deepEqual(line, lineBefore, "mutate = false - input should NOT be mutated"); - scale(line, 1.5, { orgin: "centroid", muate: "nonBoolean" }); + // @ts-expect-error testing JS runtime for mis-typed option + scale(line, 1.5, { origin: "centroid", mutate: "nonBoolean" }); t.deepEqual( line, lineBefore, @@ -165,6 +183,7 @@ test("scale -- mutated FeatureCollection", (t) => { ); scale(line, 1.5, { origin: "centroid", mutate: false }); t.deepEqual(line, lineBefore, "mutate = false - input should NOT be mutated"); + // @ts-expect-error testing JS runtime for mis-typed option scale(line, 1.5, { origin: "centroid", mutate: "nonBoolean" }); t.deepEqual( line, @@ -175,7 +194,7 @@ test("scale -- mutated FeatureCollection", (t) => { }); test("scale -- Issue #895", (t) => { - const bbox = [-122.93, 45.385, -122.294, 45.772]; + const bbox: BBox = [-122.93, 45.385, -122.294, 45.772]; const grid = hexGrid(bbox, 2, { units: "miles" }); featureEach(grid, (feature, index) => { const factor = index % 2 === 0 ? 0.4 : 0.6; @@ -238,8 +257,11 @@ test("scale -- factor 0 or less throws error", (t) => { }); // style result -function colorize(geojson) { +function colorize(geojson: FeatureCollection | Feature) { featureEach(geojson, (feature, index) => { + // We are going to add some properties, so make sure properties attribute is + // present. + feature.properties = feature.properties ?? {}; if ( feature.geometry.type === "Point" || feature.geometry.type === "MultiPoint" @@ -258,8 +280,8 @@ function colorize(geojson) { // define origin, as defined in transform-scale, and style it function markedOrigin( - geojson, - origin, + geojson: Feature, + origin: Corners | Coord | undefined, properties = { "marker-color": "#00F", "marker-symbol": "circle" } ) { // Input Geometry|Feature|Array @@ -271,25 +293,42 @@ function markedOrigin( ? geojson.bbox : turfBBox(geojson); + // Having to disable eslint below for lines which fail the no-fallthrough + // rule, though only because of the ts-expect-error rules. Once we remove + // southeast, bottomright, rightbottom, etc we should be able to remove all + // these supressions. + /* eslint-disable no-fallthrough */ switch (origin) { case "sw": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "southwest": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "westsouth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "bottomleft": return point([west, south], properties); case "se": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "southeast": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "eastsouth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "bottomright": return point([east, south], properties); case "nw": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "northwest": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "westnorth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "topleft": return point([west, north], properties); case "ne": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "northeast": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "eastnorth": + // @ts-expect-error undocumented, to be removed for v8 #techdebt case "topright": return point([east, north], properties); case "center": @@ -301,4 +340,5 @@ function markedOrigin( cid.properties = properties; return cid; } + /* eslint-enable no-fallthrough */ } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c3bd610b3..ca7282bda2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5857,6 +5857,12 @@ importers: '@turf/rhumb-distance': specifier: workspace:^ version: link:../turf-rhumb-distance + '@types/geojson': + specifier: 7946.0.8 + version: 7946.0.8 + tslib: + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@turf/bbox-polygon': specifier: workspace:^ @@ -5891,6 +5897,9 @@ importers: tsx: specifier: ^4.6.2 version: 4.6.2 + typescript: + specifier: ^5.2.2 + version: 5.3.3 write-json-file: specifier: ^5.0.0 version: 5.0.0