@unvt/charites 0.1.1 → 0.1.4

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.
Files changed (106) hide show
  1. package/.all-contributorsrc +24 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.js +17 -0
  4. package/.github/CONTRIBUTING.md +30 -0
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  7. package/.github/PULL_REQUEST_TEMPLATE.md +25 -0
  8. package/.github/workflows/build-docs.yml +72 -0
  9. package/.github/workflows/build.yml +1 -0
  10. package/.prettierrc.js +6 -0
  11. package/LICENSE +1 -1
  12. package/README.md +23 -106
  13. package/dist/cli/build.js +63 -0
  14. package/dist/cli/convert.js +19 -0
  15. package/dist/cli/init.js +26 -0
  16. package/dist/cli/serve.js +34 -0
  17. package/dist/cli.js +10 -66
  18. package/dist/commands/build.js +39 -3
  19. package/dist/commands/convert.js +6 -23
  20. package/dist/commands/init.js +15 -22
  21. package/dist/commands/serve.js +8 -3
  22. package/dist/lib/build-sprite.js +71 -0
  23. package/dist/lib/defaultValues.js +3 -3
  24. package/dist/lib/error.js +9 -0
  25. package/dist/lib/get-sprite-slug.js +16 -0
  26. package/dist/lib/tileinfo-importer/base-importer.js +41 -0
  27. package/dist/lib/tileinfo-importer/index.js +6 -0
  28. package/dist/lib/tileinfo-importer/metadata-importer.js +38 -0
  29. package/dist/lib/tileinfo-importer/tilejson-importer.js +25 -0
  30. package/dist/lib/validate-style.js +2 -2
  31. package/dist/lib/yaml-parser.js +2 -2
  32. package/dist/lib/yaml-writer.js +48 -0
  33. package/dist/types/index.js +15 -0
  34. package/dist/types/metadatajson.js +2 -0
  35. package/dist/types/tilejson.js +2 -0
  36. package/dist/types/vector_layers.js +2 -0
  37. package/docs/.tx/config +62 -0
  38. package/docs/Makefile +170 -0
  39. package/docs/Pipfile +20 -0
  40. package/docs/Pipfile.lock +429 -0
  41. package/docs/README.md +43 -0
  42. package/docs/make.bat +35 -0
  43. package/docs/source/_static/.gitkeep +0 -0
  44. package/docs/source/_templates/.gitkeep +0 -0
  45. package/docs/source/conf.py +69 -0
  46. package/docs/source/development/index.rst +40 -0
  47. package/docs/source/index.rst +61 -0
  48. package/docs/source/install/index.rst +10 -0
  49. package/docs/source/install/install.rst +7 -0
  50. package/docs/source/install/install_on_nanban.rst +9 -0
  51. package/docs/source/install/recommended_environment.rst +6 -0
  52. package/docs/source/usage/commandline_interface.rst +102 -0
  53. package/docs/source/usage/examples.rst +74 -0
  54. package/docs/source/usage/global_options.rst +21 -0
  55. package/docs/source/usage/index.rst +10 -0
  56. package/package.json +12 -4
  57. package/provider/default/app.css +10 -0
  58. package/provider/default/app.js +31 -5
  59. package/provider/default/index.html +7 -0
  60. package/provider/geolonia/app.css +10 -0
  61. package/provider/geolonia/app.js +29 -5
  62. package/provider/geolonia/index.html +7 -0
  63. package/provider/mapbox/app.css +10 -0
  64. package/provider/mapbox/app.js +31 -5
  65. package/provider/mapbox/index.html +7 -0
  66. package/src/cli/build.ts +77 -0
  67. package/src/cli/convert.ts +18 -0
  68. package/src/cli/init.ts +34 -0
  69. package/src/cli/serve.ts +39 -0
  70. package/src/cli.ts +12 -76
  71. package/src/commands/build.ts +71 -9
  72. package/src/commands/convert.ts +16 -35
  73. package/src/commands/init.ts +28 -21
  74. package/src/commands/serve.ts +70 -57
  75. package/src/lib/build-sprite.ts +80 -0
  76. package/src/lib/defaultValues.ts +6 -6
  77. package/src/lib/error.ts +6 -0
  78. package/src/lib/get-sprite-slug.ts +18 -0
  79. package/src/lib/tileinfo-importer/base-importer.ts +57 -0
  80. package/src/lib/tileinfo-importer/index.ts +2 -0
  81. package/src/lib/tileinfo-importer/metadata-importer.ts +44 -0
  82. package/src/lib/tileinfo-importer/tilejson-importer.ts +29 -0
  83. package/src/lib/validate-style.ts +8 -2
  84. package/src/lib/yaml-parser.ts +9 -8
  85. package/src/lib/yaml-writer.ts +68 -0
  86. package/src/types/index.ts +3 -0
  87. package/src/types/metadatajson.ts +16 -0
  88. package/src/types/tilejson.ts +25 -0
  89. package/src/types/vector_layers.ts +11 -0
  90. package/test/build-sprite.spec.ts +24 -0
  91. package/test/build.spec.ts +121 -16
  92. package/test/convert.spec.ts +7 -7
  93. package/test/data/icons/aerialway.svg +4 -0
  94. package/test/data/init/init.yml +6 -0
  95. package/test/data/init/init_metadata.yml +60 -0
  96. package/test/data/init/init_tilejson.yml +28 -0
  97. package/test/data/init/init_tilejson_without_layers.yml +9 -0
  98. package/test/data/init/tilejson/init_decomposite.yml +13 -0
  99. package/test/data/init/tilejson/layers/bicycle_parking.yml +6 -0
  100. package/test/data/init/tilejson/layers/showers.yml +6 -0
  101. package/test/data/init/tilejson/layers/telephone.yml +6 -0
  102. package/test/get-sprite-slug.spec.ts +34 -0
  103. package/test/init.spec.ts +151 -0
  104. package/test/validate-style.spec.ts +7 -5
  105. package/test/yaml-parser.spec.ts +15 -15
  106. package/tsconfig.json +3 -1
