Reintroducing WebWorkers (pfeeew, Vite makes it tough !)
This commit is contained in:
1 parent
02f02984e5
commit
5de30283b1
52 files changed
+3362
-47
No files matched your search
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
export const thisIsAModule = true;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
declare global {
|
||||
var _allCaches: any;
|
||||
}
|
||||
|
||||
globalThis._allCaches = new Map();
|
||||
|
||||
const cache = {
|
||||
set: (params: any) => {
|
||||
const { cacheId, key, value } = params;
|
||||
if (!_allCaches.has(cacheId)) {
|
||||
_allCaches.set(cacheId, new Map());
|
||||
}
|
||||
const k = _allCaches.get(cacheId);
|
||||
k.set(key, value);
|
||||
},
|
||||
get: (params: any) => {
|
||||
const { cacheId, key } = params;
|
||||
if (!_allCaches.has(cacheId)) {
|
||||
return null;
|
||||
}
|
||||
const k = _allCaches.get(cacheId);
|
||||
if (!k.has(key)) {
|
||||
return null;
|
||||
}
|
||||
const value = k.get(key);
|
||||
k.delete(key);
|
||||
k.set(key, value);
|
||||
return value;
|
||||
},
|
||||
delete: (params: any) => {
|
||||
const { cacheId, key } = params;
|
||||
if (!_allCaches.has(cacheId)) {
|
||||
return null;
|
||||
}
|
||||
const k = _allCaches.get(cacheId);
|
||||
if (!k.has(key)) {
|
||||
return null;
|
||||
}
|
||||
const value = k.get(key);
|
||||
k.delete(key);
|
||||
return value;
|
||||
},
|
||||
map: (params: any) => {
|
||||
const { cacheId } = params;
|
||||
if (!_allCaches.has(cacheId)) {
|
||||
return null;
|
||||
}
|
||||
return _allCaches.get(cacheId);
|
||||
},
|
||||
};
|
||||
|
||||
export default cache;
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* DocURI: Rich document ids for CouchDB.
|
||||
*
|
||||
* Copyright (c) 2014 null2 GmbH Berlin
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
// type/id/subtype/index/version
|
||||
|
||||
// var docuri = (module.exports = exports = {});
|
||||
|
||||
// Cached regular expressions for matching named param parts and splatted parts
|
||||
// of route strings.
|
||||
// http://backbonejs.org/docs/backbone.html#section-158
|
||||
var optionalParam = /\((.*?)\)/g;
|
||||
var namedParam = /(\(\?)?:\w+/g;
|
||||
var splatParam = /\*\w+/g;
|
||||
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
|
||||
var paramKeys = /[*:]\w+/g;
|
||||
|
||||
// Convert a route string into a regular expression,
|
||||
// with named regular expressions for named arguments.
|
||||
// http://backbonejs.org/docs/backbone.html#section-165
|
||||
function routeToRegExp(src) {
|
||||
var keys = [],
|
||||
match;
|
||||
|
||||
while ((match = paramKeys.exec(src)) !== null) {
|
||||
keys.push(match[0]);
|
||||
}
|
||||
|
||||
var route = src
|
||||
.replace(escapeRegExp, '\\$&')
|
||||
.replace(optionalParam, '(?:$1)?')
|
||||
.replace(namedParam, function (match, optional) {
|
||||
return optional ? match : '([^/?]+)';
|
||||
})
|
||||
.replace(splatParam, '([^?]*?)');
|
||||
|
||||
keys = keys.reduce(function (memo, key) {
|
||||
var value = '\\' + key;
|
||||
|
||||
memo[key] = new RegExp(value + '(\\/|\\)|\\(|$)');
|
||||
|
||||
return memo;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
src: src,
|
||||
exp: new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'),
|
||||
keys: keys,
|
||||
};
|
||||
}
|
||||
|
||||
// Given a route and a DocURI return an object of extracted parameters.
|
||||
// Unmatched DocURIs will be treated as false.
|
||||
// http://backbonejs.org/docs/backbone.html#section-166
|
||||
function extractParameters(route, fragment, coding) {
|
||||
var params = route.exp.exec(fragment);
|
||||
|
||||
if (!params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
params = params.slice(1);
|
||||
|
||||
return Object.keys(route.keys).reduce(function (memo, key, i) {
|
||||
var param = params[i];
|
||||
|
||||
if (param) {
|
||||
var k = key.substr(1);
|
||||
var decoder = (coding[k] ?? { decoder: decodeURIComponent }).decoder;
|
||||
|
||||
if (key[0] === '*') {
|
||||
param = param.split('/').map(decoder);
|
||||
} else {
|
||||
param = decoder(param);
|
||||
}
|
||||
|
||||
memo[key.substr(1)] = param;
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Insert named parameters from object.
|
||||
function insertParameters(route, obj, coding) {
|
||||
var str = route.src;
|
||||
|
||||
Object.keys(route.keys).forEach(function (key) {
|
||||
var k = key.substr(1);
|
||||
var value = obj[k] !== undefined ? obj[k] : '';
|
||||
|
||||
var encoder = (coding[k] ?? { encoder: encodeURIComponent }).encoder;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
value = value.map(encoder).join('/');
|
||||
} else {
|
||||
value = encoder(value);
|
||||
}
|
||||
|
||||
str = str.replace(route.keys[key], value + '$1');
|
||||
});
|
||||
|
||||
// massage optional parameter
|
||||
return str.replace(/\(\/\)/g, '').replace(/[)(]/g, '');
|
||||
}
|
||||
|
||||
export const route = (route, coding = {}) => {
|
||||
route = routeToRegExp(route);
|
||||
|
||||
return function (source, target) {
|
||||
source = source || {};
|
||||
|
||||
if (target) {
|
||||
source = extractParameters(route, source, coding);
|
||||
Object.keys(target).forEach(function (key) {
|
||||
source[key] = target[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof source === 'object') {
|
||||
return insertParameters(route, source, coding);
|
||||
}
|
||||
|
||||
if (typeof source === 'string') {
|
||||
return extractParameters(route, source, coding);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default route;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Rectangle } from '../components/map/types';
|
||||
|
||||
// cf https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#ECMAScript_(JavaScript/ActionScript,_etc.)
|
||||
export const lon2tile = (lon: number, zoom: number) => {
|
||||
return ((Number(lon) + 180) / 360) * Math.pow(2, zoom);
|
||||
};
|
||||
export const lat2tile = (lat: number, zoom: number) => {
|
||||
return (
|
||||
((1 -
|
||||
Math.log(
|
||||
Math.tan((Number(lat) * Math.PI) / 180) +
|
||||
1 / Math.cos((Number(lat) * Math.PI) / 180)
|
||||
) /
|
||||
Math.PI) /
|
||||
2) *
|
||||
Math.pow(2, zoom)
|
||||
);
|
||||
};
|
||||
|
||||
export function tile2long(x: number, z: number) {
|
||||
return (x / Math.pow(2, z)) * 360 - 180;
|
||||
}
|
||||
|
||||
export function tile2lat(y: number, z: number) {
|
||||
var n = Math.PI - (2 * Math.PI * y) / Math.pow(2, z);
|
||||
return (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
||||
}
|
||||
|
||||
export const rectanglesIntersect = (r1: Rectangle, r2: Rectangle) =>
|
||||
!(
|
||||
r2.topLeft.x > r1.bottomRight.x ||
|
||||
r2.bottomRight.x < r1.topLeft.x ||
|
||||
r2.topLeft.y > r1.bottomRight.y ||
|
||||
r2.bottomRight.y < r1.topLeft.y
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Zheng-Xiang Ke
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,91 @@
|
||||
# gpx-parser-builder
|
||||
A simple gpx parser and builder between GPX string and JavaScript object. It is dependent on [isomorphic-xml2js](https://github.com/RikkiGibson/isomorphic-xml2js).
|
||||
|
||||
[](https://www.npmjs.com/package/gpx-parser-builder)
|
||||
[](https://github.com/kf99916/gpx-parser-builder/stargazers)
|
||||
[](https://github.com/kf99916/gpx-parser-builder/network)
|
||||
[](https://www.npmjs.com/package/gpx-parser-builder)
|
||||
[](https://github.com/kf99916/gpx-parser-builder/blob/master/LICENSE)
|
||||
|
||||
## Requirements
|
||||
|
||||
gpx-parser-builder is written with ECMAScript 6. You can leverage [Babel](https://babeljs.io/) and [Webpack](https://webpack.js.org/) to make all browsers available.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install gpx-parser-builder --save
|
||||
```
|
||||
|
||||
## Version
|
||||
|
||||
v1.0.0+ is a breaking change for v0.2.2-. v1.0.0+ fully supports gpx files including waypoints, routes, and tracks. Every gpx type is 1-1 corresponding to a JavaScript class.
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
import GPX from 'gpx-parser-builder';
|
||||
|
||||
// Parse gpx
|
||||
const gpx = GPX.parse('GPX_STRING');
|
||||
|
||||
window.console.dir(gpx.metadata);
|
||||
window.console.dir(gpx.wpt);
|
||||
window.console.dir(gpx.trk);
|
||||
|
||||
// Build gpx
|
||||
window.console.log(gpx.toString());
|
||||
```
|
||||
|
||||
Get more details about usage with the unit tests.
|
||||
|
||||
### GPX
|
||||
|
||||
The GPX JavaScript object.
|
||||
|
||||
`constructor(object)`
|
||||
|
||||
```javascript
|
||||
const gpx = new Gpx({$:{...}, metadat: {...}, wpt:[{...},{...}]}, trk: {...}, rte: {...})
|
||||
```
|
||||
|
||||
#### Member Variables
|
||||
|
||||
`$` the attributes for the gpx element. Default value:
|
||||
```javascript
|
||||
{
|
||||
'version': '1.1',
|
||||
'creator': 'gpx-parser-builder',
|
||||
'xmlns': 'http://www.topografix.com/GPX/1/1',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xsi:schemaLocation': 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd'
|
||||
}
|
||||
```
|
||||
|
||||
`metadata` the metadata for the gpx.
|
||||
|
||||
`wpt` array of waypoints. It is corresponded to `<wpt>`. The type of all elements in `wpt` is `Waypoint`;
|
||||
|
||||
`rte` array of routes. It is corresponded to `<rte>`. The type of all elements in `rte` is `Route`;
|
||||
|
||||
`trk` array of tracks. It is corresponded to `<trk>`. The type of all elements in `trk` is `Track`;
|
||||
|
||||
#### Static Methods
|
||||
|
||||
`parse(gpxString)` parse gpx string to Gpx object. return `null` if parsing failed.
|
||||
|
||||
#### Member Methods
|
||||
|
||||
`toString(options)` GPX object to gpx string. The options is for [isomorphic-xml2js](https://github.com/RikkiGibson/isomorphic-xml2js).
|
||||
|
||||
## Save as GPX file in the frontend
|
||||
|
||||
You can leverage [StreamSaver.js](https://github.com/jimmywarting/StreamSaver.js) or [FileSaver.js](https://github.com/eligrey/FileSaver.js) to save as GPX file. ⚠️Not all borwsers support the above file techniques. ⚠️️️
|
||||
|
||||
## Author
|
||||
|
||||
Zheng-Xiang Ke, kf99916@gmail.com
|
||||
|
||||
## License
|
||||
|
||||
gpx-parser-builder is available under the MIT license. See the LICENSE file for more info.
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "gpx-parser-builder",
|
||||
"version": "1.0.2",
|
||||
"description": "A simple gpx parser and builder between GPX string and JavaScript object",
|
||||
"main": "./src/gpx.js",
|
||||
"scripts": {
|
||||
"test": "mocha --require @babel/register test/**/*.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/kf99916/gpx-parser-builder.git"
|
||||
},
|
||||
"keywords": [
|
||||
"gpx",
|
||||
"parser",
|
||||
"builder"
|
||||
],
|
||||
"author": "Zheng-Xiang Ke",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/kf99916/gpx-parser-builder/issues"
|
||||
},
|
||||
"homepage": "https://github.com/kf99916/gpx-parser-builder",
|
||||
"files": [
|
||||
"src"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.7",
|
||||
"@babel/preset-env": "~7.7",
|
||||
"@babel/register": "~7.7",
|
||||
"mocha": "~6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"isomorphic-xml2js": "~0.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export default class Bounds {
|
||||
constructor(object) {
|
||||
this.minlat = object.minlat;
|
||||
this.minlon = object.minlon;
|
||||
this.maxlat = object.maxlat;
|
||||
this.maxlon = object.maxlon;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export default class Copyright {
|
||||
constructor(object) {
|
||||
this.author = object.author;
|
||||
this.year = object.year;
|
||||
this.license = object.license;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
declare module 'gpx-parser-builder' {
|
||||
class GPX {
|
||||
static parse(gpxString: any): any;
|
||||
constructor(object: any);
|
||||
$: any;
|
||||
extensions: any;
|
||||
metadata: any;
|
||||
wpt: any;
|
||||
rte: any;
|
||||
trk: any;
|
||||
toString(options: any): string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import * as xml2js from 'isomorphic-xml2js';
|
||||
import Metadata from './metadata';
|
||||
import Waypoint from './waypoint';
|
||||
import Route from './route';
|
||||
import Track from './track';
|
||||
import {removeEmpty, allDatesToISOString} from './utils';
|
||||
|
||||
const defaultAttributes = {
|
||||
version: '1.1',
|
||||
creator: 'gpx-parser-builder',
|
||||
xmlns: 'http://www.topografix.com/GPX/1/1',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xsi:schemaLocation':
|
||||
'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd'
|
||||
}
|
||||
|
||||
export default class GPX {
|
||||
constructor(object) {
|
||||
this.$ = Object.assign({}, defaultAttributes, object.$ || object.attributes || {});
|
||||
this.extensions = object.extensions;
|
||||
|
||||
if (object.metadata) {
|
||||
this.metadata = new Metadata(object.metadata);
|
||||
}
|
||||
if (object.wpt) {
|
||||
if (!Array.isArray(object.wpt)) {
|
||||
object.wpt = [object.wpt];
|
||||
}
|
||||
this.wpt = object.wpt.map(wpt => new Waypoint(wpt));
|
||||
}
|
||||
if (object.rte) {
|
||||
if (!Array.isArray(object.rte)) {
|
||||
object.rte = [object.rte];
|
||||
}
|
||||
this.rte = object.rte.map(rte => new Route(rte));
|
||||
}
|
||||
if (object.trk) {
|
||||
if (!Array.isArray(object.trk)) {
|
||||
object.trk = [object.trk];
|
||||
}
|
||||
this.trk = object.trk.map(trk => new Track(trk));
|
||||
}
|
||||
|
||||
removeEmpty(this);
|
||||
}
|
||||
|
||||
static parse(gpxString) {
|
||||
let gpx;
|
||||
xml2js.parseString(gpxString, {
|
||||
explicitArray: false
|
||||
}, (err, xml) => {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
if (!xml.gpx) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpx = new GPX({
|
||||
attributes: xml.gpx.$,
|
||||
metadata: xml.gpx.metadata,
|
||||
wpt: xml.gpx.wpt,
|
||||
rte: xml.gpx.rte,
|
||||
trk: xml.gpx.trk
|
||||
});
|
||||
});
|
||||
|
||||
return gpx;
|
||||
}
|
||||
|
||||
toString(options) {
|
||||
options = options || {};
|
||||
options.rootName = 'gpx';
|
||||
|
||||
const builder = new xml2js.Builder(options), gpx = new GPX(this);
|
||||
allDatesToISOString(gpx);
|
||||
return builder.buildObject(gpx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export default class Link {
|
||||
constructor(object) {
|
||||
this.$ = {};
|
||||
this.$.href = object.$.href || object.href;
|
||||
this.text = object.text;
|
||||
this.type = object.type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import Copyright from './copyright';
|
||||
import Link from './link';
|
||||
import Person from './person';
|
||||
import Bounds from './bounds';
|
||||
|
||||
export default class Metadata {
|
||||
constructor(object) {
|
||||
this.name = object.name;
|
||||
this.desc = object.desc;
|
||||
this.time = object.time ? new Date(object.time) : new Date();
|
||||
this.keywords = object.keywords;
|
||||
this.extensions = object.extensions;
|
||||
if (object.author) {
|
||||
this.author = new Person(object.author);
|
||||
}
|
||||
if (object.link) {
|
||||
if (!Array.isArray(object.link)) {
|
||||
object.link = [object.link];
|
||||
}
|
||||
this.link = object.link.map(l => new Link(l));
|
||||
}
|
||||
if (object.bounds) {
|
||||
this.bounds = new Bounds(object.bounds);
|
||||
}
|
||||
if (object.copyright) {
|
||||
this.copyright = new Copyright(object.copyright);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import Link from './link';
|
||||
|
||||
export default class Person {
|
||||
constructor(object) {
|
||||
this.name = object.name;
|
||||
this.email = object.email;
|
||||
if (object.link) {
|
||||
this.link = new Link(object.link);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import Waypoint from './waypoint';
|
||||
import Link from './link';
|
||||
|
||||
export default class Route {
|
||||
constructor(object) {
|
||||
this.name = object.name;
|
||||
this.cmt = object.cmt;
|
||||
this.desc = object.desc;
|
||||
this.src = object.src;
|
||||
this.number = object.number;
|
||||
this.type = object.type;
|
||||
this.extensions = object.extensions;
|
||||
if (object.link) {
|
||||
if (!Array.isArray(object.link)) {
|
||||
this.link = [object.link];
|
||||
}
|
||||
this.link = object.link.map(l => new Link(l));
|
||||
}
|
||||
|
||||
if (object.rtept) {
|
||||
if (!Array.isArray(object.rtept)) {
|
||||
this.rtept = [object.rtept];
|
||||
}
|
||||
this.rtept = object.rtept.map(pt => new Waypoint(pt));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import Waypoint from './waypoint';
|
||||
|
||||
export default class TrackSegment {
|
||||
constructor(object) {
|
||||
if (object.trkpt) {
|
||||
if (!Array.isArray(object.trkpt)) {
|
||||
object.trkpt = [object.trkpt];
|
||||
}
|
||||
this.trkpt = object.trkpt.map(pt => new Waypoint(pt));
|
||||
}
|
||||
this.extensions = object.extensions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import TrackSegment from './track-segment';
|
||||
import Link from './link';
|
||||
|
||||
export default class Track {
|
||||
constructor(object) {
|
||||
this.name = object.name;
|
||||
this.cmt = object.cmt;
|
||||
this.desc = object.desc;
|
||||
this.src = object.src;
|
||||
this.number = object.number;
|
||||
this.type = object.type;
|
||||
this.extensions = object.extensions;
|
||||
if (object.link) {
|
||||
if (!Array.isArray(object.link)) {
|
||||
object.link = [object.link];
|
||||
}
|
||||
this.link = object.link.map(l => new Link(l));
|
||||
}
|
||||
if (object.trkseg) {
|
||||
if (!Array.isArray(object.trkseg)) {
|
||||
object.trkseg = [object.trkseg];
|
||||
}
|
||||
this.trkseg = object.trkseg.map(seg => new TrackSegment(seg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
function removeEmpty(obj) {
|
||||
Object.entries(obj).forEach(([key, val]) => {
|
||||
if (val && val instanceof Object) {
|
||||
removeEmpty(val);
|
||||
} else if (val == null) {
|
||||
delete obj[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function allDatesToISOString(obj) {
|
||||
Object.entries(obj).forEach(([key, val]) => {
|
||||
if (val) {
|
||||
if (val instanceof Date) {
|
||||
obj[key] = val.toISOString().split('.')[0] + 'Z';
|
||||
} else if (val instanceof Object) {
|
||||
allDatesToISOString(val);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export { removeEmpty, allDatesToISOString };
|
||||
@@ -0,0 +1,32 @@
|
||||
import Link from './link';
|
||||
|
||||
export default class Waypoint {
|
||||
constructor(object) {
|
||||
this.$ = {};
|
||||
this.$.lat = object.$.lat === 0 || object.lat === 0 ? 0 : object.$.lat || object.lat || -1;
|
||||
this.$.lon = object.$.lon === 0 || object.lon === 0 ? 0 : object.$.lon || object.lon || -1;
|
||||
this.ele = object.ele;
|
||||
this.time = object.time ? new Date(object.time) : new Date();
|
||||
this.magvar = object.magvar;
|
||||
this.geoidheight = object.geoidheight;
|
||||
this.name = object.name;
|
||||
this.cmt = object.cmt;
|
||||
this.desc = object.desc;
|
||||
this.src = object.src;
|
||||
this.sym = object.sym;
|
||||
this.type = object.type;
|
||||
this.sat = object.sat;
|
||||
this.hdop = object.hdop;
|
||||
this.vdop = object.vdop;
|
||||
this.pdop = object.pdop;
|
||||
this.ageofdgpsdata = object.ageofdgpsdata;
|
||||
this.dgpsid = object.dgpsid;
|
||||
this.extensions = object.extensions;
|
||||
if (object.link) {
|
||||
if (!Array.isArray(object.link)) {
|
||||
object.link = [object.link];
|
||||
}
|
||||
this.link = object.link.map(l => new Link(l));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { assert } from 'console';
|
||||
import { findStartTime } from './gpx';
|
||||
|
||||
describe('findStartTime', () => {
|
||||
test('to be undefined for a string', () => {
|
||||
const start = findStartTime('');
|
||||
expect(start).toBeUndefined();
|
||||
});
|
||||
test('to be undefined for an object without time key', () => {
|
||||
const start = findStartTime({ foo: 'foo', bar: 'bar' });
|
||||
expect(start).toBeUndefined();
|
||||
});
|
||||
test('to be the time value for an object with a time key', () => {
|
||||
const start = findStartTime({ foo: 'foo', time: 'bar' });
|
||||
expect(start).toEqual('bar');
|
||||
});
|
||||
test('to be the lowest time value for an object with several time keys', () => {
|
||||
const start = findStartTime({
|
||||
foo: { time: 'foo' },
|
||||
time: 'bar',
|
||||
bar: { time: 'a' },
|
||||
});
|
||||
expect(start).toEqual('a');
|
||||
});
|
||||
test('to be the lowest time value for an array with several objects with time keys', () => {
|
||||
const start = findStartTime({
|
||||
foos: [{ time: 'foo' }, { time: '0' }],
|
||||
time: 'bar',
|
||||
bar: { time: 'a' },
|
||||
});
|
||||
expect(start).toEqual('0');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
const min = (s1?: string, s2?: string) => {
|
||||
return s1! < s2! ? s1 : s2;
|
||||
};
|
||||
|
||||
export const findStartTime = (x: any, startTime?: string) => {
|
||||
if (typeof x === 'object') {
|
||||
let newStartTime = startTime;
|
||||
|
||||
for (const key in x) {
|
||||
if (key === 'time') {
|
||||
newStartTime = min(newStartTime, x[key]);
|
||||
} else {
|
||||
newStartTime = findStartTime(x[key], newStartTime);
|
||||
}
|
||||
}
|
||||
return newStartTime;
|
||||
}
|
||||
else return startTime;
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
import { route } from './docuri';
|
||||
import uri from './ids';
|
||||
|
||||
describe('Checking some DocURI features', () => {
|
||||
test(', basic route', () => {
|
||||
const gpx = route('gpx/:id');
|
||||
expect(gpx({ id: 10 })).toBe('gpx/10');
|
||||
});
|
||||
test(', basic route (vice-versa', () => {
|
||||
const gpx = route('gpx/:id');
|
||||
expect(gpx('gpx/10')).toMatchObject({ id: '10' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking a multilevel route', () => {
|
||||
test(', using the two levels', () => {
|
||||
const gpx = route('gpx/:gpx/3trk/:trk');
|
||||
expect(gpx({ gpx: 10, trk: 0 })).toBe('gpx/10/3trk/0');
|
||||
});
|
||||
test(', using the two levels (vive-versa)', () => {
|
||||
const gpx = route('gpx/:gpx/3trk/:trk');
|
||||
expect(gpx('gpx/10/3trk/0')).toMatchObject({ gpx: '10', trk: '0' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking a multilevel route with optional part', () => {
|
||||
test(', using the two levels', () => {
|
||||
const gpx = route('gpx/:gpx(/3trk/:trk)');
|
||||
expect(gpx({ gpx: 10, trk: 0 })).toBe('gpx/10/3trk/0');
|
||||
});
|
||||
test(', using the two levels (vive-versa)', () => {
|
||||
const gpx = route('gpx/:gpx(/3trk/:trk)');
|
||||
expect(gpx('gpx/10/3trk/0')).toMatchObject({ gpx: '10', trk: '0' });
|
||||
});
|
||||
test(', using only one level', () => {
|
||||
const gpx = route('gpx/:gpx(/3trk/:trk)');
|
||||
expect(gpx({ gpx: 10 })).toBe('gpx/10/3trk/'); //Unfortunately !
|
||||
});
|
||||
test(', using only one level (vive-versa)', () => {
|
||||
const gpx = route('gpx/:gpx(/3trk/:trk)');
|
||||
expect(gpx('gpx/10')).toMatchObject({ gpx: '10' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking gpx ids', () => {
|
||||
const id = {
|
||||
gpx: 1234567890123456,
|
||||
};
|
||||
const key = 'gpx/1234567890123456';
|
||||
test(', vice', () => {
|
||||
const gpx = uri('gpx', id);
|
||||
expect(gpx).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const gpx = uri('gpx', key);
|
||||
expect(gpx).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking trk ids', () => {
|
||||
const id = {
|
||||
gpx: 1234567890123456,
|
||||
trk: 123456,
|
||||
};
|
||||
const key = 'gpx/1234567890123456/3trk/123456';
|
||||
test(', vice', () => {
|
||||
const rte = uri('trk', id);
|
||||
expect(rte).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const rte = uri('trk', key);
|
||||
expect(rte).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking trkseg ids', () => {
|
||||
const id = {
|
||||
gpx: 111,
|
||||
trk: 0,
|
||||
trkseg: 3,
|
||||
};
|
||||
const key = 'gpx/0000000000000111/3trk/000000/000003';
|
||||
test(', vice', () => {
|
||||
const rte = uri('trkseg', id);
|
||||
expect(rte).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const rte = uri('trkseg', key);
|
||||
expect(rte).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking trkpt ids', () => {
|
||||
const id = {
|
||||
gpx: 25,
|
||||
trk: 8,
|
||||
trkseg: 0,
|
||||
trkpt: 155,
|
||||
};
|
||||
const key = 'gpx/0000000000000025/3trk/000008/000000/000155';
|
||||
test(', vice', () => {
|
||||
const rte = uri('trkpt', id);
|
||||
expect(rte).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const rte = uri('trkpt', key);
|
||||
expect(rte).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking settings id', () => {
|
||||
test(', vice', () => {
|
||||
const rte = uri('settings', {});
|
||||
expect(rte).toBe('settings');
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const rte = uri('settings', 'settings');
|
||||
expect(rte).toMatchObject({});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import route from './docuri';
|
||||
|
||||
const integerType = (n: number) => {
|
||||
return {
|
||||
encoder: (v: number) => v.toString().padStart(n, '0'),
|
||||
decoder: parseInt,
|
||||
};
|
||||
};
|
||||
|
||||
const bigIntType = (n: number) => {
|
||||
return {
|
||||
encoder: (v: number) => v.toString().padStart(n, '0'),
|
||||
decoder: BigInt,
|
||||
};
|
||||
};
|
||||
|
||||
const coding = {
|
||||
gpx: integerType(16),
|
||||
wpt: integerType(6),
|
||||
rte: integerType(6),
|
||||
rtept: integerType(6),
|
||||
trk: integerType(6),
|
||||
trkseg: integerType(6),
|
||||
trkpt: integerType(6),
|
||||
};
|
||||
|
||||
const routes = {
|
||||
dbdef: route('dbdef', coding),
|
||||
settings: route('settings', coding),
|
||||
gpx: route('gpx/:gpx', coding),
|
||||
wpt: route('gpx/:gpx/1wpt/:wpt', coding),
|
||||
rte: route('gpx/:gpx/2rte/:rte', coding),
|
||||
rtept: route('gpx/:gpx/2rte/:rte/:rtept', coding),
|
||||
trk: route('gpx/:gpx/3trk/:trk', coding),
|
||||
trkseg: route('gpx/:gpx/3trk/:trk/:trkseg', coding),
|
||||
trkpt: route('gpx/:gpx/3trk/:trk/:trkseg/:trkpt', coding),
|
||||
extensions: route('gpx/:gpx/4extensions', coding),
|
||||
};
|
||||
|
||||
type RouteKey = keyof typeof routes;
|
||||
|
||||
const uri = (type: RouteKey, param: any) => {
|
||||
return routes[type](param);
|
||||
};
|
||||
|
||||
export default uri;
|
||||
|
||||
const minDate = -8640000000000000;
|
||||
const halfMinDate = minDate / 2;
|
||||
|
||||
export const intToGpxId = (i: number) => Math.round(i / 2) - halfMinDate;
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
interface IdGpx {
|
||||
gpx: number;
|
||||
}
|
||||
|
||||
interface IdTrk {
|
||||
gpx: number;
|
||||
trk: number;
|
||||
}
|
||||
interface IdTrkseg {
|
||||
gpx: number;
|
||||
trk: number;
|
||||
trkseg: number;
|
||||
}
|
||||
interface IdTrkpt {
|
||||
gpx: number;
|
||||
trk: number;
|
||||
trkseg: number;
|
||||
trkpt: number;
|
||||
}
|
||||
interface IdWpt {
|
||||
gpx: number;
|
||||
wpt: number;
|
||||
}
|
||||
|
||||
interface IdRte {
|
||||
gpx: number;
|
||||
rte: number;
|
||||
}
|
||||
|
||||
interface IdRtept {
|
||||
gpx: number;
|
||||
rte: number;
|
||||
rtept: number;
|
||||
}
|
||||
Reference in new issue
Block a user