shelving 1.86.0 → 1.86.2

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.
Files changed (97) hide show
  1. package/api/Resource.d.ts +2 -2
  2. package/constraint/Constraints.js +7 -6
  3. package/constraint/FilterConstraint.d.ts +4 -4
  4. package/constraint/FilterConstraint.js +17 -17
  5. package/constraint/QueryConstraints.d.ts +1 -1
  6. package/constraint/QueryConstraints.js +8 -8
  7. package/constraint/SortConstraint.d.ts +4 -4
  8. package/constraint/SortConstraint.js +3 -3
  9. package/db/Change.d.ts +4 -4
  10. package/db/Item.d.ts +4 -4
  11. package/error/ThroughError.js +1 -1
  12. package/markup/index.d.ts +1 -0
  13. package/markup/index.js +1 -0
  14. package/markup/options.d.ts +2 -2
  15. package/markup/regexp.d.ts +2 -2
  16. package/markup/render.js +19 -20
  17. package/markup/rule.d.ts +80 -0
  18. package/markup/rule.js +63 -0
  19. package/markup/rules.d.ts +17 -67
  20. package/markup/rules.js +88 -160
  21. package/package.json +17 -17
  22. package/react/useItem.js +10 -10
  23. package/react/useQuery.js +29 -29
  24. package/schema/AllowSchema.d.ts +4 -4
  25. package/schema/AllowSchema.js +3 -3
  26. package/schema/ArraySchema.d.ts +1 -1
  27. package/schema/BooleanSchema.d.ts +1 -1
  28. package/schema/DataSchema.d.ts +2 -2
  29. package/schema/DateSchema.d.ts +1 -1
  30. package/schema/DictionarySchema.d.ts +1 -1
  31. package/schema/LinkSchema.d.ts +1 -1
  32. package/schema/NumberSchema.d.ts +1 -1
  33. package/schema/NumberSchema.js +4 -4
  34. package/schema/Schema.d.ts +1 -1
  35. package/schema/StringSchema.d.ts +3 -3
  36. package/schema/ThroughSchema.d.ts +1 -1
  37. package/schema/TimeSchema.d.ts +1 -1
  38. package/state/State.d.ts +1 -1
  39. package/state/State.js +6 -6
  40. package/test/basics.d.ts +2 -2
  41. package/test/index.d.ts +1 -1
  42. package/test/people.d.ts +2 -2
  43. package/update/ArrayUpdate.d.ts +2 -1
  44. package/update/ArrayUpdate.js +9 -8
  45. package/update/DataUpdate.d.ts +1 -1
  46. package/update/DataUpdate.js +7 -6
  47. package/update/DictionaryUpdate.d.ts +1 -1
  48. package/update/DictionaryUpdate.js +8 -7
  49. package/util/array.d.ts +4 -4
  50. package/util/async.js +8 -8
  51. package/util/class.d.ts +3 -3
  52. package/util/clone.js +4 -3
  53. package/util/color.d.ts +2 -2
  54. package/util/color.js +6 -6
  55. package/util/data.d.ts +7 -14
  56. package/util/data.js +1 -19
  57. package/util/date.d.ts +3 -3
  58. package/util/debug.d.ts +1 -0
  59. package/util/debug.js +5 -5
  60. package/util/dictionary.d.ts +5 -5
  61. package/util/duration.d.ts +17 -0
  62. package/util/duration.js +52 -0
  63. package/util/entry.d.ts +3 -3
  64. package/util/equal.js +6 -3
  65. package/util/function.d.ts +8 -8
  66. package/util/hydrate.d.ts +3 -3
  67. package/util/hydrate.js +2 -2
  68. package/util/index.d.ts +1 -0
  69. package/util/index.js +1 -0
  70. package/util/iterate.d.ts +1 -1
  71. package/util/jsx.d.ts +3 -3
  72. package/util/lazy.d.ts +1 -1
  73. package/util/map.d.ts +15 -19
  74. package/util/map.js +11 -13
  75. package/util/match.d.ts +2 -2
  76. package/util/merge.d.ts +1 -1
  77. package/util/null.d.ts +1 -1
  78. package/util/number.d.ts +4 -2
  79. package/util/number.js +8 -6
  80. package/util/object.d.ts +24 -11
  81. package/util/object.js +30 -4
  82. package/util/regexp.d.ts +2 -3
  83. package/util/serialise.js +2 -2
  84. package/util/set.d.ts +4 -4
  85. package/util/sort.d.ts +2 -2
  86. package/util/source.js +2 -2
  87. package/util/string.d.ts +1 -1
  88. package/util/string.js +3 -3
  89. package/util/template.d.ts +2 -2
  90. package/util/template.js +9 -9
  91. package/util/time.d.ts +2 -2
  92. package/util/time.js +3 -3
  93. package/util/transform.d.ts +5 -5
  94. package/util/units.d.ts +39 -50
  95. package/util/units.js +36 -74
  96. package/util/url.d.ts +2 -2
  97. package/util/validate.d.ts +5 -5