@@ -9,13 +9,17 @@ import { parser } from '../lib/yaml-parser'
9
9
  import { validateStyle } from '../lib/validate-style'
10
10
  import { defaultValues } from '../lib/defaultValues'
11
11
 
12
- interface options {
12
+ export interface serveOptions {
13
13
  provider?: string
14
14
  mapboxAccessToken?: string
15
+ port?: string
15
16
  }
16
17
 
17
- export function serve(source: string, options: options) {
18
- const port = process.env.PORT || 8080
18
+ export function serve(source: string, options: serveOptions) {
19
+ let port = process.env.PORT || 8080
20
+ if (options.port) {
21
+ port = Number(options.port)
22
+ }
19
23
  let sourcePath = path.resolve(process.cwd(), source)
20
24
 
21
25
  let provider = defaultValues.provider
@@ -28,51 +32,56 @@ export function serve(source: string, options: options) {
28
32
  sourcePath = source
29
33
  }
30
34
 
31
- if (! fs.existsSync(sourcePath)) {
35
+ if (!fs.existsSync(sourcePath)) {
32
36
  throw `${sourcePath}: No such file or directory`
33
37
  }
34
38
 
35
39
  const server = http.createServer((req, res) => {
36
- const url = (req.url || '').replace(/\?.*/, '')
37
- const dir = path.join(defaultValues.providerDir, provider)
40
+ const url = (req.url || '').replace(/\?.*/, '')
41
+ const dir = path.join(defaultValues.providerDir, provider)
38
42
 
39
- switch (url) {
40
- case '/':
41
- res.statusCode = 200
42
- res.setHeader('Content-Type', 'text/html; charset=UTF-8')
43
- const content = fs.readFileSync(path.join(dir, 'index.html'), 'utf-8')
44
- res.end(content)
45
- break;
46
- case '/style.json':
47
- const style = parser(sourcePath)
48
- try {
49
- validateStyle(style, provider)
50
- } catch(error) {
51
- console.log(error)
52
- }
53
- res.statusCode = 200
54
- res.setHeader('Content-Type', 'application/json; charset=UTF-8')
55
- res.end(JSON.stringify(style))
56
- break;
57
- case '/app.css':
58
- res.statusCode = 200
59
- res.setHeader('Content-Type', 'text/css; charset=UTF-8')
60
- const css = fs.readFileSync(path.join(dir, 'app.css'), 'utf-8')
61
- res.end(css)
62
- break;
63
- case `/app.js`:
64
- res.statusCode = 200
65
- res.setHeader('Content-Type', 'application/javascript; charset=UTF-8')
66
- try {
67
- const app = fs.readFileSync(path.join(dir, 'app.js'), 'utf-8')
68
- const js = app.replace('___PORT___', `${port}`)
69
- .replace('___MAPBOX_ACCESS_TOKEN___', `${options.mapboxAccessToken || defaultValues.mapboxAccessToken}`)
70
- res.end(js)
71
- } catch(e) {
72
- throw `Invalid provider: ${provider}`
73
- }
74
- break;
75
- }
43
+ switch (url) {
44
+ case '/':
45
+ res.statusCode = 200
46
+ res.setHeader('Content-Type', 'text/html; charset=UTF-8')
47
+ const content = fs.readFileSync(path.join(dir, 'index.html'), 'utf-8')
48
+ res.end(content)
49
+ break
50
+ case '/style.json':
51
+ let style
52
+ try {
53
+ style = parser(sourcePath)
54
+ validateStyle(style, provider)
55
+ } catch (error) {
56
+ console.log(error)
57
+ }
58
+ res.statusCode = 200
59
+ res.setHeader('Content-Type', 'application/json; charset=UTF-8')
60
+ res.end(JSON.stringify(style))
61
+ break
62
+ case '/app.css':
63
+ res.statusCode = 200
64
+ res.setHeader('Content-Type', 'text/css; charset=UTF-8')
65
+ const css = fs.readFileSync(path.join(dir, 'app.css'), 'utf-8')
66
+ res.end(css)
67
+ break
68
+ case `/app.js`:
69
+ res.statusCode = 200
70
+ res.setHeader('Content-Type', 'application/javascript; charset=UTF-8')
71
+ try {
72
+ const app = fs.readFileSync(path.join(dir, 'app.js'), 'utf-8')
73
+ const js = app
74
+ .replace('___PORT___', `${port}`)
75
+ .replace(
76
+ '___MAPBOX_ACCESS_TOKEN___',
77
+ `${options.mapboxAccessToken || defaultValues.mapboxAccessToken}`,
78
+ )
79
+ res.end(js)
80
+ } catch (e) {
81
+ throw `Invalid provider: ${provider}`
82
+ }
83
+ break
84
+ }
76
85
  })
77
86
 
78
87
  server.listen(port, () => {
@@ -82,24 +91,28 @@ export function serve(source: string, options: options) {
82
91
  open(`http://localhost:${port}`)
83
92
  })
84
93
 
85
- const wss = new WebSocketServer({ server });
94
+ const wss = new WebSocketServer({ server })
86
95
 
87
96
  wss.on('connection', (ws) => {
88
- watch(path.dirname(sourcePath), { recursive: true, filter: /\.yml$/ }, (event, file) => {
89
- console.log(`${(event || '').toUpperCase()}: ${file}`)
90
- try {
91
- const style = parser(sourcePath)
97
+ watch(
98
+ path.dirname(sourcePath),
99
+ { recursive: true, filter: /\.yml$/ },
100
+ (event, file) => {
101
+ console.log(`${(event || '').toUpperCase()}: ${file}`)
92
102
  try {
93
- validateStyle(style, provider)
94
- } catch(error) {
95
- console.log(error)
103
+ const style = parser(sourcePath)
104
+ try {
105
+ validateStyle(style, provider)
106
+ } catch (error) {
107
+ console.log(error)
108
+ }
109
+ ws.send(JSON.stringify(style))
110
+ } catch (e) {
111
+ // Nothing to do
96
112
  }
97
- ws.send(JSON.stringify(style))
98
- } catch(e) {
99
- // Nothing to do
100
- }
101
- })
102
- });
113
+ },
114
+ )
115
+ })
103
116
 
104
117
  return server
105
118
  }
@@ -0,0 +1,80 @@
1
+ const spritezero = require('@mapbox/spritezero')
2
+ const fs = require('fs')
3
+ const glob = require('glob')
4
+ const path = require('path')
5
+
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
+ export async function buildSprite(
31
+ svgPath: string,
32
+ publicPath: string,
33
+ iconSlug: string,
34
+ ) {
35
+ const pxRatios = [1, 2]
36
+
37
+ for (let i = 0; i < pxRatios.length; i++) {
38
+ const pxRatio = pxRatios[i]
39
+
40
+ const svgFiles = glob
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
+ }
79
+ }
80
+ }
@@ -10,27 +10,27 @@ interface Config {
10
10
  }
11
11
 
12
12
  const homedir = os.homedir()
13
- const defaultProvider = "default"
13
+ const defaultProvider = 'default'
14
14
 
15
15
  const configDir = path.join(homedir, '.charites')
16
- fs.mkdirSync(configDir, { recursive: true });
16
+ fs.mkdirSync(configDir, { recursive: true })
17
17
 
18
18
  const configFile = path.join(configDir, 'config.yml')
19
- let config: Config = {provider: '', providerDir: '', mapboxAccessToken: ''}
19
+ let config: Config = { provider: '', providerDir: '', mapboxAccessToken: '' }
20
20
 
21
21
  try {
22
22
  const yaml = fs.readFileSync(configFile, 'utf-8')
23
23
  config = YAML.load(yaml) as Config
24
- } catch(e) {
24
+ } catch (e) {
25
25
  // nothing to do
26
26
  }
27
27
 
28
28
  export const defaultValues: Config = {
29
29
  provider: config.provider || defaultProvider,
30
30
  providerDir: path.join(path.dirname(path.dirname(__dirname)), 'provider'),
31
- mapboxAccessToken: config.mapboxAccessToken || ''
31
+ mapboxAccessToken: config.mapboxAccessToken || '',
32
32
  }
33
33
 
34
34
  export const defaultSettings = {
35
- configFile: configFile
35
+ configFile: configFile,
36
36
  }
@@ -0,0 +1,6 @@
1
+ export const error = (e: unknown) => {
2
+ if (e instanceof TypeError) {
3
+ console.error(e.message)
4
+ }
5
+ process.exit(1)
6
+ }
@@ -0,0 +1,18 @@
1
+ import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec/types'
2
+
3
+ export function getSpriteSlug(style: StyleSpecification): string | false {
4
+ if (!style.hasOwnProperty('sprite')) {
5
+ return false
6
+ }
7
+
8
+ const matchedUrl = style.sprite?.match(
9
+ /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]*)?(?:([^?#]*\/)([^\/?#]*))?(\?[^#]*)?(?:#.*)?$/,
10
+ )
11
+
12
+ if (!matchedUrl || !matchedUrl[2]) {
13
+ return false
14
+ }
15
+
16
+ // icon slug
17
+ return matchedUrl[2]
18
+ }
@@ -0,0 +1,57 @@
1
+ import { VectorLayer } from '../../types'
2
+ import {
3
+ StyleSpecification,
4
+ SourceSpecification,
5
+ LayerSpecification,
6
+ VectorSourceSpecification,
7
+ } from '@maplibre/maplibre-gl-style-spec/types'
8
+
9
+ export type TileInfoJSONResponse = {
10
+ sources: { [key: string]: SourceSpecification | VectorSourceSpecification }
11
+ layers: LayerSpecification[]
12
+ }
13
+
14
+ export abstract class BaseImporter {
15
+ protected urls: string[]
16
+
17
+ constructor(original_urls: string) {
18
+ const temp_urls = original_urls + ''
19
+ this.urls = temp_urls.split(',')
20
+ }
21
+
22
+ abstract getJSON(url: string): Promise<TileInfoJSONResponse>
23
+
24
+ async import(style: StyleSpecification) {
25
+ if (this.urls.length === 0) return
26
+ const responses = await Promise.all(
27
+ this.urls.map((url) => this.getJSON(url)),
28
+ )
29
+ responses.forEach((res) => {
30
+ Object.keys(res.sources).forEach((sourceName) => {
31
+ style.sources[sourceName] = res.sources[sourceName]
32
+ })
33
+ if (res.layers.length > 0) {
34
+ style.layers = style.layers.concat(res.layers)
35
+ }
36
+ })
37
+ return style
38
+ }
39
+
40
+ protected getVectorLayers(name: string, vector_layers: VectorLayer[]) {
41
+ const layers: LayerSpecification[] = []
42
+ if (vector_layers) {
43
+ vector_layers.forEach((layer) => {
44
+ const layerStyle: LayerSpecification = {
45
+ id: layer.id,
46
+ type: 'fill',
47
+ source: name,
48
+ 'source-layer': layer.id,
49
+ layout: {},
50
+ paint: {},
51
+ }
52
+ layers.push(layerStyle)
53
+ })
54
+ }
55
+ return layers
56
+ }
57
+ }
@@ -0,0 +1,2 @@
1
+ export { MetadataJSONImporter } from './metadata-importer'
2
+ export { TileJSONImporter } from './tilejson-importer'
@@ -0,0 +1,44 @@
1
+ import axios from 'axios'
2
+ import { MetadataJSON, VectorLayer } from '../../types'
3
+ import {
4
+ LayerSpecification,
5
+ VectorSourceSpecification,
6
+ } from '@maplibre/maplibre-gl-style-spec/types'
7
+ import { BaseImporter, TileInfoJSONResponse } from './base-importer'
8
+
9
+ export class MetadataJSONImporter extends BaseImporter {
10
+ async getJSON(url: string): Promise<TileInfoJSONResponse> {
11
+ const res = await axios.get(url)
12
+ const matadataJSON: MetadataJSON = res.data
13
+ const metadataName: string = matadataJSON.name
14
+ ? matadataJSON.name
15
+ : Math.random().toString(32).substring(2)
16
+
17
+ const sources: { [key: string]: VectorSourceSpecification } = {}
18
+ const urlSplited = url.split('/')
19
+ sources[metadataName] = {
20
+ type: 'vector',
21
+ tiles: [
22
+ url.replace(
23
+ new RegExp(urlSplited[urlSplited.length - 1], 'g'),
24
+ '{z}/{x}/{y}.pbf',
25
+ ),
26
+ ],
27
+ }
28
+ if (matadataJSON.minzoom) {
29
+ sources[metadataName].minzoom = matadataJSON.minzoom
30
+ }
31
+ if (matadataJSON.maxzoom) {
32
+ sources[metadataName].maxzoom = matadataJSON.maxzoom
33
+ }
34
+
35
+ let layers: LayerSpecification[] = []
36
+ if (matadataJSON.json) {
37
+ const vector_layers: VectorLayer[] = JSON.parse(
38
+ matadataJSON.json,
39
+ ).vector_layers
40
+ layers = this.getVectorLayers(metadataName, vector_layers)
41
+ }
42
+ return { sources, layers }
43
+ }
44
+ }
@@ -0,0 +1,29 @@
1
+ import axios from 'axios'
2
+ import { TileJSON } from '../../types'
3
+ import {
4
+ SourceSpecification,
5
+ LayerSpecification,
6
+ } from '@maplibre/maplibre-gl-style-spec/types'
7
+ import { BaseImporter, TileInfoJSONResponse } from './base-importer'
8
+
9
+ export class TileJSONImporter extends BaseImporter {
10
+ async getJSON(url: string): Promise<TileInfoJSONResponse> {
11
+ const res = await axios.get(url)
12
+ const tilejson: TileJSON = res.data
13
+ const tilesetName: string = tilejson.name
14
+ ? tilejson.name
15
+ : Math.random().toString(32).substring(2)
16
+
17
+ const sources: { [key: string]: SourceSpecification } = {}
18
+ sources[tilesetName] = {
19
+ type: 'vector',
20
+ url: url,
21
+ }
22
+
23
+ const layers: LayerSpecification[] = this.getVectorLayers(
24
+ tilesetName,
25
+ tilejson.vector_layers,
26
+ )
27
+ return { sources, layers }
28
+ }
29
+ }
@@ -1,7 +1,11 @@
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/types'
3
4
 
4
- export function validateStyle(style: object, provider: string = "default"): void {
5
+ export function validateStyle(
6
+ style: StyleSpecification,
7
+ provider = 'default',
8
+ ): void {
5
9
  let result = []
6
10
  if ('mapbox' === provider) {
7
11
  result = mapboxStyleSpec.validate(style)
@@ -17,6 +21,8 @@ export function validateStyle(style: object, provider: string = "default"): void
17
21
  }
18
22
 
19
23
  if (errors.length) {
20
- throw `\u001b[31mError:\u001b[0m ${errors.join("\n\u001b[31mError:\u001b[0m ")}`
24
+ throw `\u001b[31mError:\u001b[0m ${errors.join(
25
+ '\n\u001b[31mError:\u001b[0m ',
26
+ )}`
21
27
  }
22
28
  }
@@ -1,26 +1,27 @@
1
1
  import fs from 'fs'
2
2
  import YAML from 'js-yaml'
3
+ import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec/types'
3
4
 
4
5
  const yamlinc = require('yaml-include')
5
6
 
6
7
  interface StyleObject {
7
- [key: string]: any;
8
+ [key: string]: string
8
9
  }
9
10
 
10
- export function parser(file: string): object {
11
+ export function parser(file: string): StyleSpecification {
11
12
  yamlinc.setBaseFile(file)
12
13
  const yaml = fs.readFileSync(file, 'utf8')
13
14
 
14
15
  const obj: StyleObject = YAML.load(yaml, {
15
16
  schema: yamlinc.YAML_INCLUDE_SCHEMA,
16
17
  filename: file,
17
- json: true
18
+ json: true,
18
19
  }) as StyleObject
19
20
 
20
21
  const styleObj: StyleObject = {}
21
- let variables: StyleObject = {}
22
+ const variables: StyleObject = {}
22
23
 
23
- for (const key in obj as any) {
24
+ for (const key in obj) {
24
25
  if (key.match(/^\$/)) {
25
26
  variables[key] = obj[key]
26
27
  } else {
@@ -29,8 +30,8 @@ export function parser(file: string): object {
29
30
  }
30
31
 
31
32
  // Handle all nested variables.
32
- while(JSON.stringify(Object.values(variables)).match(/\$/)) {
33
- for (const key in variables as any) {
33
+ while (JSON.stringify(Object.values(variables)).match(/\$/)) {
34
+ for (const key in variables) {
34
35
  for (const variable in variables) {
35
36
  let _value = JSON.stringify(variables[key])
36
37
  const regex = new RegExp(`\"\\${variable}\"`, 'g')
@@ -40,7 +41,7 @@ export function parser(file: string): object {
40
41
  }
41
42
  }
42
43
 
43
- let style = JSON.stringify(styleObj)
44
+ let style: string = JSON.stringify(styleObj)
44
45
 
45
46
  for (const key in variables) {
46
47
  const regex = new RegExp(`\"\\${key}\"`, 'g')
@@ -0,0 +1,68 @@
1
+ import path from 'path'
2
+ import fs from 'fs'
3
+ import YAML from 'js-yaml'
4
+ import {
5
+ StyleSpecification,
6
+ LayerSpecification,
7
+ } from '@maplibre/maplibre-gl-style-spec/types'
8
+
9
+ export const writeYaml = (
10
+ destinationPath: string,
11
+ style: StyleSpecification,
12
+ composite = false,
13
+ ) => {
14
+ if (composite === true) {
15
+ writeCompositedYaml(destinationPath, style)
16
+ } else {
17
+ writeDecompositedYaml(destinationPath, style)
18
+ }
19
+ }
20
+
21
+ const writeCompositedYaml = (
22
+ destinationPath: string,
23
+ style: StyleSpecification,
24
+ ) => {
25
+ const styleYAML = YAML.dump(style)
26
+ let stylePath = path.resolve(process.cwd(), destinationPath)
27
+
28
+ // The `source` is absolute path.
29
+ if (destinationPath.match(/^\//)) {
30
+ stylePath = destinationPath
31
+ }
32
+
33
+ try {
34
+ fs.writeFileSync(stylePath, styleYAML)
35
+ } catch (err) {
36
+ throw `${stylePath}: Permission denied`
37
+ }
38
+ }
39
+
40
+ const writeDecompositedYaml = (
41
+ destinationPath: string,
42
+ style: StyleSpecification,
43
+ ) => {
44
+ const layers: LayerSpecification[] = []
45
+
46
+ for (let i = 0; i < style.layers.length; i++) {
47
+ const layer = style.layers[i]
48
+ const layerYml = YAML.dump(layer)
49
+ const fileName = `${style.layers[i].id}.yml`
50
+ const dirName = path.join(path.dirname(destinationPath), 'layers')
51
+ fs.mkdirSync(dirName, { recursive: true })
52
+ fs.writeFileSync(path.join(dirName, fileName), layerYml)
53
+ // @ts-ignore
54
+ layers.push(`!!inc/file ${path.join('layers', fileName)}`)
55
+ }
56
+
57
+ style.layers = layers
58
+
59
+ fs.writeFileSync(
60
+ destinationPath,
61
+ YAML.dump(style).replace(
62
+ /'\!\!inc\/file layers\/.+\.yml'/g,
63
+ function (match) {
64
+ return match.replace(/'/g, '')
65
+ },
66
+ ),
67
+ )
68
+ }
@@ -0,0 +1,3 @@
1
+ export * from './tilejson'
2
+ export * from './metadatajson'
3
+ export * from './vector_layers'
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Definition of metadata.json
3
+ */
4
+ export type MetadataJSON = {
5
+ name?: string
6
+ description?: string
7
+ version?: string
8
+ minzoom?: number
9
+ maxzoom?: number
10
+ center?: number[]
11
+ bounds?: number[]
12
+ type?: string
13
+ format: string
14
+ generator?: string
15
+ json?: string
16
+ }
@@ -0,0 +1,25 @@
1
+ import { VectorLayer } from './vector_layers'
2
+
3
+ /**
4
+ * Definition of TileJSON v3.0.0
5
+ * see https://github.com/mapbox/tilejson-spec/blob/master/3.0.0/schema.json
6
+ */
7
+ export type TileJSON = {
8
+ tilejson: string
9
+ tiles: string[]
10
+ vector_layers: VectorLayer[]
11
+ attribution?: string
12
+ bounds?: number[]
13
+ center?: number[]
14
+ data?: string[]
15
+ description?: string
16
+ fillzoom?: number
17
+ grids?: string[]
18
+ legend?: string
19
+ maxzoom?: number
20
+ minzoom?: number
21
+ name?: string
22
+ scheme?: string
23
+ template?: string
24
+ version?: string
25
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Definition of vector_layers object
3
+ * see https://github.com/mapbox/tilejson-spec/blob/master/3.0.0/schema.json
4
+ */
5
+ export type VectorLayer = {
6
+ id: string
7
+ fields: { [key: string]: string }
8
+ description: string
9
+ maxzoom: string
10
+ minzoom: string
11
+ }
@@ -0,0 +1,24 @@
1
+ import { assert } from 'chai'
2
+ import path from 'path'
3
+ import fs from 'fs'
4
+ import os from 'os'
5
+
6
+ import { buildSprite } from '../src/lib/build-sprite'
7
+ const iconsPath = path.join(__dirname, 'data/icons')
8
+ let tmpdir = ''
9
+
10
+ describe('Test for the `build-sprite.ts`.', () => {
11
+ beforeEach(function () {
12
+ tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'charites-'))
13
+ })
14
+
15
+ it("should create icon's json/png at specified path and name ", async () => {
16
+ const expectedJsonPath = path.join(tmpdir, 'basic.json')
17
+ const expectedPngPath = path.join(tmpdir, 'basic.png')
18
+
19
+ await buildSprite(iconsPath, tmpdir, `basic`)
20
+
21
+ assert.deepEqual(true, !!fs.statSync(expectedJsonPath))
22
+ assert.deepEqual(true, !!fs.statSync(expectedPngPath))
23
+ })
24
+ })