@versatiles/style 5.2.6 → 5.2.7

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 (130) hide show
  1. package/dist/index.d.ts +274 -14
  2. package/dist/index.js +3650 -11
  3. package/dist/index.js.map +1 -1
  4. package/package.json +8 -8
  5. package/src/color/abstract.ts +83 -0
  6. package/src/color/hsl.test.ts +182 -0
  7. package/src/color/hsl.ts +122 -0
  8. package/src/color/hsv.test.ts +174 -0
  9. package/src/color/hsv.ts +100 -0
  10. package/src/color/index.test.ts +119 -0
  11. package/src/color/index.ts +38 -0
  12. package/src/color/random.test.ts +35 -0
  13. package/src/color/random.ts +165 -0
  14. package/src/color/rgb.test.ts +227 -0
  15. package/src/color/rgb.ts +248 -0
  16. package/src/color/utils.test.ts +86 -0
  17. package/src/color/utils.ts +13 -0
  18. package/src/guess_style/guess_style.test.ts +134 -0
  19. package/src/guess_style/guess_style.ts +166 -0
  20. package/{dist/guess_style/index.d.ts → src/guess_style/index.ts} +1 -0
  21. package/src/index.test.ts +77 -0
  22. package/src/index.ts +18 -0
  23. package/src/lib/utils.test.ts +197 -0
  24. package/src/lib/utils.ts +134 -0
  25. package/{dist/shortbread/index.d.ts → src/shortbread/index.ts} +1 -0
  26. package/src/shortbread/layers.test.ts +36 -0
  27. package/src/shortbread/layers.ts +564 -0
  28. package/src/shortbread/properties.test.ts +44 -0
  29. package/src/shortbread/properties.ts +142 -0
  30. package/src/shortbread/template.test.ts +43 -0
  31. package/src/shortbread/template.ts +343 -0
  32. package/src/style_builder/decorator.test.ts +67 -0
  33. package/src/style_builder/decorator.ts +135 -0
  34. package/src/style_builder/recolor.test.ts +306 -0
  35. package/src/style_builder/recolor.ts +110 -0
  36. package/src/style_builder/style_builder.test.ts +103 -0
  37. package/src/style_builder/style_builder.ts +134 -0
  38. package/src/style_builder/types.ts +141 -0
  39. package/src/styles/LICENSE.md +41 -0
  40. package/src/styles/colorful.ts +1041 -0
  41. package/src/styles/eclipse.ts +11 -0
  42. package/{dist/styles/empty.d.ts → src/styles/empty.ts} +7 -3
  43. package/src/styles/graybeard.ts +11 -0
  44. package/src/styles/index.ts +33 -0
  45. package/src/styles/neutrino.ts +429 -0
  46. package/{dist/types/index.d.ts → src/types/index.ts} +1 -0
  47. package/{dist/types/maplibre.d.ts → src/types/maplibre.ts} +3 -0
  48. package/src/types/tilejson.test.ts +94 -0
  49. package/src/types/tilejson.ts +125 -0
  50. package/src/types/vector_layer.test.ts +64 -0
  51. package/src/types/vector_layer.ts +69 -0
  52. package/dist/color/abstract.d.ts +0 -34
  53. package/dist/color/abstract.js +0 -53
  54. package/dist/color/abstract.js.map +0 -1
  55. package/dist/color/hsl.d.ts +0 -23
  56. package/dist/color/hsl.js +0 -98
  57. package/dist/color/hsl.js.map +0 -1
  58. package/dist/color/hsv.d.ts +0 -20
  59. package/dist/color/hsv.js +0 -100
  60. package/dist/color/hsv.js.map +0 -1
  61. package/dist/color/index.d.ts +0 -6
  62. package/dist/color/index.js +0 -29
  63. package/dist/color/index.js.map +0 -1
  64. package/dist/color/random.d.ts +0 -9
  65. package/dist/color/random.js +0 -134
  66. package/dist/color/random.js.map +0 -1
  67. package/dist/color/rgb.d.ts +0 -28
  68. package/dist/color/rgb.js +0 -195
  69. package/dist/color/rgb.js.map +0 -1
  70. package/dist/color/utils.d.ts +0 -3
  71. package/dist/color/utils.js +0 -10
  72. package/dist/color/utils.js.map +0 -1
  73. package/dist/guess_style/guess_style.d.ts +0 -8
  74. package/dist/guess_style/guess_style.js +0 -147
  75. package/dist/guess_style/guess_style.js.map +0 -1
  76. package/dist/guess_style/index.js +0 -2
  77. package/dist/guess_style/index.js.map +0 -1
  78. package/dist/lib/utils.d.ts +0 -6
  79. package/dist/lib/utils.js +0 -126
  80. package/dist/lib/utils.js.map +0 -1
  81. package/dist/shortbread/index.js +0 -3
  82. package/dist/shortbread/index.js.map +0 -1
  83. package/dist/shortbread/layers.d.ts +0 -5
  84. package/dist/shortbread/layers.js +0 -521
  85. package/dist/shortbread/layers.js.map +0 -1
  86. package/dist/shortbread/properties.d.ts +0 -7
  87. package/dist/shortbread/properties.js +0 -125
  88. package/dist/shortbread/properties.js.map +0 -1
  89. package/dist/shortbread/template.d.ts +0 -4
  90. package/dist/shortbread/template.js +0 -339
  91. package/dist/shortbread/template.js.map +0 -1
  92. package/dist/style_builder/decorator.d.ts +0 -4
  93. package/dist/style_builder/decorator.js +0 -127
  94. package/dist/style_builder/decorator.js.map +0 -1
  95. package/dist/style_builder/recolor.d.ts +0 -22
  96. package/dist/style_builder/recolor.js +0 -89
  97. package/dist/style_builder/recolor.js.map +0 -1
  98. package/dist/style_builder/style_builder.d.ts +0 -15
  99. package/dist/style_builder/style_builder.js +0 -106
  100. package/dist/style_builder/style_builder.js.map +0 -1
  101. package/dist/style_builder/types.d.ts +0 -122
  102. package/dist/style_builder/types.js +0 -3
  103. package/dist/style_builder/types.js.map +0 -1
  104. package/dist/styles/colorful.d.ts +0 -11
  105. package/dist/styles/colorful.js +0 -956
  106. package/dist/styles/colorful.js.map +0 -1
  107. package/dist/styles/eclipse.d.ts +0 -5
  108. package/dist/styles/eclipse.js +0 -9
  109. package/dist/styles/eclipse.js.map +0 -1
  110. package/dist/styles/empty.js +0 -8
  111. package/dist/styles/empty.js.map +0 -1
  112. package/dist/styles/graybeard.d.ts +0 -5
  113. package/dist/styles/graybeard.js +0 -9
  114. package/dist/styles/graybeard.js.map +0 -1
  115. package/dist/styles/index.d.ts +0 -11
  116. package/dist/styles/index.js +0 -20
  117. package/dist/styles/index.js.map +0 -1
  118. package/dist/styles/neutrino.d.ts +0 -11
  119. package/dist/styles/neutrino.js +0 -401
  120. package/dist/styles/neutrino.js.map +0 -1
  121. package/dist/types/index.js +0 -3
  122. package/dist/types/index.js.map +0 -1
  123. package/dist/types/maplibre.js +0 -2
  124. package/dist/types/maplibre.js.map +0 -1
  125. package/dist/types/tilejson.d.ts +0 -32
  126. package/dist/types/tilejson.js +0 -87
  127. package/dist/types/tilejson.js.map +0 -1
  128. package/dist/types/vector_layer.d.ts +0 -14
  129. package/dist/types/vector_layer.js +0 -51
  130. package/dist/types/vector_layer.js.map +0 -1
