@unvt/charites 0.1.4 → 0.3.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/.all-contributorsrc +63 -0
- package/.devcontainer/Dockerfile +29 -0
- package/.devcontainer/README.md +34 -0
- package/.devcontainer/devcontainer.json +36 -0
- package/.github/CONTRIBUTING.md +6 -4
- package/.github/PULL_REQUEST_TEMPLATE.md +2 -1
- package/.github/release.yml +14 -0
- package/.github/workflows/build.yml +28 -3
- package/LICENSE +1 -1
- package/README.md +8 -3
- package/dist/cli/serve.js +1 -1
- package/dist/commands/serve.js +21 -4
- package/dist/lib/build-sprite.js +8 -62
- package/dist/lib/error.js +4 -1
- package/dist/lib/yaml-writer.js +7 -4
- package/docs/source/conf.py +3 -3
- package/docs/source/index.rst +2 -2
- package/docs/source/install/recommended_environment.rst +1 -1
- package/docs/source/usage/commandline_interface.rst +3 -3
- package/docs/source/usage/examples.rst +2 -2
- package/package.json +11 -4
- package/playwright.config.ts +29 -0
- package/provider/default/app.js +28 -33
- package/provider/default/index.html +4 -1
- package/provider/default/shared.js +67 -0
- package/provider/geolonia/app.js +27 -32
- package/provider/geolonia/index.html +4 -1
- package/provider/mapbox/app.js +30 -34
- package/provider/mapbox/index.html +4 -1
- package/src/cli/serve.ts +1 -1
- package/src/commands/serve.ts +32 -4
- package/src/lib/build-sprite.ts +8 -71
- package/src/lib/error.ts +3 -1
- package/src/lib/yaml-writer.ts +8 -4
- package/test/build-sprite.spec.ts +5 -5
- package/test/build.spec.ts +33 -23
- package/test/command.build.spec.ts +108 -0
- package/test/command.convert.spec.ts +24 -0
- package/test/command.init.spec.ts +45 -0
- package/test/data/style.json +4 -3
- package/test/playwright/provider/default/e2e.spec.ts +13 -0
- package/test/playwright/provider/geolonia/e2e.spec.ts +13 -0
- package/test/playwright/provider/mapbox/e2e.spec.ts +13 -0
- package/test/util/charitesCmd.ts +3 -0
- package/test/util/copyFixtures.ts +14 -0
- package/test/util/execPromise.ts +14 -0
- package/test/util/makeTempDir.ts +6 -0
- package/provider/geolonia/app.css +0 -17
- package/provider/mapbox/app.css +0 -17
package/provider/default/app.js
CHANGED
|
@@ -1,37 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
;(async () => {
|
|
2
|
+
const { style, center, zoom } = await window._charites.parseMapStyle()
|
|
3
|
+
const options = {
|
|
4
|
+
container: 'map',
|
|
5
|
+
hash: true,
|
|
6
|
+
style,
|
|
7
|
+
}
|
|
8
|
+
if (center) options.center = center
|
|
9
|
+
if (zoom) options.zoom = zoom
|
|
10
|
+
const map = new maplibregl.Map(options)
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
window._charites.initializeWebSocket((message) => {
|
|
13
|
+
map.setStyle(JSON.parse(message.data))
|
|
14
|
+
})
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
map.setStyle(JSON.parse(message.data))
|
|
11
|
-
})
|
|
16
|
+
map.addControl(new maplibregl.NavigationControl(), 'top-right')
|
|
12
17
|
|
|
13
|
-
map.addControl(
|
|
18
|
+
map.addControl(
|
|
19
|
+
new MaplibreLegendControl(
|
|
20
|
+
{},
|
|
21
|
+
{
|
|
22
|
+
showDefault: true,
|
|
23
|
+
showCheckbox: true,
|
|
24
|
+
onlyRendered: true,
|
|
25
|
+
reverseOrder: true,
|
|
26
|
+
},
|
|
27
|
+
),
|
|
28
|
+
'bottom-left',
|
|
29
|
+
)
|
|
14
30
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const checked = showTileBoundaries.checked
|
|
18
|
-
map.showTileBoundaries = checked
|
|
19
|
-
}
|
|
20
|
-
setShowTileBoundaries()
|
|
21
|
-
showTileBoundaries.addEventListener('click', setShowTileBoundaries)
|
|
22
|
-
|
|
23
|
-
const showCollisionBoxes = document.getElementById('showCollisionBoxes')
|
|
24
|
-
const setShowCollisionBoxes = function () {
|
|
25
|
-
const checked = showCollisionBoxes.checked
|
|
26
|
-
map.showCollisionBoxes = checked
|
|
27
|
-
}
|
|
28
|
-
setShowCollisionBoxes()
|
|
29
|
-
showCollisionBoxes.addEventListener('click', setShowCollisionBoxes)
|
|
30
|
-
|
|
31
|
-
const showPadding = document.getElementById('showPadding')
|
|
32
|
-
const setShowPadding = function () {
|
|
33
|
-
const checked = showPadding.checked
|
|
34
|
-
map.showPadding = checked
|
|
35
|
-
}
|
|
36
|
-
setShowPadding()
|
|
37
|
-
showPadding.addEventListener('click', setShowPadding)
|
|
31
|
+
window._charites.setupDebugCheckboxes(map)
|
|
32
|
+
})()
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
2
|
+
<html id="charites-default">
|
|
3
3
|
<head>
|
|
4
4
|
<link rel="stylesheet" href="/app.css" />
|
|
5
5
|
<link href='https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.css' rel='stylesheet' />
|
|
6
|
+
<link href='https://watergis.github.io/maplibre-gl-legend/maplibre-gl-legend.css' rel='stylesheet' />
|
|
6
7
|
<title>Charites Live Preview</title>
|
|
7
8
|
<script src='https://unpkg.com/maplibre-gl@1.15.2/dist/maplibre-gl.js'></script>
|
|
9
|
+
<script src="https://watergis.github.io/maplibre-gl-legend/maplibre-gl-legend.js"></script>
|
|
8
10
|
</head>
|
|
9
11
|
<body>
|
|
10
12
|
<div class="overlay">
|
|
@@ -15,6 +17,7 @@
|
|
|
15
17
|
<label><input type="checkbox" id="showPadding">show Padding</label>
|
|
16
18
|
</div>
|
|
17
19
|
<div id="map"></div>
|
|
20
|
+
<script type="text/javascript" src="/shared.js"></script>
|
|
18
21
|
<script type="text/javascript" src="/app.js"></script>
|
|
19
22
|
</body>
|
|
20
23
|
</html>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
;(async () => {
|
|
2
|
+
window._charites = {
|
|
3
|
+
initializeWebSocket: function (onmessage) {
|
|
4
|
+
const socket = new WebSocket(`ws://${window.location.host}`)
|
|
5
|
+
|
|
6
|
+
socket.addEventListener('message', onmessage)
|
|
7
|
+
},
|
|
8
|
+
parseMapStyle: async function () {
|
|
9
|
+
const mapStyleUrl = `http://${window.location.host}/style.json`
|
|
10
|
+
const mapStyleRes = await fetch(mapStyleUrl)
|
|
11
|
+
const mapStyleJson = await mapStyleRes.json()
|
|
12
|
+
|
|
13
|
+
// detect center & zoom from map style json
|
|
14
|
+
let center = mapStyleJson.hasOwnProperty('center')
|
|
15
|
+
? mapStyleJson.center
|
|
16
|
+
: undefined
|
|
17
|
+
let zoom = mapStyleJson.hasOwnProperty('zoom')
|
|
18
|
+
? mapStyleJson.zoom
|
|
19
|
+
: undefined
|
|
20
|
+
|
|
21
|
+
// detect center & zoom from tile json
|
|
22
|
+
if (center === undefined || zoom === undefined) {
|
|
23
|
+
for (const sourceName in mapStyleJson.sources) {
|
|
24
|
+
if (
|
|
25
|
+
mapStyleJson.sources[sourceName].type === 'vector' &&
|
|
26
|
+
mapStyleJson.sources[sourceName].hasOwnProperty('url')
|
|
27
|
+
) {
|
|
28
|
+
const mapTileUrl = mapStyleJson.sources[sourceName].url
|
|
29
|
+
const mapTileRes = await fetch(mapTileUrl)
|
|
30
|
+
const mapTileJson = await mapTileRes.json()
|
|
31
|
+
if (center === undefined) {
|
|
32
|
+
const bounds = mapTileJson.bounds
|
|
33
|
+
center = mapTileJson.center
|
|
34
|
+
? mapTileJson.center
|
|
35
|
+
: [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2]
|
|
36
|
+
}
|
|
37
|
+
if (zoom === undefined) {
|
|
38
|
+
zoom = (mapTileJson.minzoom + mapTileJson.maxzoom) / 2
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
style: mapStyleUrl,
|
|
46
|
+
center,
|
|
47
|
+
zoom,
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
setupDebugCheckboxes: function (map) {
|
|
51
|
+
const properties = [
|
|
52
|
+
'showTileBoundaries',
|
|
53
|
+
'showCollisionBoxes',
|
|
54
|
+
'showPadding',
|
|
55
|
+
]
|
|
56
|
+
for (const property of properties) {
|
|
57
|
+
const control = document.getElementById(property)
|
|
58
|
+
const clickHandler = function () {
|
|
59
|
+
const checked = control.checked
|
|
60
|
+
map[property] = checked
|
|
61
|
+
}
|
|
62
|
+
clickHandler()
|
|
63
|
+
control.addEventListener('click', clickHandler)
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
})()
|
package/provider/geolonia/app.js
CHANGED
|
@@ -1,35 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
;(async () => {
|
|
2
|
+
const { style, center, zoom } = await window._charites.parseMapStyle()
|
|
3
|
+
const options = {
|
|
4
|
+
container: 'map',
|
|
5
|
+
hash: true,
|
|
6
|
+
style,
|
|
7
|
+
}
|
|
8
|
+
if (center) options.center = center
|
|
9
|
+
if (zoom) options.zoom = zoom
|
|
10
|
+
const map = new geolonia.Map(options)
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
window._charites.initializeWebSocket((message) => {
|
|
13
|
+
map.setStyle(JSON.parse(message.data))
|
|
14
|
+
})
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
16
|
+
map.addControl(
|
|
17
|
+
new MaplibreLegendControl(
|
|
18
|
+
{},
|
|
19
|
+
{
|
|
20
|
+
showDefault: true,
|
|
21
|
+
showCheckbox: true,
|
|
22
|
+
onlyRendered: true,
|
|
23
|
+
reverseOrder: true,
|
|
24
|
+
},
|
|
25
|
+
),
|
|
26
|
+
'bottom-left',
|
|
27
|
+
)
|
|
12
28
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const checked = showTileBoundaries.checked
|
|
16
|
-
map.showTileBoundaries = checked
|
|
17
|
-
}
|
|
18
|
-
setShowTileBoundaries()
|
|
19
|
-
showTileBoundaries.addEventListener('click', setShowTileBoundaries)
|
|
20
|
-
|
|
21
|
-
const showCollisionBoxes = document.getElementById('showCollisionBoxes')
|
|
22
|
-
const setShowCollisionBoxes = function () {
|
|
23
|
-
const checked = showCollisionBoxes.checked
|
|
24
|
-
map.showCollisionBoxes = checked
|
|
25
|
-
}
|
|
26
|
-
setShowCollisionBoxes()
|
|
27
|
-
showCollisionBoxes.addEventListener('click', setShowCollisionBoxes)
|
|
28
|
-
|
|
29
|
-
const showPadding = document.getElementById('showPadding')
|
|
30
|
-
const setShowPadding = function () {
|
|
31
|
-
const checked = showPadding.checked
|
|
32
|
-
map.showPadding = checked
|
|
33
|
-
}
|
|
34
|
-
setShowPadding()
|
|
35
|
-
showPadding.addEventListener('click', setShowPadding)
|
|
29
|
+
window._charites.setupDebugCheckboxes(map)
|
|
30
|
+
})()
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
2
|
+
<html id="charites-geolonia">
|
|
3
3
|
<head>
|
|
4
4
|
<link rel="stylesheet" href="/app.css" />
|
|
5
5
|
<title>Charites Live Preview</title>
|
|
6
|
+
<link href='https://watergis.github.io/maplibre-gl-legend/maplibre-gl-legend.css' rel='stylesheet' />
|
|
6
7
|
</head>
|
|
7
8
|
<body>
|
|
8
9
|
<div class="overlay">
|
|
@@ -14,6 +15,8 @@
|
|
|
14
15
|
</div>
|
|
15
16
|
<div id="map"></div>
|
|
16
17
|
<script type="text/javascript" src="https://cdn.geolonia.com/v1/embed?geolonia-api-key=YOUR-API-KEY"></script>
|
|
18
|
+
<script src="https://watergis.github.io/maplibre-gl-legend/maplibre-gl-legend.js"></script>
|
|
19
|
+
<script type="text/javascript" src="/shared.js"></script>
|
|
17
20
|
<script type="text/javascript" src="/app.js"></script>
|
|
18
21
|
</body>
|
|
19
22
|
</html>
|
package/provider/mapbox/app.js
CHANGED
|
@@ -1,39 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
;(async () => {
|
|
2
|
+
mapboxgl.accessToken = '___MAPBOX_ACCESS_TOKEN___'
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const { style, center, zoom } = await window._charites.parseMapStyle()
|
|
5
|
+
const options = {
|
|
6
|
+
container: 'map',
|
|
7
|
+
hash: true,
|
|
8
|
+
style,
|
|
9
|
+
}
|
|
10
|
+
if (center) options.center = center
|
|
11
|
+
if (zoom) options.zoom = zoom
|
|
12
|
+
const map = new mapboxgl.Map(options)
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
window._charites.initializeWebSocket((message) => {
|
|
15
|
+
map.setStyle(JSON.parse(message.data))
|
|
16
|
+
})
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
map.setStyle(JSON.parse(message.data))
|
|
13
|
-
})
|
|
18
|
+
map.addControl(new mapboxgl.NavigationControl(), 'top-right')
|
|
14
19
|
|
|
15
|
-
map.addControl(
|
|
20
|
+
map.addControl(
|
|
21
|
+
new MapboxLegendControl(
|
|
22
|
+
{},
|
|
23
|
+
{
|
|
24
|
+
showDefault: true,
|
|
25
|
+
showCheckbox: true,
|
|
26
|
+
onlyRendered: true,
|
|
27
|
+
reverseOrder: true,
|
|
28
|
+
accesstoken: mapboxgl.accessToken,
|
|
29
|
+
},
|
|
30
|
+
),
|
|
31
|
+
'bottom-left',
|
|
32
|
+
)
|
|
16
33
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const checked = showTileBoundaries.checked
|
|
20
|
-
map.showTileBoundaries = checked
|
|
21
|
-
}
|
|
22
|
-
setShowTileBoundaries()
|
|
23
|
-
showTileBoundaries.addEventListener('click', setShowTileBoundaries)
|
|
24
|
-
|
|
25
|
-
const showCollisionBoxes = document.getElementById('showCollisionBoxes')
|
|
26
|
-
const setShowCollisionBoxes = function () {
|
|
27
|
-
const checked = showCollisionBoxes.checked
|
|
28
|
-
map.showCollisionBoxes = checked
|
|
29
|
-
}
|
|
30
|
-
setShowCollisionBoxes()
|
|
31
|
-
showCollisionBoxes.addEventListener('click', setShowCollisionBoxes)
|
|
32
|
-
|
|
33
|
-
const showPadding = document.getElementById('showPadding')
|
|
34
|
-
const setShowPadding = function () {
|
|
35
|
-
const checked = showPadding.checked
|
|
36
|
-
map.showPadding = checked
|
|
37
|
-
}
|
|
38
|
-
setShowPadding()
|
|
39
|
-
showPadding.addEventListener('click', setShowPadding)
|
|
34
|
+
window._charites.setupDebugCheckboxes(map)
|
|
35
|
+
})()
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
2
|
+
<html id="charites-mapbox">
|
|
3
3
|
<head>
|
|
4
4
|
<link rel="stylesheet" href="/app.css" />
|
|
5
5
|
<link href='https://api.mapbox.com/mapbox-gl-js/v2.5.0/mapbox-gl.css' rel='stylesheet' />
|
|
6
|
+
<link href='https://watergis.github.io/mapbox-gl-legend/mapbox-gl-legend.css' rel='stylesheet' />
|
|
6
7
|
<title>Charites Live Preview</title>
|
|
7
8
|
<script src='https://api.mapbox.com/mapbox-gl-js/v2.5.0/mapbox-gl.js'></script>
|
|
9
|
+
<script src="https://watergis.github.io/mapbox-gl-legend/mapbox-gl-legend.js"></script>
|
|
8
10
|
</head>
|
|
9
11
|
<body>
|
|
10
12
|
<div class="overlay">
|
|
@@ -15,6 +17,7 @@
|
|
|
15
17
|
<label><input type="checkbox" id="showPadding">show Padding</label>
|
|
16
18
|
</div>
|
|
17
19
|
<div id="map"></div>
|
|
20
|
+
<script type="text/javascript" src="/shared.js"></script>
|
|
18
21
|
<script type="text/javascript" src="/app.js"></script>
|
|
19
22
|
</body>
|
|
20
23
|
</html>
|
package/src/cli/serve.ts
CHANGED
|
@@ -15,7 +15,7 @@ program
|
|
|
15
15
|
)
|
|
16
16
|
.option(
|
|
17
17
|
'--mapbox-access-token [mapboxAccessToken]',
|
|
18
|
-
'Access Token
|
|
18
|
+
'Your Mapbox Access Token (required if using the `mapbox` provider)',
|
|
19
19
|
)
|
|
20
20
|
.option('--port [port]', 'Specify custom port')
|
|
21
21
|
.action((source: string, serveOptions: serveOptions) => {
|
package/src/commands/serve.ts
CHANGED
|
@@ -36,15 +36,25 @@ export function serve(source: string, options: serveOptions) {
|
|
|
36
36
|
throw `${sourcePath}: No such file or directory`
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
const mapboxAccessToken =
|
|
40
|
+
options.mapboxAccessToken || defaultValues.mapboxAccessToken
|
|
41
|
+
if (provider === 'mapbox' && !mapboxAccessToken) {
|
|
42
|
+
throw `Provider is mapbox, but the Mapbox Access Token is not set. Please provide it using --mapbox-access-token, or set it in \`~/.charites/config.yml\` (see the Global configuration section of the documentation for more information)`
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
const server = http.createServer((req, res) => {
|
|
40
46
|
const url = (req.url || '').replace(/\?.*/, '')
|
|
41
|
-
const
|
|
47
|
+
const defaultProviderDir = path.join(defaultValues.providerDir, 'default')
|
|
48
|
+
const providerDir = path.join(defaultValues.providerDir, provider)
|
|
42
49
|
|
|
43
50
|
switch (url) {
|
|
44
51
|
case '/':
|
|
45
52
|
res.statusCode = 200
|
|
46
53
|
res.setHeader('Content-Type', 'text/html; charset=UTF-8')
|
|
47
|
-
const content = fs.readFileSync(
|
|
54
|
+
const content = fs.readFileSync(
|
|
55
|
+
path.join(providerDir, 'index.html'),
|
|
56
|
+
'utf-8',
|
|
57
|
+
)
|
|
48
58
|
res.end(content)
|
|
49
59
|
break
|
|
50
60
|
case '/style.json':
|
|
@@ -62,14 +72,27 @@ export function serve(source: string, options: serveOptions) {
|
|
|
62
72
|
case '/app.css':
|
|
63
73
|
res.statusCode = 200
|
|
64
74
|
res.setHeader('Content-Type', 'text/css; charset=UTF-8')
|
|
65
|
-
const css = fs.readFileSync(
|
|
75
|
+
const css = fs.readFileSync(
|
|
76
|
+
path.join(defaultProviderDir, 'app.css'),
|
|
77
|
+
'utf-8',
|
|
78
|
+
)
|
|
66
79
|
res.end(css)
|
|
67
80
|
break
|
|
81
|
+
case `/shared.js`:
|
|
82
|
+
res.statusCode = 200
|
|
83
|
+
res.setHeader('Content-Type', 'application/javascript; charset=UTF-8')
|
|
84
|
+
const shared = fs.readFileSync(
|
|
85
|
+
path.join(defaultProviderDir, 'shared.js'),
|
|
86
|
+
'utf-8',
|
|
87
|
+
)
|
|
88
|
+
const js = shared.replace('___PORT___', `${port}`)
|
|
89
|
+
res.end(js)
|
|
90
|
+
break
|
|
68
91
|
case `/app.js`:
|
|
69
92
|
res.statusCode = 200
|
|
70
93
|
res.setHeader('Content-Type', 'application/javascript; charset=UTF-8')
|
|
71
94
|
try {
|
|
72
|
-
const app = fs.readFileSync(path.join(
|
|
95
|
+
const app = fs.readFileSync(path.join(providerDir, 'app.js'), 'utf-8')
|
|
73
96
|
const js = app
|
|
74
97
|
.replace('___PORT___', `${port}`)
|
|
75
98
|
.replace(
|
|
@@ -81,6 +104,11 @@ export function serve(source: string, options: serveOptions) {
|
|
|
81
104
|
throw `Invalid provider: ${provider}`
|
|
82
105
|
}
|
|
83
106
|
break
|
|
107
|
+
default:
|
|
108
|
+
res.statusCode = 404
|
|
109
|
+
res.setHeader('Content-Type', 'text/plain; charset=UTF-8')
|
|
110
|
+
res.end('Not found')
|
|
111
|
+
break
|
|
84
112
|
}
|
|
85
113
|
})
|
|
86
114
|
|
package/src/lib/build-sprite.ts
CHANGED
|
@@ -1,80 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const glob = require('glob')
|
|
1
|
+
import { generateSprite } from '@unvt/sprite-one'
|
|
4
2
|
const path = require('path')
|
|
5
3
|
|
|
6
|
-
type spriteOption = {
|
|
7
|
-
imgs: string
|
|
8
|
-
pixelRatio: number
|
|
9
|
-
format: boolean
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function generateLayoutAsync(option: spriteOption): Promise<string> {
|
|
13
|
-
return new Promise((resolve, reject) => {
|
|
14
|
-
spritezero.generateLayout(option, (err: TypeError, result: string) => {
|
|
15
|
-
if (err) reject(err)
|
|
16
|
-
else resolve(result)
|
|
17
|
-
})
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function generateImageAsync(option: string): Promise<string> {
|
|
22
|
-
return new Promise((resolve, reject) => {
|
|
23
|
-
spritezero.generateImage(option, (err: TypeError, result: string) => {
|
|
24
|
-
if (err) reject(err)
|
|
25
|
-
else resolve(result)
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
4
|
export async function buildSprite(
|
|
31
5
|
svgPath: string,
|
|
32
6
|
publicPath: string,
|
|
33
7
|
iconSlug: string,
|
|
34
|
-
) {
|
|
8
|
+
): Promise<void> {
|
|
35
9
|
const pxRatios = [1, 2]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
.sync(path.join(svgPath, `*.svg`))
|
|
42
|
-
.map(function (iconPath: string) {
|
|
43
|
-
return {
|
|
44
|
-
svg: fs.readFileSync(iconPath),
|
|
45
|
-
id: path.basename(iconPath).replace('.svg', ''),
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
let file = ''
|
|
50
|
-
if (pxRatio > 1) {
|
|
51
|
-
file = `@${pxRatio}x`
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const pngPath = path.join(publicPath, `${iconSlug}${file}.png`)
|
|
55
|
-
const jsonPath = path.join(publicPath, `${iconSlug}${file}.json`)
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const dataLayout = await generateLayoutAsync({
|
|
59
|
-
imgs: svgFiles,
|
|
60
|
-
pixelRatio: pxRatio,
|
|
61
|
-
format: true,
|
|
62
|
-
})
|
|
63
|
-
fs.writeFileSync(jsonPath, JSON.stringify(dataLayout))
|
|
64
|
-
} catch (error) {
|
|
65
|
-
throw `${publicPath}: No such file or directory`
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
const imageLayout = await generateLayoutAsync({
|
|
70
|
-
imgs: svgFiles,
|
|
71
|
-
pixelRatio: pxRatio,
|
|
72
|
-
format: false,
|
|
73
|
-
})
|
|
74
|
-
const image = await generateImageAsync(imageLayout)
|
|
75
|
-
fs.writeFileSync(pngPath, image)
|
|
76
|
-
} catch (error) {
|
|
77
|
-
throw `${publicPath}: No such file or directory`
|
|
78
|
-
}
|
|
10
|
+
const outPath = path.join(publicPath, iconSlug)
|
|
11
|
+
try {
|
|
12
|
+
await generateSprite(outPath, [svgPath], pxRatios)
|
|
13
|
+
} catch (error) {
|
|
14
|
+
throw error
|
|
79
15
|
}
|
|
16
|
+
return
|
|
80
17
|
}
|
package/src/lib/error.ts
CHANGED
package/src/lib/yaml-writer.ts
CHANGED
|
@@ -47,11 +47,15 @@ const writeDecompositedYaml = (
|
|
|
47
47
|
const layer = style.layers[i]
|
|
48
48
|
const layerYml = YAML.dump(layer)
|
|
49
49
|
const fileName = `${style.layers[i].id}.yml`
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
fs.
|
|
50
|
+
const layersDirName = path.join(path.dirname(destinationPath), 'layers')
|
|
51
|
+
const filePath = path.join(layersDirName, fileName)
|
|
52
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
53
|
+
fs.writeFileSync(filePath, layerYml)
|
|
54
|
+
|
|
55
|
+
// ts-ignore is required here because !!inc/file string is not compatible with the Layer object type.
|
|
56
|
+
// We use path.posix.join to make sure the path uses / path separators, even when run on Windows.
|
|
53
57
|
// @ts-ignore
|
|
54
|
-
layers.push(`!!inc/file ${path.join('layers', fileName)}`)
|
|
58
|
+
layers.push(`!!inc/file ${path.posix.join('layers', fileName)}`)
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
style.layers = layers
|
|
@@ -12,13 +12,13 @@ describe('Test for the `build-sprite.ts`.', () => {
|
|
|
12
12
|
tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'charites-'))
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
it("should create icon's json/png at specified path and name ",
|
|
15
|
+
it("should create icon's json/png at specified path and name ", () => {
|
|
16
16
|
const expectedJsonPath = path.join(tmpdir, 'basic.json')
|
|
17
17
|
const expectedPngPath = path.join(tmpdir, 'basic.png')
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
buildSprite(iconsPath, tmpdir, `basic`).then(() => {
|
|
20
|
+
assert.deepEqual(true, !!fs.statSync(expectedJsonPath))
|
|
21
|
+
assert.deepEqual(true, !!fs.statSync(expectedPngPath))
|
|
22
|
+
})
|
|
23
23
|
})
|
|
24
24
|
})
|
package/test/build.spec.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import chai from 'chai'
|
|
2
|
+
import chaiAsPromised from 'chai-as-promised'
|
|
2
3
|
import path from 'path'
|
|
3
4
|
import fs from 'fs'
|
|
4
5
|
import os from 'os'
|
|
@@ -6,6 +7,10 @@ import os from 'os'
|
|
|
6
7
|
import { build, buildWatch } from '../src/commands/build'
|
|
7
8
|
import { defaultValues } from '../src/lib/defaultValues'
|
|
8
9
|
|
|
10
|
+
chai.use(chaiAsPromised)
|
|
11
|
+
chai.should()
|
|
12
|
+
const assert = chai.assert
|
|
13
|
+
|
|
9
14
|
describe('Test for the `build.ts`.', () => {
|
|
10
15
|
const styleYaml = path.join(__dirname, 'data/style.yml')
|
|
11
16
|
const iconSource = path.join(__dirname, 'data/icons')
|
|
@@ -38,7 +43,12 @@ describe('Test for the `build.ts`.', () => {
|
|
|
38
43
|
|
|
39
44
|
// The file should exists.
|
|
40
45
|
assert.deepEqual(true, !!fs.statSync(styleJson))
|
|
41
|
-
|
|
46
|
+
|
|
47
|
+
const fixtureStyleJson = path.join(__dirname, 'data/style.json')
|
|
48
|
+
assert.equal(
|
|
49
|
+
fs.readFileSync(styleJson, 'utf-8'),
|
|
50
|
+
fs.readFileSync(fixtureStyleJson, 'utf-8'),
|
|
51
|
+
)
|
|
42
52
|
})
|
|
43
53
|
|
|
44
54
|
it('Should minify `data/style.yml` to JSON.', async () => {
|
|
@@ -69,50 +79,50 @@ describe('Test for the `build.ts`.', () => {
|
|
|
69
79
|
)
|
|
70
80
|
})
|
|
71
81
|
|
|
72
|
-
it('Should build icons with the option `--sprite-url`. Icon file name is set by spriteUrl',
|
|
82
|
+
it('Should build icons with the option `--sprite-url`. Icon file name is set by spriteUrl', () => {
|
|
73
83
|
const expectedIconName = 'dark'
|
|
74
84
|
const expectedPng = path.join(tmpdir, `${expectedIconName}.png`)
|
|
75
85
|
const expectedJson = path.join(tmpdir, `${expectedIconName}.json`)
|
|
76
86
|
|
|
77
|
-
|
|
87
|
+
build(styleYaml, styleJson, {
|
|
78
88
|
provider: defaultValues.provider,
|
|
79
89
|
spriteUrl: `http://localhost:8080/${expectedIconName}`,
|
|
80
90
|
spriteInput: iconSource,
|
|
81
91
|
spriteOutput: tmpdir,
|
|
92
|
+
}).then(() => {
|
|
93
|
+
assert.deepEqual(true, !!fs.statSync(expectedPng))
|
|
94
|
+
assert.deepEqual(true, !!fs.statSync(expectedJson))
|
|
82
95
|
})
|
|
83
|
-
|
|
84
|
-
assert.deepEqual(true, !!fs.statSync(expectedPng))
|
|
85
|
-
assert.deepEqual(true, !!fs.statSync(expectedJson))
|
|
86
96
|
})
|
|
87
97
|
|
|
88
|
-
it('Use sprite name that specified in style.json with no --sprite-url option',
|
|
98
|
+
it('Use sprite name that specified in style.json with no --sprite-url option', () => {
|
|
89
99
|
const expectedIconName = 'basic-white' // from test/data/style.yml
|
|
90
100
|
const expectedPng = path.join(tmpdir, `${expectedIconName}.png`)
|
|
91
101
|
const expectedJson = path.join(tmpdir, `${expectedIconName}.json`)
|
|
92
102
|
|
|
93
|
-
|
|
103
|
+
build(styleYaml, styleJson, {
|
|
94
104
|
provider: defaultValues.provider,
|
|
95
105
|
spriteInput: iconSource,
|
|
96
106
|
spriteOutput: tmpdir,
|
|
107
|
+
}).then(() => {
|
|
108
|
+
// The file should exists.
|
|
109
|
+
assert.deepEqual(true, !!fs.statSync(expectedPng))
|
|
110
|
+
assert.deepEqual(true, !!fs.statSync(expectedJson))
|
|
97
111
|
})
|
|
98
|
-
|
|
99
|
-
// The file should exists.
|
|
100
|
-
assert.deepEqual(true, !!fs.statSync(expectedPng))
|
|
101
|
-
assert.deepEqual(true, !!fs.statSync(expectedJson))
|
|
102
112
|
})
|
|
103
113
|
|
|
104
|
-
it('Should not create sprite when input directory is not exist.',
|
|
114
|
+
it('Should not create sprite when input directory is not exist.', () => {
|
|
105
115
|
const noExistInputDir = path.join(__dirname, 'data/hellooooo')
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
const promise = build(styleYaml, styleJson, {
|
|
118
|
+
provider: defaultValues.provider,
|
|
119
|
+
spriteInput: noExistInputDir,
|
|
120
|
+
spriteOutput: tmpdir,
|
|
121
|
+
})
|
|
122
|
+
return assert.isRejected(
|
|
123
|
+
promise,
|
|
124
|
+
/No such directory. Please specify valid icon input directory. For more help run charites build --help/,
|
|
125
|
+
)
|
|
116
126
|
})
|
|
117
127
|
|
|
118
128
|
it('Should watch `*.yml` and convert it to JSON', async () => {
|