GithubHelp home page GithubHelp logo

placemark / check-geojson Goto Github PK

View Code? Open in Web Editor NEW
64.0 8.0 2.0 694 KB

a checker for the geojson format. goes beyond a schema, checking semantics and producing character-level warnings.

Home Page: http://check-geojson.docs.placemark.io/

License: MIT License

TypeScript 98.11% Shell 0.26% JavaScript 1.64%
geojson maps linter

check-geojson's Introduction

check-geojson

check-geojson development is supported by ๐ŸŒŽ placemark.io

geojsonhint for 2023.

I started working on geojsonhint in 2014. It's a pretty useful project. But it has been stagnant for a long time now, and has some annoying long-term issues.

check-geojson is intended to be a full successor for geojsonhint. Like geojsonhint, it is tailored to a particular usecase: writing GeoJSON by hand, or quickly sussing out issues in GeoJSON that you've received.

Main differences from geojsonhint

  • Actively maintained
  • Written in TypeScript and includes types
  • Uses momoa to parse JSON instead of a homemade parser. This is probably the biggest one. jsonlint-lines was a hack, which I created because I could not find a single parser that actually parsed JSON and gave line numbers for values. momoa is much better than that hack, and using it makes line-level errors much cleaner.

Unlike geojsonhint, this checker only produces errors, not warnings. So things that geojsonhint would warn about, like:

  • excessive coordinate precision
  • right-hand rule compliance

This does not check for. Additionally, the crs member is ignored by this tool: as of the latest GeoJSON specification, this is not used.

We're using the same test fixtures as geojsonhint as a starter.

Install

pnpm add @placemarkio/check-geojson
yarn add @placemarkio/check-geojson

Usage

Not finalized yet

import { check } from "@placemarkio/check-geojson"

try {
  const parseValue = check('โ€ฆ geojson string โ€ฆ')
} catch (e) {
  /// e.issues
}

Maintainability Test Coverage

check-geojson's People

Contributors

deepsourcebot avatar productdevbook avatar tmcw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

check-geojson's Issues

0.1.8 seems to be very different from 0.1.7

Hey there, we are using getIssues from this library for validating our geojsons, however after bumping from 0.1.7 to 0.1.8 we have many unit tests breaking as it seems to behave very differently - do you have an upgrade guide we can follow along?

Replace tsdx

Tsdx is abandoned - and it controls a lot of subdeps. So switch to microbundle or rollup, because I want to make the TS config modern and strict.

Object mode

There should be a mode that works on JSON.parse-generated objects without the AST overhead.

Feature parsing should not accept nulls

{ type: 'Feature', properties: null, geometry: null }

Appears to be a valid object. Maybe I'm missing something in the spec but I'd expect at a minimum the geometry property to not be null.

Streaming

It would be preferable for this to run with a streaming JSON parser, though this would be quite a lot more difficult, especially because actual streaming JSON parsers are very rare. But still, it would allow running this with the important tracing information, but avoiding the overhead of generating an ast on top of the GeoJSON output.

broken build for node

Hi @tmcw, I got here after deprecation of @mapbox/geojsonhint, so thank you for creating this replacement.

I tried this very basic example in node, but it throws invalid_type.

const {check} = require('@placemarkio/check-geojson');

const examplePoint = {
  type: 'Point',
  coordinates: [0, 1],
};

check(JSON.stringify(examplePoint));

The example works perfectly fine in your tests, so I tracked the problem and found that the typescript build generates an invalid code.

look at this:

in file dist/type.d.ts

import { GeoJSON } from 'geojson';
export declare type GeoJSONTypeSet = Set<GeoJSON['type']>;
export declare const GEOJSON_FEATURE_TYPE: Set<"Point" | "MultiPoint" | "LineString" | "MultiLineString" | "Polygon" | "MultiPolygon" | "GeometryCollection" | "Feature" | "FeatureCollection">;
export declare const GEOJSON_GEOMETRY_TYPES: Set<"Point" | "MultiPoint" | "LineString" | "MultiLineString" | "Polygon" | "MultiPolygon" | "GeometryCollection" | "Feature" | "FeatureCollection">;
export declare const GEOJSON_GEOMETRY_TYPES_EX_GEOMETRY_COLLECTION: Set<"Point" | "MultiPoint" | "LineString" | "MultiLineString" | "Polygon" | "MultiPolygon" | "GeometryCollection" | "Feature" | "FeatureCollection">;
export declare const GEOJSON_TYPES: Set<"Point" | "MultiPoint" | "LineString" | "MultiLineString" | "Polygon" | "MultiPolygon" | "GeometryCollection" | "Feature" | "FeatureCollection">;

in file dist/check-geojson.cjs.development.js

