@unvt/charites 2.0.3 → 2.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/dist/cli/serve.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import { Command } from 'commander';
2
+ import { createServer } from 'vite';
3
+ import { fileURLToPath } from 'url';
4
+ import path from 'path';
2
5
  import { serve } from '../commands/serve.js';
3
6
  import { error } from '../lib/error.js';
4
7
  const program = new Command();
@@ -9,6 +12,7 @@ program
9
12
  .option('-i, --sprite-input [<icon input directory>]', 'directory path of icon source to build icons. The default <icon source> is `icons/`')
10
13
  .option('--sdf', 'Allows to use SDF sprite in charites')
11
14
  .option('--port [port]', 'Specify custom port')
15
+ .option('--vite-port [vitePort]', 'Specify custom port for vite server')
12
16
  .option('--no-open', "Don't open the preview in the default browser")
13
17
  .action(async (source, serveOptions) => {
14
18
  const options = program.opts();
@@ -16,11 +20,25 @@ program
16
20
  options.spriteInput = serveOptions.spriteInput;
17
21
  options.open = serveOptions.open;
18
22
  options.sdf = serveOptions.sdf;
23
+ options.vitePort = serveOptions.vitePort;
19
24
  try {
25
+ await startProviderDevServer(options);
20
26
  await serve(source, program.opts());
21
27
  }
22
28
  catch (e) {
23
29
  error(e);
24
30
  }
25
31
  });
32
+ const __filename = fileURLToPath(import.meta.url);
33
+ const __dirname = path.dirname(__filename);
34
+ async function startProviderDevServer(options) {
35
+ const config = {
36
+ root: path.resolve(__dirname, '../../provider'),
37
+ server: {
38
+ port: parseInt(options.vitePort ?? '5137'),
39
+ },
40
+ };
41
+ const viteServer = await createServer(config);
42
+ await viteServer.listen();
43
+ }
26
44
  export default program;
@@ -9,7 +9,6 @@ const WebSocketServer = ws.default.WebSocketServer || ws.WebSocketServer;
9
9
  import watch from 'node-watch';
10
10
  import { parser } from '../lib/yaml-parser.js';
11
11
  import { validateStyle } from '../lib/validate-style.js';
12
- import { providerDir } from '../lib/defaultValues.js';
13
12
  import { buildSprite } from '../lib/build-sprite.js';
