@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
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { StandardSchemaV1, StandardSchemaV1Issue } from "@tanstack/form-core";
|
|
2
|
+
import type { TranslateParamValues } from "../i18n/messages.js";
|
|
1
3
|
import type { TranslatableMessage } from "./form-controller.js";
|
|
4
|
+
import { type ChoiceValueOf } from "./input-values.js";
|
|
2
5
|
/**
|
|
3
6
|
* What a validator may return on failure: a plain string (an i18n key or
|
|
4
7
|
* pre-translated text) or a translatable payload with interpolation args.
|
|
@@ -8,35 +11,62 @@ import type { TranslatableMessage } from "./form-controller.js";
|
|
|
8
11
|
export type ValidationErrorMessage = string | TranslatableMessage;
|
|
9
12
|
/** A validator's verdict: nullish means the value passes. */
|
|
10
13
|
export type ValidatorResult = ValidationErrorMessage | null | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* The values ra's skip-empty gate lets into a validator's value slot next to
|
|
16
|
+
* the field's own type: the holes, and an unset multi-input's `[]`. Every
|
|
17
|
+
* built-in except `required` stands down on them, so a validator written for a
|
|
18
|
+
* `string` field is still legal on a field whose value is momentarily empty.
|
|
19
|
+
*/
|
|
20
|
+
export type EmptyValue = null | undefined | readonly unknown[];
|
|
21
|
+
/**
|
|
22
|
+
* The third validator argument (ra's `props` slot): a field binding always
|
|
23
|
+
* fills `source` with the final source path and merges its `validatorMeta`
|
|
24
|
+
* (input props in the React layer) in. `source` is optional because a validator
|
|
25
|
+
* is also a plain function an app can call with no field behind it. The open
|
|
26
|
+
* bag is the boundary — Chelone cannot know what an input passes there.
|
|
27
|
+
*/
|
|
28
|
+
export interface FieldValidatorMeta {
|
|
29
|
+
/** The FINAL field path the value came from, when a binding ran the stack. */
|
|
30
|
+
source?: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
11
33
|
/**
|
|
12
34
|
* The ra validator contract: `(value, allValues, meta)`. `meta` carries the
|
|
13
|
-
* final source path plus whatever the binding merged in (`validatorMeta` —
|
|
14
|
-
*
|
|
35
|
+
* final source path plus whatever the binding merged in (`validatorMeta` — the
|
|
36
|
+
* React layer passes input props there); it is optional so a validator that
|
|
37
|
+
* reads only the value can say only the value. Sync or async.
|
|
38
|
+
*
|
|
39
|
+
* Generic in the value and the values it is handed: `Validator<string, Post>`
|
|
40
|
+
* is a validator for a `Post`'s `string` field (its value slot also holds
|
|
41
|
+
* {@link EmptyValue}), and one written for the widest pair (`Validator`, the
|
|
42
|
+
* default) fits any field.
|
|
15
43
|
*/
|
|
16
|
-
export type Validator = (value:
|
|
44
|
+
export type Validator<TValue = unknown, TValues = unknown> = (value: TValue | EmptyValue, values: TValues, meta?: FieldValidatorMeta) => ValidatorResult | Promise<ValidatorResult>;
|
|
17
45
|
/** `required()`'s return: a validator tagged for {@link isRequired} detection. */
|
|
18
|
-
export interface RequiredValidator {
|
|
19
|
-
(value:
|
|
46
|
+
export interface RequiredValidator<TValue = unknown, TValues = unknown> {
|
|
47
|
+
(value: TValue | EmptyValue, values: TValues, meta?: FieldValidatorMeta): ValidatorResult | Promise<ValidatorResult>;
|
|
20
48
|
readonly isRequired: true;
|
|
21
49
|
}
|
|
50
|
+
/** A validator, or the `false`/nullish ra passes when a rule is switched off. */
|
|
51
|
+
export type ValidatorInput<TValue = unknown, TValues = unknown> = Validator<TValue, TValues> | false | null | undefined;
|
|
52
|
+
/** One `validate` slot: a single validator or a list of them (ra call style). */
|
|
53
|
+
export type ValidatorSlot<TValue = unknown, TValues = unknown> = ValidatorInput<TValue, TValues> | ReadonlyArray<ValidatorInput<TValue, TValues>>;
|
|
22
54
|
/** Params handed to a message factory when the error message is a function. */
|
|
23
|
-
export interface ValidationMessageParams {
|
|
24
|
-
args:
|
|
25
|
-
value:
|
|
26
|
-
values:
|
|
55
|
+
export interface ValidationMessageParams<TValue = unknown, TValues = unknown> {
|
|
56
|
+
args: TranslateParamValues | undefined;
|
|
57
|
+
value: TValue | EmptyValue;
|
|
58
|
+
values: TValues;
|
|
27
59
|
}
|
|
28
60
|
/** Builds an error message dynamically from the failing value/args. */
|
|
29
|
-
export type MessageFactory = (params: ValidationMessageParams) => ValidationErrorMessage;
|
|
61
|
+
export type MessageFactory<TValue = unknown, TValues = unknown> = (params: ValidationMessageParams<TValue, TValues>) => ValidationErrorMessage;
|
|
30
62
|
/** A built-in's `message` option: an i18n key/string or a factory. */
|
|
31
|
-
export type ValidationMessage = string | MessageFactory
|
|
63
|
+
export type ValidationMessage<TValue = unknown, TValues = unknown> = string | MessageFactory<TValue, TValues>;
|
|
32
64
|
/**
|
|
33
65
|
* ra's emptiness notion — the skip-empty gate every built-in except
|
|
34
66
|
* `required` applies: `undefined`, `null`, `''` and `[]` are empty; `0`,
|
|
35
67
|
* `false` and whitespace are values.
|
|
36
68
|
*/
|
|
37
69
|
export declare function isEmpty(value: unknown): boolean;
|
|
38
|
-
/** Loose input accepted by {@link composeValidators} and {@link isRequired}. */
|
|
39
|
-
type ValidatorInput = Validator | false | null | undefined;
|
|
40
70
|
/**
|
|
41
71
|
* Composes validators into one (ra contract): runs them SEQUENTIALLY,
|
|
42
72
|
* short-circuits on the first error, and stays synchronous while every
|
|
@@ -48,13 +78,13 @@ type ValidatorInput = Validator | false | null | undefined;
|
|
|
48
78
|
* options rather than react-hook-form rules, so fresh identities per render
|
|
49
79
|
* cannot re-trigger anything.
|
|
50
80
|
*/
|
|
51
|
-
export declare function composeValidators(...validators: ReadonlyArray<
|
|
81
|
+
export declare function composeValidators<TValue = unknown, TValues = unknown>(...validators: ReadonlyArray<ValidatorSlot<TValue, TValues>>): Validator<TValue, TValues>;
|
|
52
82
|
/**
|
|
53
83
|
* Errors when the value is empty. The ONLY built-in that fails on emptiness —
|
|
54
84
|
* every other one skips empty values so optional fields stay optional.
|
|
55
85
|
* The returned validator is tagged `.isRequired` for {@link isRequired}.
|
|
56
86
|
*/
|
|
57
|
-
export declare function required(message?: ValidationMessage): RequiredValidator
|
|
87
|
+
export declare function required<TValue = unknown, TValues = unknown>(message?: ValidationMessage<TValue, TValues>): RequiredValidator<TValue, TValues>;
|
|
58
88
|
/** Errors when a string/array value is shorter than `min`. Skips empty values. */
|
|
59
89
|
export declare function minLength(min: number, message?: ValidationMessage): Validator;
|
|
60
90
|
/** Errors when a string/array value is longer than `max`. Skips empty values. */
|
|
@@ -72,12 +102,21 @@ export declare function number(message?: ValidationMessage): Validator;
|
|
|
72
102
|
export declare function regex(pattern: RegExp, message?: ValidationMessage): Validator;
|
|
73
103
|
/** Errors when the value is not a valid email address. Skips empty values. */
|
|
74
104
|
export declare function email(message?: ValidationMessage): Validator;
|
|
75
|
-
/**
|
|
76
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Errors when the value is not one of `list`. Skips empty values.
|
|
107
|
+
*
|
|
108
|
+
* Generic in the choices: {@link ChoiceValueOf} maps the list to the value the
|
|
109
|
+
* field holds for one (a `{id, name}` pair stores its `id`), so
|
|
110
|
+
* `choices([{ id: 1, name: 'm' }])` is a validator for a number field.
|
|
111
|
+
*/
|
|
112
|
+
export declare function choices<TChoice>(list: readonly TChoice[], message?: ValidationMessage<ChoiceValueOf<TChoice>>): Validator<ChoiceValueOf<TChoice>>;
|
|
77
113
|
/**
|
|
78
114
|
* Detects requiredness from the RAW `validate` prop — a single validator or
|
|
79
115
|
* any array member tagged `.isRequired === true` (the `required()` tag).
|
|
80
116
|
* Inputs use this to render the required marker without running validation.
|
|
81
117
|
*/
|
|
82
|
-
export declare function isRequired(validate:
|
|
83
|
-
|
|
118
|
+
export declare function isRequired<TValue = unknown, TValues = unknown>(validate: ValidatorSlot<TValue, TValues>): boolean;
|
|
119
|
+
/** The validator stack a field binding runs: schema issues or a validator error. */
|
|
120
|
+
export type FieldValidatorStackResult = ValidatorResult | readonly StandardSchemaV1Issue[];
|
|
121
|
+
/** A field schema outcome: issues, or a thenable of them (an async schema). */
|
|
122
|
+
export type SchemaOutcome = ReturnType<StandardSchemaV1["~standard"]["validate"]>;
|
package/dist/form/validators.js
CHANGED
|
@@ -1,99 +1,125 @@
|
|
|
1
|
-
import { isThenable } from "
|
|
2
|
-
|
|
1
|
+
import { isThenable } from "../guards.js";
|
|
2
|
+
import { choiceIdOf } from "./input-values.js";
|
|
3
|
+
// src/form/validators.ts
|
|
4
|
+
var EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
5
|
+
/**
|
|
6
|
+
* ra's emptiness notion — the skip-empty gate every built-in except
|
|
7
|
+
* `required` applies: `undefined`, `null`, `''` and `[]` are empty; `0`,
|
|
8
|
+
* `false` and whitespace are values.
|
|
9
|
+
*/
|
|
3
10
|
function isEmpty(value) {
|
|
4
|
-
|
|
11
|
+
return value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
|
|
5
12
|
}
|
|
13
|
+
/** Resolves a {@link ValidationMessage} into the error payload (ra's getMessage). */
|
|
6
14
|
function getMessage(message, args, value, values) {
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
if (typeof message === "function") return message({
|
|
16
|
+
args,
|
|
17
|
+
value,
|
|
18
|
+
values
|
|
19
|
+
});
|
|
20
|
+
return args ? {
|
|
21
|
+
message,
|
|
22
|
+
args
|
|
23
|
+
} : message;
|
|
9
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Composes validators into one (ra contract): runs them SEQUENTIALLY,
|
|
27
|
+
* short-circuits on the first error, and stays synchronous while every
|
|
28
|
+
* consulted validator is synchronous — an async member switches the tail of
|
|
29
|
+
* the run (and only that run) to promise chaining. Accepts a rest list or a
|
|
30
|
+
* single array (ra call style); non-function members are filtered out.
|
|
31
|
+
*
|
|
32
|
+
* Unlike ra there is no memoization: bindings hold validators in mutable
|
|
33
|
+
* options rather than react-hook-form rules, so fresh identities per render
|
|
34
|
+
* cannot re-trigger anything.
|
|
35
|
+
*/
|
|
10
36
|
function composeValidators(...validators) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
if (result) return result;
|
|
25
|
-
}
|
|
26
|
-
return void 0;
|
|
27
|
-
};
|
|
28
|
-
return (value, values, meta) => runFrom(0, value, values, meta);
|
|
37
|
+
const head = validators[0];
|
|
38
|
+
const list = (Array.isArray(head) ? head : validators).filter((candidate) => typeof candidate === "function");
|
|
39
|
+
const runFrom = (start, value, values, meta) => {
|
|
40
|
+
for (let index = start; index < list.length; index++) {
|
|
41
|
+
const validator = list[index];
|
|
42
|
+
if (validator === void 0) continue;
|
|
43
|
+
const result = validator(value, values, meta);
|
|
44
|
+
if (isThenable(result)) return Promise.resolve(result).then((resolved) => resolved ? resolved : runFrom(index + 1, value, values, meta));
|
|
45
|
+
if (result) return result;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return (value, values, meta) => runFrom(0, value, values, meta);
|
|
29
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Errors when the value is empty. The ONLY built-in that fails on emptiness —
|
|
52
|
+
* every other one skips empty values so optional fields stay optional.
|
|
53
|
+
* The returned validator is tagged `.isRequired` for {@link isRequired}.
|
|
54
|
+
*/
|
|
30
55
|
function required(message = "chelone.validation.required") {
|
|
31
|
-
|
|
32
|
-
(value, values, _meta) => isEmpty(value) ? getMessage(message, void 0, value, values) : void 0,
|
|
33
|
-
{ isRequired: true }
|
|
34
|
-
);
|
|
56
|
+
return Object.assign((value, values) => isEmpty(value) ? getMessage(message, void 0, value, values) : void 0, { isRequired: true });
|
|
35
57
|
}
|
|
58
|
+
/** The length of a string/array value; `undefined` for anything else (skip). */
|
|
36
59
|
function lengthOf(value) {
|
|
37
|
-
|
|
38
|
-
return void 0;
|
|
60
|
+
if (typeof value === "string" || Array.isArray(value)) return value.length;
|
|
39
61
|
}
|
|
62
|
+
/** Errors when a string/array value is shorter than `min`. Skips empty values. */
|
|
40
63
|
function minLength(min, message = "chelone.validation.minLength") {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
64
|
+
return (value, values) => {
|
|
65
|
+
if (isEmpty(value)) return void 0;
|
|
66
|
+
const length = lengthOf(value);
|
|
67
|
+
return length !== void 0 && length < min ? getMessage(message, { min }, value, values) : void 0;
|
|
68
|
+
};
|
|
46
69
|
}
|
|
70
|
+
/** Errors when a string/array value is longer than `max`. Skips empty values. */
|
|
47
71
|
function maxLength(max, message = "chelone.validation.maxLength") {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
72
|
+
return (value, values) => {
|
|
73
|
+
if (isEmpty(value)) return void 0;
|
|
74
|
+
const length = lengthOf(value);
|
|
75
|
+
return length !== void 0 && length > max ? getMessage(message, { max }, value, values) : void 0;
|
|
76
|
+
};
|
|
53
77
|
}
|
|
78
|
+
/** Errors when the value is below `min` (`0` IS validated). Skips empty values. */
|
|
54
79
|
function minValue(min, message = "chelone.validation.minValue") {
|
|
55
|
-
|
|
80
|
+
return (value, values) => !isEmpty(value) && Number(value) < min ? getMessage(message, { min }, value, values) : void 0;
|
|
56
81
|
}
|
|
82
|
+
/** Errors when the value is above `max`. Skips empty values. */
|
|
57
83
|
function maxValue(max, message = "chelone.validation.maxValue") {
|
|
58
|
-
|
|
84
|
+
return (value, values) => !isEmpty(value) && Number(value) > max ? getMessage(message, { max }, value, values) : void 0;
|
|
59
85
|
}
|
|
86
|
+
/** Errors when the value is not coercible to a number. Skips empty values. */
|
|
60
87
|
function number(message = "chelone.validation.number") {
|
|
61
|
-
|
|
88
|
+
return (value, values) => !isEmpty(value) && Number.isNaN(Number(value)) ? getMessage(message, void 0, value, values) : void 0;
|
|
62
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Errors when a STRING value does not match `pattern` (non-strings skip, ra
|
|
92
|
+
* parity). The pattern rides the error args stringified for interpolation.
|
|
93
|
+
*/
|
|
63
94
|
function regex(pattern, message = "chelone.validation.regex") {
|
|
64
|
-
|
|
95
|
+
return (value, values) => !isEmpty(value) && typeof value === "string" && !pattern.test(value) ? getMessage(message, { pattern: String(pattern) }, value, values) : void 0;
|
|
65
96
|
}
|
|
97
|
+
/** Errors when the value is not a valid email address. Skips empty values. */
|
|
66
98
|
function email(message = "chelone.validation.email") {
|
|
67
|
-
|
|
99
|
+
return regex(EMAIL_REGEX, message);
|
|
68
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Errors when the value is not one of `list`. Skips empty values.
|
|
103
|
+
*
|
|
104
|
+
* Generic in the choices: {@link ChoiceValueOf} maps the list to the value the
|
|
105
|
+
* field holds for one (a `{id, name}` pair stores its `id`), so
|
|
106
|
+
* `choices([{ id: 1, name: 'm' }])` is a validator for a number field.
|
|
107
|
+
*/
|
|
69
108
|
function choices(list, message = "chelone.validation.oneOf") {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
{ options: list.map(String).join(", ") },
|
|
73
|
-
value,
|
|
74
|
-
values
|
|
75
|
-
) : void 0;
|
|
109
|
+
const options = list.map(choiceIdOf);
|
|
110
|
+
return (value, values) => !isEmpty(value) && !options.includes(value) ? getMessage(message, { options: options.map(String).join(", ") }, value, values) : void 0;
|
|
76
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Detects requiredness from the RAW `validate` prop — a single validator or
|
|
114
|
+
* any array member tagged `.isRequired === true` (the `required()` tag).
|
|
115
|
+
* Inputs use this to render the required marker without running validation.
|
|
116
|
+
*/
|
|
77
117
|
function isRequired(validate) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return validate.some(
|
|
81
|
-
(candidate) => typeof candidate === "function" && candidate.isRequired === true
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
return validate.isRequired === true;
|
|
118
|
+
if (Array.isArray(validate)) return validate.some((candidate) => typeof candidate === "function" && hasRequiredTag(candidate));
|
|
119
|
+
return typeof validate === "function" && hasRequiredTag(validate);
|
|
85
120
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
isRequired,
|
|
92
|
-
maxLength,
|
|
93
|
-
maxValue,
|
|
94
|
-
minLength,
|
|
95
|
-
minValue,
|
|
96
|
-
number,
|
|
97
|
-
regex,
|
|
98
|
-
required
|
|
99
|
-
};
|
|
121
|
+
/** The `required()` tag, read through an `in` check rather than a cast. */
|
|
122
|
+
function hasRequiredTag(validator) {
|
|
123
|
+
return "isRequired" in validator && validator.isRequired === true;
|
|
124
|
+
}
|
|
125
|
+
export { choices, composeValidators, email, isEmpty, isRequired, maxLength, maxValue, minLength, minValue, number, regex, required };
|
package/dist/geo/bbox.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Geometry, Polygon } from "geojson";
|
|
2
|
+
import type { LngLatBox } from "./bounds.js";
|
|
2
3
|
/**
|
|
3
4
|
* The closed rectangle ring of a bbox; `null` unless it is four finite numbers.
|
|
4
5
|
* A box with west greater than east crosses 180: its ring runs east of 180.
|
|
5
6
|
*/
|
|
6
|
-
export declare function bboxToPolygon(bbox: unknown):
|
|
7
|
+
export declare function bboxToPolygon(bbox: unknown): Polygon | null;
|
|
7
8
|
/** The box around a Polygon, west greater than east across 180; `null` for any other geometry. */
|
|
8
|
-
export declare function polygonToBBox(geometry:
|
|
9
|
+
export declare function polygonToBBox(geometry: Geometry): LngLatBox | null;
|
|
9
10
|
/**
|
|
10
11
|
* Builds a polygon-to-bbox function whose box has width over height equal to
|
|
11
12
|
* `ratio`. The box grows around the old centre, never shrinks. A zero width,
|
|
12
13
|
* a zero height or a `ratio` that is not a positive finite number yields the
|
|
13
14
|
* plain bbox.
|
|
14
15
|
*/
|
|
15
|
-
export declare function aspectLockedBBox(ratio: number): (geometry:
|
|
16
|
+
export declare function aspectLockedBBox(ratio: number): (geometry: Geometry) => LngLatBox | null;
|
package/dist/geo/bbox.js
CHANGED
|
@@ -1,56 +1,77 @@
|
|
|
1
1
|
import { geoBounds } from "./bounds.js";
|
|
2
2
|
import { isGeoBBox } from "./geojson.js";
|
|
3
|
+
// src/geo/bbox.ts
|
|
4
|
+
/**
|
|
5
|
+
* The closed rectangle ring of a bbox; `null` unless it is four finite numbers.
|
|
6
|
+
* A box with west greater than east crosses 180: its ring runs east of 180.
|
|
7
|
+
*/
|
|
3
8
|
function bboxToPolygon(bbox) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
]
|
|
18
|
-
};
|
|
9
|
+
if (!isGeoBBox(bbox)) return null;
|
|
10
|
+
const [west, south, rawEast, north] = bbox;
|
|
11
|
+
const east = west > rawEast ? rawEast + 360 : rawEast;
|
|
12
|
+
return {
|
|
13
|
+
type: "Polygon",
|
|
14
|
+
coordinates: [[
|
|
15
|
+
[west, south],
|
|
16
|
+
[east, south],
|
|
17
|
+
[east, north],
|
|
18
|
+
[west, north],
|
|
19
|
+
[west, south]
|
|
20
|
+
]]
|
|
21
|
+
};
|
|
19
22
|
}
|
|
23
|
+
/** The box around a Polygon, west greater than east across 180; `null` for any other geometry. */
|
|
20
24
|
function polygonToBBox(geometry) {
|
|
21
|
-
|
|
25
|
+
return geometry.type === "Polygon" ? geoBounds(geometry, "explicit") : null;
|
|
22
26
|
}
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
var RATIO_TOLERANCE = 1e-9;
|
|
28
|
+
var wrapLongitude = (longitude) => longitude > 180 ? longitude - 360 : longitude < -180 ? longitude + 360 : longitude;
|
|
29
|
+
/**
|
|
30
|
+
* Builds a polygon-to-bbox function whose box has width over height equal to
|
|
31
|
+
* `ratio`. The box grows around the old centre, never shrinks. A zero width,
|
|
32
|
+
* a zero height or a `ratio` that is not a positive finite number yields the
|
|
33
|
+
* plain bbox.
|
|
34
|
+
*/
|
|
25
35
|
function aspectLockedBBox(ratio) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
return (geometry) => {
|
|
37
|
+
const bbox = polygonToBBox(geometry);
|
|
38
|
+
if (!bbox || !Number.isFinite(ratio) || ratio <= 0) return bbox;
|
|
39
|
+
const [west, south, east, north] = bbox;
|
|
40
|
+
const crossing = west > east;
|
|
41
|
+
const unwrappedEast = crossing ? east + 360 : east;
|
|
42
|
+
const width = unwrappedEast - west;
|
|
43
|
+
const height = north - south;
|
|
44
|
+
if (width <= 0 || height <= 0) return bbox;
|
|
45
|
+
const current = width / height;
|
|
46
|
+
if (Math.abs(current - ratio) <= RATIO_TOLERANCE * ratio) return bbox;
|
|
47
|
+
if (current < ratio) {
|
|
48
|
+
const grow = (height * ratio - width) / 2;
|
|
49
|
+
if (!crossing) return [
|
|
50
|
+
west - grow,
|
|
51
|
+
south,
|
|
52
|
+
east + grow,
|
|
53
|
+
north
|
|
54
|
+
];
|
|
55
|
+
if (width + 2 * grow >= 360) return [
|
|
56
|
+
-180,
|
|
57
|
+
south,
|
|
58
|
+
180,
|
|
59
|
+
north
|
|
60
|
+
];
|
|
61
|
+
return [
|
|
62
|
+
wrapLongitude(west - grow),
|
|
63
|
+
south,
|
|
64
|
+
wrapLongitude(unwrappedEast + grow),
|
|
65
|
+
north
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
const grow = (width / ratio - height) / 2;
|
|
69
|
+
return [
|
|
70
|
+
west,
|
|
71
|
+
south - grow,
|
|
72
|
+
east,
|
|
73
|
+
north + grow
|
|
74
|
+
];
|
|
75
|
+
};
|
|
51
76
|
}
|
|
52
|
-
export {
|
|
53
|
-
aspectLockedBBox,
|
|
54
|
-
bboxToPolygon,
|
|
55
|
-
polygonToBBox
|
|
56
|
-
};
|
|
77
|
+
export { aspectLockedBBox, bboxToPolygon, polygonToBBox };
|
package/dist/geo/bounds.d.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Feature, FeatureCollection, Geometry } from "geojson";
|
|
2
|
+
import type { JsonObject } from "../guards.js";
|
|
3
|
+
/**
|
|
4
|
+
* `[west, south, east, north]`. Not geojson's `BBox`, which also allows six
|
|
5
|
+
* numbers.
|
|
6
|
+
*/
|
|
7
|
+
export type LngLatBox = [
|
|
8
|
+
west: number,
|
|
9
|
+
south: number,
|
|
10
|
+
east: number,
|
|
11
|
+
north: number
|
|
12
|
+
];
|
|
2
13
|
/**
|
|
3
14
|
* How `geoBounds` picks west and east. `narrowest` takes whichever arc is
|
|
4
15
|
* narrower, as for framing features. `explicit` goes across 180 only when a
|
|
@@ -12,9 +23,9 @@ export type CrossingMode = "narrowest" | "explicit";
|
|
|
12
23
|
* longitudes are narrower going round the antimeridian, west is greater than
|
|
13
24
|
* east.
|
|
14
25
|
*/
|
|
15
|
-
export declare function geoBounds(value:
|
|
26
|
+
export declare function geoBounds(value: Geometry | Feature<Geometry | null, JsonObject | null> | FeatureCollection<Geometry | null, JsonObject | null>, mode?: CrossingMode): LngLatBox | null;
|
|
16
27
|
/**
|
|
17
28
|
* Whether every corner is a valid longitude and latitude. MapLibre throws on a
|
|
18
29
|
* latitude outside ±90, so a box failing this is never fitted.
|
|
19
30
|
*/
|
|
20
|
-
export declare function isLngLatBox(box: readonly number[] | null): box is
|
|
31
|
+
export declare function isLngLatBox(box: readonly number[] | null): box is LngLatBox;
|