var GEOJSON_FEATURE_TYPE = /*#__PURE__*/new Set(['Feature']);
var GEOJSON_GEOMETRY_TYPES = /*#__PURE__*/new Set(['Point', 'MultiPoint', 'Polygon', 'MultiPolygon', 'LineString', 'MultiLineString', 'GeometryCollection']);
var GEOJSON_GEOMETRY_TYPES_EX_GEOMETRY_COLLECTION = /*#__PURE__*/new Set(['Point', 'MultiPoint', 'Polygon', 'MultiPolygon', 'LineString', 'MultiLineString']);
var GEOJSON_TYPES = /*#__PURE__*/new Set( /*#__PURE__*/[].concat(GEOJSON_GEOMETRY_TYPES, ['Feature', 'FeatureCollection']));

The variable GEOJSON_TYPES concats a Set and an Array, which causes the variable to not hold the expected values.

> console.log(GEOJSON_TYPES)
Set(3) {
  Set(7) {
    'Point',
    'MultiPoint',
    'Polygon',
    'MultiPolygon',
    'LineString',
    'MultiLineString',
    'GeometryCollection'
  },
  'Feature',
  'FeatureCollection'
}

I only know basic stuff in typescript, so I don't know if this is a config problem

Does not throw with some invalid geojson

Hi, here are tests that I expected to throw but don't. Sorry for the long post.
It seems sending the value as object does not throw, where sending the same object as stringdoes throw.
I have added additional invalid types and which ones fail.

The objects I have tested that cause the function to not throw are:

  • invalidGeojsonGeometryLineZeroLength
  • invalidGeojsonGeometryPolygonDuplicatesNodes
  • invalidGeojsonGeometryPolygonSelfIntersect
  • invalidGeojsonGeometryPolygonWithHolesCounterClockwise
  • invalidGeojsonGeometryPolygonWithoutHolesCounterClockwise
const { check: geojsonTester } = require("@placemarkio/check-geojson");

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/polygon_unclosed_polygon.geojson?short_path=2a32854
const invalidGeojsonGeometryPolygonUnclosed = {
  type: "Polygon",
  coordinates: [
    [
      [13.376753, 52.515641],
      [13.37696, 52.515011],
      [13.378033, 52.514998],
      [13.378049, 52.516176],
    ],
  ],
};

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/polygon_has_duplicate_nodes.geojson?short_path=487c8b7
const invalidGeojsonGeometryPolygonDuplicatesNodes = {
  type: "Polygon",
  coordinates: [
    [
      [13.378261, 52.513389],
      [13.377365, 52.51446],
      [13.377365, 52.51446],
      [13.376762, 52.51337],
      [13.378261, 52.513389],
    ],
  ],
};

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/polygon_has_less_than_three_unique_nodes.geojson?short_path=e1e556d
const invalidGeojsonGeometryPolygonTwoNodes = {
  type: "Polygon",
  coordinates: [
    [
      [13.377016, 52.512418],
      [13.378182, 52.51285],
      [13.377016, 52.512418],
    ],
  ],
};

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/polygon_interior_ring_not_clockwise_winding_order.geojson?short_path=1df04b0
const invalidGeojsonGeometryPolygonWithHolesCounterClockwise = {
  type: "Polygon",
  coordinates: [
    [
      [13.379307, 52.512661],
      [13.381102, 52.512687],
      [13.380973, 52.514197],
      [13.379281, 52.514133],
      [13.379307, 52.512661],
    ],
    [
      [13.380443, 52.513849],
      [13.379901, 52.513849],
      [13.379669, 52.51372],
      [13.379591, 52.513384],
      [13.379669, 52.512945],
      [13.380185, 52.512855],
      [13.380676, 52.51301],
      [13.380559, 52.513294],
      [13.379979, 52.513603],
      [13.380443, 52.513849],
    ],
  ],
};

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/polygon_exterior_ring_not_counterclockwise_winding_order.geojson?short_path=f7e7cf0
const invalidGeojsonGeometryPolygonWithoutHolesCounterClockwise = {
  type: "Polygon",
  coordinates: [
    [
      [13.379263, 52.516012],
      [13.380039, 52.516012],
      [13.380557, 52.515852],
      [13.380756, 52.515275],
      [13.380597, 52.514996],
      [13.380139, 52.514718],
      [13.379601, 52.514757],
      [13.379422, 52.514937],
      [13.379522, 52.515534],
      [13.379701, 52.515833],
      [13.379263, 52.516012],
    ],
  ],
};

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/polygon_inner_and_exterior_ring_cross.geojson?short_path=dae4bfa
const invalidGeojsonGeometryPolygonSelfIntersect = {
  type: "Polygon",
  coordinates: [
    [
      [13.382288, 52.515426],
      [13.382096, 52.514797],
      [13.383424, 52.51464],
      [13.383529, 52.515496],
      [13.382288, 52.515426],
    ],
    [
      [13.382603, 52.514954],
      [13.38262, 52.516255],
      [13.383144, 52.515321],
      [13.383127, 52.514867],
      [13.382603, 52.514954],
    ],
  ],
};

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/linestring_zero_length.geojson?short_path=14d173c
const invalidGeojsonGeometryLineZeroLength = {
  type: "LineString",
  coordinates: [
    [13.39265, 52.515046],
    [13.39265, 52.515046],
  ],
};

