Skip to content

Commit 8188c6d

Browse files
committed
Rewrite library, tests, and examples
Changed: - Replaced terribly underperformant—and too clever—throw/catch pattern with a fallback/middleware pattern. - Replaced `FilterException`, `BadValueException`, and `TypeMismatchException` with single `FilterError`. - Replaced `createFilterResolver()` with `createFilterMiddleware()` to use composite filter functions instead of iterating them for each attribute. - Renamed `createFilterFunction()` with `createFilterCallable()` for a more versatile name. - Renamed `createFilterArray()` with `createFilterList()` for a more generic name. - Altered `filterList()` to expect a string instead of relying on a try/catch. - Removed obsolete `createFilterChain()`. - Added helper function `filterFallback()` to resolve the fallback argument with support for the middleware pattern. - Integrated `filterFallback()` into `filterStringable()`, `filterToken()`, `filterValue()`, and `filterList()`. - Renamed module file for `createOrderedAttributesComparator()`. - Update benchmarks to reflect significant performance improvements.
1 parent 4a37284 commit 8188c6d

40 files changed

+1085
-1084
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,16 @@ implementations against a few simple use cases that cover most HTML attributes:
120120

121121
```
122122
# Set #1
123-
Original x 1,321,465 ops/sec ±0.16% (98 runs sampled)
124-
Current x 13,828 ops/sec ±0.35% (87 runs sampled)
123+
Original x 1,327,189 ops/sec ±0.14% (94 runs sampled)
124+
Current x 995,463 ops/sec ±0.09% (98 runs sampled)
125125
126126
# Set #2
127-
Original x 1,640,239 ops/sec ±0.13% (101 runs sampled)
128-
Current x 20,588 ops/sec ±0.29% (99 runs sampled)
127+
Original x 1,643,401 ops/sec ±0.08% (101 runs sampled)
128+
Current x 1,191,994 ops/sec ±0.13% (101 runs sampled)
129129
130130
# Set #3
131-
Original x 946,995 ops/sec ±0.12% (101 runs sampled)
132-
Current x 37,336 ops/sec ±0.23% (96 runs sampled)
131+
Original x 947,281 ops/sec ±0.07% (101 runs sampled)
132+
Current x 924,929 ops/sec ±0.06% (98 runs sampled)
133133
```
134134

135135
## Implementations in other languages

docs/api.error.md

Lines changed: 42 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -2,166 +2,97 @@
22

33
> [`@mcaskill/html-build-attributes/lib/error.js`](/src/lib/error.ts)
44
5-
The error module provides custom `Error` objects thrown to escape filters
6-
and when runtime errors occur.
5+
The error module provides a custom `Error` object meant to be used by
6+
filter functions. This is mostly useful to catch errors related to
7+
attribute value filtering.
78

89
> For all API functions listed:
910
>
10-
> * `AttrName` is a string and represents an attribute name.
11-
> * `AttrValue` is a string, boolean, or null, and represents a filtered attribute value.
1211
> * `T` represents any data type.
12+
> * `AttrName` is a string and represents an attribute name.
13+
> * `AttrValue` is a string or boolean and represents a filtered attribute value.
1314
14-
## `FilterException()`
15-
16-
The `FilterException` object represents an error with a value to be filtered.
15+
## `FilterError()`
1716

