decoders 2.0.0-beta7 → 2.0.0-beta8

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/core/array.js CHANGED
@@ -98,7 +98,7 @@ function array(decoder) {
98
98
 
99
99
 
100
100
  function nonEmptyArray(decoder) {
101
- return (0, _composition.compose)(array(decoder), (0, _composition.predicate)(function (arr) {
101
+ return (0, _composition.predicate)(array(decoder), function (arr) {
102
102
  return arr.length > 0;
103
- }, 'Must be non-empty array'));
103
+ }, 'Must be non-empty array');
104
104
  }
@@ -96,8 +96,5 @@ export function array<T>(decoder: Decoder<T>): Decoder<Array<T>> {
96
96
  * empty arrays.
97
97
  */
98
98
  export function nonEmptyArray<T>(decoder: Decoder<T>): Decoder<Array<T>> {
99
- return compose(
100
- array(decoder),
101
- predicate((arr) => arr.length > 0, 'Must be non-empty array'),
102
- );
99
+ return predicate(array(decoder), (arr) => arr.length > 0, 'Must be non-empty array');
103
100
  }
package/core/array.mjs CHANGED
@@ -85,7 +85,7 @@ export function array(decoder) {
85
85
  */
86
86
 
87
87
  export function nonEmptyArray(decoder) {
88
- return compose(array(decoder), predicate(function (arr) {
88
+ return predicate(array(decoder), function (arr) {
89
89
  return arr.length > 0;
90
- }, 'Must be non-empty array'));
90
+ }, 'Must be non-empty array');
91
91
  }
@@ -2,11 +2,13 @@ import { Decoder } from '../_types';
2
2
 
3
3
  export function map<T, V>(decoder: Decoder<T>, mapper: (value: T) => V): Decoder<V>;
4
4
  export function compose<T, V>(decoder: Decoder<T>, next: Decoder<V, T>): Decoder<V>;
5
- export function predicate<T extends F, F = unknown>(
6
- predicate: (value: F) => value is T,
5
+ export function predicate<T, N extends T>(
6
+ decoder: Decoder<T>,
7
+ predicate: (value: T) => value is N,
7
8
  msg: string,
8
- ): Decoder<T, F>;
9
+ ): Decoder<N>;
9
10
  export function predicate<T>(
11
+ decoder: Decoder<T>,
10
12
  predicate: (value: T) => boolean,
11
13
  msg: string,
12
- ): Decoder<T, T>;
14
+ ): Decoder<T>;
@@ -45,8 +45,10 @@ function compose(decoder, next) {
45
45
  */
46
46
 
47
47
 
48
- function predicate(predicateFn, msg) {
49
- return function (value) {
50
- return predicateFn(value) ? (0, _result.ok)(value) : (0, _result.err)((0, _annotate.annotate)(value, msg));
48
+ function predicate(decoder, predicateFn, msg) {
49
+ return function (blob) {
50
+ return (0, _result.andThen)(decoder(blob), function (value) {
51
+ return predicateFn(value) ? (0, _result.ok)(value) : (0, _result.err)((0, _annotate.annotate)(value, msg));
52
+ });
51
53
  };
52
54
  }
@@ -36,8 +36,13 @@ export function compose<T, V>(decoder: Decoder<T>, next: Decoder<V, T>): Decoder
36
36
  * Factory function returning a Decoder<T>, given a predicate function that
37
37
  * accepts/rejects the input of type T.
38
38
  */
39
- export function predicate<T>(predicateFn: (T) => boolean, msg: string): Decoder<T, T> {
40
- return (value: T) => {
41
- return predicateFn(value) ? ok(value) : err(annotate(value, msg));
42
- };
39
+ export function predicate<T>(
40
+ decoder: Decoder<T>,
41
+ predicateFn: (T) => boolean,
42
+ msg: string,
43
+ ): Decoder<T> {
44
+ return (blob: mixed) =>
45
+ andThen(decoder(blob), (value) =>
46
+ predicateFn(value) ? ok(value) : err(annotate(value, msg)),
47
+ );
43
48
  }
@@ -35,8 +35,10 @@ export function compose(decoder, next) {
35
35
  * accepts/rejects the input of type T.
36
36
  */
37
37
 
38
- export function predicate(predicateFn, msg) {
39
- return function (value) {
40
- return predicateFn(value) ? ok(value) : err(annotate(value, msg));
38
+ export function predicate(decoder, predicateFn, msg) {
39
+ return function (blob) {
40
+ return andThen(decoder(blob), function (value) {
41
+ return predicateFn(value) ? ok(value) : err(annotate(value, msg));
42
+ });
41
43
  };
42
44
  }
@@ -1,8 +1,8 @@
1
1
  import { Decoder, DecoderType } from '../_types';
2
2
 
3
- export type $Values<T extends object> = T[keyof T];
3
+ export type Values<T extends object> = T[keyof T];
4
4
 
5
- export function dispatch<O extends { [key: string]: Decoder<any> }>(
5
+ export function disjointUnion<O extends { [key: string]: Decoder<any> }>(
6
6
  field: string,
7
7
  mapping: O,
8
- ): Decoder<$Values<{ [key in keyof O]: DecoderType<O[key]> }>>;
8
+ ): Decoder<Values<{ [key in keyof O]: DecoderType<O[key]> }>>;
package/core/dispatch.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.dispatch = dispatch;
4
+ exports.disjointUnion = disjointUnion;
5
5
 
6
6
  var _result = require("../result");
7
7
 
@@ -31,20 +31,20 @@ var _either = require("./either");
31
31
  * Then these two decoders are equivalent:
32
32
  *
33
33
  * const shape = either(rectangle, circle)
34
- * const shape = dispatch('type', { rectangle, circle })
34
+ * const shape = disjointUnion('type', { rectangle, circle })
35
35
  *
36
36
  * Will be of type Decoder<Rectangle | Circle>.
37
37
  *
38
- * But the dispatch version will typically be more runtime-efficient. The
39
- * reason is that it will first do minimal work to "look ahead" into the `type`
40
- * field here, and based on that value, pick the decoder to invoke.
38
+ * But `disjointUnion` will typically be more runtime-efficient. The reason is
39
+ * that it will first do minimal work to "look ahead" into the `type` field
40
+ * here, and based on that value, pick the decoder to invoke.
41
41
  *
42
42
  * The `either` version will simply try to invoke each decoder, until it finds
43
43
  * one that matches.
44
44
  *
45
- * Also, the error messages will be less ambiguous using `dispatch()`.
45
+ * Also, the error messages will be less ambiguous using `disjointUnion()`.
46
46
  */
47
- function dispatch(field, mapping) {
47
+ function disjointUnion(field, mapping) {
48
48
  var _object;
49
49
 
50
50
  var base = (0, _object2.object)((_object = {}, _object[field] = (0, _either.oneOf)(Object.keys(mapping)), _object));
@@ -30,20 +30,20 @@ type anything = any;
30
30
  * Then these two decoders are equivalent:
31
31
  *
32
32
  * const shape = either(rectangle, circle)
33
- * const shape = dispatch('type', { rectangle, circle })
33
+ * const shape = disjointUnion('type', { rectangle, circle })
34
34
  *
35
35
  * Will be of type Decoder<Rectangle | Circle>.
36
36
  *
37
- * But the dispatch version will typically be more runtime-efficient. The
38
- * reason is that it will first do minimal work to "look ahead" into the `type`
39
- * field here, and based on that value, pick the decoder to invoke.
37
+ * But `disjointUnion` will typically be more runtime-efficient. The reason is
38
+ * that it will first do minimal work to "look ahead" into the `type` field
39
+ * here, and based on that value, pick the decoder to invoke.
40
40
  *
41
41
  * The `either` version will simply try to invoke each decoder, until it finds
42
42
  * one that matches.
43
43
  *
44
- * Also, the error messages will be less ambiguous using `dispatch()`.
44
+ * Also, the error messages will be less ambiguous using `disjointUnion()`.
45
45
  */
46
- export function dispatch<O: { +[field: string]: Decoder<anything>, ... }>(
46
+ export function disjointUnion<O: { +[field: string]: Decoder<anything>, ... }>(
47
47
  field: string,
48
48
  mapping: O,
49
49
  ): Decoder<$Values<$ObjMap<O, DecoderType>>> {
package/core/dispatch.mjs CHANGED
@@ -24,20 +24,20 @@ import { oneOf } from './either.mjs';
24
24
  * Then these two decoders are equivalent:
25
25
  *
26
26
  * const shape = either(rectangle, circle)
27
- * const shape = dispatch('type', { rectangle, circle })
27
+ * const shape = disjointUnion('type', { rectangle, circle })
28
28
  *
29
29
  * Will be of type Decoder<Rectangle | Circle>.
30
30
  *
31
- * But the dispatch version will typically be more runtime-efficient. The
32
- * reason is that it will first do minimal work to "look ahead" into the `type`
33
- * field here, and based on that value, pick the decoder to invoke.
31
+ * But `disjointUnion` will typically be more runtime-efficient. The reason is
32
+ * that it will first do minimal work to "look ahead" into the `type` field
33
+ * here, and based on that value, pick the decoder to invoke.
34
34
  *
35
35
  * The `either` version will simply try to invoke each decoder, until it finds
36
36
  * one that matches.
37
37
  *
38
- * Also, the error messages will be less ambiguous using `dispatch()`.
38
+ * Also, the error messages will be less ambiguous using `disjointUnion()`.
39
39
  */
40
- export function dispatch(field, mapping) {
40
+ export function disjointUnion(field, mapping) {
41
41
  var _object;
42
42
 
43
43
  var base = object((_object = {}, _object[field] = oneOf(Object.keys(mapping)), _object));
package/core/mapping.js CHANGED
@@ -13,17 +13,11 @@ var _result = require("../result");
13
13
  var _object = require("./object");
14
14
 
15
15
  /**
16
- * Given an object, will decode a Map of string keys to whatever values.
17
- *
18
- * For example, given a decoder for a Person, we can verify a Person lookup
19
- * table structure (of type Map<string, Person>) like so:
20
- *
21
- * mapping(person)
22
- *
16
+ * Like mapping(), but returns an object rather than a Map instance.
23
17
  */
24
- function mapping(decoder) {
18
+ function dict(decoder) {
25
19
  return (0, _composition.compose)(_object.pojo, function (blob) {
26
- var tuples = [];
20
+ var rv = {};
27
21
  var errors = null;
28
22
  Object.keys(blob).forEach(function (key) {
29
23
  var value = blob[key];
@@ -31,10 +25,10 @@ function mapping(decoder) {
31
25
 
32
26
  if (result.type === 'ok') {
33
27
  if (errors === null) {
34
- tuples.push([key, result.value]);
28
+ rv[key] = result.value;
35
29
  }
36
30
  } else {
37
- tuples.length = 0; // Clear the tuples array
31
+ rv = {}; // Clear the success value so it can get garbage collected early
38
32
 
39
33
  if (errors === null) {
40
34
  errors = {};
@@ -47,17 +41,27 @@ function mapping(decoder) {
47
41
  if (errors !== null) {
48
42
  return (0, _result.err)((0, _annotate.merge)((0, _annotate.annotateObject)(blob), errors));
49
43
  } else {
50
- return (0, _result.ok)(new Map(tuples));
44
+ return (0, _result.ok)(rv);
51
45
  }
52
46
  });
53
47
  }
54
48
  /**
55
- * Like mapping(), but returns an object rather than a Map instance.
49
+ * Given an object, will decode a Map of string keys to whatever values.
50
+ *
51
+ * For example, given a decoder for a Person, we can verify a Person lookup
52
+ * table structure (of type Map<string, Person>) like so:
53
+ *
54
+ * mapping(person)
55
+ *
56
56
  */
57
57
 
58
58
 
59
- function dict(decoder) {
60
- return (0, _composition.map)(mapping(decoder), function (m) {
61
- return Object.fromEntries(m);
59
+ function mapping(decoder) {
60
+ return (0, _composition.map)(dict(decoder), function (obj) {
61
+ return new Map( // This is effectively Object.entries(obj), but in a way that Flow
62
+ // will know the types are okay
63
+ Object.keys(obj).map(function (key) {
64
+ return [key, obj[key]];
65
+ }));
62
66
  });
63
67
  }
@@ -9,17 +9,11 @@ import type { Annotation } from '../annotate';
9
9
  import type { Decoder } from '../_types';
10
10
 
11
11
  /**
12
- * Given an object, will decode a Map of string keys to whatever values.
13
- *
14
- * For example, given a decoder for a Person, we can verify a Person lookup
15
- * table structure (of type Map<string, Person>) like so:
16
- *
17
- * mapping(person)
18
- *
12
+ * Like mapping(), but returns an object rather than a Map instance.
19
13
  */
20
- export function mapping<T>(decoder: Decoder<T>): Decoder<Map<string, T>> {
14
+ export function dict<T>(decoder: Decoder<T>): Decoder<{ [string]: T }> {
21
15
  return compose(pojo, (blob: { +[key: string]: mixed }) => {
22
- let tuples: Array<[string, T]> = [];
16
+ let rv: { [key: string]: T } = {};
23
17
  let errors: { [key: string]: Annotation } | null = null;
24
18
 
25
19
  Object.keys(blob).forEach((key: string) => {
@@ -27,10 +21,10 @@ export function mapping<T>(decoder: Decoder<T>): Decoder<Map<string, T>> {
27
21
  const result = decoder(value);
28
22
  if (result.type === 'ok') {
29
23
  if (errors === null) {
30
- tuples.push([key, result.value]);
24
+ rv[key] = result.value;
31
25
  }
32
26
  } else {
33
- tuples.length = 0; // Clear the tuples array
27
+ rv = {}; // Clear the success value so it can get garbage collected early
34
28
  if (errors === null) {
35
29
  errors = {};
36
30
  }
@@ -41,14 +35,28 @@ export function mapping<T>(decoder: Decoder<T>): Decoder<Map<string, T>> {
41
35
  if (errors !== null) {
42
36
  return err(merge(annotateObject(blob), errors));
43
37
  } else {
44
- return ok(new Map(tuples));
38
+ return ok(rv);
45
39
  }
46
40
  });
47
41
  }
48
42
 
49
43
  /**
50
- * Like mapping(), but returns an object rather than a Map instance.
44
+ * Given an object, will decode a Map of string keys to whatever values.
45
+ *
46
+ * For example, given a decoder for a Person, we can verify a Person lookup
47
+ * table structure (of type Map<string, Person>) like so:
48
+ *
49
+ * mapping(person)
50
+ *
51
51
  */
52
- export function dict<T>(decoder: Decoder<T>): Decoder<{ [string]: T }> {
53
- return map(mapping(decoder), (m) => Object.fromEntries(m));
52
+ export function mapping<T>(decoder: Decoder<T>): Decoder<Map<string, T>> {
53
+ return map(
54
+ dict(decoder),
55
+ (obj) =>
56
+ new Map(
57
+ // This is effectively Object.entries(obj), but in a way that Flow
58
+ // will know the types are okay
59
+ Object.keys(obj).map((key) => [key, obj[key]]),
60
+ ),
61
+ );
54
62
  }
package/core/mapping.mjs CHANGED
@@ -5,17 +5,11 @@ import { merge } from '../annotate.mjs';
5
5
  import { pojo } from './object.mjs';
6
6
 
7
7
  /**
8
- * Given an object, will decode a Map of string keys to whatever values.
9
- *
10
- * For example, given a decoder for a Person, we can verify a Person lookup
11
- * table structure (of type Map<string, Person>) like so:
12
- *
13
- * mapping(person)
14
- *
8
+ * Like mapping(), but returns an object rather than a Map instance.
15
9
  */
16
- export function mapping(decoder) {
10
+ export function dict(decoder) {
17
11
  return compose(pojo, function (blob) {
18
- var tuples = [];
12
+ var rv = {};
19
13
  var errors = null;
20
14
  Object.keys(blob).forEach(function (key) {
21
15
  var value = blob[key];
@@ -23,10 +17,10 @@ export function mapping(decoder) {
23
17
 
24
18
  if (result.type === 'ok') {
25
19
  if (errors === null) {
26
- tuples.push([key, result.value]);
20
+ rv[key] = result.value;
27
21
  }
28
22
  } else {
29
- tuples.length = 0; // Clear the tuples array
23
+ rv = {}; // Clear the success value so it can get garbage collected early
30
24
 
31
25
  if (errors === null) {
32
26
  errors = {};
@@ -39,16 +33,26 @@ export function mapping(decoder) {
39
33
  if (errors !== null) {
40
34
  return err(merge(annotateObject(blob), errors));
41
35
  } else {
42
- return ok(new Map(tuples));
36
+ return ok(rv);
43
37
  }
44
38
  });
45
39
  }
46
40
  /**
47
- * Like mapping(), but returns an object rather than a Map instance.
41
+ * Given an object, will decode a Map of string keys to whatever values.
42
+ *
43
+ * For example, given a decoder for a Person, we can verify a Person lookup
44
+ * table structure (of type Map<string, Person>) like so:
45
+ *
46
+ * mapping(person)
47
+ *
48
48
  */
49
49
 
50
- export function dict(decoder) {
51
- return map(mapping(decoder), function (m) {
52
- return Object.fromEntries(m);
50
+ export function mapping(decoder) {
51
+ return map(dict(decoder), function (obj) {
52
+ return new Map( // This is effectively Object.entries(obj), but in a way that Flow
53
+ // will know the types are okay
54
+ Object.keys(obj).map(function (key) {
55
+ return [key, obj[key]];
56
+ }));
53
57
  });
54
58
  }
package/core/number.js CHANGED
@@ -5,10 +5,10 @@ exports.positiveNumber = exports.positiveInteger = exports.number = exports.inte
5
5
 
6
6
  var _annotate = require("../annotate");
7
7
 
8
- var _composition = require("./composition");
9
-
10
8
  var _result = require("../result");
11
9
 
10
+ var _composition = require("./composition");
11
+
12
12
  var anyNumber = function anyNumber(blob) {
13
13
  return typeof blob === 'number' && !Number.isNaN(blob) ? (0, _result.ok)(blob) : (0, _result.err)((0, _annotate.annotate)(blob, 'Must be number'));
14
14
  };
@@ -21,16 +21,16 @@ var isFinite = function isFinite(n) {
21
21
  return Number.isFinite(n);
22
22
  };
23
23
 
24
- var number = (0, _composition.compose)(anyNumber, (0, _composition.predicate)(isFinite, 'Number must be finite'));
24
+ var number = (0, _composition.predicate)(anyNumber, isFinite, 'Number must be finite');
25
25
  exports.number = number;
26
- var positiveNumber = (0, _composition.compose)(number, (0, _composition.predicate)(function (n) {
26
+ var positiveNumber = (0, _composition.predicate)(number, function (n) {
27
27
  return n >= 0;
28
- }, 'Number must be positive')); // Integers
28
+ }, 'Number must be positive'); // Integers
29
29
 
30
30
  exports.positiveNumber = positiveNumber;
31
- var integer = (0, _composition.compose)(number, (0, _composition.predicate)(isInteger, 'Number must be an integer'));
31
+ var integer = (0, _composition.predicate)(number, isInteger, 'Number must be an integer');
32
32
  exports.integer = integer;
33
- var positiveInteger = (0, _composition.compose)(integer, (0, _composition.predicate)(function (n) {
33
+ var positiveInteger = (0, _composition.predicate)(integer, function (n) {
34
34
  return n >= 0;
35
- }, 'Number must be positive'));
35
+ }, 'Number must be positive');
36
36
  exports.positiveInteger = positiveInteger;
@@ -1,8 +1,8 @@
1
1
  // @flow strict
2
2
 
3
3
  import { annotate } from '../annotate';
4
- import { compose, predicate } from './composition';
5
4
  import { err, ok } from '../result';
5
+ import { predicate } from './composition';
6
6
  import type { Decoder } from '../_types';
7
7
 
8
8
  const anyNumber: Decoder<number> = (blob: mixed) => {
@@ -14,21 +14,27 @@ const anyNumber: Decoder<number> = (blob: mixed) => {
14
14
  const isInteger = (n: number) => Number.isInteger(n);
15
15
  const isFinite = (n: number) => Number.isFinite(n);
16
16
 
17
- export const number: Decoder<number> = compose(
17
+ export const number: Decoder<number> = predicate(
18
18
  anyNumber,
19
- predicate(isFinite, 'Number must be finite'),
19
+ isFinite,
20
+ 'Number must be finite',
20
21
  );
21
- export const positiveNumber: Decoder<number> = compose(
22
+
23
+ export const positiveNumber: Decoder<number> = predicate(
22
24
  number,
23
- predicate((n) => n >= 0, 'Number must be positive'),
25
+ (n) => n >= 0,
26
+ 'Number must be positive',
24
27
  );
25
28
 
26
29
  // Integers
27
- export const integer: Decoder<number> = compose(
30
+ export const integer: Decoder<number> = predicate(
28
31
  number,
29
- predicate(isInteger, 'Number must be an integer'),
32
+ isInteger,
33
+ 'Number must be an integer',
30
34
  );
31
- export const positiveInteger: Decoder<number> = compose(
35
+
36
+ export const positiveInteger: Decoder<number> = predicate(
32
37
  integer,
33
- predicate((n) => n >= 0, 'Number must be positive'),
38
+ (n) => n >= 0,
39
+ 'Number must be positive',
34
40
  );
package/core/number.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { annotate } from '../annotate.mjs';
2
- import { compose, predicate } from './composition.mjs';
3
2
  import { err, ok } from '../result.mjs';
3
+ import { predicate } from './composition.mjs';
4
4
 
5
5
  var anyNumber = function anyNumber(blob) {
6
6
  return typeof blob === 'number' && !Number.isNaN(blob) ? ok(blob) : err(annotate(blob, 'Must be number'));
@@ -14,12 +14,12 @@ var isFinite = function isFinite(n) {
14
14
  return Number.isFinite(n);
15
15
  };
16
16
 
17
- export var number = compose(anyNumber, predicate(isFinite, 'Number must be finite'));
18
- export var positiveNumber = compose(number, predicate(function (n) {
17
+ export var number = predicate(anyNumber, isFinite, 'Number must be finite');
18
+ export var positiveNumber = predicate(number, function (n) {
19
19
  return n >= 0;
20
- }, 'Number must be positive')); // Integers
20
+ }, 'Number must be positive'); // Integers
21
21
 
22
- export var integer = compose(number, predicate(isInteger, 'Number must be an integer'));
23
- export var positiveInteger = compose(integer, predicate(function (n) {
22
+ export var integer = predicate(number, isInteger, 'Number must be an integer');
23
+ export var positiveInteger = predicate(integer, function (n) {
24
24
  return n >= 0;
25
- }, 'Number must be positive'));
25
+ }, 'Number must be positive');
package/core/string.d.ts CHANGED
@@ -1,7 +1,10 @@
1
+ /// <reference lib="dom" />
2
+
1
3
  import { Decoder } from '../_types';
2
4
 
3
5
  export const string: Decoder<string>;
4
6
  export const nonEmptyString: Decoder<string>;
5
7
  export function regex(regex: RegExp, msg: string): Decoder<string>;
6
8
  export const email: Decoder<string>;
7
- export function url(schemes?: readonly string[]): Decoder<string>;
9
+ export const url: Decoder<URL>;
10
+ export const httpsUrl: Decoder<URL>;
package/core/string.js CHANGED
@@ -1,16 +1,20 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.nonEmptyString = exports.email = void 0;
4
+ exports.nonEmptyString = exports.httpsUrl = exports.email = void 0;
5
5
  exports.regex = regex;
6
6
  exports.url = exports.string = void 0;
7
7
 
8
8
  var _annotate = require("../annotate");
9
9
 
10
- var _composition = require("./composition");
10
+ var _either = require("./either");
11
11
 
12
12
  var _result = require("../result");
13
13
 
14
+ var _instanceOf = require("./instanceOf");
15
+
16
+ var _composition = require("./composition");
17
+
14
18
  /** Match groups in this regex:
15
19
  * \1 - the scheme
16
20
  * \2 - the username/password (optional)
@@ -18,9 +22,7 @@ var _result = require("../result");
18
22
  * \4 - the port (optional)
19
23
  * \5 - the path (optional)
20
24
  */
21
- var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,\w]*)?(?:#[.,!/\w]*)?)?$/; // The URL schemes the url() decoder accepts by default
22
-
23
- var DEFAULT_SCHEMES = ['https'];
25
+ var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,\w]*)?(?:#[.,!/\w]*)?)?$/;
24
26
  /**
25
27
  * Decoder that only returns Ok for string inputs. Err otherwise.
26
28
  */
@@ -44,9 +46,9 @@ var nonEmptyString = regex(/\S/, 'Must be non-empty string');
44
46
  exports.nonEmptyString = nonEmptyString;
45
47
 
46
48
  function regex(regex, msg) {
47
- return (0, _composition.compose)(string, (0, _composition.predicate)(function (s) {
49
+ return (0, _composition.predicate)(string, function (s) {
48
50
  return regex.test(s);
49
- }, msg));
51
+ }, msg);
50
52
  }
51
53
  /**
52
54
  * Decoder that only returns Ok for string inputs that match the almost perfect
@@ -55,40 +57,12 @@ function regex(regex, msg) {
55
57
 
56
58
 
57
59
  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,}))$/, 'Must be email');
58
- /**
59
- * Decoder that only returns Ok for string inputs that match URLs of the
60
- * expected scheme. Defaults to only accept HTTPS URLs. Err otherwise.
61
- *
62
- * Variants that can be used:
63
- *
64
- * - url() accepts only https:// URLs
65
- * - url([]) accepts any URL scheme
66
- * - url(['http']) accepts only HTTP
67
- * - url(['https', 'git+ssh']) accepts both https:// and git+ssh:// URLs
68
- */
69
-
70
60
  exports.email = email;
71
-
72
- var url = function url(schemes) {
73
- if (schemes === void 0) {
74
- schemes = DEFAULT_SCHEMES;
75
- }
76
-
77
- return (0, _composition.compose)(string, function (value) {
78
- var matches = value.match(url_re);
79
-
80
- if (!matches) {
81
- return (0, _result.err)((0, _annotate.annotate)(value, 'Must be URL'));
82
- } else {
83
- var scheme = matches[1];
84
-
85
- if (schemes.length === 0 || schemes.includes(scheme.toLowerCase())) {
86
- return (0, _result.ok)(value);
87
- } else {
88
- return (0, _result.err)((0, _annotate.annotate)(value, "URL scheme must be any of: " + schemes.join(', ')));
89
- }
90
- }
91
- });
92
- };
93
-
94
- exports.url = url;
61
+ var url = (0, _either.either)((0, _composition.map)(regex(url_re, 'Must be URL'), function (value) {
62
+ return new URL(value);
63
+ }), (0, _instanceOf.instanceOf)(URL));
64
+ exports.url = url;
65
+ var httpsUrl = (0, _composition.predicate)(url, function (value) {
66
+ return value.protocol === 'https:';
67
+ }, 'Must be an HTTPS URL');
68
+ exports.httpsUrl = httpsUrl;