// https://github.com/chrieke/geojson-invalid-geometry/blob/main/examples_geojson/invalid/incorrect_geometry_data_type.geojson?short_path=01db740
const invalidGeojsonGeometryType = {
  type: "LineString",
  coordinates: [
    [
      [13.383092, 52.510235],
      [13.383092, 52.509704],
      [13.38458, 52.509704],
      [13.38458, 52.510235],
      [13.383092, 52.510235],
    ],
  ],
};

try {
  geojsonTester(JSON.stringify(invalidGeojsonGeometryLineZeroLength));
  console.log("string invalidGeojsonGeometryLineZeroLength -fail");
} catch (e) {
  console.log("string invalidGeojsonGeometryLineZeroLength -pass");
}

try {
  geojsonTester(invalidGeojsonGeometryLineZeroLength);
  console.log("object invalidGeojsonGeometryLineZeroLength -fail");
} catch (e) {
  console.log("object invalidGeojsonGeometryLineZeroLength -pass");
}

try {
  geojsonTester(JSON.stringify(invalidGeojsonGeometryPolygonSelfIntersect));
  console.log("string invalidGeojsonGeometryPolygonSelfIntersect -fail");
} catch (e) {
  console.log("string invalidGeojsonGeometryPolygonSelfIntersect -pass");
}

try {
  geojsonTester(invalidGeojsonGeometryPolygonSelfIntersect);
  console.log("object invalidGeojsonGeometryPolygonSelfIntersect -fail");
} catch (e) {
  console.log("object invalidGeojsonGeometryPolygonSelfIntersect -pass");
}

try {
  geojsonTester(JSON.stringify(invalidGeojsonGeometryPolygonUnclosed));
  console.log("string invalidGeojsonGeometryPolygonUnclosed -fail");
} catch (e) {
  console.log("string invalidGeojsonGeometryPolygonUnclosed -pass");
}

try {
  geojsonTester(invalidGeojsonGeometryPolygonUnclosed);
  console.log("object invalidGeojsonGeometryPolygonUnclosed -fail");
} catch (e) {
  console.log("object invalidGeojsonGeometryPolygonUnclosed -pass");
}
string invalidGeojsonGeometryLineZeroLength -fail
object invalidGeojsonGeometryLineZeroLength -pass
string invalidGeojsonGeometryPolygonSelfIntersect -fail
object invalidGeojsonGeometryPolygonSelfIntersect -pass
string invalidGeojsonGeometryPolygonUnclosed -pass
object invalidGeojsonGeometryPolygonUnclosed -pass

Scavenge for valid objects

There should be a mode where, if you have a FeatureCollection with 999 good features and 1 bad feature, it's able to give you the 999 and report the 1.

Error during build: check-geojson.esm.js

Hi there, I receive the following error while running a build with Vite:

[vite:resolve] Failed to resolve entry for package "@placemarkio/check-geojson". The package may have incorrect main/module/exports specified in its package.json: Failed to resolve entry for package "@placemarkio/check-geojson". The package may have incorrect main/module/exports specified in its package.json.
error during build:
Error: Failed to resolve entry for package "@placemarkio/check-geojson". The package may have incorrect main/module/exports specified in its package.json: Failed to resolve entry for package "@placemarkio/check-geojson". The package may have incorrect main/module/exports specified in its package.json.
    at packageEntryFailure (/home/brian/Dev/parent-aoi-tasks/frontend/node_modules/vite/dist/node/chunks/dep-611778e0.js:38290:11)
    at resolvePackageEntry (/home/brian/Dev/parent-aoi-tasks/frontend/node_modules/vite/dist/node/chunks/dep-611778e0.js:38286:9)
    at tryNodeResolve (/home/brian/Dev/parent-aoi-tasks/frontend/node_modules/vite/dist/node/chunks/dep-611778e0.js:38093:20)
    at Object.resolveId (/home/brian/Dev/parent-aoi-tasks/frontend/node_modules/vite/dist/node/chunks/dep-611778e0.js:37901:28)
    at /home/brian/Dev/parent-aoi-tasks/frontend/node_modules/rollup/dist/shared/rollup.js:22779:37
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

I believe the issue is that in your package.json, you have "module": "dist/check-geojson.esm.js". check-geojson.esm.js doesn't seem to exist? The build completes when I remove this line. I'm wondering if this now should reference index.esm.js?

Refactoring

Got sort of a mishmosh of utility functions. Rethink them and unify around a clearer set of fundamentals.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.