@chelone/core 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/dist/assistant/assistant-session.d.ts +6 -0
  2. package/dist/assistant/assistant-session.js +204 -181
  3. package/dist/assistant/echo-transport.js +26 -29
  4. package/dist/assistant/http-transport.d.ts +10 -0
  5. package/dist/assistant/http-transport.js +98 -0
  6. package/dist/assistant/types.d.ts +1 -7
  7. package/dist/auth/access-control.d.ts +13 -5
  8. package/dist/auth/access-control.js +25 -21
  9. package/dist/auth/auth-options.d.ts +23 -17
  10. package/dist/auth/auth-options.js +82 -48
  11. package/dist/auth/permission-matrix.d.ts +12 -0
  12. package/dist/auth/permission-matrix.js +67 -0
  13. package/dist/auth/types.d.ts +14 -4
  14. package/dist/block-editor/block-document.d.ts +64 -0
  15. package/dist/block-editor/block-document.js +147 -0
  16. package/dist/block-editor/data-blocks.d.ts +63 -0
  17. package/dist/block-editor/data-blocks.js +117 -0
  18. package/dist/chart/chart-data.js +46 -44
  19. package/dist/command-menu/hotkey.js +58 -47
  20. package/dist/command-menu/recents.d.ts +4 -0
  21. package/dist/command-menu/recents.js +12 -11
  22. package/dist/command-menu/registry.d.ts +9 -5
  23. package/dist/command-menu/registry.js +36 -46
  24. package/dist/controller/calendar-dates.d.ts +12 -0
  25. package/dist/controller/calendar-dates.js +94 -113
  26. package/dist/controller/calendar-events.js +93 -88
  27. package/dist/controller/client-list-controller.d.ts +2 -2
  28. package/dist/controller/client-list-controller.js +251 -254
  29. package/dist/controller/data-table-columns.d.ts +2 -0
  30. package/dist/controller/data-table-columns.js +50 -56
  31. package/dist/controller/deep-equal.d.ts +1 -0
  32. package/dist/controller/deep-equal.js +14 -0
  33. package/dist/controller/filter-toggle.js +36 -44
  34. package/dist/controller/in-place-editor.d.ts +43 -0
  35. package/dist/controller/in-place-editor.js +43 -0
  36. package/dist/controller/infinite-list-controller.js +219 -189
  37. package/dist/controller/inspector.d.ts +55 -0
  38. package/dist/controller/inspector.js +70 -0
  39. package/dist/controller/job-monitor.d.ts +10 -4
  40. package/dist/controller/job-monitor.js +46 -47
  41. package/dist/controller/kanban-board.js +45 -24
  42. package/dist/controller/list-controller.d.ts +8 -5
  43. package/dist/controller/list-controller.js +447 -400
  44. package/dist/controller/list-params.js +96 -87
  45. package/dist/controller/pivot-grid.d.ts +4 -4
  46. package/dist/controller/pivot-grid.js +89 -95
  47. package/dist/controller/prev-next.d.ts +2 -2
  48. package/dist/controller/prev-next.js +74 -54
  49. package/dist/controller/record-controllers.d.ts +14 -6
  50. package/dist/controller/record-controllers.js +288 -257
  51. package/dist/controller/record-diff.d.ts +21 -0
  52. package/dist/controller/record-diff.js +50 -0
  53. package/dist/controller/record-timeline.d.ts +5 -5
  54. package/dist/controller/record-timeline.js +42 -30
  55. package/dist/controller/record-tree.js +57 -47
  56. package/dist/controller/record-workflow.d.ts +38 -16
  57. package/dist/controller/record-workflow.js +85 -64
  58. package/dist/controller/reference-many-controller.d.ts +2 -0
  59. package/dist/controller/reference-many-controller.js +199 -192
  60. package/dist/controller/reference-one-controller.d.ts +1 -1
  61. package/dist/controller/reference-one-controller.js +63 -56
  62. package/dist/controller/saved-queries.js +104 -91
  63. package/dist/controller/translate-fallback.js +10 -6
  64. package/dist/csv/export.d.ts +4 -3
  65. package/dist/csv/export.js +43 -40
  66. package/dist/csv/import-controller.d.ts +4 -0
  67. package/dist/csv/import-controller.js +189 -169
  68. package/dist/csv/match-headers.js +29 -22
  69. package/dist/csv/parse-with.js +60 -54
  70. package/dist/csv/run-import.js +69 -72
  71. package/dist/csv/validate-rows.d.ts +1 -1
  72. package/dist/csv/validate-rows.js +65 -52
  73. package/dist/data/cache-ops.d.ts +5 -4
  74. package/dist/data/cache-ops.js +208 -188
  75. package/dist/data/combine-data-providers.js +25 -23
  76. package/dist/data/data-provider-log.d.ts +45 -0
  77. package/dist/data/data-provider-log.js +93 -0
  78. package/dist/data/errors.js +14 -10
  79. package/dist/data/fake-provider.d.ts +6 -3
  80. package/dist/data/fake-provider.js +135 -114
  81. package/dist/data/fetch-utils.js +61 -44
  82. package/dist/data/filter-branch.d.ts +5 -0
  83. package/dist/data/filter-branch.js +10 -0
  84. package/dist/data/get-many-aggregate.js +84 -76
  85. package/dist/data/http-error.js +17 -12
  86. package/dist/data/keys.js +50 -36
  87. package/dist/data/mutation-options.d.ts +14 -9
  88. package/dist/data/mutation-options.js +93 -109
  89. package/dist/data/query-options.js +73 -68
  90. package/dist/data/remove-empty.d.ts +3 -0
  91. package/dist/data/remove-empty.js +11 -0
  92. package/dist/data/undoable.d.ts +2 -2
  93. package/dist/data/undoable.js +190 -174
  94. package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
  95. package/dist/data/with-lifecycle-callbacks.js +66 -52
  96. package/dist/environment/application-update-store.js +58 -55
  97. package/dist/environment/offline-store.js +21 -21
  98. package/dist/form/array-binding.d.ts +30 -11
  99. package/dist/form/array-binding.js +184 -166
  100. package/dist/form/choice-ids.d.ts +7 -0
  101. package/dist/form/choice-ids.js +11 -0
  102. package/dist/form/choices-controller.d.ts +22 -2
  103. package/dist/form/choices-controller.js +315 -275
  104. package/dist/form/date-format.d.ts +38 -0
  105. package/dist/form/date-format.js +89 -0
  106. package/dist/form/dirty-values.d.ts +2 -2
  107. package/dist/form/dirty-values.js +22 -11
  108. package/dist/form/duration.d.ts +22 -0
  109. package/dist/form/duration.js +49 -0
  110. package/dist/form/edit-create-form.d.ts +12 -5
  111. package/dist/form/edit-create-form.js +243 -188
  112. package/dist/form/event-value.d.ts +6 -0
  113. package/dist/form/event-value.js +17 -0
  114. package/dist/form/field-error.d.ts +14 -0
  115. package/dist/form/field-error.js +28 -0
  116. package/dist/form/field-name.d.ts +20 -0
  117. package/dist/form/field-name.js +6 -0
  118. package/dist/form/filter-form-values.js +63 -49
  119. package/dist/form/form-controller.d.ts +9 -1
  120. package/dist/form/form-controller.js +165 -160
  121. package/dist/form/form-groups.d.ts +4 -3
  122. package/dist/form/form-groups.js +79 -79
  123. package/dist/form/form-handle.d.ts +175 -0
  124. package/dist/form/form-handle.js +68 -0
  125. package/dist/form/input-binding.d.ts +56 -31
  126. package/dist/form/input-binding.js +171 -118
  127. package/dist/form/input-values.d.ts +140 -0
  128. package/dist/form/input-values.js +206 -0
  129. package/dist/form/json-text.d.ts +11 -0
  130. package/dist/form/json-text.js +62 -37
  131. package/dist/form/save-pipeline.d.ts +6 -8
  132. package/dist/form/save-pipeline.js +91 -82
  133. package/dist/form/set-form-values.d.ts +6 -0
  134. package/dist/form/set-form-values.js +10 -0
  135. package/dist/form/source.js +97 -65
  136. package/dist/form/text-of.d.ts +2 -0
  137. package/dist/form/text-of.js +7 -0
  138. package/dist/form/validators.d.ts +58 -19
  139. package/dist/form/validators.js +97 -71
  140. package/dist/geo/bbox.d.ts +5 -4
  141. package/dist/geo/bbox.js +69 -48
  142. package/dist/geo/bounds.d.ts +14 -3
  143. package/dist/geo/bounds.js +98 -68
  144. package/dist/geo/constraints.js +88 -93
  145. package/dist/geo/coordinates.d.ts +10 -0
  146. package/dist/geo/coordinates.js +44 -23
  147. package/dist/geo/editor.d.ts +13 -13
  148. package/dist/geo/editor.js +176 -153
  149. package/dist/geo/geocoding.d.ts +4 -4
  150. package/dist/geo/geocoding.js +38 -41
  151. package/dist/geo/geojson.d.ts +12 -74
  152. package/dist/geo/geojson.js +52 -40
  153. package/dist/geo/geometry-math.d.ts +4 -4
  154. package/dist/geo/geometry-math.js +100 -93
  155. package/dist/geo/index.d.ts +9 -8
  156. package/dist/geo/map-layers.d.ts +42 -7
  157. package/dist/geo/map-layers.js +88 -62
  158. package/dist/geo/map-style.d.ts +12 -0
  159. package/dist/geo/map-style.js +43 -32
  160. package/dist/geo/messages.js +48 -45
  161. package/dist/geo/nominatim.js +88 -80
  162. package/dist/geo/osm-presets.d.ts +4 -3
  163. package/dist/geo/osm-presets.js +108 -86
  164. package/dist/geo/osm-tags.js +14 -12
  165. package/dist/geo/overpass.d.ts +14 -2
  166. package/dist/geo/overpass.js +83 -90
  167. package/dist/geo/shape-value.d.ts +9 -5
  168. package/dist/geo/shape-value.js +169 -146
  169. package/dist/geo/snap-to-roads.d.ts +3 -3
  170. package/dist/geo/snap-to-roads.js +55 -50
  171. package/dist/geo/throttle.js +36 -39
  172. package/dist/guards.d.ts +44 -0
  173. package/dist/guards.js +77 -0
  174. package/dist/i18n/default-messages.js +34 -29
  175. package/dist/i18n/english-messages.d.ts +172 -0
  176. package/dist/i18n/english-messages.js +359 -189
  177. package/dist/i18n/i18n.d.ts +2 -2
  178. package/dist/i18n/i18n.js +47 -60
  179. package/dist/i18n/inflection.d.ts +34 -0
  180. package/dist/i18n/inflection.js +82 -0
  181. package/dist/i18n/messages.d.ts +10 -2
  182. package/dist/i18n/messages.js +17 -4
  183. package/dist/i18n/missing-keys.d.ts +4 -0
  184. package/dist/i18n/missing-keys.js +70 -62
  185. package/dist/i18n/translatable.d.ts +16 -1
  186. package/dist/i18n/translatable.js +40 -47
  187. package/dist/index.d.ts +87 -39
  188. package/dist/index.js +54 -301
  189. package/dist/json/deep-equal.d.ts +8 -0
  190. package/dist/json/deep-equal.js +24 -0
  191. package/dist/json/strip-json-comments.js +38 -42
  192. package/dist/noop.d.ts +2 -0
  193. package/dist/noop.js +4 -0
  194. package/dist/notification/error-message.d.ts +2 -0
  195. package/dist/notification/error-message.js +10 -0
  196. package/dist/notification/notification-store.d.ts +3 -2
  197. package/dist/notification/notification-store.js +41 -45
  198. package/dist/onboarding-tour/placement.d.ts +2 -0
  199. package/dist/onboarding-tour/placement.js +65 -78
  200. package/dist/onboarding-tour/tour-controller.js +46 -54
  201. package/dist/realtime/add-events-for-mutations.js +75 -81
  202. package/dist/realtime/announce-lock.js +16 -13
  203. package/dist/realtime/broadcast-channel-transport.js +65 -59
  204. package/dist/realtime/copy-members.js +22 -14
  205. package/dist/realtime/in-memory-lock-provider.js +40 -48
  206. package/dist/realtime/live.js +95 -101
  207. package/dist/realtime/lock-options.js +16 -16
  208. package/dist/realtime/lock-session.js +91 -78
  209. package/dist/realtime/memory-transport.js +25 -25
  210. package/dist/realtime/presence.js +120 -122
  211. package/dist/realtime/realtime-data-provider.d.ts +10 -0
  212. package/dist/realtime/realtime-data-provider.js +45 -42
  213. package/dist/realtime/reconnect-backoff.js +17 -0
  214. package/dist/realtime/sse-transport.d.ts +31 -0
  215. package/dist/realtime/sse-transport.js +235 -0
  216. package/dist/realtime/status-store.js +23 -28
  217. package/dist/realtime/topic-hub.js +62 -71
  218. package/dist/realtime/topics.js +10 -12
  219. package/dist/realtime/types.js +10 -12
  220. package/dist/realtime/unread-count.js +21 -21
  221. package/dist/realtime/websocket-transport.d.ts +32 -0
  222. package/dist/realtime/websocket-transport.js +306 -0
  223. package/dist/resource/describe-resource.d.ts +2 -0
  224. package/dist/resource/describe-resource.js +247 -219
  225. package/dist/resource/get-at-path.js +29 -14
  226. package/dist/resource/identifier.d.ts +18 -0
  227. package/dist/resource/identifier.js +27 -0
  228. package/dist/resource/record.d.ts +4 -0
  229. package/dist/resource/record.js +10 -0
  230. package/dist/resource/register.d.ts +7 -0
  231. package/dist/resource/registry-store.d.ts +45 -15
  232. package/dist/resource/registry-store.js +67 -60
  233. package/dist/resource/registry.d.ts +10 -0
  234. package/dist/resource/registry.js +8 -4
  235. package/dist/resource/source-path.d.ts +23 -2
  236. package/dist/rich-text/rich-text-extras.d.ts +134 -0
  237. package/dist/rich-text/rich-text-extras.js +181 -0
  238. package/dist/rich-text/rich-text-image.d.ts +124 -0
  239. package/dist/rich-text/rich-text-image.js +163 -0
  240. package/dist/rich-text/rich-text.d.ts +6 -0
  241. package/dist/rich-text/rich-text.js +125 -88
  242. package/dist/router/location.d.ts +24 -4
  243. package/dist/router/location.js +43 -18
  244. package/dist/router/match.js +47 -39
  245. package/dist/router/paths.js +40 -34
  246. package/dist/router/record-from-location.d.ts +1 -1
  247. package/dist/router/record-from-location.js +25 -17
  248. package/dist/store/adapters.js +51 -55
  249. package/dist/store/micro-store.js +57 -59
  250. package/dist/store/shallow-equal.d.ts +12 -0
  251. package/dist/store/shallow-equal.js +20 -0
  252. package/dist/store/store.js +54 -57
  253. package/dist/ui-defaults.d.ts +15 -0
  254. package/dist/ui-defaults.js +17 -0
  255. package/package.json +13 -11
