osm2geojson-lite 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,15 @@
1
1
  osm2geojson-lite
2
2
  ============
3
3
 
4
+ [![NPM Version](https://img.shields.io/npm/v/osm2geojson-lite)](https://www.npmjs.com/package/osm2geojson-lite) [![Codecov](https://img.shields.io/codecov/c/github/tibetty/osm2geojson-lite/master.svg)](https://codecov.io/gh/tibetty/osm2geojson-lite/)
5
+
6
+
4
7
  A lightweight (not as lightweight as xml2geojson though) yet faster convertor for [OSM](http://openstreetmap.org) [data](http://wiki.openstreetmap.org/wiki/OSM_XML) whatever in XML or JSON formats to [GeoJSON](http://www.geojson.org/) - much faster (the more complex the data source is, the more performance advantages it posesses) than osmtogeojson in most situations - implemented in pure JavaScript without any 3rd party dependency.
5
8
 
6
9
  History
7
10
  -----
8
11
  An internal function inside [query-geo-boundary](https://www.npmjs.com/package/query-geo-boundary) → stripped out to handle OSM XML only [xml2geojson-lite](https://www.npmjs.com/package/xml2geojson-lite) → this library that supports both OSM XML and OSM/Overpass JSON
9
12
 
10
- Changelog:
11
- -----
12
- * Late 2018: this repository was created and the initial version was pushed to github - almost around specific usages for myself.
13
- * 2019-2025: quite a few contributors had fixed quite a few bugs and also contributed some good ideas - thanks for their efforts!
14
- * 2025-03-03: fixed a few bugs around non-*Polygon features processing and convert it to a pure TypeScript project (codes published to [NPM](https://npmjs.org/) have become TSC compiled from now on).
15
-
16
13
  Usage
17
14
  -----
18
15
 
@@ -25,7 +22,7 @@ Installation:
25
22
  Usage:
26
23
 
27
24
  ```js
28
- const osm2geojson = require('osm2geojson-lite');
25
+ import osm2geojson from 'osm2geojson-lite';
29
26
  let geojson = osm2geojson(osm, opts);
30
27
  ```
31
28
 
@@ -46,9 +43,9 @@ Converts OSM data (XML/JSON) to GeoJSON.
46
43
 
47
44
  * `osm`: the OSM XML data in String, or OSM/Overpass JSON as object or in String
48
45
  * `opts?`: optional, the options object, right now supports below properties/fields:
49
- - `completeFeature/allFeatures`: the default value is `false`. When it's set to `true`, the returned geojson will include all elements that meet the specified conditions in `FeatureCollection` format; otherwise, only the bare geometry of the first `relation` element will be returned.
50
- - `renderTagged`: the default value is `false`. When it's set to `true`, the returned geojson will include all elements with tags (i.e., tagged) until `suppressWay` changes its behavior a bit; otherwise only the unreferenced ones get returned.
51
- - `suppressWay/excludeWay`: the default value is `true`. When it's set to `true`, the returned `FeatureCollection` will exclude all referenced `way`s even though they are tagged; otherwise the features of those `way`s will be included in the resulted result as well.
46
+ - `completeFeature`: the default value is `false`. When it's set to `true`, the returned geojson will include all elements that meet the specified conditions in `FeatureCollection` format; otherwise, only the bare geometry of the first `relation` element will be returned.
47
+ - `renderTagged`: the default value is `false`. When it's set to `true`, the returned geojson will include all elements with tags (i.e., tagged) until `excludeWay` changes its behavior a bit; otherwise only the unreferenced ones get returned.
48
+ - `excludeWay`: the default value is `true`. When it's set to `true`, the returned `FeatureCollection` will exclude all referenced `way`s even though they are tagged; otherwise the features of those `way`s will be included in the resulted result as well.
52
49
 
53
50
 
54
51
  Performance
@@ -58,9 +55,8 @@ Performance
58
55
  3. For each script, run as many as times seperately and then calculate the average cost time (ACT for short)
59
56
  4. The # listed in the table below are coarse lowest values of dividing the ACT of `osmtogeojson` by the one of this library
60
57
  ```
61
- $ cd bench
62
- $ node o2gl-bench.js
63
- $ node otg-bench.js
58
+ $ cd test
59
+ $ npm run bench
64
60
  ```
65
61
  1. XML
66
62
 
@@ -79,7 +75,7 @@ Correctness
79
75
  ---
80
76
  You can copy the converted results to [geojsonlint](http://geojsonlint.com) for the correctness validation. Up until now, `osm2geojson-lite` behaves pretty well with all the samples (also quite representative) in the `data` subfolers under `test` and `bench` directories, which also outperforms `osmtogeojson`.
81
77
 
82
- The client side example shipped along with this package, `test/index.html` ~~will automatically call `geojsonlint` validation service directly after each conversion, you can wait for a while to see the validation result after click the conversion button.~~ - because the CORS limitation, the direct post to geojsonlint was blocked, so I added a "copy to clipboard" button for you to ease the validation.
78
+ The client side example shipped along with this package, `test/index.html` - due to CORS limitation, the direct post to geojsonlint is blocked, so there's a "copy to clipboard" button for you to ease the validation.
83
79
 
84
80
  Node.JS version
85
81
  ---
@@ -91,10 +87,10 @@ Dependencies
91
87
 
92
88
  License
93
89
  ---
94
- Copyleft
90
+ MIT
95
91
 
96
92
  Collaborators
97
93
  ---
98
- * tibetty
99
- * HarelM
94
+ * [tibetty](https://github.com/tibetty/)
95
+ * [HarelM](https://github.com/HarelM)
100
96
 
package/package.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "bugs": {
26
26
  "url": "https://github.com/tibetty/osm2geojson-lite/issues"
27
27
  },
28
- "bundleDependencies": false,
28
+ "bundleDependencies": [],
29
29
  "deprecated": false,
30
30
  "description": "a lightweight yet faster osm (either in xml or in json formats) to geojson convertor - 4x faster than xmldom + osmtogeojson in most situations - implemented in pure JavaScript without any 3rd party dependency",
31
31
  "homepage": "https://github.com/tibetty/osm2geojson-lite#readme",
@@ -53,20 +53,25 @@
53
53
  "url": "git+https://github.com/tibetty/osm2geojson-lite.git"
54
54
  },
55
55
  "scripts": {
56
- "build": "npm install && make",
57
- "test": "make test"
56
+ "build-node": "tsc --declaration && cp src/polytags.json dist/node",
57
+ "build-web": "mkdir -p dist/web && browserify -s osm2geojson dist/node/index.js | uglifyjs -c -m -o dist/web/osm2geojson-lite.js",
58
+ "build": "npm run build-node && npm run build-web",
59
+ "test": "vitest test/e2e.test.ts --coverage"
58
60
  },
59
61
  "optionalDependencies": {
60
62
  "@types/geojson": "^7946.0.16"
61
63
  },
62
- "version": "1.0.3",
64
+ "version": "1.1.0",
63
65
  "directories": {
64
66
  "lib": "lib",
65
67
  "test": "test"
66
68
  },
67
69
  "devDependencies": {
70
+ "@vitest/coverage-v8": "^3.1.3",
68
71
  "browserify": "^17.0.1",
69
- "uglify-js": "^3.19.3"
72
+ "typescript": "^5.8.3",
73
+ "uglify-js": "^3.19.3",
74
+ "vitest": "^3.1.3"
70
75
  },
71
76
  "files": [
72
77
  "dist/**/*.js",
@@ -1,12 +0,0 @@
1
- import { FeatureCollection, GeometryObject } from 'geojson';
2
- interface IOptions {
3
- completeFeature?: boolean;
4
- allFeatures?: boolean;
5
- renderTagged?: boolean;
6
- excludeWay?: boolean;
7
- suppressWay?: boolean;
8
- }
9
- declare function osm2geojson(osm: string | {
10
- [k: string]: any;
11
- }, opts?: IOptions): FeatureCollection<GeometryObject>;
12
- export = osm2geojson;
@@ -1,199 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- const osmobjs_1 = require("./osmobjs");
6
- const utils_1 = require("./utils");
7
- const xmlparser_1 = __importDefault(require("./xmlparser"));
8
- function osm2geojson(osm, opts) {
9
- let completeFeature = false;
10
- let renderTagged = false;
11
- let excludeWay = true;
12
- const parseOpts = (os) => {
13
- if (os) {
14
- completeFeature = os.completeFeature || os.allFeatures ? true : false;
15
- renderTagged = os.renderTagged ? true : false;
16
- const wayOpt = os.suppressWay || os.excludeWay;
17
- if (wayOpt !== undefined && !wayOpt) {
18
- excludeWay = false;
19
- }
20
- }
21
- };
22
- if (opts) {
23
- parseOpts(opts);
24
- }
25
- const detectFormat = (o) => {
26
- if (o.elements) {
27
- return 'json';
28
- }
29
- if (o.indexOf('<osm') >= 0) {
30
- return 'xml';
31
- }
32
- if (o.trim().startsWith('{')) {
33
- return 'json-raw';
34
- }
35
- return 'invalid';
36
- };
37
- let format = detectFormat(osm);
38
- const refElements = new utils_1.RefElements();
39
- let featureArray = [];
40
- const analyzeFeaturesFromJson = (o) => {
41
- for (const elem of osm.elements) {
42
- switch (elem.type) {
43
- case 'node':
44
- const node = new osmobjs_1.Node(elem.id, refElements);
45
- if (elem.tags) {
46
- node.addTags(elem.tags);
47
- }
48
- node.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'lat', 'lon']));
49
- node.setLatLng(elem);
50
- break;
51
- case 'way':
52
- const way = new osmobjs_1.Way(elem.id, refElements);
53
- if (elem.tags) {
54
- way.addTags(elem.tags);
55
- }
56
- way.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'nodes', 'geometry']));
57
- if (elem.geometry) {
58
- way.setLatLngArray(elem.geometry);
59
- }
60
- else if (elem.nodes) {
61
- for (const n of elem.nodes) {
62
- way.addNodeRef(n);
63
- }
64
- }
65
- break;
66
- case 'relation':
67
- const relation = new osmobjs_1.Relation(elem.id, refElements);
68
- if (elem.bounds) {
69
- relation.setBounds([parseFloat(elem.bounds.minlon), parseFloat(elem.bounds.minlat), parseFloat(elem.bounds.maxlon), parseFloat(elem.bounds.maxlat)]);
70
- }
71
- if (elem.tags) {
72
- relation.addTags(elem.tags);
73
- }
74
- relation.addProps((0, utils_1.purgeProps)(elem, ['id', 'type', 'tags', 'bounds', 'members']));
75
- if (elem.members) {
76
- for (const member of elem.members) {
77
- relation.addMember(member);
78
- }
79
- }
80
- default:
81
- break;
82
- }
83
- }
84
- };
85
- const analyzeFeaturesFromXml = (o) => {
86
- const xmlParser = new xmlparser_1.default({ progressive: true });
87
- xmlParser.on('</osm.node>', (node) => {
88
- const nd = new osmobjs_1.Node(node.id, refElements);
89
- for (const [k, v] of Object.entries(node)) {
90
- if (!k.startsWith('$') && ['id', 'lon', 'lat'].indexOf(k) < 0) {
91
- nd.addProp(k, v);
92
- }
93
- }
94
- nd.setLatLng(node);
95
- if (node.$innerNodes) {
96
- for (const ind of node.$innerNodes) {
97
- if (ind.$tag === 'tag') {
98
- nd.addTag(ind.k, ind.v);
99
- }
100
- }
101
- }
102
- });
103
- xmlParser.on('</osm.way>', (node) => {
104
- const way = new osmobjs_1.Way(node.id, refElements);
105
- for (const [k, v] of Object.entries(node)) {
106
- if (!k.startsWith('$') && ['id'].indexOf(k) < 0) {
107
- way.addProp(k, v);
108
- }
109
- }
110
- if (node.$innerNodes) {
111
- for (const ind of node.$innerNodes) {
112
- if (ind.$tag === 'nd') {
113
- if (ind.lon && ind.lat) {
114
- way.addLatLng(ind);
115
- }
116
- else if (ind.ref) {
117
- way.addNodeRef(ind.ref);
118
- }
119
- }
120
- else if (ind.$tag === 'tag') {
121
- way.addTag(ind.k, ind.v);
122
- }
123
- }
124
- }
125
- });
126
- xmlParser.on('<osm.relation>', (node) => new osmobjs_1.Relation(node.id, refElements));
127
- xmlParser.on('</osm.relation.member>', (node, parent) => {
128
- const relation = refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`);
129
- const member = {
130
- type: node.type,
131
- role: node.role ? node.role : '',
132
- ref: node.ref,
133
- };
134
- if (node.lat && node.lon) {
135
- member.lat = node.lat, member.lon = node.lon, member.tags = {};
136
- for (const [k, v] of Object.entries(node)) {
137
- if (!k.startsWith('$') && ['type', 'lat', 'lon'].indexOf(k) < 0) {
138
- member[k] = v;
139
- }
140
- }
141
- }
142
- if (node.$innerNodes) {
143
- const geometry = [];
144
- const nodes = [];
145
- for (const ind of node.$innerNodes) {
146
- if (ind.lat && ind.lon) {
147
- geometry.push(ind);
148
- }
149
- else if (ind.ref) {
150
- nodes.push(ind.ref);
151
- }
152
- }
153
- if (geometry.length > 0) {
154
- member.geometry = geometry;
155
- }
156
- else if (nodes.length > 0) {
157
- member.nodes = nodes;
158
- }
159
- }
160
- relation.addMember(member);
161
- });
162
- xmlParser.on('</osm.relation.bounds>', (node, parent) => {
163
- refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`).setBounds([parseFloat(node.minlon), parseFloat(node.minlat), parseFloat(node.maxlon), parseFloat(node.maxlat)]);
164
- });
165
- xmlParser.on('</osm.relation.tag>', (node, parent) => {
166
- refElements.get(`relation/${parent === null || parent === void 0 ? void 0 : parent.id}`).addTag(node.k, node.v);
167
- });
168
- xmlParser.parse(o);
169
- };
170
- if (format === 'json-raw') {
171
- osm = JSON.parse(osm);
172
- if (osm.elements) {
173
- format = 'json';
174
- }
175
- else {
176
- format = 'invalid';
177
- }
178
- }
179
- if (format === 'json') {
180
- analyzeFeaturesFromJson(osm);
181
- }
182
- else if (format === 'xml') {
183
- analyzeFeaturesFromXml(osm);
184
- }
185
- refElements.bindAll();
186
- for (const v of refElements.values()) {
187
- if (v.refCount <= 0 || (v.hasTag && renderTagged && !(v instanceof osmobjs_1.Way && excludeWay))) {
188
- const features = v.toFeatureArray();
189
- // return the first geometry of the first relation element
190
- if (v instanceof osmobjs_1.Relation && !completeFeature && features.length > 0) {
191
- return features[0].geometry;
192
- }
193
- featureArray = featureArray.concat(features);
194
- }
195
- }
196
- return { type: 'FeatureCollection', features: featureArray };
197
- }
198
- ;
199
- module.exports = osm2geojson;
@@ -1,73 +0,0 @@
1
- import { Feature } from 'geojson';
2
- import { RefElements } from './utils';
3
- declare class OsmObject {
4
- refCount: number;
5
- protected refElems: RefElements;
6
- private type;
7
- private id;
8
- private tags;
9
- private props;
10
- private hasTag;
11
- constructor(type: string, id: string, refElems: RefElements);
12
- addTags(tags: {
13
- [k: string]: string;
14
- }): void;
15
- addTag(k: string, v: string): void;
16
- addProp(k: string, v: any): void;
17
- addProps(props: {
18
- [k: string]: string;
19
- }): void;
20
- getCompositeId(): string;
21
- getProps(): {
22
- [k: string]: string;
23
- };
24
- toFeatureArray(): Array<Feature<any, any>>;
25
- }
26
- export declare class Node extends OsmObject {
27
- private latLng;
28
- constructor(id: string, refElems: RefElements);
29
- setLatLng(latLng: {
30
- lat: string;
31
- lon: string;
32
- }): void;
33
- toFeatureArray(): Array<Feature<any, any>>;
34
- getLatLng(): {
35
- lat: string;
36
- lon: string;
37
- } | null;
38
- }
39
- export declare class Way extends OsmObject {
40
- private latLngArray;
41
- private isPolygon;
42
- constructor(id: string, refElems: RefElements);
43
- addLatLng(latLng: {
44
- lat: string;
45
- lon: string;
46
- }): void;
47
- setLatLngArray(latLngArray: Array<{
48
- lat: string;
49
- lon: string;
50
- [k: string]: any;
51
- }>): void;
52
- addNodeRef(ref: string): void;
53
- addTags(tags: {
54
- [k: string]: string;
55
- }): void;
56
- addTag(k: string, v: string): void;
57
- toCoordsArray(): string[][];
58
- toFeatureArray(): Array<Feature<any, any>>;
59
- private analyzeTag;
60
- }
61
- export declare class Relation extends OsmObject {
62
- private relations;
63
- private nodes;
64
- private bounds;
65
- [k: string]: any;
66
- constructor(id: string, refElems: RefElements);
67
- setBounds(bounds: any[]): void;
68
- addMember(member: {
69
- [k: string]: any;
70
- }): void;
71
- toFeatureArray(): Array<Feature<any, any>>;
72
- }
73
- export {};