tileserver-gl-light 4.0.0 → 4.1.1
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/PUBLISHING.md +8 -1
- package/docs/deployment.rst +2 -2
- package/package.json +5 -5
- package/public/resources/maplibre-gl-inspect.css +2 -1
- package/public/templates/index.tmpl +1 -1
- package/publish.js +15 -9
- package/src/main.js +31 -30
- package/src/serve_data.js +22 -22
- package/src/serve_font.js +12 -12
- package/src/serve_light.js +10 -0
- package/src/serve_rendered.js +121 -120
- package/src/serve_style.js +15 -15
- package/src/server.js +122 -121
- package/src/utils.js +13 -15
- package/test/metadata.js +30 -30
- package/test/setup.js +9 -5
- package/test/static.js +4 -4
- package/test/style.js +18 -18
- package/test/tiles_data.js +4 -4
- package/test/tiles_rendered.js +5 -5
package/src/server.js
CHANGED
|
@@ -1,44 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
import os from 'os';
|
|
4
5
|
process.env.UV_THREADPOOL_SIZE =
|
|
5
|
-
Math.ceil(Math.max(4,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
Math.ceil(Math.max(4, os.cpus().length * 1.5));
|
|
7
|
+
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
import chokidar from 'chokidar';
|
|
12
|
+
import clone from 'clone';
|
|
13
|
+
import cors from 'cors';
|
|
14
|
+
import enableShutdown from 'http-shutdown';
|
|
15
|
+
import express from 'express';
|
|
16
|
+
import handlebars from 'handlebars';
|
|
17
|
+
import SphericalMercator from '@mapbox/sphericalmercator';
|
|
18
|
+
const mercator = new SphericalMercator();
|
|
19
|
+
import morgan from 'morgan';
|
|
20
|
+
import {serve_data} from './serve_data.js';
|
|
21
|
+
import {serve_style} from './serve_style.js';
|
|
22
|
+
import {serve_font} from './serve_font.js';
|
|
23
|
+
import {getTileUrls, getPublicUrl} from './utils.js';
|
|
24
|
+
|
|
25
|
+
import {fileURLToPath} from 'url';
|
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
const __dirname = path.dirname(__filename);
|
|
28
|
+
const packageJson = JSON.parse(fs.readFileSync(__dirname + '/../package.json', 'utf8'));
|
|
29
|
+
|
|
26
30
|
const isLight = packageJson.name.slice(-6) === '-light';
|
|
27
|
-
|
|
28
|
-
// do not require `serve_rendered` in the light package
|
|
29
|
-
serve_rendered = require('./serve_rendered');
|
|
30
|
-
}
|
|
31
|
+
const serve_rendered = (await import(`${!isLight ? `./serve_rendered.js` : `./serve_light.js`}`)).serve_rendered;
|
|
31
32
|
|
|
32
|
-
function
|
|
33
|
+
export function server(opts) {
|
|
33
34
|
console.log('Starting server');
|
|
34
35
|
|
|
35
|
-
const app = express().disable('x-powered-by')
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
const app = express().disable('x-powered-by');
|
|
37
|
+
const serving = {
|
|
38
|
+
styles: {},
|
|
39
|
+
rendered: {},
|
|
40
|
+
data: {},
|
|
41
|
+
fonts: {}
|
|
42
|
+
};
|
|
42
43
|
|
|
43
44
|
app.enable('trust proxy');
|
|
44
45
|
|
|
@@ -46,7 +47,7 @@ function start(opts) {
|
|
|
46
47
|
const defaultLogFormat = process.env.NODE_ENV === 'production' ? 'tiny' : 'dev';
|
|
47
48
|
const logFormat = opts.logFormat || defaultLogFormat;
|
|
48
49
|
app.use(morgan(logFormat, {
|
|
49
|
-
stream: opts.logFile ? fs.createWriteStream(opts.logFile, {
|
|
50
|
+
stream: opts.logFile ? fs.createWriteStream(opts.logFile, {flags: 'a'}) : process.stdout,
|
|
50
51
|
skip: (req, res) => opts.silent && (res.statusCode === 200 || res.statusCode === 304)
|
|
51
52
|
}));
|
|
52
53
|
}
|
|
@@ -56,7 +57,7 @@ function start(opts) {
|
|
|
56
57
|
if (opts.configPath) {
|
|
57
58
|
configPath = path.resolve(opts.configPath);
|
|
58
59
|
try {
|
|
59
|
-
config =
|
|
60
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
60
61
|
} catch (e) {
|
|
61
62
|
console.log('ERROR: Config file not found or invalid!');
|
|
62
63
|
console.log(' See README.md for instructions and sample data.');
|
|
@@ -81,7 +82,7 @@ function start(opts) {
|
|
|
81
82
|
|
|
82
83
|
const startupPromises = [];
|
|
83
84
|
|
|
84
|
-
const checkPath = type => {
|
|
85
|
+
const checkPath = (type) => {
|
|
85
86
|
if (!fs.existsSync(paths[type])) {
|
|
86
87
|
console.error(`The specified path for "${type}" does not exist (${paths[type]}).`);
|
|
87
88
|
process.exit(1);
|
|
@@ -106,65 +107,65 @@ function start(opts) {
|
|
|
106
107
|
|
|
107
108
|
app.use('/data/', serve_data.init(options, serving.data));
|
|
108
109
|
app.use('/styles/', serve_style.init(options, serving.styles));
|
|
109
|
-
if (
|
|
110
|
+
if (!isLight) {
|
|
110
111
|
startupPromises.push(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
serve_rendered.init(options, serving.rendered)
|
|
113
|
+
.then((sub) => {
|
|
114
|
+
app.use('/styles/', sub);
|
|
115
|
+
})
|
|
115
116
|
);
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
const addStyle = (id, item, allowMoreData, reportFonts) => {
|
|
119
120
|
let success = true;
|
|
120
121
|
if (item.serve_data !== false) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
success = serve_style.add(options, serving.styles, item, id, opts.publicUrl,
|
|
123
|
+
(mbtiles, fromData) => {
|
|
124
|
+
let dataItemId;
|
|
125
|
+
for (const id of Object.keys(data)) {
|
|
126
|
+
if (fromData) {
|
|
127
|
+
if (id === mbtiles) {
|
|
128
|
+
dataItemId = id;
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
if (data[id].mbtiles === mbtiles) {
|
|
132
|
+
dataItemId = id;
|
|
133
|
+
}
|
|
128
134
|
}
|
|
135
|
+
}
|
|
136
|
+
if (dataItemId) { // mbtiles exist in the data config
|
|
137
|
+
return dataItemId;
|
|
129
138
|
} else {
|
|
130
|
-
if (
|
|
131
|
-
|
|
139
|
+
if (fromData || !allowMoreData) {
|
|
140
|
+
console.log(`ERROR: style "${item.style}" using unknown mbtiles "${mbtiles}"! Skipping...`);
|
|
141
|
+
return undefined;
|
|
142
|
+
} else {
|
|
143
|
+
let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles;
|
|
144
|
+
while (data[id]) id += '_';
|
|
145
|
+
data[id] = {
|
|
146
|
+
'mbtiles': mbtiles
|
|
147
|
+
};
|
|
148
|
+
return id;
|
|
132
149
|
}
|
|
133
150
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
} else {
|
|
138
|
-
if (fromData || !allowMoreData) {
|
|
139
|
-
console.log(`ERROR: style "${item.style}" using unknown mbtiles "${mbtiles}"! Skipping...`);
|
|
140
|
-
return undefined;
|
|
141
|
-
} else {
|
|
142
|
-
let id = mbtiles.substr(0, mbtiles.lastIndexOf('.')) || mbtiles;
|
|
143
|
-
while (data[id]) id += '_';
|
|
144
|
-
data[id] = {
|
|
145
|
-
'mbtiles': mbtiles
|
|
146
|
-
};
|
|
147
|
-
return id;
|
|
151
|
+
}, (font) => {
|
|
152
|
+
if (reportFonts) {
|
|
153
|
+
serving.fonts[font] = true;
|
|
148
154
|
}
|
|
149
|
-
}
|
|
150
|
-
}, font => {
|
|
151
|
-
if (reportFonts) {
|
|
152
|
-
serving.fonts[font] = true;
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
+
});
|
|
155
156
|
}
|
|
156
157
|
if (success && item.serve_rendered !== false) {
|
|
157
|
-
if (
|
|
158
|
+
if (!isLight) {
|
|
158
159
|
startupPromises.push(serve_rendered.add(options, serving.rendered, item, id, opts.publicUrl,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
(mbtiles) => {
|
|
161
|
+
let mbtilesFile;
|
|
162
|
+
for (const id of Object.keys(data)) {
|
|
163
|
+
if (id === mbtiles) {
|
|
164
|
+
mbtilesFile = data[id].mbtiles;
|
|
165
|
+
}
|
|
164
166
|
}
|
|
167
|
+
return mbtilesFile;
|
|
165
168
|
}
|
|
166
|
-
return mbtilesFile;
|
|
167
|
-
}
|
|
168
169
|
));
|
|
169
170
|
} else {
|
|
170
171
|
item.serve_rendered = false;
|
|
@@ -183,9 +184,9 @@ function start(opts) {
|
|
|
183
184
|
}
|
|
184
185
|
|
|
185
186
|
startupPromises.push(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
serve_font(options, serving.fonts).then((sub) => {
|
|
188
|
+
app.use('/', sub);
|
|
189
|
+
})
|
|
189
190
|
);
|
|
190
191
|
|
|
191
192
|
for (const id of Object.keys(data)) {
|
|
@@ -196,7 +197,7 @@ function start(opts) {
|
|
|
196
197
|
}
|
|
197
198
|
|
|
198
199
|
startupPromises.push(
|
|
199
|
-
|
|
200
|
+
serve_data.add(options, serving.data, item, id, opts.publicUrl)
|
|
200
201
|
);
|
|
201
202
|
}
|
|
202
203
|
|
|
@@ -208,8 +209,8 @@ function start(opts) {
|
|
|
208
209
|
for (const file of files) {
|
|
209
210
|
if (file.isFile() &&
|
|
210
211
|
path.extname(file.name).toLowerCase() == '.json') {
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
const id = path.basename(file.name, '.json');
|
|
213
|
+
const item = {
|
|
213
214
|
style: file.name
|
|
214
215
|
};
|
|
215
216
|
addStyle(id, item, false, false);
|
|
@@ -218,27 +219,27 @@ function start(opts) {
|
|
|
218
219
|
});
|
|
219
220
|
|
|
220
221
|
const watcher = chokidar.watch(path.join(options.paths.styles, '*.json'),
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
{
|
|
223
|
+
});
|
|
223
224
|
watcher.on('all',
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
225
|
+
(eventType, filename) => {
|
|
226
|
+
if (filename) {
|
|
227
|
+
const id = path.basename(filename, '.json');
|
|
228
|
+
console.log(`Style "${id}" changed, updating...`);
|
|
229
|
+
|
|
230
|
+
serve_style.remove(serving.styles, id);
|
|
231
|
+
if (!isLight) {
|
|
232
|
+
serve_rendered.remove(serving.rendered, id);
|
|
233
|
+
}
|
|
233
234
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
235
|
+
if (eventType == 'add' || eventType == 'change') {
|
|
236
|
+
const item = {
|
|
237
|
+
style: filename
|
|
238
|
+
};
|
|
239
|
+
addStyle(id, item, false, false);
|
|
240
|
+
}
|
|
239
241
|
}
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
+
});
|
|
242
243
|
}
|
|
243
244
|
|
|
244
245
|
app.get('/styles.json', (req, res, next) => {
|
|
@@ -250,7 +251,7 @@ function start(opts) {
|
|
|
250
251
|
version: styleJSON.version,
|
|
251
252
|
name: styleJSON.name,
|
|
252
253
|
id: id,
|
|
253
|
-
url: `${
|
|
254
|
+
url: `${getPublicUrl(opts.publicUrl, req)}styles/${id}/style.json${query}`
|
|
254
255
|
});
|
|
255
256
|
}
|
|
256
257
|
res.send(result);
|
|
@@ -265,7 +266,7 @@ function start(opts) {
|
|
|
265
266
|
} else {
|
|
266
267
|
path = `${type}/${id}`;
|
|
267
268
|
}
|
|
268
|
-
info.tiles =
|
|
269
|
+
info.tiles = getTileUrls(req, info.tiles, path, info.format, opts.publicUrl, {
|
|
269
270
|
'pbf': options.pbfAlias
|
|
270
271
|
});
|
|
271
272
|
arr.push(info);
|
|
@@ -283,7 +284,7 @@ function start(opts) {
|
|
|
283
284
|
res.send(addTileJSONs(addTileJSONs([], req, 'rendered'), req, 'data'));
|
|
284
285
|
});
|
|
285
286
|
|
|
286
|
-
|
|
287
|
+
// ------------------------------------
|
|
287
288
|
// serve web presentations
|
|
288
289
|
app.use('/', express.static(path.join(__dirname, '../public/resources')));
|
|
289
290
|
|
|
@@ -329,7 +330,7 @@ function start(opts) {
|
|
|
329
330
|
}));
|
|
330
331
|
};
|
|
331
332
|
|
|
332
|
-
serveTemplate('/$', 'index', req => {
|
|
333
|
+
serveTemplate('/$', 'index', (req) => {
|
|
333
334
|
const styles = clone(serving.styles || {});
|
|
334
335
|
for (const id of Object.keys(styles)) {
|
|
335
336
|
const style = styles[id];
|
|
@@ -345,9 +346,9 @@ function start(opts) {
|
|
|
345
346
|
style.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.png`;
|
|
346
347
|
}
|
|
347
348
|
|
|
348
|
-
style.xyz_link =
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
style.xyz_link = getTileUrls(
|
|
350
|
+
req, style.serving_rendered.tileJSON.tiles,
|
|
351
|
+
`styles/${id}`, style.serving_rendered.tileJSON.format, opts.publicUrl)[0];
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
354
|
const data = clone(serving.data || {});
|
|
@@ -365,10 +366,10 @@ function start(opts) {
|
|
|
365
366
|
data_.thumbnail = `${center[2]}/${Math.floor(centerPx[0] / 256)}/${Math.floor(centerPx[1] / 256)}.${data_.tileJSON.format}`;
|
|
366
367
|
}
|
|
367
368
|
|
|
368
|
-
data_.xyz_link =
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
369
|
+
data_.xyz_link = getTileUrls(
|
|
370
|
+
req, tilejson.tiles, `data/${id}`, tilejson.format, opts.publicUrl, {
|
|
371
|
+
'pbf': options.pbfAlias
|
|
372
|
+
})[0];
|
|
372
373
|
}
|
|
373
374
|
if (data_.filesize) {
|
|
374
375
|
let suffix = 'kB';
|
|
@@ -390,7 +391,7 @@ function start(opts) {
|
|
|
390
391
|
};
|
|
391
392
|
});
|
|
392
393
|
|
|
393
|
-
serveTemplate('/styles/:id/$', 'viewer', req => {
|
|
394
|
+
serveTemplate('/styles/:id/$', 'viewer', (req) => {
|
|
394
395
|
const id = req.params.id;
|
|
395
396
|
const style = clone(((serving.styles || {})[id] || {}).styleJSON);
|
|
396
397
|
if (!style) {
|
|
@@ -408,13 +409,13 @@ function start(opts) {
|
|
|
408
409
|
return res.redirect(301, '/styles/' + req.params.id + '/');
|
|
409
410
|
});
|
|
410
411
|
*/
|
|
411
|
-
serveTemplate('/styles/:id/wmts.xml', 'wmts', req => {
|
|
412
|
+
serveTemplate('/styles/:id/wmts.xml', 'wmts', (req) => {
|
|
412
413
|
const id = req.params.id;
|
|
413
414
|
const wmts = clone((serving.styles || {})[id]);
|
|
414
415
|
if (!wmts) {
|
|
415
416
|
return null;
|
|
416
417
|
}
|
|
417
|
-
if (wmts.hasOwnProperty(
|
|
418
|
+
if (wmts.hasOwnProperty('serve_rendered') && !wmts.serve_rendered) {
|
|
418
419
|
return null;
|
|
419
420
|
}
|
|
420
421
|
wmts.id = id;
|
|
@@ -423,7 +424,7 @@ function start(opts) {
|
|
|
423
424
|
return wmts;
|
|
424
425
|
});
|
|
425
426
|
|
|
426
|
-
serveTemplate('/data/:id/$', 'data', req => {
|
|
427
|
+
serveTemplate('/data/:id/$', 'data', (req) => {
|
|
427
428
|
const id = req.params.id;
|
|
428
429
|
const data = clone(serving.data[id]);
|
|
429
430
|
if (!data) {
|
|
@@ -447,7 +448,7 @@ function start(opts) {
|
|
|
447
448
|
}
|
|
448
449
|
});
|
|
449
450
|
|
|
450
|
-
const server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function
|
|
451
|
+
const server = app.listen(process.env.PORT || opts.port, process.env.BIND || opts.bind, function() {
|
|
451
452
|
let address = this.address().address;
|
|
452
453
|
if (address.indexOf('::') === 0) {
|
|
453
454
|
address = `[${address}]`; // literal IPv6 address
|
|
@@ -465,10 +466,10 @@ function start(opts) {
|
|
|
465
466
|
};
|
|
466
467
|
}
|
|
467
468
|
|
|
468
|
-
|
|
469
|
+
export const exports = (opts) => {
|
|
469
470
|
const running = start(opts);
|
|
470
471
|
|
|
471
|
-
running.startupPromise.catch(err => {
|
|
472
|
+
running.startupPromise.catch((err) => {
|
|
472
473
|
console.error(err.message);
|
|
473
474
|
process.exit(1);
|
|
474
475
|
});
|
package/src/utils.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import clone from 'clone';
|
|
7
|
+
import glyphCompose from '@mapbox/glyph-pbf-composite';
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
module.exports.getTileUrls = (req, domains, path, format, publicUrl, aliases) => {
|
|
10
|
+
export const getPublicUrl = (publicUrl, req) => publicUrl || `${req.protocol}://${req.headers.host}/`;
|
|
13
11
|
|
|
12
|
+
export const getTileUrls = (req, domains, path, format, publicUrl, aliases) => {
|
|
14
13
|
if (domains) {
|
|
15
14
|
if (domains.constructor === String && domains.length > 0) {
|
|
16
15
|
domains = domains.split(',');
|
|
@@ -37,7 +36,6 @@ module.exports.getTileUrls = (req, domains, path, format, publicUrl, aliases) =>
|
|
|
37
36
|
domains = [req.headers.host];
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
const key = req.query.key;
|
|
41
39
|
const queryParams = [];
|
|
42
40
|
if (req.query.key) {
|
|
43
41
|
queryParams.push(`key=${encodeURIComponent(req.query.key)}`);
|
|
@@ -57,13 +55,13 @@ module.exports.getTileUrls = (req, domains, path, format, publicUrl, aliases) =>
|
|
|
57
55
|
uris.push(`${req.protocol}://${domain}/${path}/{z}/{x}/{y}.${format}${query}`);
|
|
58
56
|
}
|
|
59
57
|
} else {
|
|
60
|
-
uris.push(`${publicUrl}${path}/{z}/{x}/{y}.${format}${query}`)
|
|
58
|
+
uris.push(`${publicUrl}${path}/{z}/{x}/{y}.${format}${query}`);
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
return uris;
|
|
64
62
|
};
|
|
65
63
|
|
|
66
|
-
|
|
64
|
+
export const fixTileJSONCenter = (tileJSON) => {
|
|
67
65
|
if (tileJSON.bounds && !tileJSON.center) {
|
|
68
66
|
const fitWidth = 1024;
|
|
69
67
|
const tiles = fitWidth / 256;
|
|
@@ -71,8 +69,8 @@ module.exports.fixTileJSONCenter = tileJSON => {
|
|
|
71
69
|
(tileJSON.bounds[0] + tileJSON.bounds[2]) / 2,
|
|
72
70
|
(tileJSON.bounds[1] + tileJSON.bounds[3]) / 2,
|
|
73
71
|
Math.round(
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
-Math.log((tileJSON.bounds[2] - tileJSON.bounds[0]) / 360 / tiles) /
|
|
73
|
+
Math.LN2
|
|
76
74
|
)
|
|
77
75
|
];
|
|
78
76
|
}
|
|
@@ -118,14 +116,14 @@ const getFontPbf = (allowedFonts, fontPath, name, range, fallbacks) => new Promi
|
|
|
118
116
|
}
|
|
119
117
|
});
|
|
120
118
|
|
|
121
|
-
|
|
119
|
+
export const getFontsPbf = (allowedFonts, fontPath, names, range, fallbacks) => {
|
|
122
120
|
const fonts = names.split(',');
|
|
123
121
|
const queue = [];
|
|
124
122
|
for (const font of fonts) {
|
|
125
123
|
queue.push(
|
|
126
|
-
|
|
124
|
+
getFontPbf(allowedFonts, fontPath, font, range, clone(allowedFonts || fallbacks))
|
|
127
125
|
);
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
return Promise.all(queue).then(values => glyphCompose.combine(values));
|
|
128
|
+
return Promise.all(queue).then((values) => glyphCompose.combine(values));
|
|
131
129
|
};
|
package/test/metadata.js
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
const testTileJSONArray = function(url) {
|
|
2
2
|
describe(url + ' is array of TileJSONs', function() {
|
|
3
3
|
it('is json', function(done) {
|
|
4
4
|
supertest(app)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
.get(url)
|
|
6
|
+
.expect(200)
|
|
7
|
+
.expect('Content-Type', /application\/json/, done);
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
it('is non-empty array', function(done) {
|
|
11
11
|
supertest(app)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
.get(url)
|
|
13
|
+
.expect(function(res) {
|
|
14
|
+
expect(res.body).to.be.a('array');
|
|
15
|
+
expect(res.body.length).to.be.greaterThan(0);
|
|
16
|
+
}).end(done);
|
|
17
17
|
});
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const testTileJSON = function(url) {
|
|
22
22
|
describe(url + ' is TileJSON', function() {
|
|
23
23
|
it('is json', function(done) {
|
|
24
24
|
supertest(app)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
.get(url)
|
|
26
|
+
.expect(200)
|
|
27
|
+
.expect('Content-Type', /application\/json/, done);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
it('has valid tiles', function(done) {
|
|
31
31
|
supertest(app)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
.get(url)
|
|
33
|
+
.expect(function(res) {
|
|
34
|
+
expect(res.body.tiles.length).to.be.greaterThan(0);
|
|
35
|
+
}).end(done);
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
38
|
};
|
|
@@ -41,8 +41,8 @@ describe('Metadata', function() {
|
|
|
41
41
|
describe('/health', function() {
|
|
42
42
|
it('returns 200', function(done) {
|
|
43
43
|
supertest(app)
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
.get('/health')
|
|
45
|
+
.expect(200, done);
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
48
|
|
|
@@ -53,21 +53,21 @@ describe('Metadata', function() {
|
|
|
53
53
|
describe('/styles.json is valid array', function() {
|
|
54
54
|
it('is json', function(done) {
|
|
55
55
|
supertest(app)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
.get('/styles.json')
|
|
57
|
+
.expect(200)
|
|
58
|
+
.expect('Content-Type', /application\/json/, done);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
it('contains valid item', function(done) {
|
|
62
62
|
supertest(app)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
.get('/styles.json')
|
|
64
|
+
.expect(function(res) {
|
|
65
|
+
expect(res.body).to.be.a('array');
|
|
66
|
+
expect(res.body.length).to.be.greaterThan(0);
|
|
67
|
+
expect(res.body[0].version).to.be.equal(8);
|
|
68
|
+
expect(res.body[0].id).to.be.a('string');
|
|
69
|
+
expect(res.body[0].name).to.be.a('string');
|
|
70
|
+
}).end(done);
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
73
|
|
package/test/setup.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
process.env.NODE_ENV = 'test';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import {expect} from 'chai';
|
|
4
|
+
import supertest from 'supertest';
|
|
5
|
+
import {server} from '../src/server.js';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
global.expect = expect;
|
|
8
|
+
global.supertest = supertest;
|
|
7
9
|
|
|
8
10
|
before(function() {
|
|
9
11
|
console.log('global setup');
|
|
10
12
|
process.chdir('test_data');
|
|
11
|
-
|
|
13
|
+
const running = server({
|
|
12
14
|
configPath: 'config.json',
|
|
13
15
|
port: 8888,
|
|
14
16
|
publicUrl: '/test/'
|
|
@@ -20,5 +22,7 @@ before(function() {
|
|
|
20
22
|
|
|
21
23
|
after(function() {
|
|
22
24
|
console.log('global teardown');
|
|
23
|
-
global.server.close(function() {
|
|
25
|
+
global.server.close(function() {
|
|
26
|
+
console.log('Done'); process.exit();
|
|
27
|
+
});
|
|
24
28
|
});
|
package/test/static.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
const testStatic = function(prefix, q, format, status, scale, type, query) {
|
|
2
2
|
if (scale) q += '@' + scale + 'x';
|
|
3
|
-
|
|
3
|
+
let path = '/styles/' + prefix + '/static/' + q + '.' + format;
|
|
4
4
|
if (query) {
|
|
5
5
|
path += query;
|
|
6
6
|
}
|
|
7
7
|
it(path + ' returns ' + status, function(done) {
|
|
8
|
-
|
|
8
|
+
const test = supertest(app).get(path);
|
|
9
9
|
if (status) test.expect(status);
|
|
10
10
|
if (type) test.expect('Content-Type', type);
|
|
11
11
|
test.end(done);
|
|
12
12
|
});
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const prefix = 'test-style';
|
|
16
16
|
|
|
17
17
|
describe('Static endpoints', function() {
|
|
18
18
|
describe('center-based', function() {
|