afformative 0.6.2 → 0.7.0-beta.1
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/README.md +97 -101
- package/dist/index.d.mts +33 -0
- package/dist/index.mjs +14 -0
- package/package.json +35 -12
- package/dist/afformative.cjs.js +0 -73
- package/dist/afformative.esm.js +0 -64
- package/dist/afformative.umd.js +0 -140
- package/dist/afformative.umd.min.js +0 -1
- package/dist/types/index.d.ts +0 -2
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/makeFormatter.d.ts +0 -94
- package/dist/types/makeFormatter.d.ts.map +0 -1
- package/src/index.ts +0 -1
- package/src/makeFormatter.test.ts +0 -159
- package/src/makeFormatter.ts +0 -214
- package/tsconfig.build.json +0 -6
package/README.md
CHANGED
|
@@ -11,11 +11,11 @@ A standardized way to format values in your React components.
|
|
|
11
11
|
</h3>
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
|
-
Afformative helps UI component libraries
|
|
14
|
+
Afformative helps UI component libraries display arbitrary data in a reusable, plug-and-play fashion. Formatting dates and enum translations in your select fields and data grids has never been easier.
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
18
|
-
<a href="https://github.com/wafflepie/
|
|
18
|
+
<a href="https://github.com/wafflepie/afformative/blob/master/LICENSE">
|
|
19
19
|
<img src="https://flat.badgen.net/badge/license/MIT/blue" alt="MIT License" />
|
|
20
20
|
</a>
|
|
21
21
|
|
|
@@ -26,94 +26,113 @@ Afformative helps UI component libraries visualise arbitrary data in a reusable,
|
|
|
26
26
|
|
|
27
27
|
## Installation
|
|
28
28
|
|
|
29
|
-
Use
|
|
29
|
+
Use one of these commands, depending on your preferred package manager:
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
32
|
yarn add afformative
|
|
33
33
|
|
|
34
|
+
pnpm add afformative
|
|
35
|
+
|
|
34
36
|
npm i afformative
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
## Quick Start
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
### The Holy Standard
|
|
41
|
+
A formatter is an object with `format`, `stringify`, and `compare` methods. Formatters must be created using the `createFormatter` function.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
`createFormatter` accepts a single object parameter. `format` is the only required property, but specifying `stringify` is recommended in most cases.
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
```tsx
|
|
46
|
+
import { createFormatter } from "afformative"
|
|
47
|
+
import { ReactNode } from "react"
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const dateFormatter = createFormatter<Date, ReactNode>({
|
|
50
|
+
format: value => <time dateTime={value.toISOString()}>{value.toLocaleDateString()}</time>,
|
|
51
|
+
stringify: value => value.toLocaleDateString(),
|
|
52
|
+
})
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
dateFormatter.format(new Date()) // <time dateTime="2026-05-30T09:17:26.263Z">30/05/2026</time>
|
|
55
|
+
dateFormatter.formatAsString(new Date()) // "30/05/2026"
|
|
53
56
|
```
|
|
54
57
|
|
|
55
|
-
Consume formatters in your UI component library
|
|
58
|
+
Consume formatters in your UI component library via a conventional `formatter` prop.
|
|
56
59
|
|
|
57
|
-
```
|
|
58
|
-
import {
|
|
60
|
+
```tsx
|
|
61
|
+
import { Formatter } from "afformative"
|
|
62
|
+
import { ReactNode } from "react"
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<select {...otherProps}>
|
|
65
|
-
{items.map(item => {
|
|
66
|
-
const text = formatter.format(item)
|
|
64
|
+
interface ListProps<TItem> {
|
|
65
|
+
formatter: Formatter<TItem, ReactNode>
|
|
66
|
+
items: TItem[]
|
|
67
|
+
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
</select>
|
|
69
|
+
const List = <TItem extends unknown>({ formatter, items }: ListProps<TItem>) => (
|
|
70
|
+
<ul>
|
|
71
|
+
{items.map(item => (
|
|
72
|
+
<li key={formatter.stringify(item)}>{formatter.format(item)}</li>
|
|
73
|
+
))}
|
|
74
|
+
</ul>
|
|
75
75
|
)
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Although formatters can render icons or custom translation components, we often need to access primitive data instead of React elements.
|
|
78
|
+
The `stringify` method is useful when you need a plain string representation of a value. For example, a combobox component can use it to match items against the user's typed input.
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
## Compare
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
Every formatter exposes a `compare` method, which can be used to sort values. The default implementation compares the return values of `stringify` via `localeCompare`. In the following example, `Amount` objects are sorted first by currency, then by value.
|
|
85
83
|
|
|
86
|
-
```
|
|
87
|
-
import {
|
|
84
|
+
```tsx
|
|
85
|
+
import { createFormatter } from "afformative"
|
|
86
|
+
import { ReactNode } from "react"
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
interface Amount {
|
|
89
|
+
currency: string
|
|
90
|
+
value: number
|
|
91
|
+
}
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
const amountFormatter = createFormatter<Amount, ReactNode>({
|
|
94
|
+
format: ({ currency, value }) => (
|
|
95
|
+
<span className="currency">{`${currency} ${value.toFixed(2)}`}</span>
|
|
96
|
+
),
|
|
97
|
+
stringify: ({ currency, value }) => `${currency} ${value.toFixed(2)}`,
|
|
98
|
+
compare: (a, b) => a.currency.localeCompare(b.currency) || a.value - b.value,
|
|
95
99
|
})
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
const amounts: Amount[] = [
|
|
102
|
+
{ currency: "USD", value: 3 },
|
|
103
|
+
{ currency: "EUR", value: 1 },
|
|
104
|
+
{ currency: "EUR", value: 5 },
|
|
105
|
+
{ currency: "USD", value: 2 },
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
amounts.sort(amountFormatter.compare)
|
|
109
|
+
// [{ EUR, 1 }, { EUR, 5 }, { USD, 2 }, { USD, 3 }]
|
|
99
110
|
```
|
|
100
111
|
|
|
101
|
-
|
|
112
|
+
## Usage Context
|
|
102
113
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
You can pass an optional usage context object to all formatter methods. Let's use a dummy table component as an example.
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import { Formatter } from "afformative"
|
|
118
|
+
import { ReactNode } from "react"
|
|
107
119
|
|
|
108
|
-
|
|
120
|
+
interface TableFormatterUsageContext {
|
|
121
|
+
row: number[]
|
|
122
|
+
cellIndex: number
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface TableProps {
|
|
126
|
+
rows: number[][]
|
|
127
|
+
formatter: Formatter<number, ReactNode, TableFormatterUsageContext>
|
|
128
|
+
}
|
|
109
129
|
|
|
110
|
-
|
|
111
|
-
const Table = ({ rows, formatter = identityFormatter }) => (
|
|
130
|
+
const Table = ({ rows, formatter }: TableProps) => (
|
|
112
131
|
<table>
|
|
113
132
|
{rows.map(row => (
|
|
114
133
|
<tr>
|
|
115
134
|
{row.map((cell, cellIndex) => (
|
|
116
|
-
<td>{formatter.format(cell,
|
|
135
|
+
<td>{formatter.format(cell, { row, cellIndex })}</td>
|
|
117
136
|
))}
|
|
118
137
|
</tr>
|
|
119
138
|
))}
|
|
@@ -121,72 +140,49 @@ const Table = ({ rows, formatter = identityFormatter }) => (
|
|
|
121
140
|
)
|
|
122
141
|
```
|
|
123
142
|
|
|
124
|
-
|
|
143
|
+
Usage context allows the users of this table component to write purpose-built formatters, making it possible to take other values in the same row into account. For example, the following formatter would change the color of the cell value based on the previous value in the same row.
|
|
125
144
|
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return <span>{value}</span>
|
|
130
|
-
}
|
|
145
|
+
```tsx
|
|
146
|
+
import { createFormatter } from "afformative"
|
|
147
|
+
import { ReactNode } from "react"
|
|
131
148
|
|
|
132
|
-
|
|
149
|
+
import { TableFormatterUsageContext } from "./Table"
|
|
133
150
|
|
|
134
|
-
|
|
151
|
+
const rowTrendFormatter = createFormatter<number, ReactNode, TableFormatterUsageContext>({
|
|
152
|
+
format: (value, { row, cellIndex }) => {
|
|
153
|
+
if (cellIndex === 0) {
|
|
154
|
+
return <span>{value}</span>
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const previousValue = row[cellIndex - 1]
|
|
158
|
+
|
|
159
|
+
return <span style={{ color: value >= previousValue ? "green" : "red" }}>{value}</span>
|
|
160
|
+
},
|
|
135
161
|
})
|
|
136
162
|
```
|
|
137
163
|
|
|
138
|
-
|
|
164
|
+
This formatter only makes sense in the context of our table component.
|
|
139
165
|
|
|
140
|
-
Because `row` and `cellIndex` are passed as the
|
|
166
|
+
Because `row` and `cellIndex` are passed as the usage context, the formatter still receives only the cell value as its first parameter. This means generic formatters (e.g. a currency formatter) can be passed to the table component without any changes.
|
|
141
167
|
|
|
142
|
-
|
|
168
|
+
## Accessing React Context
|
|
143
169
|
|
|
144
|
-
|
|
170
|
+
Create formatters inside custom hooks to access React context values such as translations or application state.
|
|
145
171
|
|
|
146
|
-
```
|
|
147
|
-
const useEnumFormatter = enumType => {
|
|
148
|
-
|
|
149
|
-
// `makeSelectEnumTranslationKeys` is a made-up Redux selector factory.
|
|
150
|
-
const enumTranslationKeys = useSelector(makeSelectEnumTranslationKeys(enumType))
|
|
172
|
+
```tsx
|
|
173
|
+
const useEnumFormatter = (enumType: string): Formatter<string, ReactNode> => {
|
|
174
|
+
const enumTranslationKeys = useSelector(selectEnumTranslationKeys(enumType))
|
|
151
175
|
const intl = useIntl()
|
|
152
176
|
|
|
153
177
|
return useMemo(
|
|
154
178
|
() =>
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
id: enumTranslationKeys[value],
|
|
159
|
-
}),
|
|
179
|
+
createFormatter<string, ReactNode>(
|
|
180
|
+
value => <FormattedMessage defaultMessage={value} id={enumTranslationKeys[value]} />,
|
|
181
|
+
value => intl.formatMessage({ defaultMessage: value, id: enumTranslationKeys[value] }),
|
|
160
182
|
),
|
|
161
183
|
[intl, enumTranslationKeys],
|
|
162
184
|
)
|
|
163
185
|
}
|
|
164
|
-
|
|
165
|
-
const someEnumFormatter = useEnumFormatter("someEnum")
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Consuming Formatters
|
|
169
|
-
|
|
170
|
-
As mentioned earlier, formatters should be passed to components using the conventional `formatter` prop. Alternatively, if you need to pass multiple formatters (e.g. in case of column definitions), pass an array of objects where each object has a `formatter` property.
|
|
171
|
-
|
|
172
|
-
All formatters also expose the `wrap` method. You can use this method to alter the behaviour of the formatter for some specific values.
|
|
173
|
-
|
|
174
|
-
```js
|
|
175
|
-
const useSnowflakeAwareFormatter = formatter => {
|
|
176
|
-
const intl = useIntl()
|
|
177
|
-
|
|
178
|
-
return useMemo(
|
|
179
|
-
() =>
|
|
180
|
-
formatter.wrap((delegate, value) => {
|
|
181
|
-
if (isSnowflake(value)) {
|
|
182
|
-
return intl.formatMessage(messages.snowflake)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return delegate(value)
|
|
186
|
-
}),
|
|
187
|
-
[formatter, intl],
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
186
|
```
|
|
191
187
|
|
|
192
188
|
## Changelog
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/createFormatter.d.ts
|
|
2
|
+
interface FormatterFormatDefinition<TInput, TOutput, TUsageContext extends object = object> {
|
|
3
|
+
(value: TInput, usageContext: Partial<TUsageContext>): TOutput;
|
|
4
|
+
}
|
|
5
|
+
interface FormatterFormat<TInput, TOutput, TUsageContext extends object = object> {
|
|
6
|
+
(value: TInput, usageContext?: Partial<TUsageContext>): TOutput;
|
|
7
|
+
}
|
|
8
|
+
interface FormatterStringifyDefinition<TInput, TUsageContext extends object = object> {
|
|
9
|
+
(value: TInput, usageContext: Partial<TUsageContext>): string;
|
|
10
|
+
}
|
|
11
|
+
interface FormatterStringify<TInput, TUsageContext extends object = object> {
|
|
12
|
+
(value: TInput, usageContext?: Partial<TUsageContext>): string;
|
|
13
|
+
}
|
|
14
|
+
interface FormatterCompareDefinition<TInput, TUsageContext extends object = object> {
|
|
15
|
+
(a: TInput, b: TInput, usageContext: Partial<TUsageContext>): number;
|
|
16
|
+
}
|
|
17
|
+
interface FormatterCompare<TInput, TUsageContext extends object = object> {
|
|
18
|
+
(a: TInput, b: TInput, usageContext?: Partial<TUsageContext>): number;
|
|
19
|
+
}
|
|
20
|
+
interface Formatter<TInput, TOutput, TUsageContext extends object = object> {
|
|
21
|
+
compare: FormatterCompare<TInput, TUsageContext>;
|
|
22
|
+
format: FormatterFormat<TInput, TOutput, TUsageContext>;
|
|
23
|
+
stringify: FormatterStringify<TInput, TUsageContext>;
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
interface CreateFormatterParam<TInput, TOutput, TUsageContext extends object = object> {
|
|
27
|
+
compare?: FormatterCompareDefinition<TInput, TUsageContext>;
|
|
28
|
+
format: FormatterFormatDefinition<TInput, TOutput, TUsageContext>;
|
|
29
|
+
stringify?: FormatterStringifyDefinition<TInput, TUsageContext>;
|
|
30
|
+
}
|
|
31
|
+
declare const createFormatter: <TInput, TOutput, TUsageContext extends object = object>(param: CreateFormatterParam<TInput, TOutput, TUsageContext>) => Formatter<TInput, TOutput, TUsageContext>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { CreateFormatterParam, Formatter, FormatterCompare, FormatterCompareDefinition, FormatterFormat, FormatterFormatDefinition, FormatterStringify, FormatterStringifyDefinition, createFormatter };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/createFormatter.ts
|
|
2
|
+
const createFormatter = (param) => {
|
|
3
|
+
const { format: formatParam, stringify: stringifyParam, compare: compareParam, ...rest } = param;
|
|
4
|
+
const format = (value, usageContext) => formatParam(value, usageContext ?? {});
|
|
5
|
+
const stringify = stringifyParam ? (value, usageContext) => stringifyParam(value, usageContext ?? {}) : (value, usageContext) => String(format(value, usageContext ?? {}));
|
|
6
|
+
return {
|
|
7
|
+
compare: compareParam ? (a, b, usageContext) => compareParam(a, b, usageContext ?? {}) : (a, b, usageContext) => stringify(a, usageContext ?? {}).localeCompare(stringify(b, usageContext ?? {})),
|
|
8
|
+
format,
|
|
9
|
+
stringify,
|
|
10
|
+
...rest
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { createFormatter };
|
package/package.json
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "afformative",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"license": "MIT",
|
|
5
|
-
"main": "dist/afformative.cjs.js",
|
|
6
|
-
"module": "dist/afformative.esm.js",
|
|
7
|
-
"unpkg": "dist/afformative.umd.js",
|
|
8
|
-
"types": "dist/types/index.d.ts",
|
|
3
|
+
"version": "0.7.0-beta.1",
|
|
9
4
|
"description": "A standardized way to format values in your React components.",
|
|
10
5
|
"keywords": [
|
|
11
6
|
"react",
|
|
@@ -24,15 +19,43 @@
|
|
|
24
19
|
"values"
|
|
25
20
|
],
|
|
26
21
|
"repository": "https://github.com/wafflepie/afformative",
|
|
22
|
+
"license": "MIT",
|
|
27
23
|
"contributors": [
|
|
28
|
-
"Vaclav Jancarik <
|
|
24
|
+
"Vaclav Jancarik <hi@wafflepie.dev>"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"type": "module",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./dist/index.mjs",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
29
34
|
],
|
|
30
|
-
"
|
|
31
|
-
"
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsdown",
|
|
37
|
+
"prepublishOnly": "pnpm run build",
|
|
38
|
+
"release": "bumpp",
|
|
39
|
+
"test": "pnpm test:prettier && pnpm run test:typescript && pnpm run test:eslint && pnpm run test:vitest",
|
|
40
|
+
"test:eslint": "eslint src",
|
|
41
|
+
"test:prettier": "prettier --check src",
|
|
42
|
+
"test:typescript": "tsc --noEmit",
|
|
43
|
+
"test:vitest": "vitest run"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@eslint/js": "^10.0.1",
|
|
47
|
+
"@types/node": "^25.6.2",
|
|
48
|
+
"@typescript/native-preview": "^7.0.0-dev.20260527.2",
|
|
49
|
+
"bumpp": "^11.1.0",
|
|
50
|
+
"eslint": "^10.4.1",
|
|
51
|
+
"prettier": "^3.8.3",
|
|
52
|
+
"tsdown": "^0.22.1",
|
|
53
|
+
"typescript": "^6.0.3",
|
|
54
|
+
"typescript-eslint": "^8.60.0",
|
|
55
|
+
"vitest": "^4.1.7"
|
|
32
56
|
},
|
|
57
|
+
"packageManager": "pnpm@11.5.0+sha512.dbfcc4f81cf48597afd4bc391ffdf12c11f1a9fb83a395bfa6b0a2d9cc2fd8ffebafdb1ccbd529632153f793904c2615b7f09fe1a345473fd1c35845172a8eb1",
|
|
33
58
|
"publishConfig": {
|
|
34
59
|
"access": "public"
|
|
35
|
-
}
|
|
36
|
-
"sideEffects": false,
|
|
37
|
-
"gitHead": "3e3b893eee2b69d29019b3683b9d1d719192a2b5"
|
|
60
|
+
}
|
|
38
61
|
}
|
package/dist/afformative.cjs.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
|
|
6
|
-
var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
|
|
7
|
-
|
|
8
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
|
-
|
|
10
|
-
var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
|
|
11
|
-
var _objectWithoutProperties__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutProperties);
|
|
12
|
-
|
|
13
|
-
// TODO: Update `FormatDefinition` type based on this snippet. Sadly, TypeScript cannot correctly
|
|
14
|
-
// verify the return type of the format definition based on the suggestions, printing errors such
|
|
15
|
-
// as `Type 'string' is not assignable to type '"primitive" extends TSuggestion ? string : string'`
|
|
16
|
-
// which is, of course, nonsense. Same applies to `FormatChainDefinition`.
|
|
17
|
-
//
|
|
18
|
-
// interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
19
|
-
// <TSuggestion extends Suggestion>(
|
|
20
|
-
// value: TInput,
|
|
21
|
-
// usageSuggestions: TSuggestion[],
|
|
22
|
-
// dataContext: Partial<TDataContext>,
|
|
23
|
-
// ): PrimitiveSuggestion extends TSuggestion ? TPrimitiveOutput : TOutput
|
|
24
|
-
// }
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Creates a new formatter.
|
|
28
|
-
*
|
|
29
|
-
* @param format Function used to format the value.
|
|
30
|
-
* @param formatterOptions Additional options for the formatter.
|
|
31
|
-
*/
|
|
32
|
-
var makeFormatter = function makeFormatter(format, formatterOptions) {
|
|
33
|
-
var formatter = function formatter(_ref) {
|
|
34
|
-
var _format;
|
|
35
|
-
|
|
36
|
-
var children = _ref.children,
|
|
37
|
-
_ref$suggestions = _ref.suggestions,
|
|
38
|
-
suggestions = _ref$suggestions === void 0 ? [] : _ref$suggestions,
|
|
39
|
-
dataContext = _objectWithoutProperties__default['default'](_ref, ["children", "suggestions"]);
|
|
40
|
-
|
|
41
|
-
return (_format = format(children, suggestions, dataContext)) !== null && _format !== void 0 ? _format : null;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
formatter.displayName = formatterOptions === null || formatterOptions === void 0 ? void 0 : formatterOptions.displayName;
|
|
45
|
-
|
|
46
|
-
formatter.format = function (value) {
|
|
47
|
-
var usageSuggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
48
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
49
|
-
return format(value, usageSuggestions, dataContext);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
formatter.formatAsPrimitive = function (value) {
|
|
53
|
-
var usageSuggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
54
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
55
|
-
return format(value, ["primitive"].concat(_toConsumableArray__default['default'](usageSuggestions)), dataContext);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
formatter.wrap = function (nextFormat, nextFormatterOptions) {
|
|
59
|
-
var nextFormatter = makeFormatter(function (value, usageSuggestions, dataContext) {
|
|
60
|
-
var delegate = function delegate(delegatedValue, delegatedUsageSuggestions, delegatedDataContext) {
|
|
61
|
-
return formatter.format(delegatedValue, delegatedUsageSuggestions !== null && delegatedUsageSuggestions !== void 0 ? delegatedUsageSuggestions : usageSuggestions, delegatedDataContext !== null && delegatedDataContext !== void 0 ? delegatedDataContext : dataContext);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return nextFormat(delegate, value, usageSuggestions, dataContext);
|
|
65
|
-
}, nextFormatterOptions !== null && nextFormatterOptions !== void 0 ? nextFormatterOptions : formatterOptions);
|
|
66
|
-
nextFormatter.innerFormatter = formatter;
|
|
67
|
-
return nextFormatter;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
return formatter;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
exports.makeFormatter = makeFormatter;
|
package/dist/afformative.esm.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import _toConsumableArray from '@babel/runtime/helpers/esm/toConsumableArray';
|
|
2
|
-
import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
|
|
3
|
-
|
|
4
|
-
// TODO: Update `FormatDefinition` type based on this snippet. Sadly, TypeScript cannot correctly
|
|
5
|
-
// verify the return type of the format definition based on the suggestions, printing errors such
|
|
6
|
-
// as `Type 'string' is not assignable to type '"primitive" extends TSuggestion ? string : string'`
|
|
7
|
-
// which is, of course, nonsense. Same applies to `FormatChainDefinition`.
|
|
8
|
-
//
|
|
9
|
-
// interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
10
|
-
// <TSuggestion extends Suggestion>(
|
|
11
|
-
// value: TInput,
|
|
12
|
-
// usageSuggestions: TSuggestion[],
|
|
13
|
-
// dataContext: Partial<TDataContext>,
|
|
14
|
-
// ): PrimitiveSuggestion extends TSuggestion ? TPrimitiveOutput : TOutput
|
|
15
|
-
// }
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Creates a new formatter.
|
|
19
|
-
*
|
|
20
|
-
* @param format Function used to format the value.
|
|
21
|
-
* @param formatterOptions Additional options for the formatter.
|
|
22
|
-
*/
|
|
23
|
-
var makeFormatter = function makeFormatter(format, formatterOptions) {
|
|
24
|
-
var formatter = function formatter(_ref) {
|
|
25
|
-
var _format;
|
|
26
|
-
|
|
27
|
-
var children = _ref.children,
|
|
28
|
-
_ref$suggestions = _ref.suggestions,
|
|
29
|
-
suggestions = _ref$suggestions === void 0 ? [] : _ref$suggestions,
|
|
30
|
-
dataContext = _objectWithoutProperties(_ref, ["children", "suggestions"]);
|
|
31
|
-
|
|
32
|
-
return (_format = format(children, suggestions, dataContext)) !== null && _format !== void 0 ? _format : null;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
formatter.displayName = formatterOptions === null || formatterOptions === void 0 ? void 0 : formatterOptions.displayName;
|
|
36
|
-
|
|
37
|
-
formatter.format = function (value) {
|
|
38
|
-
var usageSuggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
39
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
40
|
-
return format(value, usageSuggestions, dataContext);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
formatter.formatAsPrimitive = function (value) {
|
|
44
|
-
var usageSuggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
45
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
46
|
-
return format(value, ["primitive"].concat(_toConsumableArray(usageSuggestions)), dataContext);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
formatter.wrap = function (nextFormat, nextFormatterOptions) {
|
|
50
|
-
var nextFormatter = makeFormatter(function (value, usageSuggestions, dataContext) {
|
|
51
|
-
var delegate = function delegate(delegatedValue, delegatedUsageSuggestions, delegatedDataContext) {
|
|
52
|
-
return formatter.format(delegatedValue, delegatedUsageSuggestions !== null && delegatedUsageSuggestions !== void 0 ? delegatedUsageSuggestions : usageSuggestions, delegatedDataContext !== null && delegatedDataContext !== void 0 ? delegatedDataContext : dataContext);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
return nextFormat(delegate, value, usageSuggestions, dataContext);
|
|
56
|
-
}, nextFormatterOptions !== null && nextFormatterOptions !== void 0 ? nextFormatterOptions : formatterOptions);
|
|
57
|
-
nextFormatter.innerFormatter = formatter;
|
|
58
|
-
return nextFormatter;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return formatter;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export { makeFormatter };
|
package/dist/afformative.umd.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Afformative = {}));
|
|
5
|
-
}(this, (function (exports) { 'use strict';
|
|
6
|
-
|
|
7
|
-
function _arrayLikeToArray(arr, len) {
|
|
8
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
9
|
-
|
|
10
|
-
for (var i = 0, arr2 = new Array(len); i < len; i++) {
|
|
11
|
-
arr2[i] = arr[i];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return arr2;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function _arrayWithoutHoles(arr) {
|
|
18
|
-
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function _iterableToArray(iter) {
|
|
22
|
-
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function _unsupportedIterableToArray(o, minLen) {
|
|
26
|
-
if (!o) return;
|
|
27
|
-
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
28
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
29
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
30
|
-
if (n === "Map" || n === "Set") return Array.from(o);
|
|
31
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function _nonIterableSpread() {
|
|
35
|
-
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function _toConsumableArray(arr) {
|
|
39
|
-
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
43
|
-
if (source == null) return {};
|
|
44
|
-
var target = {};
|
|
45
|
-
var sourceKeys = Object.keys(source);
|
|
46
|
-
var key, i;
|
|
47
|
-
|
|
48
|
-
for (i = 0; i < sourceKeys.length; i++) {
|
|
49
|
-
key = sourceKeys[i];
|
|
50
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
51
|
-
target[key] = source[key];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return target;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function _objectWithoutProperties(source, excluded) {
|
|
58
|
-
if (source == null) return {};
|
|
59
|
-
var target = _objectWithoutPropertiesLoose(source, excluded);
|
|
60
|
-
var key, i;
|
|
61
|
-
|
|
62
|
-
if (Object.getOwnPropertySymbols) {
|
|
63
|
-
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
|
|
64
|
-
|
|
65
|
-
for (i = 0; i < sourceSymbolKeys.length; i++) {
|
|
66
|
-
key = sourceSymbolKeys[i];
|
|
67
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
68
|
-
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
69
|
-
target[key] = source[key];
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return target;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// TODO: Update `FormatDefinition` type based on this snippet. Sadly, TypeScript cannot correctly
|
|
77
|
-
// verify the return type of the format definition based on the suggestions, printing errors such
|
|
78
|
-
// as `Type 'string' is not assignable to type '"primitive" extends TSuggestion ? string : string'`
|
|
79
|
-
// which is, of course, nonsense. Same applies to `FormatChainDefinition`.
|
|
80
|
-
//
|
|
81
|
-
// interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
82
|
-
// <TSuggestion extends Suggestion>(
|
|
83
|
-
// value: TInput,
|
|
84
|
-
// usageSuggestions: TSuggestion[],
|
|
85
|
-
// dataContext: Partial<TDataContext>,
|
|
86
|
-
// ): PrimitiveSuggestion extends TSuggestion ? TPrimitiveOutput : TOutput
|
|
87
|
-
// }
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Creates a new formatter.
|
|
91
|
-
*
|
|
92
|
-
* @param format Function used to format the value.
|
|
93
|
-
* @param formatterOptions Additional options for the formatter.
|
|
94
|
-
*/
|
|
95
|
-
var makeFormatter = function makeFormatter(format, formatterOptions) {
|
|
96
|
-
var formatter = function formatter(_ref) {
|
|
97
|
-
var _format;
|
|
98
|
-
|
|
99
|
-
var children = _ref.children,
|
|
100
|
-
_ref$suggestions = _ref.suggestions,
|
|
101
|
-
suggestions = _ref$suggestions === void 0 ? [] : _ref$suggestions,
|
|
102
|
-
dataContext = _objectWithoutProperties(_ref, ["children", "suggestions"]);
|
|
103
|
-
|
|
104
|
-
return (_format = format(children, suggestions, dataContext)) !== null && _format !== void 0 ? _format : null;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
formatter.displayName = formatterOptions === null || formatterOptions === void 0 ? void 0 : formatterOptions.displayName;
|
|
108
|
-
|
|
109
|
-
formatter.format = function (value) {
|
|
110
|
-
var usageSuggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
111
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
112
|
-
return format(value, usageSuggestions, dataContext);
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
formatter.formatAsPrimitive = function (value) {
|
|
116
|
-
var usageSuggestions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
117
|
-
var dataContext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
118
|
-
return format(value, ["primitive"].concat(_toConsumableArray(usageSuggestions)), dataContext);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
formatter.wrap = function (nextFormat, nextFormatterOptions) {
|
|
122
|
-
var nextFormatter = makeFormatter(function (value, usageSuggestions, dataContext) {
|
|
123
|
-
var delegate = function delegate(delegatedValue, delegatedUsageSuggestions, delegatedDataContext) {
|
|
124
|
-
return formatter.format(delegatedValue, delegatedUsageSuggestions !== null && delegatedUsageSuggestions !== void 0 ? delegatedUsageSuggestions : usageSuggestions, delegatedDataContext !== null && delegatedDataContext !== void 0 ? delegatedDataContext : dataContext);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
return nextFormat(delegate, value, usageSuggestions, dataContext);
|
|
128
|
-
}, nextFormatterOptions !== null && nextFormatterOptions !== void 0 ? nextFormatterOptions : formatterOptions);
|
|
129
|
-
nextFormatter.innerFormatter = formatter;
|
|
130
|
-
return nextFormatter;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
return formatter;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
exports.makeFormatter = makeFormatter;
|
|
137
|
-
|
|
138
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
139
|
-
|
|
140
|
-
})));
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
!function(t,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r((t="undefined"!=typeof globalThis?globalThis:t||self).Afformative={})}(this,(function(t){"use strict";function r(t,r){(null==r||r>t.length)&&(r=t.length);for(var e=0,n=Array(r);r>e;e++)n[e]=t[e];return n}function e(t){return function(t){if(Array.isArray(t))return r(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return r(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function n(t,r){if(null==t)return{};var e,n,o=function(t,r){if(null==t)return{};var e,n,o={},i=Object.keys(t);for(n=0;i.length>n;n++)0>r.indexOf(e=i[n])&&(o[e]=t[e]);return o}(t,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(n=0;i.length>n;n++)0>r.indexOf(e=i[n])&&Object.prototype.propertyIsEnumerable.call(t,e)&&(o[e]=t[e])}return o}t.makeFormatter=function t(r,o){var i=function(t){var e,o=t.children,i=t.suggestions,u=void 0===i?[]:i,l=n(t,["children","suggestions"]);return null!==(e=r(o,u,l))&&void 0!==e?e:null};return i.displayName=null==o?void 0:o.displayName,i.format=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return r(t,e,n)},i.formatAsPrimitive=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return r(t,["primitive"].concat(e(n)),o)},i.wrap=function(r,e){var n=t((function(t,e,n){return r((function(t,r,o){return i.format(t,null!=r?r:e,null!=o?o:n)}),t,e,n)}),null!=e?e:o);return n.innerFormatter=i,n},i},Object.defineProperty(t,"__esModule",{value:!0})}));
|
package/dist/types/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA"}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
declare type PrimitiveSuggestion = "primitive";
|
|
2
|
-
declare type SemanticSuggestion = "abbreviated" | "icon" | "verbose";
|
|
3
|
-
declare type Suggestion = PrimitiveSuggestion | SemanticSuggestion;
|
|
4
|
-
interface FormatterOptions {
|
|
5
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
6
|
-
displayName?: string;
|
|
7
|
-
}
|
|
8
|
-
declare type DataContext = Record<string, any>;
|
|
9
|
-
interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
10
|
-
(
|
|
11
|
-
/** Value to format. */
|
|
12
|
-
value: TInput,
|
|
13
|
-
/** Suggestions passed by the consumer of a formatter. */
|
|
14
|
-
usageSuggestions: Suggestion[],
|
|
15
|
-
/** Additional data context to be used by the formatter. */
|
|
16
|
-
dataContext: Partial<TDataContext>): TOutput | TPrimitiveOutput;
|
|
17
|
-
}
|
|
18
|
-
interface FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
19
|
-
<TSuggestion extends Suggestion>(
|
|
20
|
-
/** Value to format. */
|
|
21
|
-
value: TInput,
|
|
22
|
-
/** Suggestions the formatter should take note of. */
|
|
23
|
-
usageSuggestions?: TSuggestion[],
|
|
24
|
-
/** Additional data context the formatter might find useful. */
|
|
25
|
-
dataContext?: Partial<TDataContext>): PrimitiveSuggestion extends TSuggestion ? TPrimitiveOutput : TOutput;
|
|
26
|
-
}
|
|
27
|
-
interface FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
28
|
-
(
|
|
29
|
-
/** Value to format. */
|
|
30
|
-
value: TInput,
|
|
31
|
-
/** Suggestions the formatter should take note of in addition to `primitive`. */
|
|
32
|
-
usageSuggestions?: Suggestion[],
|
|
33
|
-
/** Additional data context the formatter might find useful. */
|
|
34
|
-
dataContext?: Partial<TDataContext>): TPrimitiveOutput;
|
|
35
|
-
}
|
|
36
|
-
interface FormatChainDefinition<TInnerInput, TInnerOutput, TInnerPrimitiveInput, TInnerDataContext extends DataContext, TOuterInput, TOuterOutput, TOuterPrimitiveOutput, TOuterDataContext extends DataContext> {
|
|
37
|
-
(
|
|
38
|
-
/**
|
|
39
|
-
* The `formatter.format` method which can be used to delegate the formatting
|
|
40
|
-
* to the wrapped formatter. Delegation is simplified so if no suggestions or contextual
|
|
41
|
-
* props are passed, the original ones are used instead.
|
|
42
|
-
*/
|
|
43
|
-
delegate: FormatMethod<TInnerInput, TInnerOutput, TInnerPrimitiveInput, TInnerDataContext>,
|
|
44
|
-
/** Value to format. */
|
|
45
|
-
value: TOuterInput,
|
|
46
|
-
/** Suggestions the formatter should take note of. */
|
|
47
|
-
usageSuggestions: Suggestion[],
|
|
48
|
-
/** Additional data context the formatter might find useful. */
|
|
49
|
-
dataContext: Partial<TOuterDataContext>): TOuterOutput | TOuterPrimitiveOutput;
|
|
50
|
-
}
|
|
51
|
-
declare type FormatterProps<TInput, TDataContext extends DataContext> = {
|
|
52
|
-
/** Value to format. */
|
|
53
|
-
children: TInput;
|
|
54
|
-
/** Suggestions the formatter should take note of. */
|
|
55
|
-
suggestions?: Suggestion[];
|
|
56
|
-
} & Partial<TDataContext>;
|
|
57
|
-
export interface Formatter<TInput, TOutput, TPrimitiveOutput = TOutput, TDataContext extends DataContext = DataContext> {
|
|
58
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
59
|
-
displayName?: string;
|
|
60
|
-
/** Formats a value. */
|
|
61
|
-
format: FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext>;
|
|
62
|
-
/** Formats a value with the `primitive` suggestion. */
|
|
63
|
-
formatAsPrimitive: FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext>;
|
|
64
|
-
/** The callee of the `.wrap` method used to produce this formatter. */
|
|
65
|
-
innerFormatter?: Formatter<any, any, any, any>;
|
|
66
|
-
/**
|
|
67
|
-
* Creates a new formatter from an existing one. Allows overriding of formatter behaviour
|
|
68
|
-
* for certain values.
|
|
69
|
-
*/
|
|
70
|
-
wrap: <TNextInput = TInput, TNextOutput = TOutput, TNextPrimitiveOutput = TPrimitiveOutput, TNextDataContext extends DataContext = TDataContext>(
|
|
71
|
-
/**
|
|
72
|
-
* Function used to format the value. Has the same signature as the one passed
|
|
73
|
-
* to `makeFormatter`, except a `delegate` function is passed in the first position.
|
|
74
|
-
* This function can be used to delegate formatting to the original (inner) formatter.
|
|
75
|
-
*/
|
|
76
|
-
nextFormat: FormatChainDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext, TNextInput, TNextOutput, TNextPrimitiveOutput, TNextDataContext>,
|
|
77
|
-
/** New formatter options, replacing the original ones. */
|
|
78
|
-
nextFormatterOptions?: FormatterOptions) => Formatter<TNextInput, TNextOutput, TNextPrimitiveOutput, TNextDataContext>;
|
|
79
|
-
/**
|
|
80
|
-
* Backwards-compatible way to use the formatter as a React component.
|
|
81
|
-
*
|
|
82
|
-
* @deprecated Since v0.6.0. Prefer using the `Formatter.format` method instead.
|
|
83
|
-
*/
|
|
84
|
-
(props: FormatterProps<TInput, TDataContext>): TOutput | TPrimitiveOutput | null;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Creates a new formatter.
|
|
88
|
-
*
|
|
89
|
-
* @param format Function used to format the value.
|
|
90
|
-
* @param formatterOptions Additional options for the formatter.
|
|
91
|
-
*/
|
|
92
|
-
export declare const makeFormatter: <TInput, TOutput, TPrimitiveOutput = TOutput, TDataContext extends DataContext = DataContext>(format: FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext>, formatterOptions?: FormatterOptions | undefined) => Formatter<TInput, TOutput, TPrimitiveOutput, TDataContext>;
|
|
93
|
-
export {};
|
|
94
|
-
//# sourceMappingURL=makeFormatter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"makeFormatter.d.ts","sourceRoot":"","sources":["../../src/makeFormatter.ts"],"names":[],"mappings":"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"}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./makeFormatter"
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { makeFormatter } from "./makeFormatter"
|
|
2
|
-
|
|
3
|
-
const toUpperCase = (string: string) => string.toUpperCase()
|
|
4
|
-
|
|
5
|
-
describe("makeFormatter", () => {
|
|
6
|
-
it("handles trivial formatting", () => {
|
|
7
|
-
const formatter = makeFormatter<string, string>(toUpperCase)
|
|
8
|
-
expect(formatter.format("foo")).toBe("FOO")
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
it("accepts a `name` option", () => {
|
|
12
|
-
const formatter = makeFormatter<string, string>(toUpperCase, { displayName: "UpperFormatter" })
|
|
13
|
-
expect(formatter.displayName).toBe("UpperFormatter")
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
it("passes `suggestions` to `format`", () => {
|
|
17
|
-
const formatter = makeFormatter<string, string>((value, suggestions) => {
|
|
18
|
-
if (suggestions.includes("abbreviated")) {
|
|
19
|
-
return value[0]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return value
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
expect(formatter.format("foo", ["abbreviated"])).toBe("f")
|
|
26
|
-
expect(formatter.format("foo", [])).toBe("foo")
|
|
27
|
-
expect(formatter.format("foo")).toBe("foo")
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it("handles formatting with the `primitive` suggestion", () => {
|
|
31
|
-
type Structure = { value: string }
|
|
32
|
-
|
|
33
|
-
const formatter = makeFormatter<Structure, Structure, string>((value, suggestions) => {
|
|
34
|
-
if (suggestions.includes("primitive")) {
|
|
35
|
-
return value.value
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return value
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
expect(formatter.format({ value: "foo" }, ["primitive"])).toBe("foo")
|
|
42
|
-
expect(formatter.formatAsPrimitive({ value: "foo" })).toBe("foo")
|
|
43
|
-
expect(formatter.formatAsPrimitive({ value: "foo" }, ["primitive"])).toBe("foo")
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it("supports simple behavior wrapping", () => {
|
|
47
|
-
const formatter = makeFormatter<string, string>(toUpperCase)
|
|
48
|
-
|
|
49
|
-
const wrappedFormatter = formatter.wrap((delegate, value) =>
|
|
50
|
-
value === "foo" ? "override" : delegate(value),
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
expect(wrappedFormatter.format("foo")).toBe("override")
|
|
54
|
-
expect(wrappedFormatter.format("bar")).toBe("BAR")
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it("supports simple behavior wrapping with suggestions", () => {
|
|
58
|
-
const formatter = makeFormatter<string, string>(toUpperCase)
|
|
59
|
-
|
|
60
|
-
const wrappedFormatter = formatter.wrap((delegate, value, suggestions) =>
|
|
61
|
-
value === "foo" && suggestions.includes("abbreviated") ? "f" : delegate(value),
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
expect(wrappedFormatter.format("foo")).toBe("FOO")
|
|
65
|
-
expect(wrappedFormatter.format("foo", ["abbreviated"])).toBe("f")
|
|
66
|
-
expect(wrappedFormatter.format("bar")).toBe("BAR")
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it("supports simple behavior wrapping with the `primitive` suggestion", () => {
|
|
70
|
-
type Structure = { value: string }
|
|
71
|
-
|
|
72
|
-
const formatter = makeFormatter<string, string>(toUpperCase)
|
|
73
|
-
|
|
74
|
-
const wrappedFormatter = formatter.wrap<Structure, Structure, string>(
|
|
75
|
-
(delegate, value, suggestions) => (suggestions.includes("primitive") ? value.value : value),
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
expect(wrappedFormatter.format({ value: "foo" }, ["primitive"])).toBe("foo")
|
|
79
|
-
expect(wrappedFormatter.formatAsPrimitive({ value: "foo" })).toBe("foo")
|
|
80
|
-
expect(wrappedFormatter.formatAsPrimitive({ value: "foo" }, ["primitive"])).toBe("foo")
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it("supports simple behavior wrapping with data context", () => {
|
|
84
|
-
const formatter = makeFormatter<string, string>(toUpperCase)
|
|
85
|
-
|
|
86
|
-
interface WrappedDataContext {
|
|
87
|
-
forcedValue?: string
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const wrappedFormatter = formatter.wrap(
|
|
91
|
-
(delegate, value, suggestions, { forcedValue }: WrappedDataContext) =>
|
|
92
|
-
forcedValue ?? delegate(value),
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
expect(wrappedFormatter.format("foo")).toBe("FOO")
|
|
96
|
-
expect(wrappedFormatter.format("foo", undefined, { forcedValue: "override" })).toBe("override")
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it("passes the original suggestions when they are not passed manually to `format` when wrapping", () => {
|
|
100
|
-
const formatter = makeFormatter<string, string>((value, suggestions) => {
|
|
101
|
-
if (suggestions.includes("abbreviated")) {
|
|
102
|
-
return value[0]
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return value
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
const wrappedFormatter = formatter.wrap((delegate, value) => delegate(value))
|
|
109
|
-
expect(wrappedFormatter.format("foo", ["abbreviated"])).toBe("f")
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it("sets the `innerFormatter` static property when wrapping", () => {
|
|
113
|
-
const formatter = makeFormatter<string, string>(toUpperCase)
|
|
114
|
-
const wrappedFormatter = formatter.wrap((delegate, value) => delegate(value))
|
|
115
|
-
expect(wrappedFormatter.innerFormatter).toBe(formatter)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it("handles complex wrapping with structural changes", () => {
|
|
119
|
-
interface BasicDataContext {
|
|
120
|
-
index?: number
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const basicFormatter = makeFormatter(
|
|
124
|
-
(value: string, suggestions, dataContext: BasicDataContext): string | undefined =>
|
|
125
|
-
value[dataContext.index ?? 0],
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
expect(basicFormatter.format("test", [], { index: 2 })).toBe("s")
|
|
129
|
-
|
|
130
|
-
interface ComplexStructure {
|
|
131
|
-
index: number
|
|
132
|
-
value: string
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
interface ComplexDataContext {
|
|
136
|
-
getIndex?: (structure: ComplexStructure) => number
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const complexFormatter = basicFormatter.wrap(
|
|
140
|
-
(delegate, value: ComplexStructure, suggestions, dataContext: ComplexDataContext) =>
|
|
141
|
-
delegate(value.value, suggestions, { index: dataContext.getIndex?.(value) }),
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
expect(complexFormatter.format({ index: 3, value: "procrastination" })).toBe("p")
|
|
145
|
-
|
|
146
|
-
expect(
|
|
147
|
-
complexFormatter.format({ index: 3, value: "procrastination" }, [], {
|
|
148
|
-
getIndex: ({ index }) => index,
|
|
149
|
-
}),
|
|
150
|
-
).toBe("c")
|
|
151
|
-
|
|
152
|
-
const boundComplexFormatter = complexFormatter.wrap(
|
|
153
|
-
(delegate, value, suggestions, dataContext) =>
|
|
154
|
-
delegate(value, suggestions, { ...dataContext, getIndex: ({ index }) => index }),
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
expect(boundComplexFormatter.format({ index: 2, value: "swag" })).toBe("a")
|
|
158
|
-
})
|
|
159
|
-
})
|
package/src/makeFormatter.ts
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
type PrimitiveSuggestion = "primitive"
|
|
2
|
-
type SemanticSuggestion = "abbreviated" | "icon" | "verbose"
|
|
3
|
-
type Suggestion = PrimitiveSuggestion | SemanticSuggestion
|
|
4
|
-
|
|
5
|
-
interface FormatterOptions {
|
|
6
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
7
|
-
displayName?: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type DataContext = Record<string, any>
|
|
11
|
-
|
|
12
|
-
// TODO: Update `FormatDefinition` type based on this snippet. Sadly, TypeScript cannot correctly
|
|
13
|
-
// verify the return type of the format definition based on the suggestions, printing errors such
|
|
14
|
-
// as `Type 'string' is not assignable to type '"primitive" extends TSuggestion ? string : string'`
|
|
15
|
-
// which is, of course, nonsense. Same applies to `FormatChainDefinition`.
|
|
16
|
-
//
|
|
17
|
-
// interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
18
|
-
// <TSuggestion extends Suggestion>(
|
|
19
|
-
// value: TInput,
|
|
20
|
-
// usageSuggestions: TSuggestion[],
|
|
21
|
-
// dataContext: Partial<TDataContext>,
|
|
22
|
-
// ): PrimitiveSuggestion extends TSuggestion ? TPrimitiveOutput : TOutput
|
|
23
|
-
// }
|
|
24
|
-
|
|
25
|
-
interface FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
26
|
-
(
|
|
27
|
-
/** Value to format. */
|
|
28
|
-
value: TInput,
|
|
29
|
-
/** Suggestions passed by the consumer of a formatter. */
|
|
30
|
-
usageSuggestions: Suggestion[],
|
|
31
|
-
/** Additional data context to be used by the formatter. */
|
|
32
|
-
dataContext: Partial<TDataContext>,
|
|
33
|
-
): TOutput | TPrimitiveOutput
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
37
|
-
<TSuggestion extends Suggestion>(
|
|
38
|
-
/** Value to format. */
|
|
39
|
-
value: TInput,
|
|
40
|
-
/** Suggestions the formatter should take note of. */
|
|
41
|
-
usageSuggestions?: TSuggestion[],
|
|
42
|
-
/** Additional data context the formatter might find useful. */
|
|
43
|
-
dataContext?: Partial<TDataContext>,
|
|
44
|
-
): PrimitiveSuggestion extends TSuggestion ? TPrimitiveOutput : TOutput
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext extends DataContext> {
|
|
48
|
-
(
|
|
49
|
-
/** Value to format. */
|
|
50
|
-
value: TInput,
|
|
51
|
-
/** Suggestions the formatter should take note of in addition to `primitive`. */
|
|
52
|
-
usageSuggestions?: Suggestion[],
|
|
53
|
-
/** Additional data context the formatter might find useful. */
|
|
54
|
-
dataContext?: Partial<TDataContext>,
|
|
55
|
-
): TPrimitiveOutput
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
interface FormatChainDefinition<
|
|
59
|
-
TInnerInput,
|
|
60
|
-
TInnerOutput,
|
|
61
|
-
TInnerPrimitiveInput,
|
|
62
|
-
TInnerDataContext extends DataContext,
|
|
63
|
-
TOuterInput,
|
|
64
|
-
TOuterOutput,
|
|
65
|
-
TOuterPrimitiveOutput,
|
|
66
|
-
TOuterDataContext extends DataContext
|
|
67
|
-
> {
|
|
68
|
-
(
|
|
69
|
-
/**
|
|
70
|
-
* The `formatter.format` method which can be used to delegate the formatting
|
|
71
|
-
* to the wrapped formatter. Delegation is simplified so if no suggestions or contextual
|
|
72
|
-
* props are passed, the original ones are used instead.
|
|
73
|
-
*/
|
|
74
|
-
delegate: FormatMethod<TInnerInput, TInnerOutput, TInnerPrimitiveInput, TInnerDataContext>,
|
|
75
|
-
/** Value to format. */
|
|
76
|
-
value: TOuterInput,
|
|
77
|
-
/** Suggestions the formatter should take note of. */
|
|
78
|
-
usageSuggestions: Suggestion[],
|
|
79
|
-
/** Additional data context the formatter might find useful. */
|
|
80
|
-
dataContext: Partial<TOuterDataContext>,
|
|
81
|
-
): TOuterOutput | TOuterPrimitiveOutput
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
type FormatterProps<TInput, TDataContext extends DataContext> = {
|
|
85
|
-
/** Value to format. */
|
|
86
|
-
children: TInput
|
|
87
|
-
/** Suggestions the formatter should take note of. */
|
|
88
|
-
suggestions?: Suggestion[]
|
|
89
|
-
} & Partial<TDataContext>
|
|
90
|
-
|
|
91
|
-
export interface Formatter<
|
|
92
|
-
TInput,
|
|
93
|
-
TOutput,
|
|
94
|
-
TPrimitiveOutput = TOutput,
|
|
95
|
-
TDataContext extends DataContext = DataContext
|
|
96
|
-
> {
|
|
97
|
-
/** Formatter name, useful for debugging or advanced pattern matching. */
|
|
98
|
-
displayName?: string
|
|
99
|
-
/** Formats a value. */
|
|
100
|
-
format: FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext>
|
|
101
|
-
/** Formats a value with the `primitive` suggestion. */
|
|
102
|
-
formatAsPrimitive: FormatAsPrimitiveMethod<TInput, TPrimitiveOutput, TDataContext>
|
|
103
|
-
/** The callee of the `.wrap` method used to produce this formatter. */
|
|
104
|
-
innerFormatter?: Formatter<any, any, any, any>
|
|
105
|
-
/**
|
|
106
|
-
* Creates a new formatter from an existing one. Allows overriding of formatter behaviour
|
|
107
|
-
* for certain values.
|
|
108
|
-
*/
|
|
109
|
-
wrap: <
|
|
110
|
-
TNextInput = TInput,
|
|
111
|
-
TNextOutput = TOutput,
|
|
112
|
-
TNextPrimitiveOutput = TPrimitiveOutput,
|
|
113
|
-
TNextDataContext extends DataContext = TDataContext
|
|
114
|
-
>(
|
|
115
|
-
/**
|
|
116
|
-
* Function used to format the value. Has the same signature as the one passed
|
|
117
|
-
* to `makeFormatter`, except a `delegate` function is passed in the first position.
|
|
118
|
-
* This function can be used to delegate formatting to the original (inner) formatter.
|
|
119
|
-
*/
|
|
120
|
-
nextFormat: FormatChainDefinition<
|
|
121
|
-
TInput,
|
|
122
|
-
TOutput,
|
|
123
|
-
TPrimitiveOutput,
|
|
124
|
-
TDataContext,
|
|
125
|
-
TNextInput,
|
|
126
|
-
TNextOutput,
|
|
127
|
-
TNextPrimitiveOutput,
|
|
128
|
-
TNextDataContext
|
|
129
|
-
>,
|
|
130
|
-
/** New formatter options, replacing the original ones. */
|
|
131
|
-
nextFormatterOptions?: FormatterOptions,
|
|
132
|
-
) => Formatter<TNextInput, TNextOutput, TNextPrimitiveOutput, TNextDataContext>
|
|
133
|
-
/**
|
|
134
|
-
* Backwards-compatible way to use the formatter as a React component.
|
|
135
|
-
*
|
|
136
|
-
* @deprecated Since v0.6.0. Prefer using the `Formatter.format` method instead.
|
|
137
|
-
*/
|
|
138
|
-
(props: FormatterProps<TInput, TDataContext>): TOutput | TPrimitiveOutput | null
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Creates a new formatter.
|
|
143
|
-
*
|
|
144
|
-
* @param format Function used to format the value.
|
|
145
|
-
* @param formatterOptions Additional options for the formatter.
|
|
146
|
-
*/
|
|
147
|
-
export const makeFormatter = <
|
|
148
|
-
TInput,
|
|
149
|
-
TOutput,
|
|
150
|
-
TPrimitiveOutput = TOutput,
|
|
151
|
-
TDataContext extends DataContext = DataContext
|
|
152
|
-
>(
|
|
153
|
-
format: FormatDefinition<TInput, TOutput, TPrimitiveOutput, TDataContext>,
|
|
154
|
-
formatterOptions?: FormatterOptions,
|
|
155
|
-
): Formatter<TInput, TOutput, TPrimitiveOutput, TDataContext> => {
|
|
156
|
-
const formatter: Formatter<TInput, TOutput, TPrimitiveOutput, TDataContext> = ({
|
|
157
|
-
children,
|
|
158
|
-
suggestions = [],
|
|
159
|
-
...dataContext
|
|
160
|
-
}) => format(children, suggestions, dataContext as any) ?? null
|
|
161
|
-
|
|
162
|
-
formatter.displayName = formatterOptions?.displayName
|
|
163
|
-
|
|
164
|
-
formatter.format = (value, usageSuggestions = [], dataContext = {}) =>
|
|
165
|
-
format(value, usageSuggestions, dataContext) as any
|
|
166
|
-
|
|
167
|
-
formatter.formatAsPrimitive = (value, usageSuggestions = [], dataContext = {}) =>
|
|
168
|
-
format(value, ["primitive", ...usageSuggestions], dataContext) as any
|
|
169
|
-
|
|
170
|
-
formatter.wrap = <
|
|
171
|
-
TNextInput,
|
|
172
|
-
TNextOutput,
|
|
173
|
-
TNextPrimitiveOutput,
|
|
174
|
-
TNextDataContext extends DataContext
|
|
175
|
-
>(
|
|
176
|
-
nextFormat: FormatChainDefinition<
|
|
177
|
-
TInput,
|
|
178
|
-
TOutput,
|
|
179
|
-
TPrimitiveOutput,
|
|
180
|
-
TDataContext,
|
|
181
|
-
TNextInput,
|
|
182
|
-
TNextOutput,
|
|
183
|
-
TNextPrimitiveOutput,
|
|
184
|
-
TNextDataContext
|
|
185
|
-
>,
|
|
186
|
-
nextFormatterOptions?: FormatterOptions,
|
|
187
|
-
) => {
|
|
188
|
-
const nextFormatter: Formatter<
|
|
189
|
-
TNextInput,
|
|
190
|
-
TNextOutput,
|
|
191
|
-
TNextPrimitiveOutput,
|
|
192
|
-
TNextDataContext
|
|
193
|
-
> = makeFormatter((value, usageSuggestions, dataContext) => {
|
|
194
|
-
const delegate: FormatMethod<TInput, TOutput, TPrimitiveOutput, TDataContext> = (
|
|
195
|
-
delegatedValue,
|
|
196
|
-
delegatedUsageSuggestions,
|
|
197
|
-
delegatedDataContext,
|
|
198
|
-
) =>
|
|
199
|
-
formatter.format(
|
|
200
|
-
delegatedValue,
|
|
201
|
-
delegatedUsageSuggestions ?? usageSuggestions,
|
|
202
|
-
(delegatedDataContext ?? dataContext) as any,
|
|
203
|
-
) as any
|
|
204
|
-
|
|
205
|
-
return nextFormat(delegate, value, usageSuggestions, dataContext) as any
|
|
206
|
-
}, nextFormatterOptions ?? formatterOptions)
|
|
207
|
-
|
|
208
|
-
nextFormatter.innerFormatter = formatter
|
|
209
|
-
|
|
210
|
-
return nextFormatter
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return formatter
|
|
214
|
-
}
|