Skip to content

Commit

Permalink
Modernize (ES entry point, drop transpilation, better tests) (#180)
Browse files Browse the repository at this point in the history
* switch to module entry point & native test runner

* update readme
  • Loading branch information
mourner authored Jun 12, 2024
1 parent 6eb1731 commit 52f2ef8
Show file tree
Hide file tree
Showing 10 changed files with 420 additions and 1,064 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
language: node_js
node_js: 14
node_js: 20
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@ GeoJSON-VT only operates on zoom levels up to 24.

### Install

Install using NPM (`npm install geojson-vt`) or Yarn (`yarn add geojson-vt`), then:
Install using NPM (`npm install geojson-vt`), then:

```js
// import as a ES module
import geojsonvt from 'geojson-vt';

// or require in Node / Browserify
const geojsonvt = require('geojson-vt');
// import from a CDN in the browser:
import geojsonvt from 'https://esm.run/geojson-vt';
```

Or use a browser build directly:

```html
<script src="https://unpkg.com/geojson-vt@3.2.0/geojson-vt.js"></script>
<script src="https://unpkg.com/geojson-vt/geojson-vt.js"></script>
```
19 changes: 11 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"version": "3.2.1",
"description": "Slice GeoJSON data into vector tiles efficiently",
"homepage": "https://github.com/mapbox/geojson-vt",
"type": "module",
"exports": "src/index.js",
"sideEffects": false,
"keywords": [
"spatial",
"geojson",
Expand All @@ -19,26 +22,26 @@
"jsdelivr": "geojson-vt.js",
"unpkg": "geojson-vt.js",
"devDependencies": {
"@rollup/plugin-buble": "^1.0.2",
"@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-terser": "^0.4.4",
"benchmark": "^2.1.4",
"c8": "^7.12.0",
"eslint": "^8.33.0",
"c8": "^10.1.1",
"eslint": "^8.57.0",
"eslint-config-mourner": "^3.0.0",
"esm": "^3.2.25",
"rollup": "^3.12.0",
"tape": "^5.6.3"
"rollup": "^3.29.3"
},
"eslintConfig": {
"extends": "mourner",
"parserOptions": {
"ecmaVersion": 2020
},
"globals": {
"topojson": true
}
},
"license": "ISC",
"scripts": {
"pretest": "eslint src/*.js test/*.js debug/viz.js",
"test": "c8 tape -r esm test/test-*.js",
"test": "c8 node --test",
"build": "rollup -c",
"watch": "rollup -cw",
"prepublishOnly": "npm run test && npm run build"
Expand Down
12 changes: 2 additions & 10 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import terser from '@rollup/plugin-terser';
import buble from '@rollup/plugin-buble';

const config = (file, plugins) => ({
input: 'src/index.js',
Expand All @@ -12,14 +11,7 @@ const config = (file, plugins) => ({
plugins
});

const bubleConfig = {
transforms: {
dangerousForOf: true,
},
objectAssign: 'Object.assign',
};

export default [
config('geojson-vt-dev.js', [buble(bubleConfig)]),
config('geojson-vt.js', [terser(), buble(bubleConfig)])
config('geojson-vt-dev.js', []),
config('geojson-vt.js', [terser()])
];
28 changes: 11 additions & 17 deletions test/test-clip.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@

import test from 'tape';
import test from 'node:test';
import assert from 'node:assert/strict';

import clip from '../src/clip.js';

/*eslint comma-spacing:0*/

const geom1 = [0,0,0,50,0,0,50,10,0,20,10,0,20,20,0,30,20,0,30,30,0,50,30,0,50,40,0,25,40,0,25,50,0,0,50,0,0,60,0,25,60,0];
const geom2 = [0,0,0,50,0,0,50,10,0,0,10,0];

test('clips polylines', (t) => {
test('clips polylines', () => {

const clipped = clip([
{geometry: geom1, type: 'LineString', tags: 1, minX: 0, minY: 0, maxX: 50, maxY: 60},
Expand All @@ -25,12 +27,10 @@ test('clips polylines', (t) => {
[40,10,1,10,10,1]], tags: 2, minX: 10, minY: 0, maxX: 40, maxY: 10}
];

t.equal(JSON.stringify(clipped), JSON.stringify(expected));

t.end();
assert.equal(JSON.stringify(clipped), JSON.stringify(expected));
});

test('clips lines with line metrics on', (t) => {
test('clips lines with line metrics on', () => {

const geom = geom1.slice();
geom.size = 0;
Expand All @@ -45,19 +45,17 @@ test('clips lines with line metrics on', (t) => {
const clipped = clip([{geometry: geom, type: 'LineString', minX: 0, minY: 0, maxX: 50, maxY: 60}],
1, 10, 40, 0, -Infinity, Infinity, {lineMetrics: true});

t.same(
assert.deepEqual(
clipped.map(f => [f.geometry.start, f.geometry.end]),
[[10, 40], [70, 130], [160, 200], [230, 245]]
);

t.end();
});

function closed(geometry) {
return [geometry.concat(geometry.slice(0, 3))];
}

test('clips polygons', (t) => {
test('clips polygons', () => {

const clipped = clip([
{geometry: closed(geom1), type: 'Polygon', tags: 1, minX: 0, minY: 0, maxX: 50, maxY: 60},
Expand All @@ -69,20 +67,16 @@ test('clips polygons', (t) => {
{id: null, type: 'Polygon', geometry: [[10,0,1,40,0,1,40,10,1,10,10,1,10,0,1]], tags: 2, minX: 10, minY: 0, maxX: 40, maxY: 10}
];

t.equal(JSON.stringify(clipped), JSON.stringify(expected));

t.end();
assert.equal(JSON.stringify(clipped), JSON.stringify(expected));
});

test('clips points', (t) => {
test('clips points', () => {

const clipped = clip([
{geometry: geom1, type: 'MultiPoint', tags: 1, minX: 0, minY: 0, maxX: 50, maxY: 60},
{geometry: geom2, type: 'MultiPoint', tags: 2, minX: 0, minY: 0, maxX: 50, maxY: 10}
], 1, 10, 40, 0, -Infinity, Infinity, {});

t.same(clipped, [{id: null, type: 'MultiPoint',
assert.deepEqual(clipped, [{id: null, type: 'MultiPoint',
geometry: [20,10,0,20,20,0,30,20,0,30,30,0,25,40,0,25,50,0,25,60,0], tags: 1, minX: 20, minY: 10, maxX: 30, maxY: 60}]);

t.end();
});
29 changes: 13 additions & 16 deletions test/test-full.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

import test from 'tape';
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'fs';
import path from 'path';

import geojsonvt from '../src/index.js';

testTiles('us-states.json', 'us-states-tiles.json', {indexMaxZoom: 7, indexMaxPoints: 200});
Expand All @@ -13,35 +14,31 @@ testTiles('single-geom.json', 'single-geom-tiles.json', {indexMaxZoom: 0, indexM
testTiles('ids.json', 'ids-promote-id-tiles.json', {indexMaxZoom: 0, promoteId: 'prop0'});
testTiles('ids.json', 'ids-generate-id-tiles.json', {indexMaxZoom: 0, generateId: true});

test('throws on invalid GeoJSON', (t) => {
t.throws(() => {
test('throws on invalid GeoJSON', () => {
assert.throws(() => {
genTiles({type: 'Pologon'});
});
t.end();
});

function testTiles(inputFile, expectedFile, options) {
test(`full tiling test: ${ expectedFile.replace('-tiles.json', '')}`, (t) => {
test(`full tiling test: ${ expectedFile.replace('-tiles.json', '')}`, () => {
const tiles = genTiles(getJSON(inputFile), options);
// fs.writeFileSync(path.join(__dirname, '/fixtures/' + expectedFile), JSON.stringify(tiles));
t.same(tiles, getJSON(expectedFile));
t.end();
assert.deepEqual(tiles, getJSON(expectedFile));
});
}

test('empty geojson', (t) => {
t.same({}, genTiles(getJSON('empty.json')));
t.end();
test('empty geojson', () => {
assert.deepEqual({}, genTiles(getJSON('empty.json')));
});

test('null geometry', (t) => {
test('null geometry', () => {
// should ignore features with null geometry
t.same({}, genTiles(getJSON('feature-null-geometry.json')));
t.end();
assert.deepEqual({}, genTiles(getJSON('feature-null-geometry.json')));
});

function getJSON(name) {
return JSON.parse(fs.readFileSync(path.join(__dirname, `/fixtures/${ name}`)));
return JSON.parse(fs.readFileSync(new URL(`fixtures/${name}`, import.meta.url)));
}

function genTiles(data, options) {
Expand All @@ -55,7 +52,7 @@ function genTiles(data, options) {
for (const id in index.tiles) {
const tile = index.tiles[id];
const z = tile.z;
output[`z${ z }-${ tile.x }-${ tile.y}`] = index.getTile(z, tile.x, tile.y).features;
output[`z${z}-${tile.x}-${tile.y}`] = index.getTile(z, tile.x, tile.y).features;
}

return output;
Expand Down
46 changes: 20 additions & 26 deletions test/test-get-tile.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

import test from 'tape';
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'fs';
import path from 'path';

import geojsonvt from '../src/index.js';

const square = [{
Expand All @@ -11,56 +12,51 @@ const square = [{
id: '42'
}];

test('getTile: us-states.json', (t) => {
test('getTile: us-states.json', () => {
const log = console.log;

console.log = function () {};
const index = geojsonvt(getJSON('us-states.json'), {debug: 2});

t.same(index.getTile(7, 37, 48).features, getJSON('us-states-z7-37-48.json'), 'z7-37-48');
t.same(index.getTile('7', '37', '48').features, getJSON('us-states-z7-37-48.json'), 'z, x, y as strings');
assert.deepEqual(index.getTile(7, 37, 48).features, getJSON('us-states-z7-37-48.json'), 'z7-37-48');
assert.deepEqual(index.getTile('7', '37', '48').features, getJSON('us-states-z7-37-48.json'), 'z, x, y as strings');

t.same(index.getTile(9, 148, 192).features, square, 'z9-148-192 (clipped square)');
// t.same(index.getTile(11, 592, 768).features, square, 'z11-592-768 (clipped square)');
assert.deepEqual(index.getTile(9, 148, 192).features, square, 'z9-148-192 (clipped square)');

t.equal(index.getTile(11, 800, 400), null, 'non-existing tile');
t.equal(index.getTile(-5, 123.25, 400.25), null, 'invalid tile');
t.equal(index.getTile(25, 200, 200), null, 'invalid tile');
assert.equal(index.getTile(11, 800, 400), null, 'non-existing tile');
assert.equal(index.getTile(-5, 123.25, 400.25), null, 'invalid tile');
assert.equal(index.getTile(25, 200, 200), null, 'invalid tile');

console.log = log;

t.equal(index.total, 37);

t.end();
assert.equal(index.total, 37);
});

test('getTile: unbuffered tile left/right edges', (t) => {
test('getTile: unbuffered tile left/right edges', () => {
const index = geojsonvt({
type: 'LineString',
coordinates: [[0, 90], [0, -90]]
}, {
buffer: 0
});

t.same(index.getTile(2, 1, 1), null);
t.same(index.getTile(2, 2, 1).features, [{geometry: [[[0, 0], [0, 4096]]], type: 2, tags: null}]);
t.end();
assert.deepEqual(index.getTile(2, 1, 1), null);
assert.deepEqual(index.getTile(2, 2, 1).features, [{geometry: [[[0, 0], [0, 4096]]], type: 2, tags: null}]);
});

test('getTile: unbuffered tile top/bottom edges', (t) => {
test('getTile: unbuffered tile top/bottom edges', () => {
const index = geojsonvt({
type: 'LineString',
coordinates: [[-90, 66.51326044311188], [90, 66.51326044311188]]
}, {
buffer: 0
});

t.same(index.getTile(2, 1, 0).features, [{geometry: [[[0, 4096], [4096, 4096]]], type: 2, tags: null}]);
t.same(index.getTile(2, 1, 1).features, []);
t.end();
assert.deepEqual(index.getTile(2, 1, 0).features, [{geometry: [[[0, 4096], [4096, 4096]]], type: 2, tags: null}]);
assert.deepEqual(index.getTile(2, 1, 1).features, []);
});

test('getTile: polygon clipping on the boundary', (t) => {
test('getTile: polygon clipping on the boundary', () => {
const index = geojsonvt({
type: 'Polygon',
coordinates: [[
Expand All @@ -74,15 +70,13 @@ test('getTile: polygon clipping on the boundary', (t) => {
buffer: 1024
});

t.same(index.getTile(5, 19, 9).features, [{
assert.deepEqual(index.getTile(5, 19, 9).features, [{
geometry: [[[3072, 3072], [5120, 3072], [5120, 5120], [3072, 5120], [3072, 3072]]],
type: 3,
tags: null
}]);

t.end();
});

function getJSON(name) {
return JSON.parse(fs.readFileSync(path.join(__dirname, `/fixtures/${ name}`)));
return JSON.parse(fs.readFileSync(new URL(`fixtures/${name}`, import.meta.url)));
}
Loading

0 comments on commit 52f2ef8

Please sign in to comment.