@@ -0,0 +1,564 @@
1
+
2
+
3
+ import type { LegacyFilterSpecification } from '@maplibre/maplibre-gl-style-spec';
4
+ import type { MaplibreLayerDefinition } from '../types/index.js';
5
+ import { Language } from '../style_builder/types.js';
6
+
7
+ export function getShortbreadLayers(option: { readonly language: Language }): MaplibreLayerDefinition[] {
8
+ const { language } = option;
9
+ const nameField = language ? '{name_' + language + '}' : '{name}';
10
+
11
+ return [
12
+
13
+ // background
14
+ { id: 'background', type: 'background' },
15
+
16
+ // ocean
17
+ { id: 'water-ocean', type: 'fill', 'source-layer': 'ocean' },
18
+
19
+ // land
20
+ {
21
+ id: 'land-glacier',
22
+ type: 'fill', 'source-layer': 'water_polygons',
23
+ filter: ['all', ['==', 'kind', 'glacier']],
24
+ },
25
+
26
+ ...[
27
+ { id: 'commercial', kinds: ['commercial', 'retail'] },
28
+ { id: 'industrial', kinds: ['industrial', 'quarry', 'railway'] },
29
+ { id: 'residential', kinds: ['garages', 'residential'] },
30
+ { id: 'agriculture', kinds: ['brownfield', 'farmland', 'farmyard', 'greenfield', 'greenhouse_horticulture', 'orchard', 'plant_nursery', 'vineyard'] },
31
+ { id: 'waste', kinds: ['landfill'] },
32
+ { id: 'park', kinds: ['park', 'village_green', 'recreation_ground'] },
33
+ { id: 'garden', kinds: ['allotments', 'garden'] },
34
+ { id: 'burial', kinds: ['cemetery', 'grave_yard'] },
35
+ { id: 'leisure', kinds: ['miniature_golf', 'playground', 'golf_course'] },
36
+ { id: 'rock', kinds: ['bare_rock', 'scree', 'shingle'] },
37
+ { id: 'forest', kinds: ['forest'] },
38
+ { id: 'grass', kinds: ['grass', 'grassland', 'meadow', 'wet_meadow'] },
39
+ { id: 'vegetation', kinds: ['heath', 'scrub'] },
40
+ { id: 'sand', kinds: ['beach', 'sand'] },
41
+ { id: 'wetland', kinds: ['bog', 'marsh', 'string_bog', 'swamp'] },
42
+ ].map(({ id, kinds }: { readonly id: string; readonly kinds: readonly string[] }): MaplibreLayerDefinition => ({
43
+ id: 'land-' + id,
44
+ type: 'fill',
45
+ 'source-layer': 'land',
46
+ filter: ['all',
47
+ ['in', 'kind', ...kinds],
48
+ ],
49
+ })),
50
+
51
+ // water-lines
52
+ ...['river', 'canal', 'stream', 'ditch'].map((t: string): MaplibreLayerDefinition => ({
53
+ id: 'water-' + t,
54
+ type: 'line',
55
+ 'source-layer': 'water_lines',
56
+ filter: ['all',
57
+ ['in', 'kind', t],
58
+ ['!=', 'tunnel', true],
59
+ ['!=', 'bridge', true],
60
+ ],
61
+ })),
62
+
63
+ // water polygons
64
+ {
65
+ id: 'water-area',
66
+ type: 'fill', 'source-layer': 'water_polygons',
67
+ filter: ['==', 'kind', 'water'],
68
+ },
69
+ {
70
+ id: 'water-area-river',
71
+ type: 'fill', 'source-layer': 'water_polygons',
72
+ filter: ['==', 'kind', 'river'],
73
+ },
74
+ {
75
+ id: 'water-area-small',
76
+ type: 'fill', 'source-layer': 'water_polygons',
77
+ filter: ['in', 'kind', 'reservoir', 'basin', 'dock'],
78
+ },
79
+
80
+
81
+ // dam
82
+ { id: 'water-dam-area', type: 'fill', 'source-layer': 'dam_polygons', filter: ['==', 'kind', 'dam'] },
83
+ { id: 'water-dam', type: 'line', 'source-layer': 'dam_lines', filter: ['==', 'kind', 'dam'] },
84
+
85
+ // pier
86
+ { id: 'water-pier-area', type: 'fill', 'source-layer': 'pier_polygons', filter: ['in', 'kind', 'pier', 'breakwater', 'groyne'] },
87
+ { id: 'water-pier', type: 'line', 'source-layer': 'pier_lines', filter: ['in', 'kind', 'pier', 'breakwater', 'groyne'] },
88
+
89
+ // site
90
+ ...['danger_area', 'sports_center', 'university', 'college', 'school', 'hospital', 'prison', 'parking', 'bicycle_parking', 'construction'].map((t): MaplibreLayerDefinition => ({
91
+ id: 'site-' + t.replace(/_/g, ''),
92
+ type: 'fill',
93
+ 'source-layer': 'sites',
94
+ filter: ['in', 'kind', t],
95
+ })),
96
+
97
+ // airport
98
+ {
99
+ id: 'airport-area',
100
+ type: 'fill', 'source-layer': 'street_polygons', filter: ['in', 'kind', 'runway', 'taxiway'],
101
+ },
102
+ {
103
+ id: 'airport-taxiway:outline',
104
+ type: 'line', 'source-layer': 'streets', filter: ['==', 'kind', 'taxiway'],
105
+ },
106
+ {
107
+ id: 'airport-runway:outline',
108
+ type: 'line', 'source-layer': 'streets', filter: ['==', 'kind', 'runway'],
109
+ },
110
+ {
111
+ id: 'airport-taxiway',
112
+ type: 'line', 'source-layer': 'streets', filter: ['==', 'kind', 'taxiway'],
113
+ },
114
+ {
115
+ id: 'airport-runway',
116
+ type: 'line', 'source-layer': 'streets', filter: ['==', 'kind', 'runway'],
117
+ },
118
+
119
+ // building
120
+ {
121
+ id: 'building:outline',
122
+ type: 'fill', 'source-layer': 'buildings',
123
+ },
124
+ {
125
+ id: 'building',
126
+ type: 'fill', 'source-layer': 'buildings',
127
+ },
128
+
129
+ // tunnel-, street-, bridges-bridge
130
+ ...['tunnel', 'street', 'bridge'].flatMap((c): MaplibreLayerDefinition[] => {
131
+ let filter: LegacyFilterSpecification[];
132
+ let prefix: string;
133
+ let suffixes: Array<string> = [];
134
+ const results: MaplibreLayerDefinition[] = [];
135
+ switch (c) {
136
+ case 'tunnel':
137
+ filter = [['==', 'tunnel', true]];
138
+ prefix = 'tunnel-';
139
+ suffixes = [':outline', ''];
140
+ break;
141
+ case 'street':
142
+ filter = [['!=', 'bridge', true], ['!=', 'tunnel', true]];
143
+ prefix = '';
144
+ suffixes = [':outline', ''];
145
+ break;
146
+ case 'bridge':
147
+ filter = [['==', 'bridge', true]];
148
+ prefix = 'bridge-';
149
+ suffixes = [':bridge', ':outline', ''];
150
+ break;
151
+ }
152
+
153
+
154
+ // in osm data streets on bridges are often not tagged as such
155
+ // to be able to have multiple levels of bridges cross over each
156
+ // other in the right order without using a secondary property.
157
+ // this results in bridge-polygons being rendered above streets.
158
+ // therefore bridge polygons are *under* surface streets here.
159
+ // this workaround is also wrong, but everyone is using it since
160
+ // it's simpler than removing all these tagging hacks from osm.
161
+
162
+ // bridges, above tunnel, below street
163
+ if (c === 'street') results.push({
164
+ id: 'bridge',
165
+ type: 'fill',
166
+ 'source-layer': 'bridges',
167
+ });
168
+
169
+ suffixes.forEach(suffix => {
170
+
171
+ // pedestrian zone — no outline
172
+ if (suffix === ':outline') results.push({
173
+ id: prefix + 'street-pedestrian-zone',
174
+ type: 'fill',
175
+ 'source-layer': 'street_polygons',
176
+ filter: ['all',
177
+ ...filter,
178
+ ['==', 'kind', 'pedestrian'],
179
+ ],
180
+ });
181
+
182
+ // non-car streets
183
+ ['footway', 'steps', 'path', 'cycleway'].forEach(t => {
184
+ results.push({
185
+ id: prefix + 'way-' + t.replace(/_/g, '') + suffix,
186
+ type: 'line',
187
+ 'source-layer': 'streets',
188
+ filter: ['all',
189
+ ...filter,
190
+ ['in', 'kind', t],
191
+ ],
192
+ });
193
+ });
194
+
195
+ // no links
196
+ const noDrivewayExpression: LegacyFilterSpecification = ['!=', 'service', 'driveway'];
197
+ ['track', 'pedestrian', 'service', 'living_street', 'residential', 'unclassified'].forEach(t => {
198
+ results.push({
199
+ id: prefix + 'street-' + t.replace(/_/g, '') + suffix,
200
+ type: 'line',
201
+ 'source-layer': 'streets',
202
+ filter: ['all',
203
+ ['==', 'kind', t],
204
+ ...filter,
205
+ ...(t === 'service') ? [noDrivewayExpression] : [], // ignore driveways
206
+ ],
207
+ });
208
+ });
209
+
210
+ // no links, bicycle=designated
211
+ if (suffix === '') ['track', 'pedestrian', 'service', 'living_street', 'residential', 'unclassified'].forEach(t => {
212
+ results.push({
213
+ id: prefix + 'street-' + t.replace(/_/g, '') + '-bicycle',
214
+ type: 'line',
215
+ 'source-layer': 'streets',
216
+ filter: ['all',
217
+ ['==', 'kind', t],
218
+ ['==', 'bicycle', 'designated'],
219
+ ...filter,
220
+ ...(t === 'service') ? [noDrivewayExpression] : [], // ignore driveways
221
+ ],
222
+ });
223
+ });
224
+
225
+ // links
226
+ ['tertiary', 'secondary', 'primary', 'trunk', 'motorway'].forEach(t => {
227
+ results.push({
228
+ id: prefix + 'street-' + t.replace(/_/g, '') + '-link' + suffix,
229
+ type: 'line',
230
+ 'source-layer': 'streets',
231
+ filter: ['all',
232
+ ...filter,
233
+ ['in', 'kind', t],
234
+ ['==', 'link', true],
235
+ ],
236
+ });
237
+ });
238
+
239
+ // main
240
+ ['tertiary', 'secondary', 'primary', 'trunk', 'motorway'].forEach(t => {
241
+ results.push({
242
+ id: prefix + 'street-' + t.replace(/_/g, '') + suffix,
243
+ type: 'line',
244
+ 'source-layer': 'streets',
245
+ filter: ['all',
246
+ ...filter,
247
+ ['in', 'kind', t],
248
+ ['!=', 'link', true],
249
+ ],
250
+ });
251
+ });
252
+
253
+ });
254
+
255
+ // separate outline for trains
256
+ [':outline', ''].forEach(suffix => {
257
+ // transport
258
+ ['rail', 'light_rail', 'subway', 'narrow_gauge', 'tram', 'funicular', 'monorail', 'bus_guideway', 'busway'].reverse().forEach((t) => {
259
+ results.push({
260
+ id: prefix + 'transport-' + t.replace(/_/g, '') + suffix,
261
+ type: 'line',
262
+ 'source-layer': 'streets',
263
+ filter: ['all',
264
+ ['in', 'kind', t],
265
+ ['!has', 'service'],
266
+ ...filter,
267
+ ],
268
+ });
269
+ });
270
+
271
+ if (c === 'street') {
272
+ // aerialway, no bridges, above street evel
273
+ ['cable_car', 'gondola', 'goods', 'chair_lift', 'drag_lift', 't-bar', 'j-bar', 'platter', 'rope-tow'].reverse().forEach((t) => {
274
+ results.push({
275
+ id: 'aerialway-' + t.replace(/[_-]+/g, '') + suffix,
276
+ type: 'line',
277
+ 'source-layer': 'aerialways',
278
+ filter: ['all',
279
+ ...filter,
280
+ ['in', 'kind', t],
281
+ ],
282
+ });
283
+ });
284
+
285
+ // ferry — only on street level
286
+ results.push({
287
+ id: 'transport-ferry' + suffix,
288
+ type: 'line',
289
+ 'source-layer': 'ferries',
290
+ });
291
+ }
292
+ });
293
+
294
+ return results;
295
+ }),
296
+
297
+ // poi, one layer per type
298
+ ...['amenity', 'leisure', 'tourism', 'shop', 'man_made', 'historic', 'emergency', 'highway', 'office'].map((key): MaplibreLayerDefinition => ({
299
+ id: 'poi-' + key,
300
+
301
+ type: 'symbol',
302
+ 'source-layer': 'pois',
303
+ filter: ['to-boolean', ['get', key]],
304
+ })),
305
+
306
+ // boundary
307
+ ...[':outline', ''].flatMap((suffix): MaplibreLayerDefinition[] => [
308
+ {
309
+ id: 'boundary-country' + suffix,
310
+ type: 'line',
311
+ 'source-layer': 'boundaries',
312
+ filter: ['all',
313
+ ['==', 'admin_level', 2],
314
+ ['!=', 'maritime', true],
315
+ ['!=', 'disputed', true],
316
+ ['!=', 'coastline', true],
317
+ ],
318
+ },
319
+ {
320
+ id: 'boundary-country-disputed' + suffix,
321
+ type: 'line',
322
+ 'source-layer': 'boundaries',
323
+ filter: ['all',
324
+ ['==', 'admin_level', 2],
325
+ ['==', 'disputed', true],
326
+ ['!=', 'maritime', true],
327
+ ['!=', 'coastline', true],
328
+ ],
329
+ },
330
+ {
331
+ id: 'boundary-country-maritime' + suffix,
332
+ type: 'line',
333
+ 'source-layer': 'boundaries',
334
+ filter: ['all',
335
+ ['==', 'admin_level', 2],
336
+ ['==', 'maritime', true],
337
+ ['!=', 'disputed', true],
338
+ ['!=', 'coastline', true],
339
+ ],
340
+ },
341
+ {
342
+ id: 'boundary-state' + suffix,
343
+ type: 'line',
344
+ 'source-layer': 'boundaries',
345
+ filter: ['all',
346
+ ['==', 'admin_level', 4],
347
+ ['!=', 'maritime', true],
348
+ ['!=', 'disputed', true],
349
+ ['!=', 'coastline', true],
350
+ ],
351
+ },
352
+ ]),
353
+
354
+ // label-address
355
+ {
356
+ id: 'label-address-housenumber',
357
+ type: 'symbol',
358
+ 'source-layer': 'addresses',
359
+ filter: ['has', 'housenumber'],
360
+ layout: { 'text-field': '{housenumber}' },
361
+ },
362
+
363
+ // label-motorway
364
+ {
365
+ id: 'label-motorway-exit',
366
+ type: 'symbol',
367
+ 'source-layer': 'street_labels_points', // docs say `streets_labels_points`, but layer is actually called `street_labels_points`
368
+ filter: ['==', 'kind', 'motorway_junction'],
369
+ layout: { 'text-field': '{ref}' },
370
+ // FIXME shield
371
+ },
372
+ {
373
+ id: 'label-motorway-shield',
374
+ type: 'symbol',
375
+ 'source-layer': 'street_labels',
376
+ filter: ['==', 'kind', 'motorway'],
377
+ layout: { 'text-field': '{ref}' },
378
+ // FIXME shield
379
+ },
380
+
381
+ // label-street
382
+ ...['pedestrian', 'living_street', 'residential', 'unclassified', 'tertiary', 'secondary', 'primary', 'trunk'].map((t: string): MaplibreLayerDefinition => ({
383
+ id: 'label-street-' + t.replace(/_/g, ''),
384
+ type: 'symbol',
385
+ 'source-layer': 'street_labels',
386
+ filter: ['==', 'kind', t],
387
+ layout: { 'text-field': nameField },
388
+ })),
389
+
390
+ // label-place of small places
391
+ ...[ /*'locality', 'island', 'farm', 'dwelling',*/ 'neighbourhood', 'quarter', 'suburb', 'hamlet', 'village', 'town'].map((id: string): MaplibreLayerDefinition => ({
392
+ id: 'label-place-' + id.replace(/_/g, ''),
393
+ type: 'symbol',
394
+ 'source-layer': 'place_labels',
395
+ filter: ['==', 'kind', id],
396
+ layout: { 'text-field': nameField },
397
+ })),
398
+
399
+ // label-boundary
400
+ {
401
+ id: 'label-boundary-state',
402
+ type: 'symbol',
403
+ 'source-layer': 'boundary_labels',
404
+ filter: ['in', 'admin_level', 4, '4'],
405
+ layout: { 'text-field': nameField },
406
+ },
407
+
408
+ // label-place-* of large places
409
+ ...['city', 'state_capital', 'capital'].map((id: string): MaplibreLayerDefinition => ({
410
+ id: 'label-place-' + id.replace(/_/g, ''),
411
+ type: 'symbol',
412
+ 'source-layer': 'place_labels',
413
+ filter: ['==', 'kind', id],
414
+ layout: { 'text-field': nameField },
415
+ })),
416
+
417
+ {
418
+ id: 'label-boundary-country-small',
419
+ type: 'symbol',
420
+ 'source-layer': 'boundary_labels',
421
+ filter: ['all',
422
+ ['in', 'admin_level', 2, '2'],
423
+ ['<=', 'way_area', 10000000],
424
+ ],
425
+ layout: { 'text-field': nameField },
426
+ },
427
+ {
428
+ id: 'label-boundary-country-medium',
429
+ type: 'symbol',
430
+ 'source-layer': 'boundary_labels',
431
+ filter: ['all',
432
+ ['in', 'admin_level', 2, '2'],
433
+ ['<', 'way_area', 90000000],
434
+ ['>', 'way_area', 10000000],
435
+ ],
436
+ layout: { 'text-field': nameField },
437
+ },
438
+ {
439
+ id: 'label-boundary-country-large',
440
+ type: 'symbol',
441
+ 'source-layer': 'boundary_labels',
442
+ filter: ['all',
443
+ ['in', 'admin_level', 2, '2'],
444
+ ['>=', 'way_area', 90000000],
445
+ ],
446
+ layout: { 'text-field': nameField },
447
+ },
448
+
449
+ // marking
450
+ {
451
+ id: 'marking-oneway', // streets → oneway
452
+ type: 'symbol',
453
+ 'source-layer': 'streets',
454
+ filter: ['all',
455
+ ['==', 'oneway', true],
456
+ ['in', 'kind', 'trunk', 'primary', 'secondary', 'tertiary', 'unclassified', 'residential', 'living_street'],
457
+ ],
458
+ layout: {
459
+ 'symbol-placement': 'line',
460
+ 'symbol-spacing': 175,
461
+ 'icon-rotate': 90,
462
+ 'icon-rotation-alignment': 'map',
463
+ 'icon-padding': 5,
464
+ 'symbol-avoid-edges': true,
465
+ },
466
+ },
467
+ {
468
+ id: 'marking-oneway-reverse', // oneway_reverse
469
+ type: 'symbol',
470
+ 'source-layer': 'streets',
471
+ filter: ['all',
472
+ ['==', 'oneway_reverse', true],
473
+ ['in', 'kind', 'trunk', 'primary', 'secondary', 'tertiary', 'unclassified', 'residential', 'living_street'],
474
+ ],
475
+ layout: {
476
+ 'symbol-placement': 'line',
477
+ 'symbol-spacing': 75,
478
+ 'icon-rotate': -90,
479
+ 'icon-rotation-alignment': 'map',
480
+ 'icon-padding': 5,
481
+ 'symbol-avoid-edges': true,
482
+ },
483
+ },
484
+ {
485
+ id: 'marking-bicycle', // bicycle=designated or kind=cycleway
486
+ type: 'symbol',
487
+ 'source-layer': 'streets',
488
+ filter: ['all',
489
+ ['==', 'bicycle', 'designated'],
490
+ ['==', 'kind', 'cycleway'],
491
+ ],
492
+ layout: {
493
+ 'symbol-placement': 'line',
494
+ 'symbol-spacing': 50,
495
+ },
496
+ },
497
+
498
+ // symbol
499
+ {
500
+ id: 'symbol-transit-bus',
501
+ type: 'symbol',
502
+ 'source-layer': 'public_transport',
503
+ filter: ['==', 'kind', 'bus_stop'],
504
+ layout: { 'text-field': nameField },
505
+ },
506
+ {
507
+ id: 'symbol-transit-tram',
508
+ type: 'symbol',
509
+ 'source-layer': 'public_transport',
510
+ filter: ['==', 'kind', 'tram_stop'],
511
+ layout: { 'text-field': nameField },
512
+ },
513
+ {
514
+ id: 'symbol-transit-subway',
515
+ type: 'symbol',
516
+ 'source-layer': 'public_transport',
517
+ filter: ['all',
518
+ ['in', 'kind', 'station', 'halt'],
519
+ ['==', 'station', 'subway'],
520
+ ],
521
+ layout: { 'text-field': nameField },
522
+ },
523
+ {
524
+ id: 'symbol-transit-lightrail',
525
+ type: 'symbol',
526
+ 'source-layer': 'public_transport',
527
+ filter: ['all',
528
+ ['in', 'kind', 'station', 'halt'],
529
+ ['==', 'station', 'light_rail'],
530
+ ],
531
+ layout: { 'text-field': nameField },
532
+ },
533
+ {
534
+ id: 'symbol-transit-station',
535
+ type: 'symbol',
536
+ 'source-layer': 'public_transport',
537
+ filter: ['all',
538
+ ['in', 'kind', 'station', 'halt'],
539
+ ['!in', 'station', 'light_rail', 'subway'],
540
+ ],
541
+ layout: { 'text-field': nameField },
542
+ },
543
+ {
544
+ id: 'symbol-transit-airfield',
545
+ type: 'symbol',
546
+ 'source-layer': 'public_transport',
547
+ filter: ['all',
548
+ ['==', 'kind', 'aerodrome'],
549
+ ['!has', 'iata'],
550
+ ],
551
+ layout: { 'text-field': nameField },
552
+ },
553
+ {
554
+ id: 'symbol-transit-airport',
555
+ type: 'symbol',
556
+ 'source-layer': 'public_transport',
557
+ filter: ['all',
558
+ ['==', 'kind', 'aerodrome'],
559
+ ['has', 'iata'],
560
+ ],
561
+ layout: { 'text-field': nameField },
562
+ },
563
+ ];
564
+ }
@@ -0,0 +1,44 @@
1
+ import type { ShortbreadProperty } from './properties.js';
2
+ import propertyLookup from './properties.js';
3
+
4
+ describe('propertyLookup', () => {
5
+ it('should be a Map', () => {
6
+ expect(propertyLookup).toBeInstanceOf(Map);
7
+ });
8
+
9
+ it('should contain keys for each type and property', () => {
10
+ const expectedTypes = ['background', 'fill', 'line', 'symbol'];
11
+
12
+ expectedTypes.forEach(type => {
13
+ propertyLookup.forEach((value, key) => {
14
+ if (key.startsWith(type)) {
15
+ expect(key).toMatch(new RegExp(`^${type}/`));
16
+ }
17
+ });
18
+ });
19
+ });
20
+
21
+ it('should contain the correct properties for each type', () => {
22
+ const expectedProps = ['filter', 'maxzoom', 'minzoom', 'visibility'];
23
+
24
+ expectedProps.forEach(prop => {
25
+ propertyLookup.forEach((value, key) => {
26
+ if (key.endsWith(prop)) {
27
+ expect(value.some((p: ShortbreadProperty) => p.key === prop)).toBeTruthy();
28
+ }
29
+ });
30
+ });
31
+ });
32
+
33
+ it('should store properties with the correct structure', () => {
34
+ propertyLookup.forEach(properties => {
35
+ properties.forEach((prop: ShortbreadProperty) => {
36
+ expect(prop).toHaveProperty('key');
37
+ expect(prop).toHaveProperty('parent');
38
+ expect(prop).toHaveProperty('valueType');
39
+ expect(['layer', 'layout', 'paint']).toContain(prop.parent);
40
+ });
41
+ });
42
+ });
43
+ });
44
+