package/api/Resource.d.ts CHANGED
@@ -27,9 +27,9 @@ export declare class Resource<P = unknown, R = void> implements Validatable<R> {
27
27
  validate(unsafeResult: unknown): R;
28
28
  }
29
29
  /** Extract the payload type from a `Resource`. */
30
- export declare type PayloadType<X extends Resource> = X extends Resource<infer Y, unknown> ? Y : never;
30
+ export type PayloadType<X extends Resource> = X extends Resource<infer Y, unknown> ? Y : never;
31
31
  /** Extract the result type from a `Resource`. */
32
- export declare type ResourceType<X extends Resource> = X extends Resource<unknown, infer Y> ? Y : never;
32
+ export type ResourceType<X extends Resource> = X extends Resource<unknown, infer Y> ? Y : never;
33
33
  /**
34
34
  * Shortcut to create a new `Resource` (consistent with `Schema` shortcuts.
35
35
  * - Sets `undefined` as the default type for payload and result.
@@ -1,11 +1,8 @@
1
+ import { getPrototype } from "../util/object.js";
1
2
  import { withArrayItems, omitArrayItems } from "../util/array.js";
2
3
  import { Constraint } from "./Constraint.js";
3
4
  /** Type of Rule that is powered by several sub-constraints (e.g. `Filters` and `Sorts` and `Query` itself extend this). */
