@unvt/charites 0.3.0 → 0.4.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/.eslintrc.js +1 -1
- package/.github/workflows/build-docs.yml +4 -4
- package/.github/workflows/build.yml +8 -7
- package/dist/cli/build.js +4 -4
- package/dist/cli/convert.js +2 -2
- package/dist/cli/init.js +3 -3
- package/dist/cli/serve.js +7 -3
- package/dist/commands/build.js +7 -12
- package/dist/commands/convert.js +2 -12
- package/dist/commands/init.js +1 -1
- package/dist/commands/serve.js +65 -12
- package/dist/lib/build-sprite.js +6 -8
- package/dist/lib/error.js +2 -1
- package/dist/lib/tileinfo-importer/index.js +1 -0
- package/dist/lib/yaml-writer.js +21 -12
- package/dist/types/index.js +6 -2
- package/docs/Pipfile.lock +136 -193
- package/docs/source/index.rst +2 -2
- package/docs/source/install/img/windows-guide-01.png +0 -0
- package/docs/source/install/index.rst +1 -0
- package/docs/source/install/install.rst +1 -0
- package/docs/source/install/install_on_nanban.rst +1 -1
- package/docs/source/install/installation_guide_for_windows.rst +52 -0
- package/docs/source/install/recommended_environment.rst +2 -2
- package/docs/source/usage/commandline_interface.rst +21 -8
- package/docs/source/usage/example2.rst +166 -0
- package/docs/source/usage/img/example02-001.png +0 -0
- package/docs/source/usage/img/example02-002.png +0 -0
- package/docs/source/usage/img/example02-003.png +0 -0
- package/docs/source/usage/img/example02-004.png +0 -0
- package/docs/source/usage/img/example02-005.png +0 -0
- package/docs/source/usage/img/example02-006.png +0 -0
- package/docs/source/usage/img/example02-007.png +0 -0
- package/docs/source/usage/img/example02-008.png +0 -0
- package/docs/source/usage/img/example02-009.png +0 -0
- package/docs/source/usage/img/example02-010.png +0 -0
- package/docs/source/usage/img/example02-011.png +0 -0
- package/docs/source/usage/img/example02-012.png +0 -0
- package/docs/source/usage/img/example02-013.png +0 -0
- package/docs/source/usage/img/example02-014.png +0 -0
- package/docs/source/usage/img/example02-015.png +0 -0
- package/docs/source/usage/img/example02-016.png +0 -0
- package/docs/source/usage/img/example02-017.png +0 -0
- package/docs/source/usage/img/example02-018.png +0 -0
- package/docs/source/usage/index.rst +1 -0
- package/package.json +31 -29
- package/provider/default/app.js +1 -3
- package/provider/default/index.html +2 -2
- package/provider/default/shared.js +11 -2
- package/provider/geolonia/app.js +1 -3
- package/provider/mapbox/app.js +1 -3
- package/src/cli/init.ts +1 -1
- package/src/cli/serve.ts +9 -2
- package/src/commands/build.ts +2 -6
- package/src/commands/convert.ts +2 -10
- package/src/commands/init.ts +1 -1
- package/src/commands/serve.ts +80 -11
- package/src/lib/build-sprite.ts +2 -6
- package/src/lib/get-sprite-slug.ts +1 -1
- package/src/lib/tileinfo-importer/base-importer.ts +1 -1
- package/src/lib/tileinfo-importer/metadata-importer.ts +1 -1
- package/src/lib/tileinfo-importer/tilejson-importer.ts +1 -1
- package/src/lib/validate-style.ts +1 -1
- package/src/lib/yaml-parser.ts +1 -1
- package/src/lib/yaml-writer.ts +23 -14
- package/test/build.spec.ts +2 -2
- package/test/command.serve.spec.ts +103 -0
- package/test/convert.spec.ts +24 -4
- package/test/data/convert.json +7 -0
- package/test/init.spec.ts +7 -5
- package/test/util/charitesCmd.ts +3 -1
- package/test/util/execPromise.ts +51 -1
- package/test/util/index.ts +3 -0
- package/test/validate-style.spec.ts +1 -1
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
SourceSpecification,
|
|
5
5
|
LayerSpecification,
|
|
6
6
|
VectorSourceSpecification,
|
|
7
|
-
} from '@maplibre/maplibre-gl-style-spec
|
|
7
|
+
} from '@maplibre/maplibre-gl-style-spec'
|
|
8
8
|
|
|
9
9
|
export type TileInfoJSONResponse = {
|
|
10
10
|
sources: { [key: string]: SourceSpecification | VectorSourceSpecification }
|
|
@@ -3,7 +3,7 @@ import { MetadataJSON, VectorLayer } from '../../types'
|
|
|
3
3
|
import {
|
|
4
4
|
LayerSpecification,
|
|
5
5
|
VectorSourceSpecification,
|
|
6
|
-
} from '@maplibre/maplibre-gl-style-spec
|
|
6
|
+
} from '@maplibre/maplibre-gl-style-spec'
|
|
7
7
|
import { BaseImporter, TileInfoJSONResponse } from './base-importer'
|
|
8
8
|
|
|
9
9
|
export class MetadataJSONImporter extends BaseImporter {
|
|
@@ -3,7 +3,7 @@ import { TileJSON } from '../../types'
|
|
|
3
3
|
import {
|
|
4
4
|
SourceSpecification,
|
|
5
5
|
LayerSpecification,
|
|
6
|
-
} from '@maplibre/maplibre-gl-style-spec
|
|
6
|
+
} from '@maplibre/maplibre-gl-style-spec'
|
|
7
7
|
import { BaseImporter, TileInfoJSONResponse } from './base-importer'
|
|
8
8
|
|
|
9
9
|
export class TileJSONImporter extends BaseImporter {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const maplibreStyleSpec = require('@maplibre/maplibre-gl-style-spec')
|
|
2
2
|
const mapboxStyleSpec = require('@mapbox/mapbox-gl-style-spec')
|
|
3
|
-
import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec
|
|
3
|
+
import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec'
|
|
4
4
|
|
|
5
5
|
export function validateStyle(
|
|
6
6
|
style: StyleSpecification,
|
package/src/lib/yaml-parser.ts
CHANGED
package/src/lib/yaml-writer.ts
CHANGED
|
@@ -4,7 +4,7 @@ import YAML from 'js-yaml'
|
|
|
4
4
|
import {
|
|
5
5
|
StyleSpecification,
|
|
6
6
|
LayerSpecification,
|
|
7
|
-
} from '@maplibre/maplibre-gl-style-spec
|
|
7
|
+
} from '@maplibre/maplibre-gl-style-spec'
|
|
8
8
|
|
|
9
9
|
export const writeYaml = (
|
|
10
10
|
destinationPath: string,
|
|
@@ -30,13 +30,26 @@ const writeCompositedYaml = (
|
|
|
30
30
|
stylePath = destinationPath
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
fs.writeFileSync(stylePath, styleYAML)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class IncFileTag {
|
|
37
|
+
value: string
|
|
38
|
+
constructor(fileName: string) {
|
|
39
|
+
// We use path.posix.join to make sure the path uses / path separators, even when run on Windows.
|
|
40
|
+
this.value = path.posix.join('layers', fileName)
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
|
|
44
|
+
const INC_PATH_TYPE = new YAML.Type('tag:yaml.org,2002:inc/file', {
|
|
45
|
+
kind: 'scalar',
|
|
46
|
+
resolve: (data) => data,
|
|
47
|
+
construct: (data) => new IncFileTag(data),
|
|
48
|
+
instanceOf: IncFileTag,
|
|
49
|
+
represent: (tag) => (tag as IncFileTag).value,
|
|
50
|
+
})
|
|
51
|
+
const INC_PATH_OUTPUT_SCHEMA = YAML.DEFAULT_SCHEMA.extend([INC_PATH_TYPE])
|
|
52
|
+
|
|
40
53
|
const writeDecompositedYaml = (
|
|
41
54
|
destinationPath: string,
|
|
42
55
|
style: StyleSpecification,
|
|
@@ -52,21 +65,17 @@ const writeDecompositedYaml = (
|
|
|
52
65
|
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
53
66
|
fs.writeFileSync(filePath, layerYml)
|
|
54
67
|
|
|
55
|
-
// ts-ignore is required here because !!inc/file
|
|
56
|
-
// We use path.posix.join to make sure the path uses / path separators, even when run on Windows.
|
|
68
|
+
// ts-ignore is required here because the !!inc/file object is not compatible with the Layer object type.
|
|
57
69
|
// @ts-ignore
|
|
58
|
-
layers.push(
|
|
70
|
+
layers.push(new IncFileTag(fileName))
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
style.layers = layers
|
|
62
74
|
|
|
63
75
|
fs.writeFileSync(
|
|
64
76
|
destinationPath,
|
|
65
|
-
YAML.dump(style
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return match.replace(/'/g, '')
|
|
69
|
-
},
|
|
70
|
-
),
|
|
77
|
+
YAML.dump(style, {
|
|
78
|
+
schema: INC_PATH_OUTPUT_SCHEMA,
|
|
79
|
+
}),
|
|
71
80
|
)
|
|
72
81
|
}
|
package/test/build.spec.ts
CHANGED
|
@@ -46,8 +46,8 @@ describe('Test for the `build.ts`.', () => {
|
|
|
46
46
|
|
|
47
47
|
const fixtureStyleJson = path.join(__dirname, 'data/style.json')
|
|
48
48
|
assert.equal(
|
|
49
|
-
fs.readFileSync(styleJson, 'utf-8'),
|
|
50
|
-
fs.readFileSync(fixtureStyleJson, 'utf-8'),
|
|
49
|
+
fs.readFileSync(styleJson, 'utf-8').replace(/\r\n/gm, '\n'),
|
|
50
|
+
fs.readFileSync(fixtureStyleJson, 'utf-8').replace(/\r\n/gm, '\n'),
|
|
51
51
|
)
|
|
52
52
|
})
|
|
53
53
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { expect } from 'chai'
|
|
2
|
+
import { AbortController } from 'node-abort-controller'
|
|
3
|
+
import axios from 'axios'
|
|
4
|
+
import { abortableExecFile } from './util/execPromise'
|
|
5
|
+
import { copyFixturesDir, copyFixturesFile } from './util/copyFixtures'
|
|
6
|
+
import { makeTempDir } from './util/makeTempDir'
|
|
7
|
+
import { charitesCliJs } from './util/charitesCmd'
|
|
8
|
+
import { sleep } from './util'
|
|
9
|
+
|
|
10
|
+
let tmpdir = ''
|
|
11
|
+
|
|
12
|
+
describe('Test for `charites serve`', () => {
|
|
13
|
+
beforeEach(async function () {
|
|
14
|
+
tmpdir = makeTempDir()
|
|
15
|
+
copyFixturesFile('style.yml', tmpdir)
|
|
16
|
+
copyFixturesDir('layers', tmpdir)
|
|
17
|
+
copyFixturesDir('icons', tmpdir)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('charites serve style.yml', async () => {
|
|
21
|
+
const abort = new AbortController()
|
|
22
|
+
const server = abortableExecFile(
|
|
23
|
+
process.execPath,
|
|
24
|
+
[charitesCliJs, 'serve', '--no-open', 'style.yml'],
|
|
25
|
+
abort.signal,
|
|
26
|
+
tmpdir,
|
|
27
|
+
)
|
|
28
|
+
try {
|
|
29
|
+
await sleep(500)
|
|
30
|
+
await Promise.all([
|
|
31
|
+
(async () => {
|
|
32
|
+
const res = await axios('http://127.0.0.1:8080/style.json', {})
|
|
33
|
+
expect(res.data.version).to.equal(8)
|
|
34
|
+
})(),
|
|
35
|
+
(async () => {
|
|
36
|
+
await axios('http://127.0.0.1:8080/sprite.json', {
|
|
37
|
+
validateStatus: (status) => status === 404,
|
|
38
|
+
})
|
|
39
|
+
})(),
|
|
40
|
+
])
|
|
41
|
+
} finally {
|
|
42
|
+
abort.abort()
|
|
43
|
+
}
|
|
44
|
+
abort.abort()
|
|
45
|
+
const { stdout, stderr } = await server
|
|
46
|
+
expect(stderr).to.equal('')
|
|
47
|
+
expect(stdout).to.match(/^Your map is running on http:\/\/localhost:8080/m)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('charites serve --sprite-input ./icons style.yml', async () => {
|
|
51
|
+
const abort = new AbortController()
|
|
52
|
+
const server = abortableExecFile(
|
|
53
|
+
process.execPath,
|
|
54
|
+
[
|
|
55
|
+
charitesCliJs,
|
|
56
|
+
'serve',
|
|
57
|
+
'--no-open',
|
|
58
|
+
'--sprite-input',
|
|
59
|
+
'./icons',
|
|
60
|
+
'style.yml',
|
|
61
|
+
],
|
|
62
|
+
abort.signal,
|
|
63
|
+
tmpdir,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await sleep(500)
|
|
68
|
+
await Promise.all([
|
|
69
|
+
(async () => {
|
|
70
|
+
const res = await axios('http://127.0.0.1:8080/style.json', {})
|
|
71
|
+
expect(res.status).to.equal(200)
|
|
72
|
+
expect(res.data.version).to.equal(8)
|
|
73
|
+
expect(res.data.sprite).to.equal('http://127.0.0.1:8080/sprite')
|
|
74
|
+
})(),
|
|
75
|
+
(async () => {
|
|
76
|
+
const res = await axios('http://127.0.0.1:8080/sprite.json', {})
|
|
77
|
+
expect(res.status).to.equal(200)
|
|
78
|
+
expect(Object.entries(res.data).length).to.be.greaterThan(0)
|
|
79
|
+
})(),
|
|
80
|
+
(async () => {
|
|
81
|
+
const res = await axios('http://127.0.0.1:8080/sprite@2x.json', {})
|
|
82
|
+
expect(res.status).to.equal(200)
|
|
83
|
+
expect(Object.entries(res.data).length).to.be.greaterThan(0)
|
|
84
|
+
})(),
|
|
85
|
+
(async () => {
|
|
86
|
+
const res = await axios('http://127.0.0.1:8080/sprite.png', {})
|
|
87
|
+
expect(res.status).to.equal(200)
|
|
88
|
+
expect(res.data.length).to.be.greaterThan(0)
|
|
89
|
+
})(),
|
|
90
|
+
(async () => {
|
|
91
|
+
const res = await axios('http://127.0.0.1:8080/sprite@2x.png', {})
|
|
92
|
+
expect(res.status).to.equal(200)
|
|
93
|
+
expect(res.data.length).to.be.greaterThan(0)
|
|
94
|
+
})(),
|
|
95
|
+
])
|
|
96
|
+
} finally {
|
|
97
|
+
abort.abort()
|
|
98
|
+
}
|
|
99
|
+
const { stdout, stderr } = await server
|
|
100
|
+
expect(stderr).to.equal('')
|
|
101
|
+
expect(stdout).to.match(/^Your map is running on http:\/\/localhost:8080/m)
|
|
102
|
+
})
|
|
103
|
+
})
|
package/test/convert.spec.ts
CHANGED
|
@@ -4,14 +4,24 @@ import fs from 'fs'
|
|
|
4
4
|
import os from 'os'
|
|
5
5
|
|
|
6
6
|
import { convert } from '../src/commands/convert'
|
|
7
|
+
import { build } from '../src/commands/build'
|
|
8
|
+
|
|
9
|
+
let tmp: string
|
|
7
10
|
|
|
8
11
|
describe('Test for the `convert.ts`.', () => {
|
|
9
|
-
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'charites-'))
|
|
10
12
|
const jsonPath = path.join(__dirname, 'data/convert.json')
|
|
11
|
-
const yamlPath = path.join(tmp, 'convert.yml')
|
|
12
|
-
const layerPath = path.join(tmp, 'layers/background.yml')
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'charites-'))
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
fs.rmSync(tmp, { recursive: true })
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('Should convert `data/convert.json` to YAML and the YAML should be valid.', async () => {
|
|
23
|
+
const yamlPath = path.join(tmp, 'convert.yml')
|
|
24
|
+
|
|
15
25
|
convert(jsonPath, yamlPath)
|
|
16
26
|
const yml = fs.readFileSync(yamlPath, 'utf-8')
|
|
17
27
|
|
|
@@ -27,13 +37,23 @@ sprite: https://sprites.geolonia.com/basic-white
|
|
|
27
37
|
glyphs: https://glyphs.geolonia.com/{fontstack}/{range}.pbf
|
|
28
38
|
layers:
|
|
29
39
|
- !!inc/file layers/background.yml
|
|
40
|
+
- !!inc/file >-
|
|
41
|
+
layers/background-with-very-long-name-background-with-very-long-name-background-with-very-long-name.yml
|
|
30
42
|
id: example
|
|
31
43
|
`,
|
|
32
44
|
yml,
|
|
33
45
|
)
|
|
46
|
+
|
|
47
|
+
const outJsonPath = path.join(tmp, 'converted-back.json')
|
|
48
|
+
// This will throw an error if the outputted YAML was invalid
|
|
49
|
+
await build(yamlPath, outJsonPath, { provider: 'default' })
|
|
50
|
+
assert.isTrue(fs.existsSync(outJsonPath))
|
|
34
51
|
})
|
|
35
52
|
|
|
36
53
|
it('Should create layers directory.', () => {
|
|
54
|
+
const yamlPath = path.join(tmp, 'convert.yml')
|
|
55
|
+
const layerPath = path.join(tmp, 'layers/background.yml')
|
|
56
|
+
|
|
37
57
|
convert(jsonPath, yamlPath)
|
|
38
58
|
|
|
39
59
|
const result = fs.existsSync(layerPath)
|
package/test/data/convert.json
CHANGED
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
"paint": {
|
|
18
18
|
"background-color": "rgba(19, 28, 54, 1)"
|
|
19
19
|
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "background-with-very-long-name-background-with-very-long-name-background-with-very-long-name",
|
|
23
|
+
"type": "background",
|
|
24
|
+
"paint": {
|
|
25
|
+
"background-color": "rgba(19, 28, 54, 1)"
|
|
26
|
+
}
|
|
20
27
|
}
|
|
21
28
|
],
|
|
22
29
|
"id": "example"
|
package/test/init.spec.ts
CHANGED
|
@@ -84,11 +84,13 @@ describe('Test for the `init.ts`.', () => {
|
|
|
84
84
|
assert.deepEqual(true, !!fs.statSync(styleYaml))
|
|
85
85
|
// the file should be the same with init_tilejson.yml
|
|
86
86
|
assert.deepEqual(
|
|
87
|
-
fs.readFileSync(styleYaml, 'utf8'),
|
|
88
|
-
fs
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
fs.readFileSync(styleYaml, 'utf8').replace(/\r\n/gm, '\n'),
|
|
88
|
+
fs
|
|
89
|
+
.readFileSync(
|
|
90
|
+
path.join(__dirname, 'data/init/tilejson/init_decomposite.yml'),
|
|
91
|
+
'utf-8',
|
|
92
|
+
)
|
|
93
|
+
.replace(/\r\n/gm, '\n'),
|
|
92
94
|
)
|
|
93
95
|
assert.deepEqual(
|
|
94
96
|
YAML.load(
|
package/test/util/charitesCmd.ts
CHANGED
package/test/util/execPromise.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import child_process from 'child_process'
|
|
2
2
|
import util from 'util'
|
|
3
|
+
|
|
4
|
+
// MEMO: Remove node-abort-controller when requiring NodeJS >=16
|
|
5
|
+
// NOTE: AbortController is available by default from NodeJS 15
|
|
6
|
+
import { AbortSignal } from 'node-abort-controller'
|
|
3
7
|
import { makeTempDir } from './makeTempDir'
|
|
4
8
|
const execSync = util.promisify(child_process.exec)
|
|
5
9
|
|
|
6
|
-
|
|
10
|
+
type ExecResult = {
|
|
11
|
+
stdout: string
|
|
12
|
+
stderr: string
|
|
13
|
+
cwd: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const exec: (cmd: string, cwd?: string) => Promise<ExecResult> = async (
|
|
17
|
+
cmd,
|
|
18
|
+
cwd,
|
|
19
|
+
) => {
|
|
7
20
|
const temp = cwd ? cwd : makeTempDir()
|
|
8
21
|
const { stdout, stderr } = await execSync(cmd, {
|
|
9
22
|
encoding: 'utf8',
|
|
@@ -12,3 +25,40 @@ export const exec = async (cmd: string, cwd?: string) => {
|
|
|
12
25
|
|
|
13
26
|
return { stdout, stderr, cwd: temp }
|
|
14
27
|
}
|
|
28
|
+
|
|
29
|
+
// MEMO: This can be replaced with the native AbortSignal support in child_process.exec after
|
|
30
|
+
// requiring NodeJS >= 16.4.0, see:
|
|
31
|
+
// https://nodejs.org/docs/latest-v16.x/api/child_process.html#child_processexeccommand-options-callback
|
|
32
|
+
export const abortableExecFile = (
|
|
33
|
+
file: string,
|
|
34
|
+
args: string[],
|
|
35
|
+
signal: AbortSignal,
|
|
36
|
+
cwd?: string,
|
|
37
|
+
) =>
|
|
38
|
+
new Promise<ExecResult>((resolve, reject) => {
|
|
39
|
+
const temp = cwd ? cwd : makeTempDir()
|
|
40
|
+
|
|
41
|
+
// Because Windows can't catch the SIGINT signal (it doesn't have signals)
|
|
42
|
+
// we set a flag in the parent whether the command can die or not.
|
|
43
|
+
// If the command exits before we request it to exit, the error will be
|
|
44
|
+
// thrown, but if it exits after we request it to exit, it won't be an error.
|
|
45
|
+
let noErrorOnDie = false
|
|
46
|
+
const process = child_process.execFile(
|
|
47
|
+
file,
|
|
48
|
+
args,
|
|
49
|
+
{
|
|
50
|
+
encoding: 'utf8',
|
|
51
|
+
cwd: temp,
|
|
52
|
+
},
|
|
53
|
+
(error, stdout, stderr) => {
|
|
54
|
+
if (error && noErrorOnDie !== true) {
|
|
55
|
+
return reject(error)
|
|
56
|
+
}
|
|
57
|
+
resolve({ stdout, stderr, cwd: temp })
|
|
58
|
+
},
|
|
59
|
+
)
|
|
60
|
+
signal.addEventListener('abort', () => {
|
|
61
|
+
noErrorOnDie = true
|
|
62
|
+
process.kill('SIGINT')
|
|
63
|
+
})
|
|
64
|
+
})
|