shelving 1.126.1 → 1.126.3

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.
@@ -9,8 +9,11 @@
9
9
  export declare class Feedback {
10
10
  /** String feedback message that is safe to show to a user. */
11
11
  readonly message: string;
12
- /** Nested details providing deeper feedback. */
13
- readonly value: unknown;
14
- constructor(feedback: string, value?: unknown);
12
+ constructor(message: string);
15
13
  toString(): string;
16
14
  }
15
+ /** Feedback with a known and typed `.value` field. */
16
+ export declare class ValueFeedback<T> extends Feedback {
17
+ readonly value: T;
18
+ constructor(message: string, value: T);
19
+ }
@@ -9,13 +9,18 @@
9
9
  export class Feedback {
10
10
  /** String feedback message that is safe to show to a user. */
11
11
  message;
12
- /** Nested details providing deeper feedback. */
13
- value;
14
- constructor(feedback, value) {
15
- this.message = feedback;
16
- this.value = value;
12
+ constructor(message) {
13
+ this.message = message;
17
14
  }
18
15
  toString() {
19
16
  return this.message;
20
17
  }
21
18
  }
19
+ /** Feedback with a known and typed `.value` field. */
20
+ export class ValueFeedback extends Feedback {
21
+ value;
22
+ constructor(message, value) {
23
+ super(message);
24
+ this.value = value;
25
+ }
26
+ }
@@ -1,10 +1,13 @@
1
1
  import type { ImmutableDictionary } from "../util/dictionary.js";
2
2
  import { Feedback } from "./Feedback.js";
3
- /** Feedback with a list of sub-feedbacks. */
3
+ /** Feedback with a set of named messages. */
4
4
  export declare class Feedbacks extends Feedback {
5
- /** List of sub-feedbacks. */
6
- readonly feedbacks: ImmutableDictionary<Feedback>;
7
- /** List of sub-messages. */
8
- get messages(): ImmutableDictionary<string>;
9
- constructor(feedbacks: ImmutableDictionary<Feedback>, value?: unknown);
5
+ /** List of named messages. */
6
+ readonly messages: ImmutableDictionary<string>;
7
+ constructor(messages: ImmutableDictionary<string>);
8
+ }
9
+ /** Feedbacks with a known and typed `.value` field. */
10
+ export declare class ValueFeedbacks<T> extends Feedbacks {
11
+ readonly value: T;
12
+ constructor(messages: ImmutableDictionary<string>, value: T);
10
13
  }
@@ -1,17 +1,18 @@
1
- import { getProp } from "../util/object.js";
2
- import { mapDictionary } from "../util/transform.js";
3
1
  import { Feedback } from "./Feedback.js";
4
- /** Feedback with a list of sub-feedbacks. */
2
+ /** Feedback with a set of named messages. */
5
3
  export class Feedbacks extends Feedback {
6
- /** List of sub-feedbacks. */
7
- feedbacks;
8
- /** List of sub-messages. */
9
- get messages() {
10
- return mapDictionary(this.feedbacks, getProp, "message");
4
+ /** List of named messages. */
5
+ messages;
6
+ constructor(messages) {
7
+ super("Multiple errors");
8
+ this.messages = messages;
11
9
  }
12
- constructor(feedbacks, value) {
13
- const first = Object.values(feedbacks)[0];
14
- super(first?.message || "Unknown error", value);
15
- this.feedbacks = feedbacks;
10
+ }
11
+ /** Feedbacks with a known and typed `.value` field. */
12
+ export class ValueFeedbacks extends Feedbacks {
13
+ value;
14
+ constructor(messages, value) {
15
+ super(messages);
16
+ this.value = value;
16
17
  }
17
18
  }
@@ -1,3 +1,2 @@
1
1
  export * from "./Feedback.js";
2
2
  export * from "./Feedbacks.js";
3
- export * from "./hydrations.js";
package/feedback/index.js CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from "./Feedback.js";
2
2
  export * from "./Feedbacks.js";
3
- export * from "./hydrations.js";
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.126.1",
14
+ "version": "1.126.3",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { getFirstItem } from "../util/array.js";
3
3
  import { getMap, isMapItem } from "../util/map.js";
4
4
  import { getString } from "../util/string.js";
@@ -15,7 +15,7 @@ export class AllowSchema extends Schema {
15
15
  validate(unsafeValue = this.value) {
16
16
  if (isMapItem(this.allow, unsafeValue))
17
17
  return unsafeValue;
18
- throw new Feedback("Unknown value", unsafeValue);
18
+ throw new ValueFeedback("Unknown value", unsafeValue);
19
19
  }
20
20
  /** Iterate over the the allowed options in `[key, value]` format. */
21
21
  [Symbol.iterator]() {
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { getUniqueArray, isArray } from "../util/array.js";
3
3
  import { validateArray } from "../util/validate.js";
4
4
  import { Schema } from "./Schema.js";
@@ -43,13 +43,13 @@ export class ArraySchema extends Schema {
43
43
  }
44
44
  validate(unsafeValue = this.value) {
45
45
  if (!isArray(unsafeValue))
46
- throw new Feedback("Must be array", unsafeValue);
46
+ throw new ValueFeedback("Must be array", unsafeValue);
47
47
  const validArray = validateArray(unsafeValue, this.items);
48
48
  const uniqueArray = this.unique ? getUniqueArray(validArray) : validArray;
49
49
  if (uniqueArray.length < this.min)
50
- throw new Feedback(uniqueArray.length ? `Minimum ${this.min} items` : "Required", uniqueArray);
50
+ throw new ValueFeedback(uniqueArray.length ? `Minimum ${this.min} items` : "Required", uniqueArray);
51
51
  if (uniqueArray.length > this.max)
52
- throw new Feedback(`Maximum ${this.max} items`, uniqueArray);
52
+ throw new ValueFeedback(`Maximum ${this.max} items`, uniqueArray);
53
53
  return uniqueArray;
54
54
  }
55
55
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { isData } from "../util/data.js";
3
3
  import { validateData } from "../util/validate.js";
4
4
  import { OPTIONAL } from "./OptionalSchema.js";
@@ -12,7 +12,7 @@ export class DataSchema extends Schema {
12
12
  }
13
13
  validate(unsafeValue = this.value) {
14
14
  if (!isData(unsafeValue))
15
- throw new Feedback("Must be object", unsafeValue);
15
+ throw new ValueFeedback("Must be object", unsafeValue);
16
16
  return validateData(unsafeValue, this.props);
17
17
  }
18
18
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { formatDate, getOptionalDate, getYMD } from "../util/date.js";
3
3
  import { OPTIONAL } from "./OptionalSchema.js";
4
4
  import { Schema } from "./Schema.js";
@@ -14,11 +14,11 @@ export class DateSchema extends Schema {
14
14
  validate(unsafeValue = this.value) {
15
15
  const optionalDate = getOptionalDate(unsafeValue);
16
16
  if (!optionalDate)
17
- throw new Feedback(unsafeValue ? "Invalid date" : "Required", unsafeValue);
17
+ throw new ValueFeedback(unsafeValue ? "Invalid date" : "Required", unsafeValue);
18
18
  if (this.min && optionalDate < this.min)
19
- throw new Feedback(`Minimum ${formatDate(this.min)}`, optionalDate);
19
+ throw new ValueFeedback(`Minimum ${formatDate(this.min)}`, optionalDate);
20
20
  if (this.max && optionalDate > this.max)
21
- throw new Feedback(`Maximum ${formatDate(this.max)}`, optionalDate);
21
+ throw new ValueFeedback(`Maximum ${formatDate(this.max)}`, optionalDate);
22
22
  return getYMD(optionalDate);
23
23
  }
24
24
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { isDictionary } from "../util/dictionary.js";
3
3
  import { validateDictionary } from "../util/validate.js";
4
4
  import { Schema } from "./Schema.js";
@@ -15,13 +15,13 @@ export class DictionarySchema extends Schema {
15
15
  }
16
16
  validate(unsafeValue = this.value) {
17
17
  if (!isDictionary(unsafeValue))
18
- throw new Feedback("Must be object", unsafeValue);
18
+ throw new ValueFeedback("Must be object", unsafeValue);
19
19
  const validDictionary = validateDictionary(unsafeValue, this.items);
20
20
  const length = Object.keys(validDictionary).length;
21
21
  if (length < this.min)
22
- throw new Feedback(length ? `Minimum ${this.min} items` : "Required", validDictionary);
22
+ throw new ValueFeedback(length ? `Minimum ${this.min} items` : "Required", validDictionary);
23
23
  if (length > this.max)
24
- throw new Feedback(`Maximum ${this.max} items`, validDictionary);
24
+ throw new ValueFeedback(`Maximum ${this.max} items`, validDictionary);
25
25
  return validDictionary;
26
26
  }
27
27
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { isArrayItem } from "../util/array.js";
3
3
  import { splitOptionalEntity } from "../util/entity.js";
4
4
  import { OPTIONAL } from "./OptionalSchema.js";
@@ -14,9 +14,9 @@ export class EntitySchema extends StringSchema {
14
14
  const entity = super.validate(unsafeValue);
15
15
  const [type] = splitOptionalEntity(entity);
16
16
  if (!type)
17
- throw new Feedback("Must be entity", unsafeValue);
17
+ throw new ValueFeedback("Must be entity", unsafeValue);
18
18
  if (this.types && !isArrayItem(this.types, type))
19
- throw new Feedback("Invalid entity type", type);
19
+ throw new ValueFeedback("Invalid entity type", type);
20
20
  return entity;
21
21
  }
22
22
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { getOptionalFileExtension } from "../util/file.js";
3
3
  import { isProp } from "../util/object.js";
4
4
  import { OPTIONAL } from "./OptionalSchema.js";
@@ -14,9 +14,9 @@ export class FileSchema extends StringSchema {
14
14
  const path = super.validate(unsafeValue);
15
15
  const extension = getOptionalFileExtension(path);
16
16
  if (!extension)
17
- throw new Feedback("Must be file name with extension", unsafeValue);
17
+ throw new ValueFeedback("Must be file name with extension", unsafeValue);
18
18
  if (this.types && !isProp(this.types, extension))
19
- throw new Feedback("Invalid file type", extension);
19
+ throw new ValueFeedback("Invalid file type", extension);
20
20
  return path;
21
21
  }
22
22
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { getOptionalLinkURL } from "../util/link.js";
3
3
  import { OPTIONAL } from "./OptionalSchema.js";
4
4
  import { StringSchema } from "./StringSchema.js";
@@ -30,7 +30,7 @@ export class LinkSchema extends StringSchema {
30
30
  const unsafeString = super.validate(unsafeValue);
31
31
  const url = getOptionalLinkURL(super.sanitize(unsafeString), this.base, this.schemes, this.hosts);
32
32
  if (!url)
33
- throw new Feedback(unsafeString ? "Invalid format" : "Required", unsafeString);
33
+ throw new ValueFeedback(unsafeString ? "Invalid format" : "Required", unsafeString);
34
34
  return url.href;
35
35
  }
36
36
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { formatNumber, getOptionalNumber, roundStep } from "../util/number.js";
3
3
  import { OPTIONAL } from "./OptionalSchema.js";
4
4
  import { Schema } from "./Schema.js";
@@ -16,12 +16,12 @@ export class NumberSchema extends Schema {
16
16
  validate(unsafeValue = this.value) {
17
17
  const optionalNumber = getOptionalNumber(unsafeValue);
18
18
  if (typeof optionalNumber !== "number")
19
- throw new Feedback("Must be number", unsafeValue);
19
+ throw new ValueFeedback("Must be number", unsafeValue);
20
20
  const roundedNumber = typeof this.step === "number" ? roundStep(optionalNumber, this.step) : optionalNumber;
21
21
  if (roundedNumber > this.max)
22
- throw new Feedback(`Maximum ${formatNumber(this.max)}`, roundedNumber);
22
+ throw new ValueFeedback(`Maximum ${formatNumber(this.max)}`, roundedNumber);
23
23
  if (roundedNumber < this.min)
24
- throw new Feedback(`Minimum ${formatNumber(this.min)}`, roundedNumber);
24
+ throw new ValueFeedback(`Minimum ${formatNumber(this.min)}`, roundedNumber);
25
25
  return roundedNumber;
26
26
  }
27
27
  }
@@ -1,11 +1,11 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { ThroughSchema } from "./ThroughSchema.js";
3
3
  /** Validate a value of a specifed type, but throw `Feedback` if the validated value is falsy. */
4
4
  export class RequiredSchema extends ThroughSchema {
5
5
  validate(unsafeValue) {
6
6
  const safeValue = super.validate(unsafeValue);
7
7
  if (!safeValue)
8
- throw new Feedback("Required", safeValue);
8
+ throw new ValueFeedback("Required", safeValue);
9
9
  return safeValue;
10
10
  }
11
11
  }
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { sanitizeLines, sanitizeString } from "../util/string.js";
3
3
  import { OPTIONAL } from "./OptionalSchema.js";
4
4
  import { Schema } from "./Schema.js";
@@ -41,14 +41,14 @@ export class StringSchema extends Schema {
41
41
  validate(unsafeValue = this.value) {
42
42
  const possibleString = typeof unsafeValue === "number" ? unsafeValue.toString() : unsafeValue;
43
43
  if (typeof possibleString !== "string")
44
- throw new Feedback("Must be string", unsafeValue);
44
+ throw new ValueFeedback("Must be string", unsafeValue);
45
45
  const saneString = this.sanitize(possibleString);
46
46
  if (saneString.length < this.min)
47
- throw new Feedback(saneString ? `Minimum ${this.min} characters` : "Required", saneString);
47
+ throw new ValueFeedback(saneString ? `Minimum ${this.min} characters` : "Required", saneString);
48
48
  if (saneString.length > this.max)
49
- throw new Feedback(`Maximum ${this.max} characters`, saneString);
49
+ throw new ValueFeedback(`Maximum ${this.max} characters`, saneString);
50
50
  if (this.match && !this.match.test(saneString))
51
- throw new Feedback(saneString ? "Invalid format" : "Required", saneString);
51
+ throw new ValueFeedback(saneString ? "Invalid format" : "Required", saneString);
52
52
  return saneString;
53
53
  }
54
54
  /**
@@ -1,4 +1,4 @@
1
- import { Feedback } from "../feedback/Feedback.js";
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
2
  import { roundStep } from "../util/number.js";
3
3
  import { Time, getOptionalTime } from "../util/time.js";
4
4
  import { OPTIONAL } from "./OptionalSchema.js";
@@ -21,12 +21,12 @@ export class TimeSchema extends Schema {
21
21
  validate(unsafeValue = this.value) {
22
22
  const optionalTime = getOptionalTime(unsafeValue);
23
23
  if (!optionalTime)
24
- throw new Feedback(unsafeValue ? "Invalid time" : "Required", unsafeValue);
24
+ throw new ValueFeedback(unsafeValue ? "Invalid time" : "Required", unsafeValue);
25
25
  const roundedTime = typeof this.step === "number" ? new Time(roundStep(optionalTime.time, this.step)) : optionalTime;
26
26
  if (this.max && roundedTime > this.max)
27
- throw new Feedback(`Maximum ${this.max.format()}`, roundedTime);
27
+ throw new ValueFeedback(`Maximum ${this.max.format()}`, roundedTime);
28
28
  if (this.min && roundedTime < this.min)
29
- throw new Feedback(`Minimum ${this.min.format()}`, roundedTime);
29
+ throw new ValueFeedback(`Minimum ${this.min.format()}`, roundedTime);
30
30
  return roundedTime.long;
31
31
  }
32
32
  }
package/util/validate.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ValueError } from "../error/ValueError.js";
2
2
  import { Feedback } from "../feedback/Feedback.js";
3
- import { Feedbacks } from "../feedback/Feedbacks.js";
3
+ import { ValueFeedbacks } from "../feedback/Feedbacks.js";
4
4
  import { getLastItem, isArray } from "./array.js";
5
5
  import { getDataProps } from "./data.js";
6
6
  import { getDictionaryItems } from "./dictionary.js";
@@ -31,7 +31,7 @@ export function assertValid(unsafeValue, validator) {
31
31
  export function* validateItems(unsafeItems, validator) {
32
32
  let index = 0;
33
33
  let valid = true;
34
- const feedbacks = {};
34
+ const messages = {};
35
35
  for (const unsafeItem of unsafeItems) {
36
36
  try {
37
37
  yield validator.validate(unsafeItem);
@@ -39,13 +39,13 @@ export function* validateItems(unsafeItems, validator) {
39
39
  catch (thrown) {
40
40
  if (!(thrown instanceof Feedback))
41
41
  throw thrown;
42
- feedbacks[index] = thrown;
42
+ messages[index] = thrown.message;
43
43
  valid = false;
44
44
  }
45
45
  index++;
46
46
  }
47
47
  if (!valid)
48
- throw new Feedbacks(feedbacks, unsafeItems);
48
+ throw new ValueFeedbacks(messages, unsafeItems);
49
49
  }
50
50
  /**
51
51
  * Validate an array of items.
@@ -59,7 +59,7 @@ export function validateArray(unsafeArray, validator) {
59
59
  let valid = true;
60
60
  let changed = true;
61
61
  const safeArray = [];
62
- const feedbacks = {};
62
+ const messages = {};
63
63
  for (const unsafeItem of unsafeArray) {
64
64
  try {
65
65
  const safeItem = validator.validate(unsafeItem);
@@ -70,13 +70,13 @@ export function validateArray(unsafeArray, validator) {
70
70
  catch (thrown) {
71
71
  if (!(thrown instanceof Feedback))
72
72
  throw thrown;
73
- feedbacks[index] = thrown;
73
+ messages[index] = thrown.message;
74
74
  valid = false;
75
75
  }
76
76
  index++;
77
77
  }
78
78
  if (!valid)
79
- throw new Feedbacks(feedbacks, unsafeArray);
79
+ throw new ValueFeedbacks(messages, unsafeArray);
80
80
  return changed || !isArray(unsafeArray) ? safeArray : unsafeArray;
81
81
  }
82
82
  /**
@@ -89,7 +89,7 @@ export function validateDictionary(unsafeDictionary, validator) {
89
89
  let valid = true;
90
90
  let changed = false;
91
91
  const safeDictionary = {};
92
- const feedbacks = {};
92
+ const messages = {};
93
93
  for (const [key, unsafeValue] of getDictionaryItems(unsafeDictionary)) {
94
94
  try {
95
95
  const safeValue = validator.validate(unsafeValue);
@@ -100,12 +100,12 @@ export function validateDictionary(unsafeDictionary, validator) {
100
100
  catch (thrown) {
101
101
  if (!(thrown instanceof Feedback))
102
102
  throw thrown;
103
- feedbacks[key] = thrown;
103
+ messages[key] = thrown.message;
104
104
  valid = false;
105
105
  }
106
106
  }
107
107
  if (!valid)
108
- throw new Feedbacks(feedbacks, unsafeDictionary);
108
+ throw new ValueFeedbacks(messages, unsafeDictionary);
109
109
  return changed || isIterable(unsafeDictionary) ? safeDictionary : unsafeDictionary;
110
110
  }
111
111
  /**
@@ -122,7 +122,7 @@ export function validateData(unsafeData, validators) {
122
122
  let valid = true;
123
123
  let changed = true;
124
124
  const safeData = id && typeof unsafeData.id === "string" ? { id: unsafeData.id } : {};
125
- const feedbacks = {};
125
+ const messages = {};
126
126
  for (const [key, validator] of getDataProps(validators)) {
127
127
  const unsafeValue = unsafeData[key];
128
128
  if (unsafeValue === undefined && partial)
@@ -136,12 +136,12 @@ export function validateData(unsafeData, validators) {
136
136
  catch (thrown) {
137
137
  if (!(thrown instanceof Feedback))
138
138
  throw thrown;
139
- feedbacks[key] = thrown;
139
+ messages[key] = thrown.message;
140
140
  valid = false;
141
141
  }
142
142
  }
143
143
  if (!valid)
144
- throw new Feedbacks(feedbacks, unsafeData);
144
+ throw new ValueFeedbacks(messages, unsafeData);
145
145
  return changed ? safeData : unsafeData;
146
146
  }
147
147
  /** Store a list of current contexts. */
@@ -1,3 +0,0 @@
1
- import type { Hydrations } from "../util/hydrate.js";
2
- /** Set of hydrations for all feedback classes. */
3
- export declare const FEEDBACK_HYDRATIONS: Hydrations;
@@ -1,7 +0,0 @@
1
- import { Feedback } from "./Feedback.js";
2
- import { Feedbacks } from "./Feedbacks.js";
3
- /** Set of hydrations for all feedback classes. */
4
- export const FEEDBACK_HYDRATIONS = {
5
- Feedback,
6
- Feedbacks,
7
- };