umap-project 2.4.2__py3-none-any.whl → 2.5.0__py3-none-any.whl

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 (177) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  3. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/hu/LC_MESSAGES/django.po +100 -50
  6. umap/static/umap/base.css +4 -1
  7. umap/static/umap/css/contextmenu.css +11 -0
  8. umap/static/umap/css/dialog.css +24 -3
  9. umap/static/umap/css/panel.css +4 -2
  10. umap/static/umap/css/slideshow.css +69 -0
  11. umap/static/umap/css/tableeditor.css +69 -0
  12. umap/static/umap/css/tooltip.css +3 -3
  13. umap/static/umap/img/16-white.svg +4 -0
  14. umap/static/umap/img/source/16-white.svg +5 -1
  15. umap/static/umap/js/components/alerts/alert.css +10 -10
  16. umap/static/umap/js/modules/autocomplete.js +23 -1
  17. umap/static/umap/js/modules/browser.js +14 -8
  18. umap/static/umap/js/modules/facets.js +40 -10
  19. umap/static/umap/js/modules/formatter.js +153 -0
  20. umap/static/umap/js/modules/global.js +10 -1
  21. umap/static/umap/js/modules/help.js +25 -25
  22. umap/static/umap/js/modules/importer.js +4 -4
  23. umap/static/umap/js/modules/importers/communesfr.js +3 -1
  24. umap/static/umap/js/modules/importers/datasets.js +8 -6
  25. umap/static/umap/js/modules/importers/geodatamine.js +10 -10
  26. umap/static/umap/js/modules/importers/overpass.js +18 -14
  27. umap/static/umap/js/modules/rules.js +13 -1
  28. umap/static/umap/js/modules/schema.js +16 -12
  29. umap/static/umap/js/{umap.share.js → modules/share.js} +60 -99
  30. umap/static/umap/js/modules/slideshow.js +141 -0
  31. umap/static/umap/js/modules/tableeditor.js +329 -0
  32. umap/static/umap/js/modules/ui/base.js +93 -0
  33. umap/static/umap/js/modules/ui/contextmenu.js +50 -0
  34. umap/static/umap/js/modules/ui/dialog.js +169 -31
  35. umap/static/umap/js/modules/ui/panel.js +6 -4
  36. umap/static/umap/js/modules/ui/tooltip.js +5 -75
  37. umap/static/umap/js/modules/utils.js +20 -0
  38. umap/static/umap/js/umap.controls.js +1 -1
  39. umap/static/umap/js/umap.features.js +22 -14
  40. umap/static/umap/js/umap.forms.js +157 -154
  41. umap/static/umap/js/umap.js +48 -34
  42. umap/static/umap/js/umap.layer.js +232 -164
  43. umap/static/umap/js/umap.permissions.js +1 -1
  44. umap/static/umap/js/umap.popup.js +1 -1
  45. umap/static/umap/locale/am_ET.js +22 -5
  46. umap/static/umap/locale/am_ET.json +19 -5
  47. umap/static/umap/locale/ar.js +22 -5
  48. umap/static/umap/locale/ar.json +19 -5
  49. umap/static/umap/locale/ast.js +22 -5
  50. umap/static/umap/locale/ast.json +19 -5
  51. umap/static/umap/locale/bg.js +22 -5
  52. umap/static/umap/locale/bg.json +19 -5
  53. umap/static/umap/locale/br.js +22 -5
  54. umap/static/umap/locale/br.json +19 -5
  55. umap/static/umap/locale/ca.js +56 -39
  56. umap/static/umap/locale/ca.json +53 -39
  57. umap/static/umap/locale/cs_CZ.js +22 -5
  58. umap/static/umap/locale/cs_CZ.json +19 -5
  59. umap/static/umap/locale/da.js +22 -5
  60. umap/static/umap/locale/da.json +19 -5
  61. umap/static/umap/locale/de.js +22 -5
  62. umap/static/umap/locale/de.json +19 -5
  63. umap/static/umap/locale/el.js +27 -10
  64. umap/static/umap/locale/el.json +19 -5
  65. umap/static/umap/locale/en.js +22 -6
  66. umap/static/umap/locale/en.json +19 -5
  67. umap/static/umap/locale/en_US.json +19 -5
  68. umap/static/umap/locale/es.js +22 -6
  69. umap/static/umap/locale/es.json +19 -5
  70. umap/static/umap/locale/et.js +22 -5
  71. umap/static/umap/locale/et.json +19 -5
  72. umap/static/umap/locale/eu.js +167 -150
  73. umap/static/umap/locale/eu.json +167 -150
  74. umap/static/umap/locale/fa_IR.js +22 -5
  75. umap/static/umap/locale/fa_IR.json +19 -5
  76. umap/static/umap/locale/fi.js +22 -5
  77. umap/static/umap/locale/fi.json +19 -5
  78. umap/static/umap/locale/fr.js +22 -6
  79. umap/static/umap/locale/fr.json +19 -5
  80. umap/static/umap/locale/gl.js +22 -5
  81. umap/static/umap/locale/gl.json +19 -5
  82. umap/static/umap/locale/he.js +22 -5
  83. umap/static/umap/locale/he.json +19 -5
  84. umap/static/umap/locale/hr.js +22 -5
  85. umap/static/umap/locale/hr.json +19 -5
  86. umap/static/umap/locale/hu.js +89 -72
  87. umap/static/umap/locale/hu.json +89 -75
  88. umap/static/umap/locale/id.js +22 -5
  89. umap/static/umap/locale/id.json +19 -5
  90. umap/static/umap/locale/is.js +22 -5
  91. umap/static/umap/locale/is.json +19 -5
  92. umap/static/umap/locale/it.js +22 -5
  93. umap/static/umap/locale/it.json +19 -5
  94. umap/static/umap/locale/ja.js +22 -5
  95. umap/static/umap/locale/ja.json +19 -5
  96. umap/static/umap/locale/ko.js +22 -5
  97. umap/static/umap/locale/ko.json +19 -5
  98. umap/static/umap/locale/lt.js +22 -5
  99. umap/static/umap/locale/lt.json +19 -5
  100. umap/static/umap/locale/ms.js +22 -5
  101. umap/static/umap/locale/ms.json +19 -5
  102. umap/static/umap/locale/nl.js +22 -5
  103. umap/static/umap/locale/nl.json +19 -5
  104. umap/static/umap/locale/no.js +22 -5
  105. umap/static/umap/locale/no.json +19 -5
  106. umap/static/umap/locale/pl.js +22 -5
  107. umap/static/umap/locale/pl.json +19 -5
  108. umap/static/umap/locale/pl_PL.json +19 -5
  109. umap/static/umap/locale/pt.js +22 -6
  110. umap/static/umap/locale/pt.json +21 -7
  111. umap/static/umap/locale/pt_BR.js +22 -5
  112. umap/static/umap/locale/pt_BR.json +19 -5
  113. umap/static/umap/locale/pt_PT.js +22 -5
  114. umap/static/umap/locale/pt_PT.json +19 -5
  115. umap/static/umap/locale/ro.js +22 -5
  116. umap/static/umap/locale/ro.json +19 -5
  117. umap/static/umap/locale/ru.js +22 -5
  118. umap/static/umap/locale/ru.json +19 -5
  119. umap/static/umap/locale/sk_SK.js +22 -5
  120. umap/static/umap/locale/sk_SK.json +19 -5
  121. umap/static/umap/locale/sl.js +22 -5
  122. umap/static/umap/locale/sl.json +19 -5
  123. umap/static/umap/locale/sr.js +22 -5
  124. umap/static/umap/locale/sr.json +19 -5
  125. umap/static/umap/locale/sv.js +22 -5
  126. umap/static/umap/locale/sv.json +19 -5
  127. umap/static/umap/locale/th_TH.js +22 -5
  128. umap/static/umap/locale/th_TH.json +19 -5
  129. umap/static/umap/locale/tr.js +22 -5
  130. umap/static/umap/locale/tr.json +19 -5
  131. umap/static/umap/locale/uk_UA.js +22 -5
  132. umap/static/umap/locale/uk_UA.json +19 -5
  133. umap/static/umap/locale/vi.js +22 -5
  134. umap/static/umap/locale/vi.json +19 -5
  135. umap/static/umap/locale/vi_VN.json +19 -5
  136. umap/static/umap/locale/zh.js +22 -5
  137. umap/static/umap/locale/zh.json +19 -5
  138. umap/static/umap/locale/zh_CN.json +19 -5
  139. umap/static/umap/locale/zh_TW.Big5.json +19 -5
  140. umap/static/umap/locale/zh_TW.js +22 -5
  141. umap/static/umap/locale/zh_TW.json +19 -5
  142. umap/static/umap/map.css +2 -145
  143. umap/static/umap/vars.css +5 -0
  144. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +410 -428
  145. umap/static/umap/vendors/geojson-to-gpx/index.js +155 -0
  146. umap/static/umap/vendors/osmtogeojson/osmtogeojson.js +1 -2
  147. umap/static/umap/vendors/togeojson/togeojson.es.js +1109 -0
  148. umap/static/umap/vendors/togeojson/{togeojson.umd.js.map → togeojson.es.mjs.map} +1 -1
  149. umap/static/umap/vendors/tokml/tokml.es.js +895 -0
  150. umap/static/umap/vendors/tokml/tokml.es.mjs.map +1 -0
  151. umap/storage.py +5 -1
  152. umap/templates/umap/components/alerts/alert.html +3 -3
  153. umap/templates/umap/css.html +3 -0
  154. umap/templates/umap/js.html +0 -6
  155. umap/tests/fixtures/categorized_highway.geojson +1 -0
  156. umap/tests/fixtures/test_import_osm_relation.json +130 -0
  157. umap/tests/integration/conftest.py +8 -1
  158. umap/tests/integration/test_browser.py +3 -2
  159. umap/tests/integration/test_categorized_layer.py +141 -0
  160. umap/tests/integration/test_conditional_rules.py +21 -0
  161. umap/tests/integration/test_datalayer.py +9 -4
  162. umap/tests/integration/test_edit_datalayer.py +1 -0
  163. umap/tests/integration/test_edit_polygon.py +1 -1
  164. umap/tests/integration/test_export_map.py +2 -3
  165. umap/tests/integration/test_import.py +22 -0
  166. umap/tests/integration/test_tableeditor.py +158 -4
  167. umap/tests/integration/test_websocket_sync.py +2 -2
  168. {umap_project-2.4.2.dist-info → umap_project-2.5.0.dist-info}/METADATA +8 -8
  169. {umap_project-2.4.2.dist-info → umap_project-2.5.0.dist-info}/RECORD +172 -162
  170. umap/static/umap/js/umap.slideshow.js +0 -163
  171. umap/static/umap/js/umap.tableeditor.js +0 -118
  172. umap/static/umap/vendors/togeojson/togeojson.umd.js +0 -2
  173. umap/static/umap/vendors/togpx/togpx.js +0 -547
  174. umap/static/umap/vendors/tokml/tokml.js +0 -343
  175. {umap_project-2.4.2.dist-info → umap_project-2.5.0.dist-info}/WHEEL +0 -0
  176. {umap_project-2.4.2.dist-info → umap_project-2.5.0.dist-info}/entry_points.txt +0 -0
  177. {umap_project-2.4.2.dist-info → umap_project-2.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,895 @@
1
+ /**
2
+ * @typedef {import('unist').Node} Node
3
+ * @typedef {import('unist').Parent} Parent
4
+ * @typedef {import('unist').Literal} Literal
5
+ * @typedef {Object.<string, unknown>} Props
6
+ * @typedef {Array.<Node>|string} ChildrenOrValue
7
+ *
8
+ * @typedef {(<T extends string, P extends Record<string, unknown>, C extends Node[]>(type: T, props: P, children: C) => {type: T, children: C} & P)} BuildParentWithProps
9
+ * @typedef {(<T extends string, P extends Record<string, unknown>>(type: T, props: P, value: string) => {type: T, value: string} & P)} BuildLiteralWithProps
10
+ * @typedef {(<T extends string, P extends Record<string, unknown>>(type: T, props: P) => {type: T} & P)} BuildVoidWithProps
11
+ * @typedef {(<T extends string, C extends Node[]>(type: T, children: C) => {type: T, children: C})} BuildParent
12
+ * @typedef {(<T extends string>(type: T, value: string) => {type: T, value: string})} BuildLiteral
13
+ * @typedef {(<T extends string>(type: T) => {type: T})} BuildVoid
14
+ */
15
+
16
+ var u = /**
17
+ * @type {BuildVoid & BuildVoidWithProps & BuildLiteral & BuildLiteralWithProps & BuildParent & BuildParentWithProps}
18
+ */ (
19
+ /**
20
+ * @param {string} type Type of node
21
+ * @param {Props|ChildrenOrValue} [props] Additional properties for node (or `children` or `value`)
22
+ * @param {ChildrenOrValue} [value] `children` or `value` of node
23
+ * @returns {Node}
24
+ */
25
+ function (type, props, value) {
26
+ /** @type {Node} */
27
+ var node = {type: String(type)};
28
+
29
+ if (
30
+ (value === undefined || value === null) &&
31
+ (typeof props === 'string' || Array.isArray(props))
32
+ ) {
33
+ value = props;
34
+ } else {
35
+ Object.assign(node, props);
36
+ }
37
+
38
+ if (Array.isArray(value)) {
39
+ node.children = value;
40
+ } else if (value !== undefined && value !== null) {
41
+ node.value = String(value);
42
+ }
43
+
44
+ return node
45
+ }
46
+ );
47
+
48
+ /**
49
+ * @typedef {import('xast').Root} Root
50
+ * @typedef {import('xast').Element} Element
51
+ * @typedef {Root['children'][number]} Child
52
+ * @typedef {Child|Root} Node
53
+ * @typedef {Root|Element} XResult
54
+ * @typedef {string|number|boolean|null|undefined} XValue
55
+ * @typedef {{[attribute: string]: XValue}} XAttributes Attributes to support JS primitive types
56
+ *
57
+ * @typedef {string|number|null|undefined} XPrimitiveChild
58
+ * @typedef {Array.<Node|XPrimitiveChild>} XArrayChild
59
+ * @typedef {Node|XPrimitiveChild|XArrayChild} XChild
60
+ * @typedef {import('./jsx-classic').Element} x.JSX.Element
61
+ * @typedef {import('./jsx-classic').IntrinsicAttributes} x.JSX.IntrinsicAttributes
62
+ * @typedef {import('./jsx-classic').IntrinsicElements} x.JSX.IntrinsicElements
63
+ * @typedef {import('./jsx-classic').ElementChildrenAttribute} x.JSX.ElementChildrenAttribute
64
+ */
65
+
66
+ /**
67
+ * Create XML trees in xast.
68
+ *
69
+ * @param name Qualified name. Case sensitive and can contain a namespace prefix (such as `rdf:RDF`). Pass `null|undefined` to build a root.
70
+ * @param attributes Map of attributes. Nullish (null or undefined) or NaN values are ignored, other values (strings, booleans) are cast to strings.
71
+ * @param children (Lists of) child nodes. When strings are encountered, they are mapped to Text nodes.
72
+ */
73
+ const x =
74
+ /**
75
+ * @type {{
76
+ * (): Root
77
+ * (name: null|undefined, ...children: XChild[]): Root
78
+ * (name: string, attributes: XAttributes, ...children: XChild[]): Element
79
+ * (name: string, ...children: XChild[]): Element
80
+ * }}
81
+ */
82
+ (
83
+ /**
84
+ * Hyperscript compatible DSL for creating virtual xast trees.
85
+ *
86
+ * @param {string|null} [name]
87
+ * @param {XAttributes|XChild} [attributes]
88
+ * @param {XChild[]} children
89
+ * @returns {XResult}
90
+ */
91
+ function (name, attributes, ...children) {
92
+ var index = -1;
93
+ /** @type {XResult} */
94
+ var node;
95
+ /** @type {string} */
96
+ var key;
97
+
98
+ if (name === undefined || name === null) {
99
+ node = {type: 'root', children: []};
100
+ // @ts-ignore Root builder doesn’t accept attributes.
101
+ children.unshift(attributes);
102
+ } else if (typeof name === 'string') {
103
+ node = {type: 'element', name, attributes: {}, children: []};
104
+
105
+ if (isAttributes(attributes)) {
106
+ for (key in attributes) {
107
+ // Ignore nullish and NaN values.
108
+ if (
109
+ attributes[key] !== undefined &&
110
+ attributes[key] !== null &&
111
+ (typeof attributes[key] !== 'number' ||
112
+ !Number.isNaN(attributes[key]))
113
+ ) {
114
+ // @ts-ignore Pretty sure we just set it.
115
+ node.attributes[key] = String(attributes[key]);
116
+ }
117
+ }
118
+ } else {
119
+ children.unshift(attributes);
120
+ }
121
+ } else {
122
+ throw new TypeError('Expected element name, got `' + name + '`')
123
+ }
124
+
125
+ // Handle children.
126
+ while (++index < children.length) {
127
+ addChild(node.children, children[index]);
128
+ }
129
+
130
+ return node
131
+ }
132
+ );
133
+
134
+ /**
135
+ * @param {Array.<Child>} nodes
136
+ * @param {XChild} value
137
+ */
138
+ function addChild(nodes, value) {
139
+ var index = -1;
140
+
141
+ if (value === undefined || value === null) ; else if (typeof value === 'string' || typeof value === 'number') {
142
+ nodes.push({type: 'text', value: String(value)});
143
+ } else if (Array.isArray(value)) {
144
+ while (++index < value.length) {
145
+ addChild(nodes, value[index]);
146
+ }
147
+ } else if (typeof value === 'object' && 'type' in value) {
148
+ if (value.type === 'root') {
149
+ addChild(nodes, value.children);
150
+ } else {
151
+ nodes.push(value);
152
+ }
153
+ } else {
154
+ throw new TypeError('Expected node, nodes, string, got `' + value + '`')
155
+ }
156
+ }
157
+
158
+ /**
159
+ * @param {XAttributes|XChild} value
160
+ * @returns {value is XAttributes}
161
+ */
162
+ function isAttributes(value) {
163
+ if (
164
+ value === null ||
165
+ value === undefined ||
166
+ typeof value !== 'object' ||
167
+ Array.isArray(value)
168
+ ) {
169
+ return false
170
+ }
171
+
172
+ return true
173
+ }
174
+
175
+ /**
176
+ * @typedef {import('./index.js').Parent} Parent
177
+ * @typedef {import('./index.js').Context} Context
178
+ * @typedef {import('./index.js').Child} Child
179
+ */
180
+
181
+ /**
182
+ * Serialize all children of `parent`.
183
+ *
184
+ * @param {Parent} parent
185
+ * @param {Context} ctx
186
+ * @returns {string}
187
+ *
188
+ */
189
+ function all(parent, ctx) {
190
+ /** @type {Array.<Child>} */
191
+ var children = (parent && parent.children) || [];
192
+ var index = -1;
193
+ /** @type {Array.<string>} */
194
+ var results = [];
195
+
196
+ while (++index < children.length) {
197
+ results[index] = one(children[index], ctx);
198
+ }
199
+
200
+ return results.join('')
201
+ }
202
+
203
+ /**
204
+ * @typedef {Object} CoreOptions
205
+ * @property {string[]} [subset=[]]
206
+ * Whether to only escape the given subset of characters.
207
+ * @property {boolean} [escapeOnly=false]
208
+ * Whether to only escape possibly dangerous characters.
209
+ * Those characters are `"`, `&`, `'`, `<`, `>`, and `` ` ``.
210
+ *
211
+ * @typedef {Object} FormatOptions
212
+ * @property {(code: number, next: number, options: CoreWithFormatOptions) => string} format
213
+ * Format strategy.
214
+ *
215
+ * @typedef {CoreOptions & FormatOptions & import('./util/format-smart.js').FormatSmartOptions} CoreWithFormatOptions
216
+ */
217
+
218
+ /**
219
+ * Encode certain characters in `value`.
220
+ *
221
+ * @param {string} value
222
+ * @param {CoreWithFormatOptions} options
223
+ * @returns {string}
224
+ */
225
+ function core(value, options) {
226
+ value = value.replace(
227
+ options.subset ? charactersToExpression(options.subset) : /["&'<>`]/g,
228
+ basic
229
+ );
230
+
231
+ if (options.subset || options.escapeOnly) {
232
+ return value
233
+ }
234
+
235
+ return (
236
+ value
237
+ // Surrogate pairs.
238
+ .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, surrogate)
239
+ // BMP control characters (C0 except for LF, CR, SP; DEL; and some more
240
+ // non-ASCII ones).
241
+ .replace(
242
+ // eslint-disable-next-line no-control-regex, unicorn/no-hex-escape
243
+ /[\x01-\t\v\f\x0E-\x1F\x7F\x81\x8D\x8F\x90\x9D\xA0-\uFFFF]/g,
244
+ basic
245
+ )
246
+ )
247
+
248
+ /**
249
+ * @param {string} pair
250
+ * @param {number} index
251
+ * @param {string} all
252
+ */
253
+ function surrogate(pair, index, all) {
254
+ return options.format(
255
+ (pair.charCodeAt(0) - 0xd800) * 0x400 +
256
+ pair.charCodeAt(1) -
257
+ 0xdc00 +
258
+ 0x10000,
259
+ all.charCodeAt(index + 2),
260
+ options
261
+ )
262
+ }
263
+
264
+ /**
265
+ * @param {string} character
266
+ * @param {number} index
267
+ * @param {string} all
268
+ */
269
+ function basic(character, index, all) {
270
+ return options.format(
271
+ character.charCodeAt(0),
272
+ all.charCodeAt(index + 1),
273
+ options
274
+ )
275
+ }
276
+ }
277
+
278
+ /**
279
+ * @param {string[]} subset
280
+ * @returns {RegExp}
281
+ */
282
+ function charactersToExpression(subset) {
283
+ /** @type {string[]} */
284
+ const groups = [];
285
+ let index = -1;
286
+
287
+ while (++index < subset.length) {
288
+ groups.push(subset[index].replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'));
289
+ }
290
+
291
+ return new RegExp('(?:' + groups.join('|') + ')', 'g')
292
+ }
293
+
294
+ /**
295
+ * The smallest way to encode a character.
296
+ *
297
+ * @param {number} code
298
+ * @returns {string}
299
+ */
300
+ function formatBasic(code) {
301
+ return '&#x' + code.toString(16).toUpperCase() + ';'
302
+ }
303
+
304
+ /**
305
+ * @typedef {import('./core.js').CoreOptions & import('./util/format-smart.js').FormatSmartOptions} Options
306
+ * @typedef {import('./core.js').CoreOptions} LightOptions
307
+ */
308
+
309
+ /**
310
+ * Encode special characters in `value` as hexadecimals.
311
+ *
312
+ * @param {string} value
313
+ * Value to encode.
314
+ * @param {LightOptions} [options]
315
+ * Configuration.
316
+ * @returns {string}
317
+ * Encoded value.
318
+ */
319
+ function stringifyEntitiesLight(value, options) {
320
+ return core(value, Object.assign({format: formatBasic}, options))
321
+ }
322
+
323
+ var noncharacter = /[\u0000-\u0008\u000B\u000C\u000E-\u001F]/g;
324
+
325
+ /**
326
+ * Escape a string.
327
+ *
328
+ * @param {string} value
329
+ * @param {Array.<string>} subset
330
+ * @param {RegExp} [unsafe]
331
+ * @returns {string}
332
+ */
333
+ function escape(value, subset, unsafe) {
334
+ var result = clean(value);
335
+
336
+ return unsafe ? result.replace(unsafe, encode) : encode(result)
337
+
338
+ /**
339
+ * @param {string} $0
340
+ * @returns {string}
341
+ */
342
+ function encode($0) {
343
+ return stringifyEntitiesLight($0, {subset})
344
+ }
345
+ }
346
+
347
+ /**
348
+ * @param {string} value
349
+ * @returns {string}
350
+ */
351
+ function clean(value) {
352
+ return String(value || '').replace(noncharacter, '')
353
+ }
354
+
355
+ var subset$3 = ['\t', '\n', ' ', '"', '&', "'", '/', '<', '=', '>'];
356
+
357
+ /**
358
+ * Serialize a node name.
359
+ *
360
+ * @param {string} value
361
+ * @returns {string}
362
+ */
363
+ function name(value) {
364
+ return escape(value, subset$3)
365
+ }
366
+
367
+ /**
368
+ * Count how often a character (or substring) is used in a string.
369
+ *
370
+ * @param {string} value
371
+ * Value to search in.
372
+ * @param {string} character
373
+ * Character (or substring) to look for.
374
+ * @return {number}
375
+ * Number of times `character` occurred in `value`.
376
+ */
377
+ function ccount(value, character) {
378
+ const source = String(value);
379
+
380
+ if (typeof character !== 'string') {
381
+ throw new TypeError('Expected character')
382
+ }
383
+
384
+ let count = 0;
385
+ let index = source.indexOf(character);
386
+
387
+ while (index !== -1) {
388
+ count++;
389
+ index = source.indexOf(character, index + character.length);
390
+ }
391
+
392
+ return count
393
+ }
394
+
395
+ /**
396
+ * @typedef {import('./index.js').Context} Context
397
+ */
398
+
399
+ /**
400
+ * Serialize an attribute value.
401
+ *
402
+ * @param {string} value
403
+ * @param {Context} ctx
404
+ * @returns {string}
405
+ */
406
+ function value(value, ctx) {
407
+ var primary = ctx.quote;
408
+ var secondary = ctx.alternative;
409
+ var result = String(value);
410
+ var quote =
411
+ secondary && ccount(result, primary) > ccount(result, secondary)
412
+ ? secondary
413
+ : primary;
414
+
415
+ return quote + escape(result, ['<', '&', quote]) + quote
416
+ }
417
+
418
+ /**
419
+ * @typedef {import('./index.js').Handle} Handle
420
+ * @typedef {import('./index.js').Element} Element
421
+ * @typedef {import('./index.js').Attributes} Attributes
422
+ */
423
+
424
+ var own$1 = {}.hasOwnProperty;
425
+
426
+ /**
427
+ * Serialize an element.
428
+ *
429
+ * @type {Handle}
430
+ * @param {Element} node
431
+ */
432
+ function element(node, ctx) {
433
+ var nodeName = name(node.name);
434
+ var content = all(node, ctx);
435
+ /** @type {Attributes} */
436
+ var attributes = node.attributes || {};
437
+ var close = content ? false : ctx.close;
438
+ /** @type {Array.<string>} */
439
+ var attrs = [];
440
+ /** @type {string} */
441
+ var key;
442
+ /** @type {Attributes[keyof Attributes]} */
443
+ var result;
444
+
445
+ for (key in attributes) {
446
+ if (own$1.call(attributes, key)) {
447
+ result = attributes[key];
448
+
449
+ if (result !== null && result !== undefined) {
450
+ attrs.push(name(key) + '=' + value(result, ctx));
451
+ }
452
+ }
453
+ }
454
+
455
+ return (
456
+ '<' +
457
+ nodeName +
458
+ (attrs.length === 0 ? '' : ' ' + attrs.join(' ')) +
459
+ (close ? (ctx.tight ? '' : ' ') + '/' : '') +
460
+ '>' +
461
+ content +
462
+ (close ? '' : '</' + nodeName + '>')
463
+ )
464
+ }
465
+
466
+ /**
467
+ * @typedef {import('./index.js').Handle} Handle
468
+ * @typedef {import('./index.js').Text} Text
469
+ */
470
+
471
+ var subset$2 = ['&', '<'];
472
+
473
+ /**
474
+ * Serialize a text.
475
+ *
476
+ * @type {Handle}
477
+ * @param {Text} node
478
+ */
479
+ function text(node) {
480
+ return escape(node.value, subset$2)
481
+ }
482
+
483
+ /**
484
+ * @typedef {import('./index.js').Handle} Handle
485
+ * @typedef {import('./index.js').Comment} Comment
486
+ */
487
+
488
+ /**
489
+ * Serialize a comment.
490
+ *
491
+ * @type {Handle}
492
+ * @param {Comment} node
493
+ */
494
+ function comment(node) {
495
+ return '<!--' + escape(node.value, ['-']) + '-->'
496
+ }
497
+
498
+ /**
499
+ * @typedef {import('./index.js').Handle} Handle
500
+ * @typedef {import('./index.js').Doctype} Doctype
501
+ */
502
+
503
+ /**
504
+ * Serialize a doctype.
505
+ *
506
+ * @type {Handle}
507
+ * @param {Doctype} node
508
+ */
509
+ function doctype(node, ctx) {
510
+ var nodeName = name(node.name);
511
+ var pub = node.public;
512
+ var sys = node.system;
513
+ var result = '<!DOCTYPE';
514
+
515
+ if (nodeName !== '') {
516
+ result += ' ' + nodeName;
517
+ }
518
+
519
+ if (pub !== null && pub !== undefined && pub !== '') {
520
+ result += ' PUBLIC ' + value(pub, ctx);
521
+ } else if (sys !== null && sys !== undefined && sys !== '') {
522
+ result += ' SYSTEM';
523
+ }
524
+
525
+ if (sys !== null && sys !== undefined && sys !== '') {
526
+ result += ' ' + value(sys, ctx);
527
+ }
528
+
529
+ return result + '>'
530
+ }
531
+
532
+ /**
533
+ * @typedef {import('./index.js').Handle} Handle
534
+ * @typedef {import('./index.js').Instruction} Instruction
535
+ */
536
+
537
+ var unsafe$1 = /\?>/g;
538
+ var subset$1 = ['>'];
539
+
540
+ /**
541
+ * Serialize an instruction.
542
+ *
543
+ * @type {Handle}
544
+ * @param {Instruction} node
545
+ */
546
+ function instruction(node) {
547
+ var nodeName = name(node.name) || 'x';
548
+ var result = escape(node.value, subset$1, unsafe$1);
549
+ return '<?' + nodeName + (result ? ' ' + result : '') + '?>'
550
+ }
551
+
552
+ /**
553
+ * @typedef {import('./index.js').Handle} Handle
554
+ * @typedef {import('./index.js').Cdata} Cdata
555
+ */
556
+
557
+ var unsafe = /]]>/g;
558
+ var subset = ['>'];
559
+
560
+ /**
561
+ * Serialize a CDATA section.
562
+ *
563
+ * @type {Handle}
564
+ * @param {Cdata} node
565
+ */
566
+ function cdata(node) {
567
+ return '<![CDATA[' + escape(node.value, subset, unsafe) + ']]>'
568
+ }
569
+
570
+ /**
571
+ * @typedef {import('./index.js').Handle} Handle
572
+ * @typedef {import('./index.js').Raw} Raw
573
+ */
574
+
575
+ /**
576
+ * Serialize a (non-standard) raw.
577
+ *
578
+ * @type {Handle}
579
+ * @param {Raw} node
580
+ */
581
+ function raw(node, ctx) {
582
+ // @ts-ignore Looks like a text.
583
+ return ctx.dangerous ? node.value : text(node)
584
+ }
585
+
586
+ /**
587
+ * @typedef {import('./index.js').Handle} Handle
588
+ */
589
+
590
+ var own = {}.hasOwnProperty;
591
+
592
+ var handlers = {
593
+ root: all,
594
+ element,
595
+ text,
596
+ comment,
597
+ doctype,
598
+ instruction,
599
+ cdata,
600
+ raw
601
+ };
602
+
603
+ /**
604
+ * Serialize a node.
605
+ *
606
+ * @type {Handle}
607
+ */
608
+ function one(node, ctx) {
609
+ var type = node && node.type;
610
+
611
+ if (!type) {
612
+ throw new Error('Expected node, not `' + node + '`')
613
+ }
614
+
615
+ if (!own.call(handlers, type)) {
616
+ throw new Error('Cannot compile unknown node `' + type + '`')
617
+ }
618
+
619
+ // @ts-ignore Hush, it works.
620
+ return handlers[type](node, ctx)
621
+ }
622
+
623
+ /**
624
+ * @typedef {import('xast').Root} Root
625
+ * @typedef {import('xast').Element} Element
626
+ * @typedef {import('xast').Cdata} Cdata
627
+ * @typedef {import('xast').Comment} Comment
628
+ * @typedef {import('xast').Doctype} Doctype
629
+ * @typedef {import('xast').Instruction} Instruction
630
+ * @typedef {import('xast').Text} Text
631
+ * @typedef {import('xast').Literal & {type: 'raw'}} Raw
632
+ * @typedef {Root|Element} Parent
633
+ * @typedef {import('xast').Attributes} Attributes
634
+ * @typedef {Root['children'][number]} Child
635
+ * @typedef {Child|Root} Node
636
+ *
637
+ * @typedef {'"'|"'"} Quote
638
+ *
639
+ * @typedef Options
640
+ * @property {Quote} [quote='"'] Preferred quote to use
641
+ * @property {boolean} [quoteSmart=false] Use the other quote if that results in
642
+ * less bytes
643
+ * @property {boolean} [closeEmptyElements=false] Close elements without any
644
+ * content with slash (/) on the opening tag instead of an end tag:
645
+ * `<circle />` instead of `<circle></circle>`.
646
+ * See `tightClose` to control whether a space is used before the slash.
647
+ * @property {boolean} [tightClose=false] Do not use an extra space when closing
648
+ * self-closing elements: `<circle/>` instead of `<circle />`.
649
+ * @property {boolean} [allowDangerousXml=false] Allow `raw` nodes and insert
650
+ * them as raw XML. When falsey, encodes `raw` nodes.
651
+ * Only set this if you completely trust the content!
652
+ *
653
+ * @typedef Context
654
+ * @property {Quote} quote
655
+ * @property {Quote} alternative
656
+ * @property {boolean} close
657
+ * @property {boolean} tight
658
+ * @property {boolean} dangerous
659
+ *
660
+ * @callback Handle
661
+ * @param {Node} node
662
+ * @param {Context} context
663
+ * @returns {string}
664
+ */
665
+
666
+ /**
667
+ * Serialize the given xast tree (or list of nodes).
668
+ *
669
+ * @param {Node|Array.<Node>} node
670
+ * @param {Options} [options]
671
+ * @returns {string}
672
+ */
673
+ function toXml(node, options = {}) {
674
+ var quote = options.quote || '"';
675
+ /** @type {Quote} */
676
+ var alternative = quote === '"' ? "'" : '"';
677
+ var smart = options.quoteSmart;
678
+ /** @type {Node} */
679
+ // @ts-ignore Assume no `root` in `node`.
680
+ var value = Array.isArray(node) ? {type: 'root', children: node} : node;
681
+
682
+ if (quote !== '"' && quote !== "'") {
683
+ throw new Error('Invalid quote `' + quote + '`, expected `\'` or `"`')
684
+ }
685
+
686
+ return one(value, {
687
+ dangerous: options.allowDangerousXml,
688
+ close: options.closeEmptyElements,
689
+ tight: options.tightClose,
690
+ quote,
691
+ alternative: smart ? alternative : null
692
+ })
693
+ }
694
+
695
+ const BR = u('text', '\n');
696
+ const TAB = u('text', ' ');
697
+ /**
698
+ * Convert nested folder structure to KML. This expects
699
+ * input that follows the same patterns as [toGeoJSON](https://github.com/placemark/togeojson)'s
700
+ * kmlWithFolders method: a tree of folders and features,
701
+ * starting with a root element.
702
+ */
703
+ function foldersToKML(root) {
704
+ return toXml(u('root', [
705
+ x('kml', { xmlns: 'http://www.opengis.net/kml/2.2' }, x('Document', root.children.flatMap((child) => convertChild(child)))),
706
+ ]));
707
+ }
708
+ /**
709
+ * Convert a GeoJSON FeatureCollection to a string of
710
+ * KML data.
711
+ */
712
+ function toKML(featureCollection) {
713
+ return toXml(u('root', [
714
+ x('kml', { xmlns: 'http://www.opengis.net/kml/2.2' }, x('Document', featureCollection.features.flatMap((feature) => convertFeature(feature)))),
715
+ ]));
716
+ }
717
+ function convertChild(child) {
718
+ switch (child.type) {
719
+ case 'Feature':
720
+ return convertFeature(child);
721
+ case 'folder':
722
+ return convertFolder(child);
723
+ }
724
+ }
725
+ function convertFolder(folder) {
726
+ const id = ['string', 'number'].includes(typeof folder.meta.id)
727
+ ? {
728
+ id: String(folder.meta.id),
729
+ }
730
+ : {};
731
+ return [
732
+ BR,
733
+ x('Folder', id, [
734
+ BR,
735
+ ...folderMeta(folder.meta),
736
+ BR,
737
+ TAB,
738
+ ...folder.children.flatMap((child) => convertChild(child)),
739
+ ]),
740
+ ];
741
+ }
742
+ const META_PROPERTIES = [
743
+ 'address',
744
+ 'description',
745
+ 'name',
746
+ 'open',
747
+ 'visibility',
748
+ 'phoneNumber',
749
+ ];
750
+ function folderMeta(meta) {
751
+ return META_PROPERTIES.filter((p) => meta[p] !== undefined).map((p) => {
752
+ return x(p, [u('text', String(meta[p]))]);
753
+ });
754
+ }
755
+ function convertFeature(feature) {
756
+ const { id } = feature;
757
+ const idMember = ['string', 'number'].includes(typeof id)
758
+ ? {
759
+ id: id,
760
+ }
761
+ : {};
762
+ return [
763
+ BR,
764
+ x('Placemark', idMember, [
765
+ BR,
766
+ ...propertiesToTags(feature.properties),
767
+ BR,
768
+ TAB,
769
+ ...(feature.geometry ? [convertGeometry(feature.geometry)] : []),
770
+ ]),
771
+ ];
772
+ }
773
+ function join(position) {
774
+ return `${position[0]},${position[1]}`;
775
+ }
776
+ function coord1(coordinates) {
777
+ return x('coordinates', [u('text', join(coordinates))]);
778
+ }
779
+ function coord2(coordinates) {
780
+ return x('coordinates', [u('text', coordinates.map(join).join('\n'))]);
781
+ }
782
+ function toString(value) {
783
+ switch (typeof value) {
784
+ case 'string': {
785
+ return value;
786
+ }
787
+ case 'boolean':
788
+ case 'number': {
789
+ return String(value);
790
+ }
791
+ case 'object': {
792
+ try {
793
+ return JSON.stringify(value);
794
+ }
795
+ catch (e) {
796
+ return '';
797
+ }
798
+ }
799
+ }
800
+ return '';
801
+ }
802
+ function maybeCData(value) {
803
+ if (value &&
804
+ typeof value === 'object' &&
805
+ '@type' in value &&
806
+ value['@type'] === 'html' &&
807
+ 'value' in value &&
808
+ typeof value.value === 'string') {
809
+ return u('cdata', value.value);
810
+ }
811
+ return toString(value);
812
+ }
813
+ function propertiesToTags(properties) {
814
+ if (!properties)
815
+ return [];
816
+ const { name, description, visibility, ...otherProperties } = properties;
817
+ return [
818
+ name && x('name', [u('text', toString(name))]),
819
+ description && x('description', [u('text', maybeCData(description))]),
820
+ visibility !== undefined &&
821
+ x('visibility', [u('text', visibility ? '1' : '0')]),
822
+ x('ExtendedData', Object.entries(otherProperties).flatMap(([name, value]) => [
823
+ BR,
824
+ TAB,
825
+ x('Data', { name: name }, [
826
+ x('value', [
827
+ u('text', typeof value === 'string' ? value : JSON.stringify(value)),
828
+ ]),
829
+ ]),
830
+ ])),
831
+ ].filter(Boolean);
832
+ }
833
+ const linearRing = (ring) => x('LinearRing', [coord2(ring)]);
834
+ function convertMultiPoint(geometry) {
835
+ return x('MultiGeometry', geometry.coordinates.flatMap((coordinates) => [
836
+ BR,
837
+ convertGeometry({
838
+ type: 'Point',
839
+ coordinates,
840
+ }),
841
+ ]));
842
+ }
843
+ function convertMultiLineString(geometry) {
844
+ return x('MultiGeometry', geometry.coordinates.flatMap((coordinates) => [
845
+ BR,
846
+ convertGeometry({
847
+ type: 'LineString',
848
+ coordinates,
849
+ }),
850
+ ]));
851
+ }
852
+ function convertMultiPolygon(geometry) {
853
+ return x('MultiGeometry', geometry.coordinates.flatMap((coordinates) => [
854
+ BR,
855
+ convertGeometry({
856
+ type: 'Polygon',
857
+ coordinates,
858
+ }),
859
+ ]));
860
+ }
861
+ function convertPolygon(geometry) {
862
+ const [outerBoundary, ...innerRings] = geometry.coordinates;
863
+ return x('Polygon', [
864
+ BR,
865
+ x('outerBoundaryIs', [BR, TAB, linearRing(outerBoundary)]),
866
+ ...innerRings.flatMap((innerRing) => [
867
+ BR,
868
+ x('innerBoundaryIs', [BR, TAB, linearRing(innerRing)]),
869
+ ]),
870
+ ]);
871
+ }
872
+ function convertGeometry(geometry) {
873
+ switch (geometry.type) {
874
+ case 'Point':
875
+ return x('Point', [coord1(geometry.coordinates)]);
876
+ case 'MultiPoint':
877
+ return convertMultiPoint(geometry);
878
+ case 'LineString':
879
+ return x('LineString', [coord2(geometry.coordinates)]);
880
+ case 'MultiLineString':
881
+ return convertMultiLineString(geometry);
882
+ case 'Polygon':
883
+ return convertPolygon(geometry);
884
+ case 'MultiPolygon':
885
+ return convertMultiPolygon(geometry);
886
+ case 'GeometryCollection':
887
+ return x('MultiGeometry', geometry.geometries.flatMap((geometry) => [
888
+ BR,
889
+ convertGeometry(geometry),
890
+ ]));
891
+ }
892
+ }
893
+
894
+ export { foldersToKML, toKML };
895
+ //# sourceMappingURL=tokml.es.mjs.map