4
5
  export class Constraints extends Constraint {
5
- constructor(...constraints) {
6
- super();
7
- this._constraints = constraints;
8
- }
9
6
  /** Get the first constraint. */
10
7
  get first() {
11
8
  return this._constraints[0];
@@ -18,15 +15,19 @@ export class Constraints extends Constraint {
18
15
  get size() {
19
16
  return this._constraints.length;
20
17
  }
18
+ constructor(...constraints) {
19
+ super();
20
+ this._constraints = constraints;
21
+ }
21
22
  /** Clone this set of constraints but add additional constraints. */
22
23
  with(...constraints) {
23
24
  const _constraints = withArrayItems(this._constraints, ...constraints);
24
- return _constraints !== this._constraints ? { __proto__: Object.getPrototypeOf(this), ...this, _constraints: _constraints } : this;
25
+ return _constraints !== this._constraints ? { __proto__: getPrototype(this), ...this, _constraints: _constraints } : this;
25
26
  }
26
27
  /** Clone this set of constraints but remove specific constraints. */
27
28
  omit(...constraints) {
28
29
  const _constraints = omitArrayItems(this._constraints, ...constraints);
29
- return _constraints !== this._constraints ? { __proto__: Object.getPrototypeOf(this), ...this, _constraints: _constraints } : this;
30
+ return _constraints !== this._constraints ? { __proto__: getPrototype(this), ...this, _constraints: _constraints } : this;
30
31
  }
31
32
  /** Iterate over the constraints. */
32
33
  [Symbol.iterator]() {
@@ -4,11 +4,11 @@ import { ImmutableArray } from "../util/array.js";
4
4
  import { Matchable } from "../util/match.js";
5
5
  import type { Constraint } from "./Constraint.js";
6
6
  /** Possible operator references. */
7
- export declare type FilterOperator = "IS" | "NOT" | "IN" | "OUT" | "CONTAINS" | "LT" | "LTE" | "GT" | "GTE";
7
+ export type FilterOperator = "IS" | "NOT" | "IN" | "OUT" | "CONTAINS" | "LT" | "LTE" | "GT" | "GTE";
8
8
  /** Format that allows filters to be specified as a string, e.g. `!name` means `name is not` and `age>` means `age is more than` and `tags[]` means `tags array contains` */
9
- export declare type FilterKey<T extends Data> = DataKey<T> | `${DataKey<T>}` | `!${DataKey<T>}` | `${DataKey<T>}[]` | `${DataKey<T>}<` | `${DataKey<T>}<=` | `${DataKey<T>}>` | `${DataKey<T>}>=`;
9
+ export type FilterKey<T extends Data> = DataKey<T> | `${DataKey<T>}` | `!${DataKey<T>}` | `${DataKey<T>}[]` | `${DataKey<T>}<` | `${DataKey<T>}<=` | `${DataKey<T>}>` | `${DataKey<T>}>=`;
10
10
  /** Format that allows multiple filters to be specified as a plain object. */
11
- export declare type FilterProps<T extends Data> = {
11
+ export type FilterProps<T extends Data> = {
12
12
  [K in DataKey<T> as `${K}` | `!${K}`]?: T[K] | ImmutableArray<T[K]>;
13
13
  } & {
14
14
  [K in DataKey<T> as `${K}[]`]?: Required<T>[K] extends ImmutableArray<infer X> ? X : never;
@@ -16,7 +16,7 @@ export declare type FilterProps<T extends Data> = {
16
16
  [K in DataKey<T> as `${K}<` | `${K}<=` | `${K}>` | `${K}>=`]?: T[K];
17
17
  };
18
18
  /** List of filters in a flexible format. */
19
- export declare type FilterList<T extends Data> = Nullish<FilterProps<T> | FilterConstraint<T>> | Iterable<FilterList<T>>;
19
+ export type FilterList<T extends Data> = Nullish<FilterProps<T> | FilterConstraint<T>> | Iterable<FilterList<T>>;
20
20
  /**
21
21
  * Filter: filters a list of data.
22
22
  *
@@ -21,6 +21,23 @@ const MATCHERS = {
21
21
  * @param value Value the specified property should be matched against.
22
22
  */
23
23
  export class FilterConstraint {
24
+ get filterKey() {
25
+ const { operator, key } = this;
26
+ if (operator === "NOT" || operator === "OUT")
27
+ return `!${key}`;
28
+ else if (operator === "CONTAINS")
29
+ return `${key}[]`;
30
+ else if (operator === "LT")
31
+ return `${key}<`;
32
+ else if (operator === "LTE")
33
+ return `${key}<=`;
34
+ else if (operator === "GT")
35
+ return `${key}>`;
36
+ else if (operator === "GTE")
37
+ return `${key}>=`;
38
+ else
39
+ return key;
40
+ }
24
41
  constructor(filterKey, value) {
25
42
  if (filterKey.startsWith("!")) {
26
43
  this.key = filterKey.slice(1);
@@ -52,23 +69,6 @@ export class FilterConstraint {
52
69
  }
53
70
  this.value = value;
54
71
  }
55
- get filterKey() {
56
- const { operator, key } = this;
57
- if (operator === "NOT" || operator === "OUT")
58
- return `!${key}`;
59
- else if (operator === "CONTAINS")
60
- return `${key}[]`;
61
- else if (operator === "LT")
62
- return `${key}<`;
63
- else if (operator === "LTE")
64
- return `${key}<=`;
65
- else if (operator === "GT")
66
- return `${key}>`;
67
- else if (operator === "GTE")
68
- return `${key}>=`;
69
- else
70
- return key;
71
- }
72
72
  match(item) {
73
73
  return MATCHERS[this.operator](item[this.key], this.value);
74
74
  }
@@ -31,7 +31,7 @@ export declare class QueryConstraints<T extends Data = Data> extends Constraint<
31
31
  readonly filters: FilterConstraints<T>;
32
32
  readonly sorts: SortConstraints<T>;
33
33
  readonly limit: number | null;
34
- constructor(filters?: FilterList<Partial<T>>, sorts?: SortList<Partial<T>>, limit?: number | null);
34
+ constructor(filters?: FilterList<Partial<T>> | FilterConstraints<T>, sorts?: SortList<Partial<T>> | SortConstraints<T>, limit?: number | null);
35
35
  filter(...filters: FilterList<Partial<T>>[]): this;
36
36
  get unfilter(): this;
37
37
  match(item: T): boolean;
@@ -1,4 +1,4 @@
1
- import { getProp } from "../util/object.js";
1
+ import { getProp, getPrototype } from "../util/object.js";
2
2
  import { assert } from "../util/assert.js";
3
3
  import { limitArray } from "../util/array.js";
4
4
  import { FilterConstraints } from "./FilterConstraints.js";
@@ -19,7 +19,7 @@ export class QueryConstraints extends Constraint {
19
19
  // Implement `Filterable`
20
20
  filter(...filters) {
21
21
  return {
22
- __proto__: Object.getPrototypeOf(this),
22
+ __proto__: getPrototype(this),
23
23
  ...this,
24
24
  filters: this.filters.filter(...filters),
25
25
  };
@@ -28,7 +28,7 @@ export class QueryConstraints extends Constraint {
28
28
  if (!this.filters.size)
29
29
  return this;
30
30
  return {
31
- __proto__: Object.getPrototypeOf(this),
31
+ __proto__: getPrototype(this),
32
32
  ...this,
33
33
  filters: EMPTY_FILTERS,
34
34
  };
@@ -39,7 +39,7 @@ export class QueryConstraints extends Constraint {
39
39
  // Implement `Sortable`
40
40
  sort(...sorts) {
41
41
  return {
42
- __proto__: Object.getPrototypeOf(this),
42
+ __proto__: getPrototype(this),
43
43
  ...this,
44
44
  sorts: this.sorts.sort(...sorts),
45
45
  };
@@ -48,7 +48,7 @@ export class QueryConstraints extends Constraint {
48
48
  if (!this.sorts.size)
49
49
  return this;
50
50
  return {
51
- __proto__: Object.getPrototypeOf(this),
51
+ __proto__: getPrototype(this),
52
52
  ...this,
53
53
  sorts: EMPTY_SORTS,
54
54
  };
@@ -59,14 +59,14 @@ export class QueryConstraints extends Constraint {
59
59
  // Implement `Queryable`
60
60
  after(item) {
61
61
  return {
62
- __proto__: Object.getPrototypeOf(this),
62
+ __proto__: getPrototype(this),
63
63
  ...this,
64
64
  filters: this.filters.with(..._getAfterFilters(this.sorts, item)),
65
65
  };
66
66
  }
67
67
  before(item) {
68
68
  return {
69
- __proto__: Object.getPrototypeOf(this),
69
+ __proto__: getPrototype(this),
70
70
  ...this,
71
71
  filters: this.filters.with(..._getBeforeFilters(this.sorts, item)),
72
72
  };
@@ -75,7 +75,7 @@ export class QueryConstraints extends Constraint {
75
75
  if (this.limit === limit)
76
76
  return this;
77
77
  return {
78
- __proto__: Object.getPrototypeOf(this),
78
+ __proto__: getPrototype(this),
79
79
  ...this,
80
80
  limit,
81
81
  };
@@ -4,13 +4,13 @@ import type { Nullish } from "../util/null.js";
4
4
  import { Rankable } from "../util/sort.js";
5
5
  import type { Constraint } from "./Constraint.js";
6
6
  /** Format that allows sorts to be set as a plain string, e.g. `name` sorts by name in ascending order and `!date` sorts by date in descending order. */
7
- export declare type SortKey<T extends Data> = DataKey<T> | `${DataKey<T>}` | `!${DataKey<T>}`;
7
+ export type SortKey<T extends Data> = DataKey<T> | `${DataKey<T>}` | `!${DataKey<T>}`;
8
8
  /** One or more sort keys. */
9
- export declare type SortKeys<T extends Data> = SortKey<T> | ImmutableArray<SortKey<T>>;
9
+ export type SortKeys<T extends Data> = SortKey<T> | ImmutableArray<SortKey<T>>;
10
10
  /** Possible operator references. */
11
- export declare type SortDirection = "ASC" | "DESC";
11
+ export type SortDirection = "ASC" | "DESC";
12
12
  /** List of sorts in a flexible format. */
13
- export declare type SortList<T extends Data> = Nullish<SortKeys<T> | SortConstraint<T> | Iterable<SortList<T>>>;
13
+ export type SortList<T extends Data> = Nullish<SortKeys<T> | SortConstraint<T> | Iterable<SortList<T>>>;
14
14
  /** Sort a list of values. */
15
15
  export declare class SortConstraint<T extends Data = Data> implements Constraint<T>, Rankable<T> {
16
16
  readonly key: string;
@@ -1,6 +1,9 @@
1
1
  import { rank, rankAsc, rankDesc, sortItems } from "../util/sort.js";
2
2
  /** Sort a list of values. */
3
3
  export class SortConstraint {
4
+ get sortKey() {
5
+ return `"${this.direction === "DESC" ? "!" : ""}${this.key}"`;
6
+ }
4
7
  constructor(sortKey) {
5
8
  if (sortKey.startsWith("!")) {
6
9
  this.key = sortKey.slice(1);
@@ -11,9 +14,6 @@ export class SortConstraint {
11
14
  this.direction = "ASC";
12
15
  }
13
16
  }
14
- get sortKey() {
15
- return `"${this.direction === "DESC" ? "!" : ""}${this.key}"`;
16
- }
17
17
  rank(left, right) {
18
18
  return rank(left[this.key], this.direction === "ASC" ? rankAsc : rankDesc, right[this.key]);
19
19
  }
package/db/Change.d.ts CHANGED
@@ -33,13 +33,13 @@ export interface DeleteChange<T extends Datas, K extends DataKey<T> = DataKey<T>
33
33
  readonly id: string;
34
34
  }
35
35
  /** Set, update, or delete change on an item. */
36
- export declare type ItemChange<T extends Datas, K extends DataKey<T> = DataKey<T>> = SetChange<T, K> | UpdateChange<T, K> | DeleteChange<T, K>;
36
+ export type ItemChange<T extends Datas, K extends DataKey<T> = DataKey<T>> = SetChange<T, K> | UpdateChange<T, K> | DeleteChange<T, K>;
37
37
  /** Array of item changes. */
38
- export declare type ItemChanges<T extends Datas, K extends DataKey<T> = DataKey<T>> = ImmutableArray<ItemChange<T, K>>;
38
+ export type ItemChanges<T extends Datas, K extends DataKey<T> = DataKey<T>> = ImmutableArray<ItemChange<T, K>>;
39
39
  /** Write change on an item. */
40
- export declare type WriteChange<T extends Datas, K extends DataKey<T> = DataKey<T>> = ItemChange<T, K> | AddChange<T, K>;
40
+ export type WriteChange<T extends Datas, K extends DataKey<T> = DataKey<T>> = ItemChange<T, K> | AddChange<T, K>;
41
41
  /** Array of write changes. */
42
- export declare type WriteChanges<T extends Datas, K extends DataKey<T> = DataKey<T>> = ImmutableArray<WriteChange<T, K>>;
42
+ export type WriteChanges<T extends Datas, K extends DataKey<T> = DataKey<T>> = ImmutableArray<WriteChange<T, K>>;
43
43
  /** Apply a set of changes to a synchronous provider. */
44
44
  export declare function changeProvider<T extends Datas, K extends DataKey<T>>(provider: Provider<T>, ...changes: DeepIterable<Nullish<WriteChange<T, K>>>[]): ItemChanges<T, K>;
45
45
  /** Apply a set of changes to an asynchronous provider. */
package/db/Item.d.ts CHANGED
@@ -7,15 +7,15 @@ import type { DeleteChange, SetChange, UpdateChange } from "./Change.js";
7
7
  import type { AsyncQuery, Query } from "./Query.js";
8
8
  import type { AsyncDatabase, Database } from "./Database.js";
9
9
  /** Item data with a string ID that uniquely identifies it. */
10
- export declare type ItemData<T extends Data = Data> = T & {
10
+ export type ItemData<T extends Data = Data> = T & {
11
11
  id: string;
12
12
  };
13
13
  /** Entity or `null` to indicate the item doesn't exist. */
14
- export declare type ItemValue<T extends Data = Data> = ItemData<T> | null;
14
+ export type ItemValue<T extends Data = Data> = ItemData<T> | null;
15
15
  /** An array of item data. */
16
- export declare type ItemArray<T extends Data = Data> = ImmutableArray<ItemData<T>>;
16
+ export type ItemArray<T extends Data = Data> = ImmutableArray<ItemData<T>>;
17
17
  /** A set of query constraints for item data. */
18
- export declare type ItemConstraints<T extends Data = Data> = QueryConstraints<ItemData<T>>;
18
+ export type ItemConstraints<T extends Data = Data> = QueryConstraints<ItemData<T>>;
19
19
  /** Reference to an item in a synchronous or asynchronous database. */
20
20
  declare abstract class BaseItem<T extends Datas = Datas, K extends DataKey<T> = DataKey<T>> implements AsyncIterable<ItemValue<T[K]>> {
21
21
  abstract readonly db: Database<T> | AsyncDatabase<T>;
@@ -7,7 +7,7 @@ export class ThroughError extends Error {
7
7
  constructor(message, cause) {
8
8
  super(message);
9
9
  this.cause = cause;
10
- this.stack = `${this.stack}\nCause: ${cause instanceof Error ? cause.stack : debug(cause)}`;
10
+ this.stack = `${this.stack || ""}\nCause: ${cause instanceof Error ? cause.stack || "" : debug(cause)}`;
11
11
  }
12
12
  }
13
13
  ThroughError.prototype.name = "ThroughError";
package/markup/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./options.js";
2
+ export * from "./rule.js";
2
3
  export * from "./rules.js";
3
4
  export * from "./render.js";
4
5
  export * from "./regexp.js";
package/markup/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./options.js";
2
+ export * from "./rule.js";
2
3
  export * from "./rules.js";
3
4
  export * from "./render.js";
4
5
  export * from "./regexp.js";
@@ -1,6 +1,6 @@
1
- import { MarkupRules } from "./rules.js";
1
+ import type { MarkupRules } from "./rule.js";
2
2
  /** The current parsing options (represents the current state of the parsing). */
3
- export declare type MarkupOptions = {
3
+ export type MarkupOptions = {
4
4
  /** The active list of parsing rules. */
5
5
  readonly rules: MarkupRules;
6
6
  /** The initial context to start parsing in (rules may render their children with a different context). */
@@ -2,13 +2,13 @@ import type { Data } from "../util/data.js";
2
2
  import { NamedRegExp, NamedRegExpData, PossibleRegExp } from "../util/regexp.js";
3
3
  import type { MarkupOptions } from "./options.js";
4
4
  /** Subset of `NamedRegExpArray<T>` that are the only things we're required return from a `MarkupMatcher` function. */
5
- export declare type MarkupMatch<T extends Data | undefined = Data | undefined> = {
5
+ export type MarkupMatch<T extends Data | undefined> = {
6
6
  0: string;
7
7
  index: number;
8
8
  groups: T;
9
9
  };
10
10
  /** Function that matches a string and returns a `MarkupMatch` or `null` or `void` */
11
- export declare type MarkupMatcher<T extends Data | undefined = Data | undefined> = (input: string, options: MarkupOptions) => MarkupMatch<T> | null | void;
11
+ export type MarkupMatcher<T extends Data> = (input: string, options: MarkupOptions) => MarkupMatch<T> | null | void;
12
12
  export declare const LINE_REGEXP: RegExp;
13
13
  export declare const LINE_START_REGEXP: RegExp;
14
14
  export declare const LINE_END_REGEXP: RegExp;
package/markup/render.js CHANGED
@@ -77,49 +77,48 @@ function _renderElement(element, options, context) {
77
77
  */
78
78
  function* _parseString(input, options, context, offset = 0) {
79
79
  let matchedRule = undefined;
80
- let matchedPriority = Number.MIN_SAFE_INTEGER;
81
- let matchedIndex = Number.MIN_SAFE_INTEGER;
82
- let matchedLength = 0;
83
- let matchedGroups = undefined;
80
+ let matchedResult = undefined;
81
+ let highPriority = Number.MIN_SAFE_INTEGER;
82
+ let lowIndex = Number.MIN_SAFE_INTEGER;
84
83
  // Loop through all rules in the list and see if any match.
85
84
  for (const rule of options.rules) {
86
85
  // Only apply this rule if both:
87
86
  // 1. The priority is equal or higher to the current priority.
88
87
  // 2. The rule is allowed in the current context.
89
- const { priority = 0, match, contexts } = rule;
90
- if (priority >= matchedPriority && contexts.includes(context)) {
91
- const result = typeof match === "function" ? match(input, options) : match.exec(input);
88
+ const { priority } = rule;
89
+ if (rule.priority >= highPriority && rule.contexts.includes(context)) {
90
+ const result = rule.match(input, options);
92
91
  if (result) {
93
92
  // Use the match if it has length and is earlier in the string or is higher priority.
94
- const { 0: { length } = "", index, groups } = result;
95
- if (length && (index < matchedIndex || priority > matchedPriority)) {
93
+ const { 0: { length } = "", index } = result;
94
+ if (length && (index < lowIndex || rule.priority > highPriority)) {
96
95
  matchedRule = rule;
97
- matchedPriority = priority;
98
- matchedIndex = index;
99
- matchedLength = length;
100
- matchedGroups = groups;
96
+ matchedResult = result;
97
+ highPriority = priority;
98
+ lowIndex = index;
101
99
  }
102
100
  }
103
101
  }
104
102
  }
105
103
  // Did at least one rule match?
106
- if (matchedRule && matchedLength) {
104
+ if (matchedRule && matchedResult) {
107
105
  // If index is more than zero, then the string before the match may match another rule at lower priority.
108
- const prefix = input.slice(0, matchedIndex);
106
+ const prefix = input.slice(0, lowIndex);
109
107
  if (prefix.length)
110
108
  yield* _parseString(prefix, options, context, offset);
111
109
  // Call the rule's `render()` function to generate the node.
112
110
  // React gets annoyed if we don't set a `key:` property on lists of elements.
113
111
  // We use the string offset as the `.key` property in the element because it's cheap to calculate and guaranteed to be unique within the string.
114
112
  // Trying to generate an incrementing number would require tracking the number and passing it back and forth through `_parseString()`
115
- const { render, subcontext } = matchedRule;
116
- const element = render(matchedGroups, options);
117
- element.key = offset + matchedIndex;
113
+ const { 0: { length } = "", groups, index } = matchedResult;
114
+ const element = matchedRule.render(groups, options);
115
+ element.key = offset + index;
116
+ const { subcontext } = matchedRule;
118
117
  yield subcontext ? _renderElement(element, options, subcontext) : element;
119
118
  // Decrement the content.
120
- const suffix = input.slice(matchedIndex + matchedLength);
119
+ const suffix = input.slice(index + length);
121
120
  if (suffix.length)
122
- yield* _parseString(suffix, options, context, offset + matchedIndex + matchedLength);
121
+ yield* _parseString(suffix, options, context, offset + index + length);
123
122
  }
124
123
  else {
125
124
  // If nothing matched return the entire string..
@@ -0,0 +1,80 @@
1
+ import { NamedRegExp, NamedRegExpArray, NamedRegExpData } from "../util/regexp.js";
2
+ import { Data } from "../util/data.js";
3
+ import { JSXElement } from "../util/jsx.js";
4
+ import { ImmutableArray } from "../util/array.js";
5
+ import { MarkupOptions } from "./options.js";
6
+ export type MarkupRuleMatch<T extends Data = Data> = {
7
+ 0: string;
8
+ index: number;
9
+ groups?: T;
10
+ };
11
+ export declare abstract class MarkupRule {
12
+ /**
13
+ * Contexts this rule should be applied in,
14
+ *
15
+ * @example `["block", "inline", "list"]`
16
+ */
17
+ readonly contexts: ImmutableArray<string>;
18
+ /**
19
+ * Context that children should be rendered with.
20
+ *
21
+ * @example `"inline"` // Children of the element rendered by this rule will be parsed against markup rules applied in the "inline" context.
22
+ */
23
+ readonly subcontext: string | null;
24
+ /**
25
+ * Priority for this rule (defaults to zero).
26
+ *
27
+ * @example e.g. `<p>` rule is lower priority than other blocks so it matches last and paragraphs can be interrupted by e.g. `<ul>` and `<blockquote>`.
28
+ * @example e.g. `<code>` rule is higher priority than other inlines so e.g. `<strong>` or `<em>` don't match inside a code block.
29
+ */
30
+ readonly priority: number;
31
+ constructor(contexts: ImmutableArray<string>, //
32
+ subcontext?: string | null, priority?: number);
33
+ /** Match an input string against this */
34
+ abstract match(input: string, options: MarkupOptions): MarkupRuleMatch | null;
35
+ /** Render the JSX element for this rule using the props matched by `.match` */
36
+ abstract render(props: Data | undefined, options: MarkupOptions): JSXElement;
37
+ }
38
+ export declare class RegExpMarkupRule extends MarkupRule {
39
+ private readonly _regexp;
40
+ private readonly _render;
41
+ constructor(_regexp: RegExp, //
42
+ _render: (props: Data, options: MarkupOptions) => JSXElement, contexts: ImmutableArray<string>, subcontext?: string | null, priority?: number);
43
+ match(input: string): MarkupRuleMatch | null;
44
+ render(props: Data, options: MarkupOptions): JSXElement;
45
+ }
46
+ export declare class NamedRegExpMarkupRule<T extends NamedRegExpData> extends MarkupRule {
47
+ private readonly _regexp;
48
+ private readonly _render;
49
+ constructor(_regexp: NamedRegExp<T>, //
50
+ _render: (props: T, options: MarkupOptions) => JSXElement, contexts: ImmutableArray<string>, subcontext?: string | null, priority?: number);
51
+ match(input: string): NamedRegExpArray<T> | null;
52
+ render(props: T, options: MarkupOptions): JSXElement;
53
+ }
54
+ export declare class LinkRegExpMarkupRule extends MarkupRule {
55
+ readonly _regexp: NamedRegExp<{
56
+ title?: string;
57
+ href: string;
58
+ }>;
59
+ readonly _render: (props: {
60
+ title: string;
61
+ href: string;
62
+ }, options: MarkupOptions) => JSXElement;
63
+ constructor(_regexp: NamedRegExp<{
64
+ title?: string;
65
+ href: string;
66
+ }>, //
67
+ _render: (props: {
68
+ title: string;
69
+ href: string;
70
+ }, options: MarkupOptions) => JSXElement, contexts: ImmutableArray<string>, subcontext?: string | null, priority?: number);
71
+ match(input: string, { schemes, url: base }: MarkupOptions): MarkupRuleMatch<{
72
+ title: string;
73
+ href: string;
74
+ }> | null;
75
+ render(props: {
76
+ title: string;
77
+ href: string;
78
+ }, options: MarkupOptions): JSXElement<import("../util/jsx.js").JSXProps>;
79
+ }
80
+ export type MarkupRules = MarkupRule[];
package/markup/rule.js ADDED
@@ -0,0 +1,63 @@
1
+ import { formatURL, getOptionalURL } from "../util/url.js";
2
+ export class MarkupRule {
3
+ constructor(contexts, //
4
+ subcontext = null, priority = 0) {
5
+ this.contexts = contexts;
6
+ this.subcontext = subcontext;
7
+ this.priority = priority;
8
+ }
9
+ }
10
+ export class RegExpMarkupRule extends MarkupRule {
11
+ constructor(_regexp, //
12
+ _render, contexts, subcontext, priority) {
13
+ super(contexts, subcontext, priority);
14
+ this._regexp = _regexp;
15
+ this._render = _render;
16
+ }
17
+ match(input) {
18
+ return this._regexp.exec(input);
19
+ }
20
+ render(props, options) {
21
+ return this._render(props, options);
22
+ }
23
+ }
24
+ export class NamedRegExpMarkupRule extends MarkupRule {
25
+ constructor(_regexp, //
26
+ _render, contexts, subcontext, priority) {
27
+ super(contexts, subcontext, priority);
28
+ this._regexp = _regexp;
29
+ this._render = _render;
30
+ }
31
+ match(input) {
32
+ return this._regexp.exec(input);
33
+ }
34
+ render(props, options) {
35
+ return this._render(props, options);
36
+ }
37
+ }
38
+ export class LinkRegExpMarkupRule extends MarkupRule {
39
+ constructor(_regexp, //
40
+ _render, contexts, subcontext, priority) {
41
+ super(contexts, subcontext, priority);
42
+ this._regexp = _regexp;
43
+ this._render = _render;
44
+ }
45
+ // Validates that the link is a valid URL (using `getOptionalURL()` to resolve relative links relative to `options.url`).
46
+ // Validates that the link's URL scheme is in the `options.schemes` whitelist (defaults to `http` and `https`).
47
+ // Generates a default title for the link using `formatURL()` (e.g. `shax.com/my/dir`).
48
+ match(input, { schemes, url: base }) {
49
+ const match = this._regexp.exec(input);
50
+ if (match) {
51
+ const { 0: first, index, groups } = match;
52
+ const { href, title } = groups;
53
+ const url = getOptionalURL(href, base);
54
+ if (url && schemes.includes(url.protocol)) {
55
+ return { 0: first, index, groups: { href: url.href, title: (title === null || title === void 0 ? void 0 : title.trim()) || formatURL(url) } };
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ render(props, options) {
61
+ return this._render(props, options);
62
+ }
63
+ }