@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/bounds.js
CHANGED
|
@@ -1,74 +1,104 @@
|
|
|
1
|
-
|
|
1
|
+
// src/geo/bounds.ts
|
|
2
|
+
var MAX_LONGITUDE = 540;
|
|
3
|
+
/**
|
|
4
|
+
* The `[west, east]` arc over `longitudes`, which wraps (west greater than
|
|
5
|
+
* east) when going round the antimeridian is narrower. Left plain when a value
|
|
6
|
+
* is no longitude, such as a projected coordinate.
|
|
7
|
+
*/
|
|
2
8
|
function longitudeArc(longitudes, west, east, mode) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
24
|
-
return arc;
|
|
9
|
+
if (east <= 180 && (mode === "explicit" || east - west <= 180)) return [west, east];
|
|
10
|
+
const wrapped = /* @__PURE__ */ new Set();
|
|
11
|
+
for (const longitude of longitudes) {
|
|
12
|
+
if (longitude < -180 || longitude > MAX_LONGITUDE) return [west, east];
|
|
13
|
+
wrapped.add(longitude > 180 ? longitude - 360 : longitude);
|
|
14
|
+
}
|
|
15
|
+
const sorted = [...wrapped].sort((x, y) => x - y);
|
|
16
|
+
const min = sorted[0] ?? west;
|
|
17
|
+
const max = sorted[sorted.length - 1] ?? east;
|
|
18
|
+
let widest = 360 - (max - min);
|
|
19
|
+
if (widest <= 0) return [min, max];
|
|
20
|
+
let arc = [min, max];
|
|
21
|
+
sorted.forEach((longitude, i) => {
|
|
22
|
+
const gap = longitude - (sorted[i - 1] ?? longitude);
|
|
23
|
+
if (gap > widest) {
|
|
24
|
+
widest = gap;
|
|
25
|
+
arc = [longitude, sorted[i - 1] ?? longitude];
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return arc;
|
|
25
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* `[west, south, east, north]` over every position of a geometry, Feature or
|
|
32
|
+
* FeatureCollection; `null` when there is none. Altitude is ignored. When the
|
|
33
|
+
* longitudes are narrower going round the antimeridian, west is greater than
|
|
34
|
+
* east.
|
|
35
|
+
*/
|
|
26
36
|
function geoBounds(value, mode = "narrowest") {
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
37
|
+
const state = { box: null };
|
|
38
|
+
const longitudes = /* @__PURE__ */ new Set();
|
|
39
|
+
const extend = (position) => {
|
|
40
|
+
const [longitude, latitude] = position;
|
|
41
|
+
if (longitude === void 0 || latitude === void 0) return;
|
|
42
|
+
longitudes.add(longitude);
|
|
43
|
+
const box = state.box;
|
|
44
|
+
if (!box) {
|
|
45
|
+
state.box = [
|
|
46
|
+
longitude,
|
|
47
|
+
latitude,
|
|
48
|
+
longitude,
|
|
49
|
+
latitude
|
|
50
|
+
];
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
box[0] = Math.min(box[0], longitude);
|
|
54
|
+
box[1] = Math.min(box[1], latitude);
|
|
55
|
+
box[2] = Math.max(box[2], longitude);
|
|
56
|
+
box[3] = Math.max(box[3], latitude);
|
|
57
|
+
};
|
|
58
|
+
const walk = (node) => {
|
|
59
|
+
if (!node) return;
|
|
60
|
+
switch (node.type) {
|
|
61
|
+
case "FeatureCollection":
|
|
62
|
+
for (const feature of node.features) walk(feature);
|
|
63
|
+
break;
|
|
64
|
+
case "Feature":
|
|
65
|
+
walk(node.geometry);
|
|
66
|
+
break;
|
|
67
|
+
case "GeometryCollection":
|
|
68
|
+
for (const geometry of node.geometries) walk(geometry);
|
|
69
|
+
break;
|
|
70
|
+
case "Point":
|
|
71
|
+
extend(node.coordinates);
|
|
72
|
+
break;
|
|
73
|
+
case "MultiPoint":
|
|
74
|
+
case "LineString":
|
|
75
|
+
for (const position of node.coordinates) extend(position);
|
|
76
|
+
break;
|
|
77
|
+
case "MultiLineString":
|
|
78
|
+
case "Polygon":
|
|
79
|
+
for (const line of node.coordinates) for (const position of line) extend(position);
|
|
80
|
+
break;
|
|
81
|
+
case "MultiPolygon": for (const polygon of node.coordinates) for (const ring of polygon) for (const position of ring) extend(position);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
walk(value);
|
|
85
|
+
if (!state.box) return null;
|
|
86
|
+
const [west, south, east, north] = state.box;
|
|
87
|
+
const [arcWest, arcEast] = longitudeArc(longitudes, west, east, mode);
|
|
88
|
+
return [
|
|
89
|
+
arcWest,
|
|
90
|
+
south,
|
|
91
|
+
arcEast,
|
|
92
|
+
north
|
|
93
|
+
];
|
|
65
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether every corner is a valid longitude and latitude. MapLibre throws on a
|
|
97
|
+
* latitude outside ±90, so a box failing this is never fitted.
|
|
98
|
+
*/
|
|
66
99
|
function isLngLatBox(box) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
100
|
+
if (!box) return false;
|
|
101
|
+
const [west = 0, south = 0, east = 0, north = 0] = box;
|
|
102
|
+
return Math.abs(west) <= 180 && Math.abs(east) <= 180 && Math.abs(south) <= 90 && Math.abs(north) <= 90;
|
|
70
103
|
}
|
|
71
|
-
export {
|
|
72
|
-
geoBounds,
|
|
73
|
-
isLngLatBox
|
|
74
|
-
};
|
|
104
|
+
export { geoBounds, isLngLatBox };
|
package/dist/geo/constraints.js
CHANGED
|
@@ -1,121 +1,116 @@
|
|
|
1
1
|
import { isEmpty } from "../form/validators.js";
|
|
2
|
+
import { isRecord } from "../guards.js";
|
|
2
3
|
import { bboxToPolygon } from "./bbox.js";
|
|
3
4
|
import { isGeoJsonValue } from "./geojson.js";
|
|
4
5
|
import { geoAreaM2, hasSelfIntersection } from "./geometry-math.js";
|
|
6
|
+
// src/geo/constraints.ts
|
|
7
|
+
/**
|
|
8
|
+
* The geometry of each member of a geometry, Feature or FeatureCollection. A
|
|
9
|
+
* BBox is the rectangle it covers.
|
|
10
|
+
*/
|
|
5
11
|
function members(value) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (value.type === "Feature") return value.geometry ? [value.geometry] : [];
|
|
13
|
-
return [value];
|
|
12
|
+
const box = bboxToPolygon(value);
|
|
13
|
+
if (box) return [box];
|
|
14
|
+
if (!isGeoJsonValue(value)) return [];
|
|
15
|
+
if (value.type === "FeatureCollection") return value.features.flatMap((feature) => members(feature));
|
|
16
|
+
if (value.type === "Feature") return value.geometry ? [value.geometry] : [];
|
|
17
|
+
return [value];
|
|
14
18
|
}
|
|
15
19
|
function ringVertices(ring) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return closed ? ring.length - 1 : ring.length;
|
|
20
|
+
const first = ring[0];
|
|
21
|
+
const last = ring[ring.length - 1];
|
|
22
|
+
return ring.length > 1 && first !== void 0 && last !== void 0 && first[0] === last[0] && first[1] === last[1] ? ring.length - 1 : ring.length;
|
|
20
23
|
}
|
|
21
24
|
function geometryVertices(geometry) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return geometry.coordinates.reduce(
|
|
32
|
-
(sum, ring) => sum + ringVertices(ring),
|
|
33
|
-
0
|
|
34
|
-
);
|
|
35
|
-
case "MultiPolygon":
|
|
36
|
-
return geometry.coordinates.reduce(
|
|
37
|
-
(sum, polygon) => sum + polygon.reduce((inner, ring) => inner + ringVertices(ring), 0),
|
|
38
|
-
0
|
|
39
|
-
);
|
|
40
|
-
case "GeometryCollection":
|
|
41
|
-
return geometry.geometries.reduce(
|
|
42
|
-
(sum, part) => sum + geometryVertices(part),
|
|
43
|
-
0
|
|
44
|
-
);
|
|
45
|
-
}
|
|
25
|
+
switch (geometry.type) {
|
|
26
|
+
case "Point": return 1;
|
|
27
|
+
case "MultiPoint":
|
|
28
|
+
case "LineString": return geometry.coordinates.length;
|
|
29
|
+
case "MultiLineString": return geometry.coordinates.reduce((sum, line) => sum + line.length, 0);
|
|
30
|
+
case "Polygon": return geometry.coordinates.reduce((sum, ring) => sum + ringVertices(ring), 0);
|
|
31
|
+
case "MultiPolygon": return geometry.coordinates.reduce((sum, polygon) => sum + polygon.reduce((inner, ring) => inner + ringVertices(ring), 0), 0);
|
|
32
|
+
case "GeometryCollection": return geometry.geometries.reduce((sum, part) => sum + geometryVertices(part), 0);
|
|
33
|
+
}
|
|
46
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Vertices of a geometry, Feature, FeatureCollection or BBox. A polygon ring counts
|
|
37
|
+
* its distinct vertices, so a triangle is 3. `0` for anything else.
|
|
38
|
+
*/
|
|
47
39
|
function countVertices(value) {
|
|
48
|
-
|
|
49
|
-
(sum, geometry) => sum + geometryVertices(geometry),
|
|
50
|
-
0
|
|
51
|
-
);
|
|
40
|
+
return members(value).reduce((sum, geometry) => sum + geometryVertices(geometry), 0);
|
|
52
41
|
}
|
|
42
|
+
/** Area of a geometry, with the parts of a GeometryCollection added up. */
|
|
53
43
|
function areaM2(geometry) {
|
|
54
|
-
|
|
44
|
+
return geometry.type === "GeometryCollection" ? geometry.geometries.reduce((sum, part) => sum + areaM2(part), 0) : geoAreaM2(geometry);
|
|
55
45
|
}
|
|
56
46
|
function hasArea(geometry) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
default:
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
47
|
+
switch (geometry.type) {
|
|
48
|
+
case "Polygon":
|
|
49
|
+
case "MultiPolygon": return true;
|
|
50
|
+
case "GeometryCollection": return geometry.geometries.some(hasArea);
|
|
51
|
+
default: return false;
|
|
52
|
+
}
|
|
66
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* A Feature or FeatureCollection that `isGeoJsonValue` refuses. Its limits
|
|
56
|
+
* cannot be checked, so a constraint fails it instead of passing it. Any other
|
|
57
|
+
* value that is not GeoJSON is left to other validators.
|
|
58
|
+
*/
|
|
67
59
|
function isUnreadable(value) {
|
|
68
|
-
|
|
69
|
-
const { type } = value;
|
|
70
|
-
return (type === "Feature" || type === "FeatureCollection") && !isGeoJsonValue(value);
|
|
60
|
+
return isRecord(value) && (value.type === "Feature" || value.type === "FeatureCollection") && !isGeoJsonValue(value);
|
|
71
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Each constraint skips empty values and a value that is not GeoJSON, fails a
|
|
64
|
+
* Feature or FeatureCollection it cannot read, and fails when any member of a
|
|
65
|
+
* FeatureCollection fails.
|
|
66
|
+
*/
|
|
72
67
|
function constraint(fails, failure) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
return (value) => {
|
|
69
|
+
if (isEmpty(value)) return void 0;
|
|
70
|
+
if (isUnreadable(value)) return failure();
|
|
71
|
+
return members(value).some(fails) ? failure() : void 0;
|
|
72
|
+
};
|
|
78
73
|
}
|
|
79
74
|
function minVertices(min) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
return constraint((geometry) => geometryVertices(geometry) < min, () => ({
|
|
76
|
+
message: "chelone.validation.minVertices",
|
|
77
|
+
args: { min }
|
|
78
|
+
}));
|
|
84
79
|
}
|
|
85
80
|
function maxVertices(max) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
return constraint((geometry) => geometryVertices(geometry) > max, () => ({
|
|
82
|
+
message: "chelone.validation.maxVertices",
|
|
83
|
+
args: { max }
|
|
84
|
+
}));
|
|
90
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Fails a member with a polygon whose area is under `min` square metres. A
|
|
88
|
+
* member with no polygon in it has no area and passes. `args.area` is rounded.
|
|
89
|
+
*/
|
|
91
90
|
function minAreaM2(min) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
91
|
+
return (value) => {
|
|
92
|
+
if (isEmpty(value)) return void 0;
|
|
93
|
+
if (isUnreadable(value)) return {
|
|
94
|
+
message: "chelone.validation.minArea",
|
|
95
|
+
args: {
|
|
96
|
+
min,
|
|
97
|
+
area: 0
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
for (const geometry of members(value)) {
|
|
101
|
+
if (!hasArea(geometry)) continue;
|
|
102
|
+
const area = areaM2(geometry);
|
|
103
|
+
if (area < min) return {
|
|
104
|
+
message: "chelone.validation.minArea",
|
|
105
|
+
args: {
|
|
106
|
+
min,
|
|
107
|
+
area: Math.round(area)
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
};
|
|
109
112
|
}
|
|
110
113
|
function noSelfIntersection() {
|
|
111
|
-
|
|
112
|
-
message: "chelone.validation.selfIntersection"
|
|
113
|
-
}));
|
|
114
|
+
return constraint(hasSelfIntersection, () => ({ message: "chelone.validation.selfIntersection" }));
|
|
114
115
|
}
|
|
115
|
-
export {
|
|
116
|
-
countVertices,
|
|
117
|
-
maxVertices,
|
|
118
|
-
minAreaM2,
|
|
119
|
-
minVertices,
|
|
120
|
-
noSelfIntersection
|
|
121
|
-
};
|
|
116
|
+
export { countVertices, maxVertices, minAreaM2, minVertices, noSelfIntersection };
|
package/dist/geo/coordinates.js
CHANGED
|
@@ -1,32 +1,40 @@
|
|
|
1
1
|
import { isEmpty } from "../form/validators.js";
|
|
2
|
-
|
|
2
|
+
// src/geo/coordinates.ts
|
|
3
|
+
var NUMERIC = /^[+-]?(\d+\.?\d*|\.\d+)(e[+-]?\d+)?$/i;
|
|
4
|
+
/** A finite number from a number or a numeric string, else `null`. `0` is valid. */
|
|
3
5
|
function toCoordinate(value) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
7
|
+
if (typeof value !== "string") return null;
|
|
8
|
+
const text = value.trim();
|
|
9
|
+
if (!NUMERIC.test(text)) return null;
|
|
10
|
+
const parsed = Number(text);
|
|
11
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
10
12
|
}
|
|
11
13
|
function rangeValidator(min, max, message) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
return (value, values) => {
|
|
15
|
+
if (isEmpty(value)) return void 0;
|
|
16
|
+
const coordinate = toCoordinate(value);
|
|
17
|
+
if (coordinate !== null && coordinate >= min && coordinate <= max) return;
|
|
18
|
+
const args = {
|
|
19
|
+
min,
|
|
20
|
+
max
|
|
21
|
+
};
|
|
22
|
+
return typeof message === "function" ? message({
|
|
23
|
+
args,
|
|
24
|
+
value,
|
|
25
|
+
values
|
|
26
|
+
}) : {
|
|
27
|
+
message,
|
|
28
|
+
args
|
|
29
|
+
};
|
|
30
|
+
};
|
|
21
31
|
}
|
|
32
|
+
/** Errors outside -90..90 (or on a non-number). Skips empty values. */
|
|
22
33
|
function latitude(message = "chelone.validation.latitude") {
|
|
23
|
-
|
|
34
|
+
return rangeValidator(-90, 90, message);
|
|
24
35
|
}
|
|
36
|
+
/** Errors outside -180..180 (or on a non-number). Skips empty values. */
|
|
25
37
|
function longitude(message = "chelone.validation.longitude") {
|
|
26
|
-
|
|
38
|
+
return rangeValidator(-180, 180, message);
|
|
27
39
|
}
|
|
28
|
-
export {
|
|
29
|
-
latitude,
|
|
30
|
-
longitude,
|
|
31
|
-
toCoordinate
|
|
32
|
-
};
|
|
40
|
+
export { latitude, longitude, toCoordinate };
|
package/dist/geo/editor.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Feature, Geometry, LineString, Point, Polygon } from "geojson";
|
|
2
|
+
import { type JsonObject } from "../guards.js";
|
|
2
3
|
import type { ShapeStyle } from "./map-layers.js";
|
|
4
|
+
type EditorGeometry = Point | LineString | Polygon;
|
|
5
|
+
/** A feature as the editor takes it: a drawable geometry, JSON properties and an id. */
|
|
6
|
+
export type EditorFeature = Feature<EditorGeometry, JsonObject> & {
|
|
7
|
+
id: string | number;
|
|
8
|
+
};
|
|
3
9
|
export declare const EDITOR_PROPERTIES: {
|
|
4
10
|
readonly mode: "mode";
|
|
5
11
|
readonly currentlyDrawing: "currentlyDrawing";
|
|
@@ -28,25 +34,19 @@ export declare const EDITOR_PROPERTIES: {
|
|
|
28
34
|
* decimals, cut to longitude and latitude, and wrapped. The source is not
|
|
29
35
|
* rewritten.
|
|
30
36
|
*/
|
|
31
|
-
export declare function toEditorFeatures(features:
|
|
37
|
+
export declare function toEditorFeatures(features: Feature<Geometry | null, JsonObject | null>[], getId: () => string | number): EditorFeature[];
|
|
32
38
|
/** What `getSnapshot()` of the editor returns, as far as core reads it. */
|
|
33
|
-
export
|
|
34
|
-
type?: "Feature";
|
|
35
|
-
id?: string | number;
|
|
36
|
-
geometry: {
|
|
37
|
-
type: string;
|
|
38
|
-
coordinates?: unknown;
|
|
39
|
-
} | null;
|
|
40
|
-
properties: object | null;
|
|
41
|
-
}
|
|
39
|
+
export type EditorSnapshotFeature = Feature<EditorGeometry, JsonObject>;
|
|
42
40
|
/**
|
|
43
41
|
* The user's features in an editor snapshot: its helper features (selection
|
|
44
42
|
* points, midpoints, closing points, snapping points and a feature still being
|
|
45
43
|
* drawn) are dropped, and `id` and `properties` come back from `chelone:id`
|
|
46
44
|
* and `chelone:properties`. A feature the editor made has no `id`, and keeps
|
|
47
|
-
* its properties but for the editor's own.
|
|
45
|
+
* its properties but for the editor's own. A feature with a coordinate that is
|
|
46
|
+
* not a finite number, or a `chelone:properties` that is not a JSON object, is
|
|
47
|
+
* left out.
|
|
48
48
|
*/
|
|
49
|
-
export declare function fromEditorFeatures(snapshot: readonly EditorSnapshotFeature[]):
|
|
49
|
+
export declare function fromEditorFeatures(snapshot: readonly EditorSnapshotFeature[]): Feature<Geometry | null, JsonObject | null>[];
|
|
50
50
|
type EditorModeStyle = Record<string, string | number>;
|
|
51
51
|
/** The `styles` option of each drawing mode, by mode name. */
|
|
52
52
|
export type EditorStyles = Record<"point" | "linestring" | "polygon" | "rectangle" | "circle" | "render" | "select", EditorModeStyle>;
|