@unvt/charites 0.1.2 → 0.1.3

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 +24 -114
  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 +32 -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 +2 -1
  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 +99 -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 +37 -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 +65 -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,12 +9,12 @@ 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
15
  }
16
16
 
17
- export function serve(source: string, options: options) {
17
+ export function serve(source: string, options: serveOptions) {
18
18
  const port = process.env.PORT || 8080
19
19
  let sourcePath = path.resolve(process.cwd(), source)
20
20
 
@@ -28,52 +28,56 @@ export function serve(source: string, options: options) {
28
28
  sourcePath = source
29
29
  }
30
30
 
31
- if (! fs.existsSync(sourcePath)) {
31
+ if (!fs.existsSync(sourcePath)) {
32
32
  throw `${sourcePath}: No such file or directory`
33
33
  }
34
34
 
35
35
  const server = http.createServer((req, res) => {
36
- const url = (req.url || '').replace(/\?.*/, '')
37
- const dir = path.join(defaultValues.providerDir, provider)
36
+ const url = (req.url || '').replace(/\?.*/, '')
37
+ const dir = path.join(defaultValues.providerDir, provider)
38
38
 
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
- let style
48
- try {
49
- style = parser(sourcePath)
50
- validateStyle(style, provider)
51
- } catch(error) {
52
- console.log(error)
53
- }
54
- res.statusCode = 200
55
- res.setHeader('Content-Type', 'application/json; charset=UTF-8')
56
- res.end(JSON.stringify(style))
57
- break;
58
- case '/app.css':
59
- res.statusCode = 200
60
- res.setHeader('Content-Type', 'text/css; charset=UTF-8')
61
- const css = fs.readFileSync(path.join(dir, 'app.css'), 'utf-8')
62
- res.end(css)
63
- break;
64
- case `/app.js`:
65
- res.statusCode = 200
66
- res.setHeader('Content-Type', 'application/javascript; charset=UTF-8')
67
- try {
68
- const app = fs.readFileSync(path.join(dir, 'app.js'), 'utf-8')
69
- const js = app.replace('___PORT___', `${port}`)
70
- .replace('___MAPBOX_ACCESS_TOKEN___', `${options.mapboxAccessToken || defaultValues.mapboxAccessToken}`)
71
- res.end(js)
72
- } catch(e) {
73
- throw `Invalid provider: ${provider}`
74
- }
75
- break;
76
- }
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
+ let style
48
+ try {
49
+ style = parser(sourcePath)
50
+ validateStyle(style, provider)
51
+ } catch (error) {
52
+ console.log(error)
53
+ }
54
+ res.statusCode = 200
55
+ res.setHeader('Content-Type', 'application/json; charset=UTF-8')
56
+ res.end(JSON.stringify(style))
57
+ break
58
+ case '/app.css':
59
+ res.statusCode = 200
60
+ res.setHeader('Content-Type', 'text/css; charset=UTF-8')
61
+ const css = fs.readFileSync(path.join(dir, 'app.css'), 'utf-8')
62
+ res.end(css)
63
+ break
64
+ case `/app.js`:
65
+ res.statusCode = 200
66
+ res.setHeader('Content-Type', 'application/javascript; charset=UTF-8')
67
+ try {
68
+ const app = fs.readFileSync(path.join(dir, 'app.js'), 'utf-8')
69
+ const js = app
70
+ .replace('___PORT___', `${port}`)
71
+ .replace(
72
+ '___MAPBOX_ACCESS_TOKEN___',
73
+ `${options.mapboxAccessToken || defaultValues.mapboxAccessToken}`,
74
+ )
75
+ res.end(js)
76
+ } catch (e) {
77
+ throw `Invalid provider: ${provider}`
78
+ }
79
+ break
80
+ }
77
81
  })
78
82
 
79
83
  server.listen(port, () => {
@@ -83,24 +87,28 @@ export function serve(source: string, options: options) {
83
87
  open(`http://localhost:${port}`)
84
88
  })
85
89
 
86
- const wss = new WebSocketServer({ server });
90
+ const wss = new WebSocketServer({ server })
87
91
 
88
92
  wss.on('connection', (ws) => {
89
- watch(path.dirname(sourcePath), { recursive: true, filter: /\.yml$/ }, (event, file) => {
90
- console.log(`${(event || '').toUpperCase()}: ${file}`)
91
- try {
92
- const style = parser(sourcePath)
93
+ watch(
94
+ path.dirname(sourcePath),
95
+ { recursive: true, filter: /\.yml$/ },
96
+ (event, file) => {
97
+ console.log(`${(event || '').toUpperCase()}: ${file}`)
93
98
  try {
94
- validateStyle(style, provider)
95
- } catch(error) {
96
- console.log(error)
99
+ const style = parser(sourcePath)
100
+ try {
101
+ validateStyle(style, provider)
102
+ } catch (error) {
103
+ console.log(error)
104
+ }
105
+ ws.send(JSON.stringify(style))
106
+ } catch (e) {
107
+ // Nothing to do
97
108
  }
98
- ws.send(JSON.stringify(style))
99
- } catch(e) {
100
- // Nothing to do
101
- }
102
- })
103
- });
109
+ },
110
+ )
111
+ })
104
112
 
105
113
  return server
106
114
  }
@@ -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
+ })