18-
The [`BadValueException`](#badvalueerror) and [`TypeMismatchException`](#typemismatcherror)
19-
objects extend the `FilterException` object.
17+
The `FilterError` object represents an error with a value being filtered.
2018

2119
### Syntax
2220

2321
```ts
24-
new FilterException(message: string, options?: object)
22+
new FilterError(message: string, options?: object)
2523
```
2624

27-
## `FilterException.describeAttr()`
25+
## `FilterError.describeAttr()`
2826

2927
A static method to format the attribute name or value.
3028

31-
This method is used by the static creator methods to generate an error message.
29+
This method is used by the static creator method to generate a descriptor
30+
for the placeholder token.
3231

3332
### Syntax
3433

3534
```ts
36-
FilterException.describeAttr(value?: T, name?: AttrName): string
35+
FilterError.describeAttr(value?: T, name?: AttrName): string
3736
```
3837

3938
### Examples
4039

4140
```js
42-
FilterException.describeAttr(null);
43-
// → null
44-
45-
FilterException.describeAttr(undefined);
46-
// → undefined
47-
48-
FilterException.describeAttr(true);
49-
// → boolean
50-
51-
FilterException.describeAttr(42);
52-
// → number
41+
FilterError.describeAttr(null);
42+
// → 'null'
5343

54-
FilterException.describeAttr('hello');
55-
//string
44+
FilterError.describeAttr(undefined);
45+
//'undefined'
5646

57-
FilterException.describeAttr([ 1, 2, 3 ]);
58-
//array
47+
FilterError.describeAttr(true);
48+
//'boolean'
5949

60-
FilterException.describeAttr(new Date());
61-
//object
50+
FilterError.describeAttr(42);
51+
//'number'
6252

63-
FilterException.describeAttr('hello', 'class');
64-
// → attribute [class]
65-
```
66-
67-
## `FilterException.createNotFilterable()`
53+
FilterError.describeAttr([ 1, 2, 3 ]);
54+
// → 'Array'
6855

69-
A static method to create a new error object with a generic "is not filterable"
70-
message derived from the provided parameters.
56+
FilterError.describeAttr({});
57+
// → 'Object'
7158

72-
This method is recommended for creating `TypeMismatchException` objects.
59+
FilterError.describeAttr(new Date());
60+
// → 'Date'
7361

74-
### Syntax
62+
FilterError.describeAttr('hello');
63+
// → 'string'
7564

76-
```ts
77-
FilterException.createNotFilterable(
78-
value?: T,
79-
name?: AttrName,
80-
options?: object
81-
): FilterException
65+
FilterError.describeAttr('hello', 'class');
66+
// → 'attribute [class]'
8267
```
8368

84-
### Example
85-
86-
```js
87-
function filterNumber(value) {
88-
if (typeof value === 'number') {
89-
return value;
90-
}
91-
92-
throw new TypeMismatchException.createNotFilterable(value);
93-
}
94-
```
95-
96-
## `FilterException.createNotConcatenable()`
97-
98-
A static method to create a new error object with a generic "is not concatenable"
99-
message derived from the provided parameters.
69+
## `FilterError.create()`
10070

101-
This method is recommended for creating `TypeMismatchException` objects.
71+
A static method to create a new error object with a message where `{attr}`
72+
is a placeholder that will be substituded with a name or value.
10273

10374
### Syntax
10475

10576
```ts
106-
FilterException.createNotConcatenable(
107-
value?: T,
77+
FilterError.create(
78+
message: string,
79+
value: T,
10880
name?: AttrName,
10981
options?: object
110-
): FilterException
82+
): FilterError
11183
```
11284

11385
### Example
11486

11587
```js
116-
function filterList(value) {
117-
const tokens = [];
118-
119-
for (const token of value) {
120-
try {
121-
tokens.push(filterString(token));
122-
} catch (err) {
123-
throw TypeMismatchException.createNotConcatenable(value, null, { cause: err });
124-
}
125-
}
126-
127-
return tokens;
128-
}
129-
```
130-
131-
## `BadValueException()`
132-
133-
The `BadValueException` object represents a value that
134-
a filter is unable to convert.
135-
136-
### Example
137-
138-
```js
139-
function assertFiniteNumber(value) {
140-
if (Number.isFinite(value)) {
141-
return value;
142-
}
143-
144-
throw new BadValueException('number is not finite');
145-
}
146-
```
147-
148-
## `TypeMismatchException()`
149-
150-
The `TypeMismatchException` object represents a value that
151-
does not conform to the filter's constraints.
152-
153-
For the [compose module](/docs/api.compose.md) and
154-
[aggregate filters](/docs/api.filter.md), this indicates a filter
155-
does not accept the value and should maybe try another filter.
156-
157-
### Example
158-
159-
```js
160-
function filterNumber(value) {
88+
function filterNumber(value, name) {
16189
if (typeof value === 'number') {
16290
return value;
16391
}
16492

165-
throw new TypeMismatchException('value is not a number');
93+
throw FilterError.create('{attr} is not a number', value, name);
16694
}
95+
96+
filterNumber(true);
97+
// → Uncaught FilterError: boolean is not a number
16798
```

0 commit comments

Comments
 (0)