@@ -2,6 +2,18 @@ import type { QueryFunctionContext } from "@tanstack/query-core";
2
2
  export interface OverpassRequestOptions {
3
3
  signal?: AbortSignal;
4
4
  }
5
+ export type OverpassElement = {
6
+ type: "node" | "way" | "relation";
7
+ id: number;
8
+ tags?: Readonly<Record<string, string>>;
9
+ };
10
+ /** The JSON body of an Overpass interpreter answer. */
11
+ export type OverpassAnswer = {
12
+ elements: OverpassElement[];
13
+ remark?: string;
14
+ };
15
+ /** True for a body with an `elements` array, which Overpass always sends. */
16
+ export declare function isOverpassAnswer(value: unknown): value is OverpassAnswer;
5
17
  export interface OverpassProvider {
6
18
  name: string;
7
19
  /**
@@ -10,7 +22,7 @@ export interface OverpassProvider {
10
22
  */
11
23
  cacheKey?: string;
12
24
  /** Runs an Overpass QL query and resolves to the parsed JSON answer. */
13
- query(query: string, options?: OverpassRequestOptions): Promise<unknown>;
25
+ query(query: string, options?: OverpassRequestOptions): Promise<OverpassAnswer>;
14
26
  }
15
27
  export declare class OverpassError extends Error {
16
28
  readonly status?: number;
@@ -41,7 +53,7 @@ export interface OverpassQueryOptions {
41
53
  }
42
54
  export interface OverpassQuery {
43
55
  queryKey: readonly unknown[];
44
- queryFn: (context: Pick<QueryFunctionContext, "signal">) => Promise<unknown>;
56
+ queryFn: (context: Pick<QueryFunctionContext, "signal">) => Promise<OverpassAnswer>;
45
57
  enabled: boolean;
46
58
  staleTime: number;
47
59
  }
@@ -1,97 +1,90 @@
1
- class OverpassError extends Error {
2
- status;
3
- constructor(message, status) {
4
- super(message);
5
- this.name = "OverpassError";
6
- this.status = status;
7
- }
8
- }
9
- class OverpassRateLimitError extends OverpassError {
10
- constructor(message = "Overpass rate limit reached (429)") {
11
- super(message, 429);
12
- this.name = "OverpassRateLimitError";
13
- }
14
- }
15
- class OverpassTimeoutError extends OverpassError {
16
- constructor(message = "Overpass query timed out", status) {
17
- super(message, status);
18
- this.name = "OverpassTimeoutError";
19
- }
1
+ // src/geo/overpass.ts
2
+ /** True for a body with an `elements` array, which Overpass always sends. */
3
+ function isOverpassAnswer(value) {
4
+ return typeof value === "object" && value !== null && "elements" in value && Array.isArray(value.elements);
20
5
  }
6
+ var OverpassError = class extends Error {
7
+ status;
8
+ constructor(message, status) {
9
+ super(message);
10
+ this.name = "OverpassError";
11
+ this.status = status;
12
+ }
13
+ };
14
+ var OverpassRateLimitError = class extends OverpassError {
15
+ constructor(message = "Overpass rate limit reached (429)") {
16
+ super(message, 429);
17
+ this.name = "OverpassRateLimitError";
18
+ }
19
+ };
20
+ /** The server answered 504, or the client's own timeout fired. */
21
+ var OverpassTimeoutError = class extends OverpassError {
22
+ constructor(message = "Overpass query timed out", status) {
23
+ super(message, status);
24
+ this.name = "OverpassTimeoutError";
25
+ }
26
+ };
27
+ /**
28
+ * A query that hits the server's time or memory limit still answers 200, with
29
+ * the elements found so far and a `remark`. That partial list must not pass
30
+ * for a complete one.
31
+ */
21
32
  function throwOnRuntimeError(answer) {
22
- const remark = answer?.remark;
23
- if (typeof remark !== "string" || !/^runtime error/i.test(remark.trim())) {
24
- return;
25
- }
26
- throw /timed out/i.test(remark) ? new OverpassTimeoutError(`Overpass ${remark.trim()}`) : new OverpassError(`Overpass ${remark.trim()}`);
33
+ const { remark } = answer;
34
+ if (typeof remark !== "string" || !/^runtime error/i.test(remark.trim())) return;
35
+ throw /timed out/i.test(remark) ? new OverpassTimeoutError(`Overpass ${remark.trim()}`) : new OverpassError(`Overpass ${remark.trim()}`);
27
36
  }
28
37
  function createOverpassProvider(options) {
29
- const { endpoint } = options;
30
- if (typeof endpoint !== "string" || endpoint.trim() === "") {
31
- throw new TypeError(
32
- 'createOverpassProvider: the "endpoint" option is required'
33
- );
34
- }
35
- const url = endpoint.trim();
36
- const timeoutMs = options.timeoutMs ?? 3e4;
37
- const doFetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
38
- return {
39
- name: "overpass",
40
- cacheKey: `overpass|${url}`,
41
- async query(query, { signal } = {}) {
42
- const timer = new AbortController();
43
- let timedOut = false;
44
- const handle = setTimeout(() => {
45
- timedOut = true;
46
- timer.abort();
47
- }, timeoutMs);
48
- try {
49
- const response = await doFetch(url, {
50
- method: "POST",
51
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
52
- body: new URLSearchParams({ data: query }).toString(),
53
- signal: signal ? AbortSignal.any([signal, timer.signal]) : timer.signal
54
- });
55
- if (response.status === 429) throw new OverpassRateLimitError();
56
- if (response.status === 504) {
57
- throw new OverpassTimeoutError(
58
- "Overpass query timed out (504)",
59
- response.status
60
- );
61
- }
62
- if (!response.ok) {
63
- throw new OverpassError(
64
- `Overpass query failed (${response.status})`,
65
- response.status
66
- );
67
- }
68
- const answer = await response.json();
69
- throwOnRuntimeError(answer);
70
- return answer;
71
- } catch (error) {
72
- if (timedOut && !(error instanceof OverpassError)) {
73
- throw new OverpassTimeoutError();
74
- }
75
- throw error;
76
- } finally {
77
- clearTimeout(handle);
78
- }
79
- }
80
- };
38
+ const { endpoint } = options;
39
+ if (typeof endpoint !== "string" || endpoint.trim() === "") throw new TypeError("createOverpassProvider: the \"endpoint\" option is required");
40
+ const url = endpoint.trim();
41
+ const timeoutMs = options.timeoutMs ?? 3e4;
42
+ const doFetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
43
+ return {
44
+ name: "overpass",
45
+ cacheKey: `overpass|${url}`,
46
+ async query(query, { signal } = {}) {
47
+ const timer = new AbortController();
48
+ let timedOut = false;
49
+ const handle = setTimeout(() => {
50
+ timedOut = true;
51
+ timer.abort();
52
+ }, timeoutMs);
53
+ try {
54
+ const response = await doFetch(url, {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
57
+ body: new URLSearchParams({ data: query }).toString(),
58
+ signal: signal ? AbortSignal.any([signal, timer.signal]) : timer.signal
59
+ });
60
+ if (response.status === 429) throw new OverpassRateLimitError();
61
+ if (response.status === 504) throw new OverpassTimeoutError("Overpass query timed out (504)", response.status);
62
+ if (!response.ok) throw new OverpassError(`Overpass query failed (${response.status})`, response.status);
63
+ const answer = await response.json();
64
+ if (!isOverpassAnswer(answer)) throw new OverpassError("Overpass answered JSON without elements");
65
+ throwOnRuntimeError(answer);
66
+ return answer;
67
+ } catch (error) {
68
+ if (timedOut && !(error instanceof OverpassError)) throw new OverpassTimeoutError();
69
+ throw error;
70
+ } finally {
71
+ clearTimeout(handle);
72
+ }
73
+ }
74
+ };
81
75
  }
82
- const ONE_HOUR_MS = 60 * 60 * 1e3;
76
+ var ONE_HOUR_MS = 36e5;
77
+ /** Query options for `useQuery`; the query's `signal` reaches the provider. */
83
78
  function overpassQueryOptions(provider, query, options = {}) {
84
- return {
85
- queryKey: ["overpass", provider.cacheKey ?? provider.name, query],
86
- queryFn: ({ signal }) => provider.query(query, { signal }),
87
- enabled: query.trim() !== "",
88
- staleTime: options.staleTime ?? ONE_HOUR_MS
89
- };
79
+ return {
80
+ queryKey: [
81
+ "overpass",
82
+ provider.cacheKey ?? provider.name,
83
+ query
84
+ ],
85
+ queryFn: ({ signal }) => provider.query(query, { signal }),
86
+ enabled: query.trim() !== "",
87
+ staleTime: options.staleTime ?? ONE_HOUR_MS
88
+ };
90
89
  }
91
- export {
92
- OverpassError,
93
- OverpassRateLimitError,
94
- OverpassTimeoutError,
95
- createOverpassProvider,
96
- overpassQueryOptions
97
- };
90
+ export { OverpassError, OverpassRateLimitError, OverpassTimeoutError, createOverpassProvider, isOverpassAnswer, overpassQueryOptions };
@@ -1,8 +1,11 @@
1
- import type { GeoBBox, GeoFeature, GeoJsonValue } from "./geojson.js";
1
+ import type { Feature, FeatureCollection, Geometry } from "geojson";
2
+ import type { JsonObject } from "../guards.js";
3
+ import type { LngLatBox } from "./bounds.js";
2
4
  /** What a drawing input stores in its form field. */
3
5
  export type ShapeValueKind = "Point" | "MultiPoint" | "LineString" | "MultiLineString" | "Polygon" | "MultiPolygon" | "GeometryCollection" | "Geometry" | "Feature" | "FeatureCollection" | "BBox";
4
6
  /** A form value of any {@link ShapeValueKind}. */
5
- export type ShapeValue = GeoJsonValue | GeoBBox;
7
+ export type ShapeValue = Geometry | Feature<Geometry | null, JsonObject | null> | FeatureCollection<Geometry | null, JsonObject | null> | LngLatBox;
8
+ type ShapeFeature = Feature<Geometry | null, JsonObject | null>;
6
9
  export interface FeaturesToShapeOptions {
7
10
  /** Width over height of a `BBox` value. */
8
11
  aspectRatio?: number;
@@ -18,14 +21,14 @@ export interface FeaturesToShapeOptions {
18
21
  * ring. A Multi kind gives one feature per part and a GeometryCollection one
19
22
  * per geometry. A value of the wrong kind, null or malformed gives `[]`.
20
23
  */
21
- export declare function shapeToFeatures(kind: ShapeValueKind, value: unknown): GeoFeature[];
24
+ export declare function shapeToFeatures(kind: ShapeValueKind, value: unknown): ShapeFeature[];
22
25
  /**
23
26
  * The parts of a value the editor cannot hold: a Polygon with holes, and a
24
27
  * FeatureCollection feature with no geometry, a GeometryCollection or a Multi
25
28
  * geometry, and a Multi geometry inside a GeometryCollection. The Geometry kind
26
29
  * holds a GeometryCollection whole. {@link featuresToShape} puts them back.
27
30
  */
28
- export declare function heldFeatures(kind: ShapeValueKind, value: unknown): GeoFeature[];
31
+ export declare function heldFeatures(kind: ShapeValueKind, value: unknown): ShapeFeature[];
29
32
  /**
30
33
  * The value to store for the editor's `features`, or `null` when none is left.
31
34
  * `prev` is the value being edited: its held parts come back, and a Feature
@@ -33,4 +36,5 @@ export declare function heldFeatures(kind: ShapeValueKind, value: unknown): GeoF
33
36
  * last feature, since a new drawing replaces the old shape. A FeatureCollection
34
37
  * keeps its other members, such as `name` and `crs`, but not its `bbox`.
35
38
  */
36
- export declare function featuresToShape(kind: ShapeValueKind, features: GeoFeature[], prev: unknown, options?: FeaturesToShapeOptions): ShapeValue | null;
39
+ export declare function featuresToShape(kind: ShapeValueKind, features: ShapeFeature[], prev: unknown, options?: FeaturesToShapeOptions): ShapeValue | null;
40
+ export {};
@@ -1,172 +1,195 @@
1
- import { polygonToBBox, aspectLockedBBox, bboxToPolygon } from "./bbox.js";
2
- import { isGeoFeatureCollection, isGeoFeature, isGeoGeometry } from "./geojson.js";
1
+ import { aspectLockedBBox, bboxToPolygon, polygonToBBox } from "./bbox.js";
2
+ import { isGeoFeature, isGeoFeatureCollection, isGeoGeometry } from "./geojson.js";
3
+ // src/geo/shape-value.ts
3
4
  function wrap(geometry) {
4
- return { type: "Feature", geometry, properties: {} };
5
+ return {
6
+ type: "Feature",
7
+ geometry,
8
+ properties: {}
9
+ };
5
10
  }
11
+ /**
12
+ * One geometry per part of a Multi geometry or a GeometryCollection. A Multi
13
+ * geometry or a GeometryCollection inside a GeometryCollection stays whole, so
14
+ * it is held and written back as it was.
15
+ */
6
16
  function singles(geometry) {
7
- switch (geometry.type) {
8
- case "MultiPoint":
9
- return geometry.coordinates.map((coordinates) => ({
10
- type: "Point",
11
- coordinates
12
- }));
13
- case "MultiLineString":
14
- return geometry.coordinates.map((coordinates) => ({
15
- type: "LineString",
16
- coordinates
17
- }));
18
- case "MultiPolygon":
19
- return geometry.coordinates.map((coordinates) => ({
20
- type: "Polygon",
21
- coordinates
22
- }));
23
- case "GeometryCollection":
24
- return geometry.geometries;
25
- default:
26
- return [geometry];
27
- }
17
+ switch (geometry.type) {
18
+ case "MultiPoint": return geometry.coordinates.map((coordinates) => ({
19
+ type: "Point",
20
+ coordinates
21
+ }));
22
+ case "MultiLineString": return geometry.coordinates.map((coordinates) => ({
23
+ type: "LineString",
24
+ coordinates
25
+ }));
26
+ case "MultiPolygon": return geometry.coordinates.map((coordinates) => ({
27
+ type: "Polygon",
28
+ coordinates
29
+ }));
30
+ case "GeometryCollection": return geometry.geometries;
31
+ default: return [geometry];
32
+ }
28
33
  }
34
+ /** The editor holds a Point, a LineString and a Polygon with one ring. */
29
35
  function isEditable(geometry) {
30
- if (!geometry) return false;
31
- if (geometry.type === "Point" || geometry.type === "LineString") return true;
32
- return geometry.type === "Polygon" && geometry.coordinates.length === 1;
36
+ if (!geometry) return false;
37
+ if (geometry.type === "Point" || geometry.type === "LineString") return true;
38
+ return geometry.type === "Polygon" && geometry.coordinates.length === 1;
33
39
  }
40
+ /** A Polygon with no ring has nothing to hold or to show. */
34
41
  function isEmptyPolygon(geometry) {
35
- return geometry.type === "Polygon" && geometry.coordinates.length === 0;
42
+ return geometry.type === "Polygon" && geometry.coordinates.length === 0;
36
43
  }
37
44
  function splitGeometries(geometries) {
38
- const editable = [];
39
- const held = [];
40
- for (const geometry of geometries) {
41
- if (isEditable(geometry)) editable.push(wrap(geometry));
42
- else if (!isEmptyPolygon(geometry)) held.push(wrap(geometry));
43
- }
44
- return { editable, held };
45
+ const editable = [];
46
+ const held = [];
47
+ for (const geometry of geometries) if (isEditable(geometry)) editable.push(wrap(geometry));
48
+ else if (!isEmptyPolygon(geometry)) held.push(wrap(geometry));
49
+ return {
50
+ editable,
51
+ held
52
+ };
45
53
  }
46
54
  function splitFeatures(features) {
47
- const editable = [];
48
- const held = [];
49
- for (const feature of features) {
50
- (isEditable(feature.geometry) ? editable : held).push(feature);
51
- }
52
- return { editable, held };
55
+ const editable = [];
56
+ const held = [];
57
+ for (const feature of features) (isEditable(feature.geometry) ? editable : held).push(feature);
58
+ return {
59
+ editable,
60
+ held
61
+ };
53
62
  }
54
- const NOTHING = { editable: [], held: [] };
63
+ var NOTHING = {
64
+ editable: [],
65
+ held: []
66
+ };
55
67
  function split(kind, value) {
56
- switch (kind) {
57
- case "Point":
58
- case "LineString":
59
- case "Polygon":
60
- return isGeoGeometry(value) && value.type === kind ? splitGeometries([value]) : NOTHING;
61
- case "MultiPoint":
62
- case "MultiLineString":
63
- case "MultiPolygon":
64
- case "GeometryCollection":
65
- return isGeoGeometry(value) && value.type === kind ? splitGeometries(singles(value)) : NOTHING;
66
- case "Geometry":
67
- return isGeoGeometry(value) ? splitGeometries([value]) : NOTHING;
68
- case "Feature":
69
- return isGeoFeature(value) ? splitFeatures([value]) : NOTHING;
70
- case "FeatureCollection":
71
- return isGeoFeatureCollection(value) ? splitFeatures(value.features) : NOTHING;
72
- case "BBox": {
73
- const polygon = bboxToPolygon(value);
74
- return polygon ? splitGeometries([polygon]) : NOTHING;
75
- }
76
- }
68
+ switch (kind) {
69
+ case "Point":
70
+ case "LineString":
71
+ case "Polygon": return isGeoGeometry(value) && value.type === kind ? splitGeometries([value]) : NOTHING;
72
+ case "MultiPoint":
73
+ case "MultiLineString":
74
+ case "MultiPolygon":
75
+ case "GeometryCollection": return isGeoGeometry(value) && value.type === kind ? splitGeometries(singles(value)) : NOTHING;
76
+ case "Geometry": return isGeoGeometry(value) ? splitGeometries([value]) : NOTHING;
77
+ case "Feature": return isGeoFeature(value) ? splitFeatures([value]) : NOTHING;
78
+ case "FeatureCollection": return isGeoFeatureCollection(value) ? splitFeatures(value.features) : NOTHING;
79
+ case "BBox": {
80
+ const polygon = bboxToPolygon(value);
81
+ return polygon ? splitGeometries([polygon]) : NOTHING;
82
+ }
83
+ }
77
84
  }
85
+ /**
86
+ * The features the editor can hold: Points, LineStrings and Polygons with one
87
+ * ring. A Multi kind gives one feature per part and a GeometryCollection one
88
+ * per geometry. A value of the wrong kind, null or malformed gives `[]`.
89
+ */
78
90
  function shapeToFeatures(kind, value) {
79
- return split(kind, value).editable;
91
+ return split(kind, value).editable;
80
92
  }
93
+ /**
94
+ * The parts of a value the editor cannot hold: a Polygon with holes, and a
95
+ * FeatureCollection feature with no geometry, a GeometryCollection or a Multi
96
+ * geometry, and a Multi geometry inside a GeometryCollection. The Geometry kind
97
+ * holds a GeometryCollection whole. {@link featuresToShape} puts them back.
98
+ */
81
99
  function heldFeatures(kind, value) {
82
- return split(kind, value).held;
100
+ return split(kind, value).held;
83
101
  }
102
+ /** The geometry of the last feature, of `type` when given. */
84
103
  function lastGeometry(features, type) {
85
- for (let i = features.length - 1; i >= 0; i--) {
86
- const geometry = features[i]?.geometry;
87
- if (!geometry) continue;
88
- if (type ? geometry.type === type : geometry.type !== "GeometryCollection") {
89
- return geometry;
90
- }
91
- }
92
- return null;
104
+ for (let i = features.length - 1; i >= 0; i--) {
105
+ const geometry = features[i]?.geometry;
106
+ if (!geometry) continue;
107
+ if (type ? geometry.type === type : geometry.type !== "GeometryCollection") return geometry;
108
+ }
109
+ return null;
93
110
  }
94
111
  function joinMulti(kind, geometries) {
95
- switch (kind) {
96
- case "MultiPoint": {
97
- const coordinates = geometries.flatMap(
98
- (g) => g.type === "Point" ? [g.coordinates] : []
99
- );
100
- return coordinates.length ? { type: "MultiPoint", coordinates } : null;
101
- }
102
- case "MultiLineString": {
103
- const coordinates = geometries.flatMap(
104
- (g) => g.type === "LineString" ? [g.coordinates] : []
105
- );
106
- return coordinates.length ? { type: "MultiLineString", coordinates } : null;
107
- }
108
- case "MultiPolygon": {
109
- const coordinates = geometries.flatMap(
110
- (g) => g.type === "Polygon" ? [g.coordinates] : []
111
- );
112
- return coordinates.length ? { type: "MultiPolygon", coordinates } : null;
113
- }
114
- }
112
+ switch (kind) {
113
+ case "MultiPoint": {
114
+ const coordinates = geometries.flatMap((g) => g.type === "Point" ? [g.coordinates] : []);
115
+ return coordinates.length ? {
116
+ type: "MultiPoint",
117
+ coordinates
118
+ } : null;
119
+ }
120
+ case "MultiLineString": {
121
+ const coordinates = geometries.flatMap((g) => g.type === "LineString" ? [g.coordinates] : []);
122
+ return coordinates.length ? {
123
+ type: "MultiLineString",
124
+ coordinates
125
+ } : null;
126
+ }
127
+ case "MultiPolygon": {
128
+ const coordinates = geometries.flatMap((g) => g.type === "Polygon" ? [g.coordinates] : []);
129
+ return coordinates.length ? {
130
+ type: "MultiPolygon",
131
+ coordinates
132
+ } : null;
133
+ }
134
+ }
115
135
  }
116
136
  function heldGeometries(kind, prev, addHeld) {
117
- if (!addHeld) return [];
118
- return heldFeatures(kind, prev).flatMap(
119
- (f) => f.geometry ? [f.geometry] : []
120
- );
137
+ if (!addHeld) return [];
138
+ return heldFeatures(kind, prev).flatMap((f) => f.geometry ? [f.geometry] : []);
121
139
  }
140
+ /**
141
+ * The value to store for the editor's `features`, or `null` when none is left.
142
+ * `prev` is the value being edited: its held parts come back, and a Feature
143
+ * keeps its `id`, `properties` and other members. A single kind takes the
144
+ * last feature, since a new drawing replaces the old shape. A FeatureCollection
145
+ * keeps its other members, such as `name` and `crs`, but not its `bbox`.
146
+ */
122
147
  function featuresToShape(kind, features, prev, options = {}) {
123
- const addHeld = options.addHeld ?? true;
124
- switch (kind) {
125
- case "Point":
126
- case "LineString":
127
- case "Polygon":
128
- return lastGeometry(features, kind);
129
- case "Geometry":
130
- return lastGeometry(features);
131
- case "MultiPoint":
132
- case "MultiLineString":
133
- case "MultiPolygon":
134
- return joinMulti(kind, [
135
- ...features.flatMap((f) => f.geometry ? [f.geometry] : []),
136
- ...heldGeometries(kind, prev, addHeld)
137
- ]);
138
- case "GeometryCollection": {
139
- const geometries = [
140
- ...features.flatMap((f) => f.geometry ? [f.geometry] : []),
141
- ...heldGeometries(kind, prev, addHeld)
142
- ];
143
- return geometries.length ? { type: "GeometryCollection", geometries } : null;
144
- }
145
- case "Feature": {
146
- const geometry = lastGeometry(features);
147
- if (!geometry) return null;
148
- if (!isGeoFeature(prev)) {
149
- return { type: "Feature", geometry, properties: {} };
150
- }
151
- const { bbox: _bbox, ...rest } = prev;
152
- return { ...rest, geometry };
153
- }
154
- case "FeatureCollection": {
155
- const all = addHeld ? [...features, ...heldFeatures(kind, prev)] : features;
156
- if (!all.length) return null;
157
- const { bbox: _bbox, ...rest } = isGeoFeatureCollection(prev) ? prev : {};
158
- return { ...rest, type: "FeatureCollection", features: all };
159
- }
160
- case "BBox": {
161
- const polygon = lastGeometry(features, "Polygon");
162
- if (!polygon) return null;
163
- const toBBox = options.aspectRatio === void 0 ? polygonToBBox : aspectLockedBBox(options.aspectRatio);
164
- return toBBox(polygon);
165
- }
166
- }
148
+ const addHeld = options.addHeld ?? true;
149
+ switch (kind) {
150
+ case "Point":
151
+ case "LineString":
152
+ case "Polygon": return lastGeometry(features, kind);
153
+ case "Geometry": return lastGeometry(features);
154
+ case "MultiPoint":
155
+ case "MultiLineString":
156
+ case "MultiPolygon": return joinMulti(kind, [...features.flatMap((f) => f.geometry ? [f.geometry] : []), ...heldGeometries(kind, prev, addHeld)]);
157
+ case "GeometryCollection": {
158
+ const geometries = [...features.flatMap((f) => f.geometry ? [f.geometry] : []), ...heldGeometries(kind, prev, addHeld)];
159
+ return geometries.length ? {
160
+ type: "GeometryCollection",
161
+ geometries
162
+ } : null;
163
+ }
164
+ case "Feature": {
165
+ const geometry = lastGeometry(features);
166
+ if (!geometry) return null;
167
+ if (!isGeoFeature(prev)) return {
168
+ type: "Feature",
169
+ geometry,
170
+ properties: {}
171
+ };
172
+ const { bbox: _bbox, ...rest } = prev;
173
+ return {
174
+ ...rest,
175
+ geometry
176
+ };
177
+ }
178
+ case "FeatureCollection": {
179
+ const all = addHeld ? [...features, ...heldFeatures(kind, prev)] : features;
180
+ if (!all.length) return null;
181
+ const { bbox: _bbox, ...rest } = isGeoFeatureCollection(prev) ? prev : {};
182
+ return {
183
+ ...rest,
184
+ type: "FeatureCollection",
185
+ features: all
186
+ };
187
+ }
188
+ case "BBox": {
189
+ const polygon = lastGeometry(features, "Polygon");
190
+ if (!polygon) return null;
191
+ return (options.aspectRatio === void 0 ? polygonToBBox : aspectLockedBBox(options.aspectRatio))(polygon);
192
+ }
193
+ }
167
194
  }
168
- export {
169
- featuresToShape,
170
- heldFeatures,
171
- shapeToFeatures
172
- };
195
+ export { featuresToShape, heldFeatures, shapeToFeatures };
@@ -1,10 +1,10 @@
1
- import type { GeoLineString } from "./geojson.js";
1
+ import type { LineString } from "geojson";
2
2
  export interface RoutingProvider {
3
3
  name: string;
4
4
  /** Resolves to the line matched to roads, or `null` when it cannot be. */
5
- snapToRoad(line: GeoLineString, options?: {
5
+ snapToRoad(line: LineString, options?: {
6
6
  signal?: AbortSignal;
7
- }): Promise<GeoLineString | null>;
7
+ }): Promise<LineString | null>;
8
8
  }
9
9
  export interface OsrmProviderOptions {
10
10
  /**