@chelone/core 0.6.0 → 0.7.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.
- package/dist/assistant/assistant-session.d.ts +6 -0
- package/dist/assistant/assistant-session.js +204 -181
- package/dist/assistant/echo-transport.js +26 -29
- package/dist/assistant/http-transport.d.ts +10 -0
- package/dist/assistant/http-transport.js +98 -0
- package/dist/assistant/types.d.ts +1 -7
- package/dist/auth/access-control.d.ts +13 -5
- package/dist/auth/access-control.js +25 -21
- package/dist/auth/auth-options.d.ts +21 -17
- package/dist/auth/auth-options.js +80 -48
- package/dist/auth/permission-matrix.d.ts +12 -0
- package/dist/auth/permission-matrix.js +67 -0
- package/dist/auth/types.d.ts +14 -4
- package/dist/block-editor/block-document.d.ts +60 -0
- package/dist/block-editor/block-document.js +143 -0
- package/dist/block-editor/data-blocks.d.ts +63 -0
- package/dist/block-editor/data-blocks.js +117 -0
- package/dist/chart/chart-data.js +46 -44
- package/dist/command-menu/hotkey.js +58 -47
- package/dist/command-menu/recents.js +8 -11
- package/dist/command-menu/registry.d.ts +9 -5
- package/dist/command-menu/registry.js +36 -46
- package/dist/controller/calendar-dates.js +82 -113
- package/dist/controller/calendar-events.js +93 -88
- package/dist/controller/client-list-controller.d.ts +2 -2
- package/dist/controller/client-list-controller.js +251 -254
- package/dist/controller/data-table-columns.d.ts +2 -0
- package/dist/controller/data-table-columns.js +50 -56
- package/dist/controller/deep-equal.d.ts +1 -0
- package/dist/controller/deep-equal.js +14 -0
- package/dist/controller/filter-toggle.js +36 -44
- package/dist/controller/in-place-editor.d.ts +42 -0
- package/dist/controller/in-place-editor.js +42 -0
- package/dist/controller/infinite-list-controller.js +219 -189
- package/dist/controller/inspector.d.ts +49 -0
- package/dist/controller/inspector.js +64 -0
- package/dist/controller/job-monitor.d.ts +3 -4
- package/dist/controller/job-monitor.js +37 -47
- package/dist/controller/kanban-board.d.ts +2 -3
- package/dist/controller/kanban-board.js +43 -24
- package/dist/controller/list-controller.d.ts +5 -5
- package/dist/controller/list-controller.js +444 -400
- package/dist/controller/list-params.js +96 -87
- package/dist/controller/pivot-grid.js +89 -95
- package/dist/controller/prev-next.d.ts +2 -2
- package/dist/controller/prev-next.js +74 -54
- package/dist/controller/record-controllers.d.ts +14 -6
- package/dist/controller/record-controllers.js +288 -257
- package/dist/controller/record-diff.d.ts +21 -0
- package/dist/controller/record-diff.js +50 -0
- package/dist/controller/record-timeline.js +42 -30
- package/dist/controller/record-tree.js +57 -47
- package/dist/controller/record-workflow.d.ts +38 -16
- package/dist/controller/record-workflow.js +85 -64
- package/dist/controller/reference-many-controller.js +198 -192
- package/dist/controller/reference-one-controller.d.ts +1 -1
- package/dist/controller/reference-one-controller.js +63 -56
- package/dist/controller/saved-queries.js +104 -91
- package/dist/controller/translate-fallback.js +10 -6
- package/dist/csv/export.d.ts +2 -1
- package/dist/csv/export.js +43 -40
- package/dist/csv/import-controller.js +185 -169
- package/dist/csv/match-headers.js +29 -22
- package/dist/csv/parse-with.js +60 -54
- package/dist/csv/run-import.js +69 -72
- package/dist/csv/validate-rows.d.ts +1 -1
- package/dist/csv/validate-rows.js +65 -52
- package/dist/data/cache-ops.d.ts +5 -4
- package/dist/data/cache-ops.js +208 -188
- package/dist/data/combine-data-providers.js +25 -23
- package/dist/data/data-provider-log.d.ts +45 -0
- package/dist/data/data-provider-log.js +93 -0
- package/dist/data/errors.js +14 -10
- package/dist/data/fake-provider.d.ts +6 -3
- package/dist/data/fake-provider.js +129 -114
- package/dist/data/fetch-utils.js +61 -44
- package/dist/data/filter-branch.d.ts +5 -0
- package/dist/data/filter-branch.js +10 -0
- package/dist/data/get-many-aggregate.js +84 -76
- package/dist/data/http-error.js +17 -12
- package/dist/data/keys.js +50 -36
- package/dist/data/mutation-options.d.ts +14 -9
- package/dist/data/mutation-options.js +93 -109
- package/dist/data/query-options.js +73 -68
- package/dist/data/remove-empty.d.ts +3 -0
- package/dist/data/remove-empty.js +11 -0
- package/dist/data/undoable.d.ts +2 -2
- package/dist/data/undoable.js +190 -174
- package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
- package/dist/data/with-lifecycle-callbacks.js +66 -52
- package/dist/environment/application-update-store.js +58 -55
- package/dist/environment/offline-store.js +21 -21
- package/dist/form/array-binding.d.ts +30 -11
- package/dist/form/array-binding.js +184 -166
- package/dist/form/choice-ids.d.ts +7 -0
- package/dist/form/choice-ids.js +11 -0
- package/dist/form/choices-controller.d.ts +3 -2
- package/dist/form/choices-controller.js +302 -275
- package/dist/form/date-format.d.ts +38 -0
- package/dist/form/date-format.js +89 -0
- package/dist/form/dirty-values.d.ts +2 -2
- package/dist/form/dirty-values.js +22 -11
- package/dist/form/duration.d.ts +22 -0
- package/dist/form/duration.js +49 -0
- package/dist/form/edit-create-form.d.ts +12 -5
- package/dist/form/edit-create-form.js +243 -188
- package/dist/form/event-value.d.ts +6 -0
- package/dist/form/event-value.js +17 -0
- package/dist/form/field-error.d.ts +14 -0
- package/dist/form/field-error.js +28 -0
- package/dist/form/field-name.d.ts +20 -0
- package/dist/form/field-name.js +6 -0
- package/dist/form/filter-form-values.js +63 -49
- package/dist/form/form-controller.d.ts +9 -1
- package/dist/form/form-controller.js +165 -160
- package/dist/form/form-groups.d.ts +4 -3
- package/dist/form/form-groups.js +79 -79
- package/dist/form/form-handle.d.ts +175 -0
- package/dist/form/form-handle.js +68 -0
- package/dist/form/input-binding.d.ts +56 -31
- package/dist/form/input-binding.js +169 -118
- package/dist/form/input-values.d.ts +130 -0
- package/dist/form/input-values.js +177 -0
- package/dist/form/json-text.js +51 -37
- package/dist/form/save-pipeline.d.ts +6 -8
- package/dist/form/save-pipeline.js +91 -82
- package/dist/form/set-form-values.d.ts +6 -0
- package/dist/form/set-form-values.js +10 -0
- package/dist/form/source.js +97 -65
- package/dist/form/text-of.d.ts +2 -0
- package/dist/form/text-of.js +7 -0
- package/dist/form/validators.d.ts +58 -19
- package/dist/form/validators.js +97 -71
- package/dist/geo/bbox.d.ts +5 -4
- package/dist/geo/bbox.js +69 -48
- package/dist/geo/bounds.d.ts +14 -3
- package/dist/geo/bounds.js +98 -68
- package/dist/geo/constraints.js +88 -93
- package/dist/geo/coordinates.js +31 -23
- package/dist/geo/editor.d.ts +13 -13
- package/dist/geo/editor.js +176 -153
- package/dist/geo/geocoding.d.ts +4 -4
- package/dist/geo/geocoding.js +38 -41
- package/dist/geo/geojson.d.ts +12 -74
- package/dist/geo/geojson.js +52 -40
- package/dist/geo/geometry-math.d.ts +4 -4
- package/dist/geo/geometry-math.js +100 -93
- package/dist/geo/index.d.ts +7 -6
- package/dist/geo/map-layers.d.ts +42 -7
- package/dist/geo/map-layers.js +88 -62
- package/dist/geo/map-style.js +31 -32
- package/dist/geo/messages.js +48 -45
- package/dist/geo/nominatim.js +88 -80
- package/dist/geo/osm-presets.d.ts +4 -3
- package/dist/geo/osm-presets.js +108 -86
- package/dist/geo/osm-tags.js +14 -12
- package/dist/geo/overpass.d.ts +14 -2
- package/dist/geo/overpass.js +83 -90
- package/dist/geo/shape-value.d.ts +9 -5
- package/dist/geo/shape-value.js +169 -146
- package/dist/geo/snap-to-roads.d.ts +3 -3
- package/dist/geo/snap-to-roads.js +55 -50
- package/dist/geo/throttle.js +36 -39
- package/dist/guards.d.ts +37 -0
- package/dist/guards.js +62 -0
- package/dist/i18n/default-messages.js +34 -29
- package/dist/i18n/english-messages.js +187 -189
- package/dist/i18n/i18n.d.ts +2 -2
- package/dist/i18n/i18n.js +47 -60
- package/dist/i18n/inflection.d.ts +34 -0
- package/dist/i18n/inflection.js +82 -0
- package/dist/i18n/messages.d.ts +10 -2
- package/dist/i18n/messages.js +17 -4
- package/dist/i18n/missing-keys.js +66 -62
- package/dist/i18n/translatable.d.ts +16 -1
- package/dist/i18n/translatable.js +40 -47
- package/dist/index.d.ts +71 -24
- package/dist/index.js +40 -288
- package/dist/json/deep-equal.d.ts +8 -0
- package/dist/json/deep-equal.js +24 -0
- package/dist/json/strip-json-comments.js +38 -42
- package/dist/noop.d.ts +2 -0
- package/dist/noop.js +4 -0
- package/dist/notification/error-message.d.ts +2 -0
- package/dist/notification/error-message.js +10 -0
- package/dist/notification/notification-store.d.ts +3 -2
- package/dist/notification/notification-store.js +41 -45
- package/dist/onboarding-tour/placement.js +63 -78
- package/dist/onboarding-tour/tour-controller.js +46 -54
- package/dist/realtime/add-events-for-mutations.js +75 -81
- package/dist/realtime/announce-lock.js +16 -13
- package/dist/realtime/broadcast-channel-transport.js +65 -59
- package/dist/realtime/copy-members.js +22 -14
- package/dist/realtime/in-memory-lock-provider.js +40 -48
- package/dist/realtime/live.js +95 -101
- package/dist/realtime/lock-options.js +16 -16
- package/dist/realtime/lock-session.js +91 -78
- package/dist/realtime/memory-transport.js +25 -25
- package/dist/realtime/presence.js +120 -122
- package/dist/realtime/realtime-data-provider.d.ts +10 -0
- package/dist/realtime/realtime-data-provider.js +45 -42
- package/dist/realtime/reconnect-backoff.js +17 -0
- package/dist/realtime/sse-transport.d.ts +31 -0
- package/dist/realtime/sse-transport.js +235 -0
- package/dist/realtime/status-store.js +23 -28
- package/dist/realtime/topic-hub.js +62 -71
- package/dist/realtime/topics.js +10 -12
- package/dist/realtime/types.js +10 -12
- package/dist/realtime/unread-count.js +21 -21
- package/dist/realtime/websocket-transport.d.ts +32 -0
- package/dist/realtime/websocket-transport.js +306 -0
- package/dist/resource/describe-resource.d.ts +2 -0
- package/dist/resource/describe-resource.js +232 -219
- package/dist/resource/get-at-path.js +29 -14
- package/dist/resource/identifier.d.ts +18 -0
- package/dist/resource/identifier.js +27 -0
- package/dist/resource/record.d.ts +4 -0
- package/dist/resource/record.js +10 -0
- package/dist/resource/register.d.ts +7 -0
- package/dist/resource/registry-store.d.ts +45 -15
- package/dist/resource/registry-store.js +67 -60
- package/dist/resource/registry.d.ts +10 -0
- package/dist/resource/registry.js +8 -4
- package/dist/resource/source-path.d.ts +16 -1
- package/dist/rich-text/rich-text-extras.d.ts +132 -0
- package/dist/rich-text/rich-text-extras.js +179 -0
- package/dist/rich-text/rich-text-image.d.ts +124 -0
- package/dist/rich-text/rich-text-image.js +163 -0
- package/dist/rich-text/rich-text.d.ts +6 -0
- package/dist/rich-text/rich-text.js +125 -88
- package/dist/router/location.d.ts +22 -4
- package/dist/router/location.js +41 -18
- package/dist/router/match.js +47 -39
- package/dist/router/paths.js +40 -34
- package/dist/router/record-from-location.d.ts +1 -1
- package/dist/router/record-from-location.js +25 -17
- package/dist/store/adapters.js +51 -55
- package/dist/store/micro-store.js +57 -59
- package/dist/store/shallow-equal.d.ts +12 -0
- package/dist/store/shallow-equal.js +20 -0
- package/dist/store/store.js +54 -57
- package/package.json +13 -11
package/dist/geo/overpass.d.ts
CHANGED
|
@@ -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<
|
|
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<
|
|
56
|
+
queryFn: (context: Pick<QueryFunctionContext, "signal">) => Promise<OverpassAnswer>;
|
|
45
57
|
enabled: boolean;
|
|
46
58
|
staleTime: number;
|
|
47
59
|
}
|
package/dist/geo/overpass.js
CHANGED
|
@@ -1,97 +1,90 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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 {
|
|
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 =
|
|
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):
|
|
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):
|
|
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:
|
|
39
|
+
export declare function featuresToShape(kind: ShapeValueKind, features: ShapeFeature[], prev: unknown, options?: FeaturesToShapeOptions): ShapeValue | null;
|
|
40
|
+
export {};
|
package/dist/geo/shape-value.js
CHANGED
|
@@ -1,172 +1,195 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
42
|
+
return geometry.type === "Polygon" && geometry.coordinates.length === 0;
|
|
36
43
|
}
|
|
37
44
|
function splitGeometries(geometries) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
63
|
+
var NOTHING = {
|
|
64
|
+
editable: [],
|
|
65
|
+
held: []
|
|
66
|
+
};
|
|
55
67
|
function split(kind, value) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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 {
|
|
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:
|
|
5
|
+
snapToRoad(line: LineString, options?: {
|
|
6
6
|
signal?: AbortSignal;
|
|
7
|
-
}): Promise<
|
|
7
|
+
}): Promise<LineString | null>;
|
|
8
8
|
}
|
|
9
9
|
export interface OsrmProviderOptions {
|
|
10
10
|
/**
|