14
13
  export async function serve(source, options) {
15
14
  let port = process.env.PORT || 8080;
@@ -55,12 +54,6 @@ export async function serve(source, options) {
55
54
  return;
56
55
  }
57
56
  switch (url) {
58
- case '/':
59
- res.statusCode = 200;
60
- res.setHeader('Content-Type', 'text/html; charset=UTF-8');
61
- const content = fs.readFileSync(path.join(providerDir, 'index.html'), 'utf-8');
62
- res.end(content);
63
- break;
64
57
  case '/style.json':
65
58
  let style;
66
59
  try {
@@ -78,24 +71,37 @@ export async function serve(source, options) {
78
71
  res.setHeader('Cache-Control', 'no-store');
79
72
  res.end(JSON.stringify(style));
80
73
  break;
81
- case '/app.css':
82
- res.statusCode = 200;
83
- res.setHeader('Content-Type', 'text/css; charset=UTF-8');
84
- const css = fs.readFileSync(path.join(providerDir, 'app.css'), 'utf-8');
85
- res.end(css);
86
- break;
87
- case `/app.js`:
88
- res.statusCode = 200;
89
- res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
90
- const app = fs.readFileSync(path.join(providerDir, 'app.js'), 'utf-8');
91
- const js = app.replace('___PORT___', `${port}`);
92
- res.end(js);
93
- break;
94
- default:
74
+ case '/sprite.json':
75
+ case '/sprite@2x.json':
76
+ case '/sprite.png':
77
+ case '/sprite@2x.png':
95
78
  res.statusCode = 404;
96
79
  res.setHeader('Content-Type', 'text/plain; charset=UTF-8');
97
80
  res.end('Not found');
98
81
  break;
82
+ default:
83
+ const vitePort = parseInt(options.vitePort || '5137');
84
+ const proxyReq = http.request({
85
+ hostname: 'localhost',
86
+ port: vitePort,
87
+ path: url,
88
+ method: req.method,
89
+ headers: req.headers,
90
+ }, (viteRes) => {
91
+ res.writeHead(viteRes.statusCode || 500, viteRes.headers);
92
+ viteRes.pipe(res, {
93
+ end: true,
94
+ });
95
+ });
96
+ req.pipe(proxyReq, {
97
+ end: true,
98
+ });
99
+ proxyReq.on('error', (err) => {
100
+ console.error('Error with proxy request:', err);
101
+ res.statusCode = 500;
102
+ res.end('Bad gateway: failed to proxy to Vite dev server');
103
+ });
104
+ break;
99
105
  }
100
106
  });
101
107
  server.listen(port, () => {
@@ -128,7 +134,7 @@ export async function serve(source, options) {
128
134
  // Nothing to do
129
135
  }
130
136
  });
131
- ws.on('close', () => {
137
+ wss.on('close', () => {
132
138
  watcher.close();
133
139
  });
134
140
  });
@@ -1,6 +1,6 @@
1
- import maplibreStyleSpec from '@maplibre/maplibre-gl-style-spec';
1
+ import { validateStyleMin, } from '@maplibre/maplibre-gl-style-spec';
2
2
  export function validateStyle(style) {
3
- const result = maplibreStyleSpec.validateStyleMin(style);
3
+ const result = validateStyleMin(style);
4
4
  const errors = [];
5
5
  for (let i = 0; i < result.length; i++) {
6
6
  const msg = result[i].message;
@@ -27,9 +27,12 @@ class IncFileTag {
27
27
  }
28
28
  const INC_PATH_TYPE = new YAML.Type('tag:yaml.org,2002:inc/file', {
29
29
  kind: 'scalar',
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
31
  resolve: (data) => data,
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
33
  construct: (data) => new IncFileTag(data),
32
34
  instanceOf: IncFileTag,
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
36
  represent: (tag) => tag.value,
34
37
  });
35
38
  const INC_PATH_OUTPUT_SCHEMA = YAML.DEFAULT_SCHEMA.extend([INC_PATH_TYPE]);
@@ -1,3 +1,3 @@
1
- export * from './tilejson';
2
- export * from './metadatajson';
3
- export * from './vector_layers';
1
+ export * from './tilejson.js';
2
+ export * from './metadatajson.js';
3
+ export * from './vector_layers.js';
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -9,7 +9,7 @@ Charites - Documentation
9
9
  :Date: 2024-08-23
10
10
  :Copyright: CC-BY-SA
11
11
  :Organization: The United Nations Vector Tile Toolkit
12
- :Version: 2.0.3
12
+ :Version: 2.1.0
13
13
  :Abstract: This document contains the complete documentation of Charites, an application to style vector tiles easily
14
14
 
15
15
  .. meta::
@@ -27,7 +27,7 @@ Checking version
27
27
  .. code-block:: bash
28
28
 
29
29
  $ charites --version
30
- 0.3.0
30
+ 2.1.0
31
31
 
32
32
 
33
33
  Inititalize `style.yml`
@@ -95,12 +95,18 @@ Realtime editor on browser
95
95
  source> is `icons/`
96
96
  --sdf Allows to use SDF sprite in charites
97
97
  --port [port] Specify custom port
98
+ --vite-port [vitePort] Specify custom port for vite server
99
+ --no-open Don't open the preview in the default browser
98
100
  -h, --help display help for command
99
101
 
100
- Charites has three options for `serve` command.
102
+ Charites has fifth options for `serve` command.
101
103
 
102
104
  - ``--sprite-input`` - If you are building icon spritesheets with Charites, you can specify the directory of SVG files to compile here. See the ``build`` command for more information.
103
105
 
104
106
  - ``--sdf`` - if this option is used together with ``--sprite-input``, the viewer will generate SDF sprite. If the option is not specified, non SDF sprite will be generated.
105
107
 
106
108
  - ``--port`` - Set http server's port number. When not specified, the default is 8080.
109
+
110
+ - ``--vite-port`` - Set Vite server's port number. When not specified, the default is 5137.
111
+
112
+ - ``--no-open`` - If this option is used, the preview will not be opened in the default browser. This is useful when you want to use the preview in a headless environment.
@@ -154,6 +154,14 @@ If you repeatedly use the same expression (color, font, etc) for several layers,
154
154
  :scale: 75%
155
155
  :align: center
156
156
 
157
+ (Tips 6) Use inspect control to view features
158
+ ################################################################
159
+ Use maplibre-gl-js inspect control to view all features of the vector sources and allows hovering over features to see their properties.
160
+
161
+ .. image:: ./img/example02-019.png
162
+ :scale: 75%
163
+ :align: center
164
+
157
165
  Step 5. Exporting style json from YAML files
158
166
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
159
167
  Once you have edited your style with YAML files, you can now export it back to json by running the following command.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unvt/charites",
3
- "version": "2.0.3",
3
+ "version": "2.1.1",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "charites": "dist/cli.js"
@@ -14,50 +14,58 @@
14
14
  "test:e2e": "npx playwright test",
15
15
  "command": "tsx ./src/cli.ts"
16
16
  },
17
+ "workspaces": [
18
+ "provider"
19
+ ],
17
20
  "author": "",
18
21
  "license": "MIT",
19
22
  "dependencies": {
20
- "@maplibre/maplibre-gl-style-spec": "^20.3.1",
21
- "@types/geojson": "^7946.0.14",
22
- "@types/jsonminify": "^0.4.3",
23
+ "@maplibre/maplibre-gl-inspect": "^1.7.1",
24
+ "@maplibre/maplibre-gl-style-spec": "^23.2.2",
23
25
  "@unvt/sprite-one": "^0.1.1",
24
- "axios": "^1.7.5",
25
- "commander": "^12.1.0",
26
- "glob": "^11.0.0",
26
+ "@watergis/maplibre-gl-legend": "^2.0.5",
27
+ "axios": "^1.9.0",
28
+ "commander": "^13.1.0",
29
+ "glob": "^11.0.2",
27
30
  "js-yaml": "^4.1.0",
28
31
  "jsonminify": "^0.4.2",
32
+ "maplibre-gl": "^5.4.0",
29
33
  "node-watch": "^0.7.4",
30
- "open": "^10.1.0",
31
- "ws": "^8.18.1"
34
+ "open": "^10.1.2",
35
+ "pmtiles": "^4.3.0",
36
+ "vite": "^6.3.4",
37
+ "ws": "^8.18.2"
32
38
  },
33
39
  "devDependencies": {
34
- "@eslint/eslintrc": "^3.1.0",
35
- "@eslint/js": "^9.9.1",
36
- "@playwright/test": "^1.46.1",
37
- "@types/chai": "^4.3.19",
38
- "@types/chai-as-promised": "^7.1.8",
40
+ "@eslint/eslintrc": "^3.3.1",
41
+ "@eslint/js": "^9.26.0",
42
+ "@playwright/test": "^1.52.0",
43
+ "@types/chai": "^5.2.1",
44
+ "@types/chai-as-promised": "^8.0.2",
39
45
  "@types/fs-extra": "^11.0.4",
46
+ "@types/geojson": "^7946.0.16",
40
47
  "@types/js-yaml": "^4.0.9",
48
+ "@types/jsonminify": "^0.4.3",
41
49
  "@types/mapbox__point-geometry": "^0.1.4",
42
- "@types/mocha": "^10.0.7",
43
- "@types/node": "^22.5.0",
44
- "@types/ws": "^8.18.0",
45
- "@typescript-eslint/eslint-plugin": "^8.3.0",
46
- "@typescript-eslint/parser": "^8.3.0",
47
- "chai": "^5.1.1",
48
- "chai-as-promised": "^8.0.0",
49
- "eslint": "^9.9.1",
50
- "eslint-config-prettier": "^9.1.0",
51
- "eslint-plugin-prettier": "^5.2.1",
52
- "fs-extra": "^11.2.0",
50
+ "@types/mocha": "^10.0.10",
51
+ "@types/node": "^22.15.3",
52
+ "@types/ws": "^8.18.1",
53
+ "@typescript-eslint/eslint-plugin": "^8.31.1",
54
+ "@typescript-eslint/parser": "^8.31.1",
55
+ "chai": "^5.2.0",
56
+ "chai-as-promised": "^8.0.1",
57
+ "eslint": "^9.26.0",
58
+ "eslint-config-prettier": "^10.1.2",
59
+ "eslint-plugin-prettier": "^5.2.6",
60
+ "fs-extra": "^11.3.0",
53
61
  "kill-port-process": "^3.2.1",
54
- "mocha": "^10.7.3",
62
+ "mocha": "^11.2.2",
55
63
  "node-abort-controller": "^3.1.1",
56
- "prettier": "^3.3.3",
64
+ "prettier": "^3.5.3",
57
65
  "ts-node": "^10.9.2",
58
66
  "tsconfig-paths": "^4.2.0",
59
- "tsx": "^4.19.3",
60
- "typescript": "^5.5.4"
67
+ "tsx": "^4.19.4",
68
+ "typescript": "^5.8.3"
61
69
  },
62
70
  "type": "module"
63
71
  }
@@ -1,13 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html id="charites-default">
3
3
  <head>
4
- <link rel="stylesheet" href="/app.css" />
5
- <link href='https://cdn.jsdelivr.net/npm/maplibre-gl/dist/maplibre-gl.css' rel='stylesheet' />
6
- <link href='https://cdn.jsdelivr.net/npm/@watergis/maplibre-gl-legend@2.0.5/dist/maplibre-gl-legend.css' rel='stylesheet' />
7
4
  <title>Charites Live Preview</title>
8
- <script src='https://cdn.jsdelivr.net/npm/maplibre-gl/dist/maplibre-gl.js'></script>
9
- <script src="https://cdn.jsdelivr.net/npm/@watergis/maplibre-gl-legend@2.0.5/dist/maplibre-gl-legend.umd.js"></script>
10
- <script src="https://cdn.jsdelivr.net/npm/pmtiles@4.3.0/dist/pmtiles.js"></script>
11
5
  </head>
12
6
  <body>
13
7
  <div class="overlay">
@@ -18,11 +12,6 @@
18
12
  <label><input type="checkbox" id="showPadding">show Padding</label>
19
13
  </div>
20
14
  <div id="map"></div>
21
- <script type="text/javascript">
22
- let protocol = new pmtiles.Protocol()
23
- maplibregl.addProtocol('pmtiles', protocol.tile)
24
- </script>
25
- <script type="text/javascript" src="/shared.js"></script>
26
- <script type="text/javascript" src="/app.js"></script>
15
+ <script type="module" src="./src/main.ts"></script>
27
16
  </body>
28
17
  </html>
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@unvt/provider",
3
+ "version": "0.0.1",
4
+ "private": true
5
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -14,4 +14,4 @@ html, body, #map
14
14
  margin: 5px;
15
15
  z-index: 90;
16
16
  background-color: rgba(255, 255, 255, 0.6);
17
- }
17
+ }
@@ -0,0 +1,148 @@
1
+ import {
2
+ Map,
3
+ Popup,
4
+ MapOptions,
5
+ NavigationControl,
6
+ addProtocol,
7
+ IControl,
8
+ } from 'maplibre-gl'
9
+ import 'maplibre-gl/dist/maplibre-gl.css'
10
+ import '@maplibre/maplibre-gl-inspect/dist/maplibre-gl-inspect.css'
11
+ import MaplibreInspect from '@maplibre/maplibre-gl-inspect'
12
+ import { MaplibreLegendControl } from '@watergis/maplibre-gl-legend'
13
+ import '@watergis/maplibre-gl-legend/dist/maplibre-gl-legend.css'
14
+ import { Protocol } from 'pmtiles'
15
+ import './app.css'
16
+
17
+ const protocol = new Protocol()
18
+ addProtocol('pmtiles', protocol.tile)
19
+
20
+ class Charites {
21
+ constructor() {}
22
+
23
+ initializeWebSocket = (map: Map) => {
24
+ const isHttps = window.location.protocol === 'https:'
25
+ const wsProtocol = isHttps ? 'wss' : 'ws'
26
+ const socket = new WebSocket(`${wsProtocol}://${window.location.host}`)
27
+
28
+ socket.addEventListener('message', (message) => {
29
+ const data = JSON.parse(message.data)
30
+ if (data.event === 'styleUpdate') {
31
+ console.log('styleUpdate', data)
32
+ map.setStyle(`//${window.location.host}/style.json`)
33
+ } else if (data.event === 'spriteUpdate') {
34
+ map.setStyle(`//${window.location.host}/style.json`, {
35
+ diff: false,
36
+ })
37
+ }
38
+ })
39
+ }
40
+
41
+ parseMapStyle = async () => {
42
+ const mapStyleUrl = `//${window.location.host}/style.json`
43
+ const mapStyleRes = await fetch(mapStyleUrl)
44
+ const mapStyleJson = await mapStyleRes.json()
45
+
46
+ // detect center & zoom from map style json
47
+ let center = mapStyleJson.hasOwnProperty('center')
48
+ ? mapStyleJson.center
49
+ : undefined
50
+ let zoom = mapStyleJson.hasOwnProperty('zoom')
51
+ ? mapStyleJson.zoom
52
+ : undefined
53
+
54
+ // detect center & zoom from tile json
55
+ if (center === undefined || zoom === undefined) {
56
+ for (const sourceName in mapStyleJson.sources) {
57
+ if (
58
+ mapStyleJson.sources[sourceName].type === 'vector' &&
59
+ mapStyleJson.sources[sourceName].hasOwnProperty('url')
60
+ ) {
61
+ const mapTileUrl = mapStyleJson.sources[sourceName].url
62
+ const mapTileRes = await fetch(mapTileUrl)
63
+ const mapTileJson = await mapTileRes.json()
64
+ if (center === undefined) {
65
+ const bounds = mapTileJson.bounds
66
+ center = mapTileJson.center
67
+ if (!center && bounds) {
68
+ center = [
69
+ (bounds[0] + bounds[2]) / 2,
70
+ (bounds[1] + bounds[3]) / 2,
71
+ ]
72
+ }
73
+ }
74
+ if (zoom === undefined) {
75
+ zoom = (mapTileJson.minzoom + mapTileJson.maxzoom) / 2
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ return {
82
+ style: mapStyleUrl,
83
+ center,
84
+ zoom,
85
+ }
86
+ }
87
+
88
+ setupDebugCheckbox = (map: Map) => {
89
+ const properties = [
90
+ 'showTileBoundaries',
91
+ 'showCollisionBoxes',
92
+ 'showPadding',
93
+ ]
94
+ for (const property of properties) {
95
+ const control = document.getElementById(property) as HTMLInputElement
96
+ const clickHandler = () => {
97
+ const checked = control.checked
98
+ map[property] = checked
99
+ }
100
+ clickHandler()
101
+ control.addEventListener('click', clickHandler)
102
+ }
103
+ }
104
+ }
105
+
106
+ const init = async () => {
107
+ const charites = new Charites()
108
+ const { style, center, zoom } = await charites.parseMapStyle()
109
+ const options: MapOptions = {
110
+ container: 'map',
111
+ hash: true,
112
+ maxPitch: 85,
113
+ style,
114
+ }
115
+ if (center) {
116
+ options.center = center
117
+ }
118
+ if (zoom) {
119
+ options.zoom = zoom
120
+ }
121
+ const map = new Map(options)
122
+
123
+ charites.initializeWebSocket(map)
124
+
125
+ map.addControl(
126
+ new MaplibreInspect({
127
+ popup: new Popup({
128
+ closeButton: false,
129
+ closeOnClick: false,
130
+ }),
131
+ }),
132
+ )
133
+ map.addControl(new NavigationControl(), 'top-right')
134
+ map.addControl(
135
+ new MaplibreLegendControl(
136
+ {},
137
+ {
138
+ showDefault: true,
139
+ showCheckbox: true,
140
+ onlyRendered: true,
141
+ reverseOrder: true,
142
+ },
143
+ ) as unknown as IControl,
144
+ 'bottom-left',
145
+ )
146
+ charites.setupDebugCheckbox(map)
147
+ }
148
+ init()
package/src/cli/serve.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { Command } from 'commander'
2
+ import { createServer, InlineConfig } from 'vite'
3
+ import { fileURLToPath } from 'url'
4
+ import path from 'path'
2
5
  import { serve, serveOptions } from '../commands/serve.js'
3
6
  import { error } from '../lib/error.js'
4
7
 
@@ -13,6 +16,7 @@ program
13
16
  )
14
17
  .option('--sdf', 'Allows to use SDF sprite in charites')
15
18
  .option('--port [port]', 'Specify custom port')
19
+ .option('--vite-port [vitePort]', 'Specify custom port for vite server')
16
20
  .option('--no-open', "Don't open the preview in the default browser")
17
21
  .action(async (source: string, serveOptions: serveOptions) => {
18
22
  const options: serveOptions = program.opts()
@@ -20,11 +24,26 @@ program
20
24
  options.spriteInput = serveOptions.spriteInput
21
25
  options.open = serveOptions.open
22
26
  options.sdf = serveOptions.sdf
27
+ options.vitePort = serveOptions.vitePort
23
28
  try {
29
+ await startProviderDevServer(options)
24
30
  await serve(source, program.opts())
25
31
  } catch (e) {
26
32
  error(e)
27
33
  }
28
34
  })
29
35
 
36
+ const __filename = fileURLToPath(import.meta.url)
37
+ const __dirname = path.dirname(__filename)
38
+ async function startProviderDevServer(options: serveOptions) {
39
+ const config: InlineConfig = {
40
+ root: path.resolve(__dirname, '../../provider'),
41
+ server: {
42
+ port: parseInt(options.vitePort ?? '5137'),
43
+ },
44
+ }
45
+
46
+ const viteServer = await createServer(config)
47
+ await viteServer.listen()
48
+ }
30
49
  export default program
@@ -10,11 +10,11 @@ import watch from 'node-watch'
10
10
 
11
11
  import { parser } from '../lib/yaml-parser.js'
12
12
  import { validateStyle } from '../lib/validate-style.js'
13
- import { providerDir } from '../lib/defaultValues.js'
14
13
  import { buildSprite } from '../lib/build-sprite.js'
15
14
 
16
15
  export interface serveOptions {
17
16
  port?: string
17
+ vitePort?: string
18
18
  spriteInput?: string
19
19
  open?: boolean
20
20
  sdf?: boolean
@@ -73,15 +73,6 @@ export async function serve(source: string, options: serveOptions) {
73
73
  }
74
74
 
75
75
  switch (url) {
76
- case '/':
77
- res.statusCode = 200
78
- res.setHeader('Content-Type', 'text/html; charset=UTF-8')
79
- const content = fs.readFileSync(
80
- path.join(providerDir, 'index.html'),
81
- 'utf-8',
82
- )
83
- res.end(content)
84
- break
85
76
  case '/style.json':
86
77
  let style
87
78
  try {
@@ -100,24 +91,40 @@ export async function serve(source: string, options: serveOptions) {
100
91
  res.setHeader('Cache-Control', 'no-store')
101
92
  res.end(JSON.stringify(style))
102
93
  break
103
- case '/app.css':
104
- res.statusCode = 200
105
- res.setHeader('Content-Type', 'text/css; charset=UTF-8')
106
- const css = fs.readFileSync(path.join(providerDir, 'app.css'), 'utf-8')
107
- res.end(css)
108
- break
109
- case `/app.js`:
110
- res.statusCode = 200
111
- res.setHeader('Content-Type', 'application/javascript; charset=UTF-8')
112
- const app = fs.readFileSync(path.join(providerDir, 'app.js'), 'utf-8')
113
- const js = app.replace('___PORT___', `${port}`)
114
- res.end(js)
115
- break
116
- default:
94
+ case '/sprite.json':
95
+ case '/sprite@2x.json':
96
+ case '/sprite.png':
97
+ case '/sprite@2x.png':
117
98
  res.statusCode = 404
118
99
  res.setHeader('Content-Type', 'text/plain; charset=UTF-8')
119
100
  res.end('Not found')
120
101
  break
102
+ default:
103
+ const vitePort = parseInt(options.vitePort || '5137')
104
+ const proxyReq = http.request(
105
+ {
106
+ hostname: 'localhost',
107
+ port: vitePort,
108
+ path: url,
109
+ method: req.method,
110
+ headers: req.headers,
111
+ },
112
+ (viteRes) => {
113
+ res.writeHead(viteRes.statusCode || 500, viteRes.headers)
114
+ viteRes.pipe(res, {
115
+ end: true,
116
+ })
117
+ },
118
+ )
119
+ req.pipe(proxyReq, {
120
+ end: true,
121
+ })
122
+ proxyReq.on('error', (err) => {
123
+ console.error('Error with proxy request:', err)
124
+ res.statusCode = 500
125
+ res.end('Bad gateway: failed to proxy to Vite dev server')
126
+ })
127
+ break
121
128
  }
122
129
  })
123
130
 
@@ -131,11 +138,11 @@ export async function serve(source: string, options: serveOptions) {
131
138
 
132
139
  const wss = new WebSocketServer({ server })
133
140
 
134
- wss.on('connection', (ws) => {
141
+ wss.on('connection', (ws: WebSocket) => {
135
142
  const watcher = watch(
136
143
  path.dirname(sourcePath),
137
144
  { recursive: true, filter: /\.yml$|\.svg$/i },
138
- (event, file) => {
145
+ (event: string, file: string) => {
139
146
  console.log(`${(event || '').toUpperCase()}: ${file}`)
140
147
  try {
141
148
  if (file?.toLowerCase().endsWith('.yml')) {
@@ -161,7 +168,7 @@ export async function serve(source: string, options: serveOptions) {
161
168
  }
162
169
  },
163
170
  )
164
- ws.on('close', () => {
171
+ wss.on('close', () => {
165
172
  watcher.close()
166
173
  })
167
174
  })
@@ -1,4 +1,4 @@
1
- import { VectorLayer } from '../../types'
1
+ import { VectorLayer } from '../../types/vector_layers.js'
2
2
  import {
3
3
  StyleSpecification,
4
4
  SourceSpecification,
@@ -1,9 +1,10 @@
1
- import maplibreStyleSpec, {
1
+ import {
2
+ validateStyleMin,
2
3
  StyleSpecification,
3
4
  } from '@maplibre/maplibre-gl-style-spec'
4
5
 
5
6
  export function validateStyle(style: StyleSpecification): void {
6
- const result = maplibreStyleSpec.validateStyleMin(style)
7
+ const result = validateStyleMin(style)
7
8
 
8
9
  const errors = []
9
10
  for (let i = 0; i < result.length; i++) {
@@ -43,10 +43,13 @@ class IncFileTag {
43
43
 
44
44
  const INC_PATH_TYPE = new YAML.Type('tag:yaml.org,2002:inc/file', {
45
45
  kind: 'scalar',
46
- resolve: (data) => data,
47
- construct: (data) => new IncFileTag(data),
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ resolve: (data: any) => data,
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ construct: (data: any) => new IncFileTag(data),
48
50
  instanceOf: IncFileTag,
49
- represent: (tag) => (tag as IncFileTag).value,
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ represent: (tag: any) => (tag as IncFileTag).value,
50
53
  })
51
54
  const INC_PATH_OUTPUT_SCHEMA = YAML.DEFAULT_SCHEMA.extend([INC_PATH_TYPE])
52
55
 
@@ -1,3 +1,3 @@
1
- export * from './tilejson'
2
- export * from './metadatajson'
3
- export * from './vector_layers'
1
+ export * from './tilejson.js'
2
+ export * from './metadatajson.js'
3
+ export * from './vector_layers.js'
@@ -1,4 +1,4 @@
1
- import { VectorLayer } from './vector_layers'
1
+ import { VectorLayer } from './vector_layers.js'
2
2
 
3
3
  /**
4
4
  * Definition of TileJSON v3.0.0
package/tsconfig.json CHANGED
@@ -13,13 +13,21 @@
13
13
  "experimentalDecorators": true,
14
14
  "emitDecoratorMetadata": true,
15
15
  "resolveJsonModule": true,
16
- "module": "ESNext",
16
+ "allowSyntheticDefaultImports": true,
17
+ "skipLibCheck": true,
18
+ "module": "Preserve",
17
19
  "moduleResolution": "node",
18
20
  "outDir": "./dist",
19
21
  "baseUrl": ".",
20
22
  "paths": {
21
23
  "*": ["node_modules/*", "src/types/*"]
22
- }
24
+ },
25
+ "types": [
26
+ "mocha",
27
+ "chai",
28
+ "node"
29
+ ],
30
+ "typeRoots": ["./node_modules/@types", "./src/types"]
23
31
  },
24
32
  "include": ["src/**/*"],
25
33
  "exclude": ["node_modules", "dist"]
@@ -1,6 +0,0 @@
1
- import { fileURLToPath } from 'url';
2
- import { dirname } from 'path';
3
- import path from 'path';
4
- const __filename = fileURLToPath(import.meta.url);
5
- const __dirname = dirname(__filename);
6
- export const providerDir = path.join(path.dirname(path.dirname(__dirname)), 'provider');
package/provider/app.js DELETED
@@ -1,112 +0,0 @@
1
- ;(async () => {
2
- window._charites = {
3
- initializeWebSocket: function (map) {
4
- const isHttps = window.location.protocol === 'https:'
5
- const wsProtocol = isHttps ? 'wss' : 'ws'
6
- const socket = new WebSocket(`${wsProtocol}://${window.location.host}`)
7
-
8
- socket.addEventListener('message', (message) => {
9
- const data = JSON.parse(message.data)
10
- if (data.event === 'styleUpdate') {
11
- map.setStyle(`//${window.location.host}/style.json`)
12
- } else if (data.event === 'spriteUpdate') {
13
- map.setStyle(`//${window.location.host}/style.json`, {
14
- diff: false,
15
- })
16
- }
17
- })
18
- },
19
- parseMapStyle: async function () {
20
- const mapStyleUrl = `//${window.location.host}/style.json`
21
- const mapStyleRes = await fetch(mapStyleUrl)
22
- const mapStyleJson = await mapStyleRes.json()
23
-
24
- // detect center & zoom from map style json
25
- let center = mapStyleJson.hasOwnProperty('center')
26
- ? mapStyleJson.center
27
- : undefined
28
- let zoom = mapStyleJson.hasOwnProperty('zoom')
29
- ? mapStyleJson.zoom
30
- : undefined
31
-
32
- // detect center & zoom from tile json
33
- if (center === undefined || zoom === undefined) {
34
- for (const sourceName in mapStyleJson.sources) {
35
- if (
36
- mapStyleJson.sources[sourceName].type === 'vector' &&
37
- mapStyleJson.sources[sourceName].hasOwnProperty('url')
38
- ) {
39
- const mapTileUrl = mapStyleJson.sources[sourceName].url
40
- const mapTileRes = await fetch(mapTileUrl)
41
- const mapTileJson = await mapTileRes.json()
42
- if (center === undefined) {
43
- const bounds = mapTileJson.bounds
44
- center = mapTileJson.center
45
- if (!center && bounds) {
46
- center = [
47
- (bounds[0] + bounds[2]) / 2,
48
- (bounds[1] + bounds[3]) / 2,
49
- ]
50
- }
51
- }
52
- if (zoom === undefined) {
53
- zoom = (mapTileJson.minzoom + mapTileJson.maxzoom) / 2
54
- }
55
- }
56
- }
57
- }
58
-
59
- return {
60
- style: mapStyleUrl,
61
- center,
62
- zoom,
63
- }
64
- },
65
- setupDebugCheckboxes: function (map) {
66
- const properties = [
67
- 'showTileBoundaries',
68
- 'showCollisionBoxes',
69
- 'showPadding',
70
- ]
71
- for (const property of properties) {
72
- const control = document.getElementById(property)
73
- const clickHandler = function () {
74
- const checked = control.checked
75
- map[property] = checked
76
- }
77
- clickHandler()
78
- control.addEventListener('click', clickHandler)
79
- }
80
- },
81
- }
82
-
83
- const { style, center, zoom } = await window._charites.parseMapStyle()
84
- const options = {
85
- container: 'map',
86
- hash: true,
87
- maxPitch: 85,
88
- style,
89
- }
90
- if (center) options.center = center
91
- if (zoom) options.zoom = zoom
92
- const map = new maplibregl.Map(options)
93
-
94
- window._charites.initializeWebSocket(map)
95
-
96
- map.addControl(new maplibregl.NavigationControl(), 'top-right')
97
-
98
- map.addControl(
99
- new MaplibreLegendControl.MaplibreLegendControl(
100
- {},
101
- {
102
- showDefault: true,
103
- showCheckbox: true,
104
- onlyRendered: true,
105
- reverseOrder: true,
106
- },
107
- ),
108
- 'bottom-left',
109
- )
110
-
111
- window._charites.setupDebugCheckboxes(map)
112
- })()
@@ -1,10 +0,0 @@
1
- import { fileURLToPath } from 'url'
2
- import { dirname } from 'path'
3
- import path from 'path'
4
-
5
- const __filename = fileURLToPath(import.meta.url)
6
- const __dirname = dirname(__filename)
7
- export const providerDir = path.join(
8
- path.dirname(path.dirname(__dirname)),
9
- 'provider',
10
- )