@jxsuite/formulas 0.0.31 → 0.0.33
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 +15 -0
- package/formulas/escapeHtml/expression.json +31 -0
- package/formulas/escapeHtml/formula.json +13 -0
- package/formulas/formatDate/expression.json +30 -0
- package/formulas/formatDate/formula.json +64 -0
- package/formulas/formatNumber/expression.json +30 -0
- package/formulas/formatNumber/formula.json +55 -0
- package/formulas/notEmpty/expression.json +46 -0
- package/formulas/notEmpty/formula.json +12 -0
- package/formulas/orBlank/expression.json +38 -0
- package/formulas/orBlank/formula.json +12 -0
- package/formulas/relativeTime/expression.json +30 -0
- package/formulas/relativeTime/formula.json +23 -0
- package/package.json +3 -3
- package/src/catalog.ts +390 -0
package/README.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Composite **pure formulas** for Jx, authored as declarative `$expression` JSON (spec §19.4c). Each formula is a named, parameterized computation (`clamp`, `sum`, `average`, `truncate`, `initials`, …) whose body is built exclusively from blessed operators, pure standard-library method operators (§19.4d), and blessed globals. No JavaScript source anywhere: every formula is inspectable data that the visual editor can open, badge with live values, and recompose.
|
|
4
4
|
|
|
5
|
+
## Formatting formulas
|
|
6
|
+
|
|
7
|
+
Six formulas exist to print a stored value from a template (`${state.formatDate($map.item.data.date, {"dateStyle":"long"})}`):
|
|
8
|
+
|
|
9
|
+
| Formula | Gives |
|
|
10
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| `formatDate(value, options)` | `Intl/formatDate` in the page's locale; `""` for a `null`, `undefined` or `""` value instead of a throw |
|
|
12
|
+
| `formatNumber(value, options)` | `Intl/formatNumber` on the same terms |
|
|
13
|
+
| `relativeTime(value, unit)` | `Intl/formatRelativeTime` on the same terms: a signed count of units, `unit` defaulting to `"day"` |
|
|
14
|
+
| `notEmpty(value)` | `false` for `null`, `undefined`, `""`, `"0"`, `0`, `false`, `NaN` and an empty array (PHP's `empty()`) |
|
|
15
|
+
| `orBlank(value)` | `""` for `null`, `undefined`, `"0"`, `0` and `false`; the value itself otherwise |
|
|
16
|
+
| `escapeHtml(text)` | `&`, `<`, `>`, `"` and `'` as character references; `""` for a missing value |
|
|
17
|
+
|
|
18
|
+
The three `Intl` ones pass `null` as the locale, so the runtime fills in `$page.locale`. A parameter whose input needs more than a text box declares a JSON Schema beside its CEM display text (`{ "text": "Intl.DateTimeFormatOptions", "type": "object", "properties": { "dateStyle": { "enum": [...] } } }`), which is what an editor derives a field from. A pure named formula in a page's state does not make the page dynamic: `jx build` resolves each call and drops the formula unless something left for the client still reads it.
|
|
19
|
+
|
|
5
20
|
## Consumption model: copy-in, not a project dependency
|
|
6
21
|
|
|
7
22
|
This package is a **studio/tooling dependency**, deliberately _not_ a runtime or project dependency. Jx documents stay self-contained plain JSON:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"operator": "replaceAll",
|
|
3
|
+
"target": {
|
|
4
|
+
"operator": "replaceAll",
|
|
5
|
+
"target": {
|
|
6
|
+
"operator": "replaceAll",
|
|
7
|
+
"target": {
|
|
8
|
+
"operator": "replaceAll",
|
|
9
|
+
"target": {
|
|
10
|
+
"operator": "replaceAll",
|
|
11
|
+
"target": {
|
|
12
|
+
"operator": "+",
|
|
13
|
+
"target": "",
|
|
14
|
+
"value": {
|
|
15
|
+
"operator": "??",
|
|
16
|
+
"target": {
|
|
17
|
+
"$ref": "$args/text"
|
|
18
|
+
},
|
|
19
|
+
"value": ""
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"value": ["&", "&"]
|
|
23
|
+
},
|
|
24
|
+
"value": ["<", "<"]
|
|
25
|
+
},
|
|
26
|
+
"value": [">", ">"]
|
|
27
|
+
},
|
|
28
|
+
"value": ["\"", """]
|
|
29
|
+
},
|
|
30
|
+
"value": ["'", "'"]
|
|
31
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "escapeHtml",
|
|
3
|
+
"description": "Text made safe to place in markup or an attribute value: &, <, >, \" and ' become character references; a missing value gives an empty string.",
|
|
4
|
+
"parameters": [
|
|
5
|
+
{
|
|
6
|
+
"name": "text",
|
|
7
|
+
"type": {
|
|
8
|
+
"text": "string | null",
|
|
9
|
+
"type": ["string", "null"]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"operator": "?:",
|
|
3
|
+
"target": {
|
|
4
|
+
"operator": "===",
|
|
5
|
+
"target": {
|
|
6
|
+
"operator": "??",
|
|
7
|
+
"target": {
|
|
8
|
+
"$ref": "$args/value"
|
|
9
|
+
},
|
|
10
|
+
"value": ""
|
|
11
|
+
},
|
|
12
|
+
"value": ""
|
|
13
|
+
},
|
|
14
|
+
"value": "",
|
|
15
|
+
"initial": {
|
|
16
|
+
"operator": "call",
|
|
17
|
+
"target": {
|
|
18
|
+
"$ref": "window#/Intl/formatDate"
|
|
19
|
+
},
|
|
20
|
+
"value": [
|
|
21
|
+
{
|
|
22
|
+
"$ref": "$args/value"
|
|
23
|
+
},
|
|
24
|
+
null,
|
|
25
|
+
{
|
|
26
|
+
"$ref": "$args/options"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "formatDate",
|
|
3
|
+
"description": "Format a date or timestamp in the page's locale (Intl.DateTimeFormat, UTC unless options name a timeZone); an empty string for a missing or empty value instead of a thrown RangeError.",
|
|
4
|
+
"parameters": [
|
|
5
|
+
{
|
|
6
|
+
"name": "value",
|
|
7
|
+
"type": {
|
|
8
|
+
"text": "string | number | null",
|
|
9
|
+
"type": ["string", "number", "null"]
|
|
10
|
+
},
|
|
11
|
+
"description": "An ISO 8601 date string or a timestamp in milliseconds."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "options",
|
|
15
|
+
"optional": true,
|
|
16
|
+
"description": "How to write it: a preset pair (dateStyle, timeStyle) or individual fields.",
|
|
17
|
+
"type": {
|
|
18
|
+
"text": "Intl.DateTimeFormatOptions",
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"dateStyle": {
|
|
22
|
+
"enum": ["full", "long", "medium", "short"]
|
|
23
|
+
},
|
|
24
|
+
"timeStyle": {
|
|
25
|
+
"enum": ["full", "long", "medium", "short"]
|
|
26
|
+
},
|
|
27
|
+
"weekday": {
|
|
28
|
+
"enum": ["long", "short", "narrow"]
|
|
29
|
+
},
|
|
30
|
+
"era": {
|
|
31
|
+
"enum": ["long", "short", "narrow"]
|
|
32
|
+
},
|
|
33
|
+
"year": {
|
|
34
|
+
"enum": ["numeric", "2-digit"]
|
|
35
|
+
},
|
|
36
|
+
"month": {
|
|
37
|
+
"enum": ["numeric", "2-digit", "long", "short", "narrow"]
|
|
38
|
+
},
|
|
39
|
+
"day": {
|
|
40
|
+
"enum": ["numeric", "2-digit"]
|
|
41
|
+
},
|
|
42
|
+
"hour": {
|
|
43
|
+
"enum": ["numeric", "2-digit"]
|
|
44
|
+
},
|
|
45
|
+
"minute": {
|
|
46
|
+
"enum": ["numeric", "2-digit"]
|
|
47
|
+
},
|
|
48
|
+
"second": {
|
|
49
|
+
"enum": ["numeric", "2-digit"]
|
|
50
|
+
},
|
|
51
|
+
"hour12": {
|
|
52
|
+
"type": "boolean"
|
|
53
|
+
},
|
|
54
|
+
"timeZoneName": {
|
|
55
|
+
"enum": ["short", "long"]
|
|
56
|
+
},
|
|
57
|
+
"timeZone": {
|
|
58
|
+
"type": "string"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"operator": "?:",
|
|
3
|
+
"target": {
|
|
4
|
+
"operator": "===",
|
|
5
|
+
"target": {
|
|
6
|
+
"operator": "??",
|
|
7
|
+
"target": {
|
|
8
|
+
"$ref": "$args/value"
|
|
9
|
+
},
|
|
10
|
+
"value": ""
|
|
11
|
+
},
|
|
12
|
+
"value": ""
|
|
13
|
+
},
|
|
14
|
+
"value": "",
|
|
15
|
+
"initial": {
|
|
16
|
+
"operator": "call",
|
|
17
|
+
"target": {
|
|
18
|
+
"$ref": "window#/Intl/formatNumber"
|
|
19
|
+
},
|
|
20
|
+
"value": [
|
|
21
|
+
{
|
|
22
|
+
"$ref": "$args/value"
|
|
23
|
+
},
|
|
24
|
+
null,
|
|
25
|
+
{
|
|
26
|
+
"$ref": "$args/options"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "formatNumber",
|
|
3
|
+
"description": "Format a number in the page's locale (Intl.NumberFormat): grouping, decimals, currency, percent, units; an empty string for a missing or empty value.",
|
|
4
|
+
"parameters": [
|
|
5
|
+
{
|
|
6
|
+
"name": "value",
|
|
7
|
+
"type": {
|
|
8
|
+
"text": "number | string | null",
|
|
9
|
+
"type": ["number", "string", "null"]
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "options",
|
|
14
|
+
"optional": true,
|
|
15
|
+
"description": "How to write it: style, currency, digits, notation.",
|
|
16
|
+
"type": {
|
|
17
|
+
"text": "Intl.NumberFormatOptions",
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"style": {
|
|
21
|
+
"enum": ["decimal", "currency", "percent", "unit"]
|
|
22
|
+
},
|
|
23
|
+
"currency": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"currencyDisplay": {
|
|
27
|
+
"enum": ["symbol", "narrowSymbol", "code", "name"]
|
|
28
|
+
},
|
|
29
|
+
"unit": {
|
|
30
|
+
"type": "string"
|
|
31
|
+
},
|
|
32
|
+
"unitDisplay": {
|
|
33
|
+
"enum": ["long", "short", "narrow"]
|
|
34
|
+
},
|
|
35
|
+
"notation": {
|
|
36
|
+
"enum": ["standard", "compact", "scientific", "engineering"]
|
|
37
|
+
},
|
|
38
|
+
"minimumFractionDigits": {
|
|
39
|
+
"type": "integer",
|
|
40
|
+
"minimum": 0,
|
|
41
|
+
"maximum": 100
|
|
42
|
+
},
|
|
43
|
+
"maximumFractionDigits": {
|
|
44
|
+
"type": "integer",
|
|
45
|
+
"minimum": 0,
|
|
46
|
+
"maximum": 100
|
|
47
|
+
},
|
|
48
|
+
"useGrouping": {
|
|
49
|
+
"type": "boolean"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"operator": "&&",
|
|
3
|
+
"target": {
|
|
4
|
+
"operator": "&&",
|
|
5
|
+
"target": {
|
|
6
|
+
"operator": "!",
|
|
7
|
+
"target": {
|
|
8
|
+
"operator": "!",
|
|
9
|
+
"target": {
|
|
10
|
+
"$ref": "$args/value"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"value": {
|
|
15
|
+
"operator": "!==",
|
|
16
|
+
"target": {
|
|
17
|
+
"$ref": "$args/value"
|
|
18
|
+
},
|
|
19
|
+
"value": "0"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"value": {
|
|
23
|
+
"operator": "!",
|
|
24
|
+
"target": {
|
|
25
|
+
"operator": "&&",
|
|
26
|
+
"target": {
|
|
27
|
+
"operator": "call",
|
|
28
|
+
"target": {
|
|
29
|
+
"$ref": "window#/Array/isArray"
|
|
30
|
+
},
|
|
31
|
+
"value": [
|
|
32
|
+
{
|
|
33
|
+
"$ref": "$args/value"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"value": {
|
|
38
|
+
"operator": "===",
|
|
39
|
+
"target": {
|
|
40
|
+
"$ref": "$args/value/length"
|
|
41
|
+
},
|
|
42
|
+
"value": 0
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "notEmpty",
|
|
3
|
+
"description": "True when a value has content: false for a missing value, \"\", \"0\", 0, false, NaN and an empty array (the test PHP's empty() makes), true for anything else.",
|
|
4
|
+
"parameters": [
|
|
5
|
+
{
|
|
6
|
+
"name": "value",
|
|
7
|
+
"type": {
|
|
8
|
+
"text": "unknown"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"operator": "?:",
|
|
3
|
+
"target": {
|
|
4
|
+
"operator": "||",
|
|
5
|
+
"target": {
|
|
6
|
+
"operator": "||",
|
|
7
|
+
"target": {
|
|
8
|
+
"operator": "===",
|
|
9
|
+
"target": {
|
|
10
|
+
"$ref": "$args/value"
|
|
11
|
+
},
|
|
12
|
+
"value": "0"
|
|
13
|
+
},
|
|
14
|
+
"value": {
|
|
15
|
+
"operator": "===",
|
|
16
|
+
"target": {
|
|
17
|
+
"$ref": "$args/value"
|
|
18
|
+
},
|
|
19
|
+
"value": 0
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"value": {
|
|
23
|
+
"operator": "===",
|
|
24
|
+
"target": {
|
|
25
|
+
"$ref": "$args/value"
|
|
26
|
+
},
|
|
27
|
+
"value": false
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"value": "",
|
|
31
|
+
"initial": {
|
|
32
|
+
"operator": "??",
|
|
33
|
+
"target": {
|
|
34
|
+
"$ref": "$args/value"
|
|
35
|
+
},
|
|
36
|
+
"value": ""
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "orBlank",
|
|
3
|
+
"description": "The value as given, or an empty string when it is missing, \"0\", 0 or false (what a PHP template prints for a field it reads as unset).",
|
|
4
|
+
"parameters": [
|
|
5
|
+
{
|
|
6
|
+
"name": "value",
|
|
7
|
+
"type": {
|
|
8
|
+
"text": "unknown"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"operator": "?:",
|
|
3
|
+
"target": {
|
|
4
|
+
"operator": "===",
|
|
5
|
+
"target": {
|
|
6
|
+
"operator": "??",
|
|
7
|
+
"target": {
|
|
8
|
+
"$ref": "$args/value"
|
|
9
|
+
},
|
|
10
|
+
"value": ""
|
|
11
|
+
},
|
|
12
|
+
"value": ""
|
|
13
|
+
},
|
|
14
|
+
"value": "",
|
|
15
|
+
"initial": {
|
|
16
|
+
"operator": "call",
|
|
17
|
+
"target": {
|
|
18
|
+
"$ref": "window#/Intl/formatRelativeTime"
|
|
19
|
+
},
|
|
20
|
+
"value": [
|
|
21
|
+
{
|
|
22
|
+
"$ref": "$args/value"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"$ref": "$args/unit"
|
|
26
|
+
},
|
|
27
|
+
null
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "relativeTime",
|
|
3
|
+
"description": "A signed count of units as a relative time in the page's locale (Intl.RelativeTimeFormat): -3 and \"day\" give \"3 days ago\"; an empty string for a missing or empty value.",
|
|
4
|
+
"parameters": [
|
|
5
|
+
{
|
|
6
|
+
"name": "value",
|
|
7
|
+
"type": {
|
|
8
|
+
"text": "number | null",
|
|
9
|
+
"type": ["number", "null"]
|
|
10
|
+
},
|
|
11
|
+
"description": "How many units away: negative for the past, positive for the future."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "unit",
|
|
15
|
+
"default": "day",
|
|
16
|
+
"type": {
|
|
17
|
+
"text": "Intl.RelativeTimeFormatUnit",
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["year", "quarter", "month", "week", "day", "hour", "minute", "second"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxsuite/formulas",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"description": "Composite pure formulas for Jx, authored as declarative $expression JSON",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"test": "bun test --isolate"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@jxsuite/schema": "^
|
|
28
|
+
"@jxsuite/schema": "^6.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@jxsuite/runtime": "^
|
|
31
|
+
"@jxsuite/runtime": "^7.0.0",
|
|
32
32
|
"@jxsuite/test-support": "^0.0.0"
|
|
33
33
|
}
|
|
34
34
|
}
|
package/src/catalog.ts
CHANGED
|
@@ -186,6 +186,51 @@ export const catalog: FormulaCatalogEntry[] = [
|
|
|
186
186
|
},
|
|
187
187
|
],
|
|
188
188
|
},
|
|
189
|
+
{
|
|
190
|
+
description:
|
|
191
|
+
"Text made safe to place in markup or an attribute value: &, <, >, \" and ' become character references; a missing value gives an empty string.",
|
|
192
|
+
expression: {
|
|
193
|
+
operator: "replaceAll",
|
|
194
|
+
target: {
|
|
195
|
+
operator: "replaceAll",
|
|
196
|
+
target: {
|
|
197
|
+
operator: "replaceAll",
|
|
198
|
+
target: {
|
|
199
|
+
operator: "replaceAll",
|
|
200
|
+
target: {
|
|
201
|
+
operator: "replaceAll",
|
|
202
|
+
target: {
|
|
203
|
+
operator: "+",
|
|
204
|
+
target: "",
|
|
205
|
+
value: {
|
|
206
|
+
operator: "??",
|
|
207
|
+
target: {
|
|
208
|
+
$ref: "$args/text",
|
|
209
|
+
},
|
|
210
|
+
value: "",
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
value: ["&", "&"],
|
|
214
|
+
},
|
|
215
|
+
value: ["<", "<"],
|
|
216
|
+
},
|
|
217
|
+
value: [">", ">"],
|
|
218
|
+
},
|
|
219
|
+
value: ['"', """],
|
|
220
|
+
},
|
|
221
|
+
value: ["'", "'"],
|
|
222
|
+
},
|
|
223
|
+
name: "escapeHtml",
|
|
224
|
+
parameters: [
|
|
225
|
+
{
|
|
226
|
+
name: "text",
|
|
227
|
+
type: {
|
|
228
|
+
text: "string | null",
|
|
229
|
+
type: ["string", "null"],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
},
|
|
189
234
|
{
|
|
190
235
|
description: "The first element of an array (index 0), or null when empty.",
|
|
191
236
|
expression: {
|
|
@@ -205,6 +250,187 @@ export const catalog: FormulaCatalogEntry[] = [
|
|
|
205
250
|
},
|
|
206
251
|
],
|
|
207
252
|
},
|
|
253
|
+
{
|
|
254
|
+
description:
|
|
255
|
+
"Format a date or timestamp in the page's locale (Intl.DateTimeFormat, UTC unless options name a timeZone); an empty string for a missing or empty value instead of a thrown RangeError.",
|
|
256
|
+
expression: {
|
|
257
|
+
operator: "?:",
|
|
258
|
+
target: {
|
|
259
|
+
operator: "===",
|
|
260
|
+
target: {
|
|
261
|
+
operator: "??",
|
|
262
|
+
target: {
|
|
263
|
+
$ref: "$args/value",
|
|
264
|
+
},
|
|
265
|
+
value: "",
|
|
266
|
+
},
|
|
267
|
+
value: "",
|
|
268
|
+
},
|
|
269
|
+
value: "",
|
|
270
|
+
initial: {
|
|
271
|
+
operator: "call",
|
|
272
|
+
target: {
|
|
273
|
+
$ref: "window#/Intl/formatDate",
|
|
274
|
+
},
|
|
275
|
+
value: [
|
|
276
|
+
{
|
|
277
|
+
$ref: "$args/value",
|
|
278
|
+
},
|
|
279
|
+
null,
|
|
280
|
+
{
|
|
281
|
+
$ref: "$args/options",
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
name: "formatDate",
|
|
287
|
+
parameters: [
|
|
288
|
+
{
|
|
289
|
+
name: "value",
|
|
290
|
+
type: {
|
|
291
|
+
text: "string | number | null",
|
|
292
|
+
type: ["string", "number", "null"],
|
|
293
|
+
},
|
|
294
|
+
description: "An ISO 8601 date string or a timestamp in milliseconds.",
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "options",
|
|
298
|
+
optional: true,
|
|
299
|
+
description: "How to write it: a preset pair (dateStyle, timeStyle) or individual fields.",
|
|
300
|
+
type: {
|
|
301
|
+
text: "Intl.DateTimeFormatOptions",
|
|
302
|
+
type: "object",
|
|
303
|
+
properties: {
|
|
304
|
+
dateStyle: {
|
|
305
|
+
enum: ["full", "long", "medium", "short"],
|
|
306
|
+
},
|
|
307
|
+
timeStyle: {
|
|
308
|
+
enum: ["full", "long", "medium", "short"],
|
|
309
|
+
},
|
|
310
|
+
weekday: {
|
|
311
|
+
enum: ["long", "short", "narrow"],
|
|
312
|
+
},
|
|
313
|
+
era: {
|
|
314
|
+
enum: ["long", "short", "narrow"],
|
|
315
|
+
},
|
|
316
|
+
year: {
|
|
317
|
+
enum: ["numeric", "2-digit"],
|
|
318
|
+
},
|
|
319
|
+
month: {
|
|
320
|
+
enum: ["numeric", "2-digit", "long", "short", "narrow"],
|
|
321
|
+
},
|
|
322
|
+
day: {
|
|
323
|
+
enum: ["numeric", "2-digit"],
|
|
324
|
+
},
|
|
325
|
+
hour: {
|
|
326
|
+
enum: ["numeric", "2-digit"],
|
|
327
|
+
},
|
|
328
|
+
minute: {
|
|
329
|
+
enum: ["numeric", "2-digit"],
|
|
330
|
+
},
|
|
331
|
+
second: {
|
|
332
|
+
enum: ["numeric", "2-digit"],
|
|
333
|
+
},
|
|
334
|
+
hour12: {
|
|
335
|
+
type: "boolean",
|
|
336
|
+
},
|
|
337
|
+
timeZoneName: {
|
|
338
|
+
enum: ["short", "long"],
|
|
339
|
+
},
|
|
340
|
+
timeZone: {
|
|
341
|
+
type: "string",
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
description:
|
|
350
|
+
"Format a number in the page's locale (Intl.NumberFormat): grouping, decimals, currency, percent, units; an empty string for a missing or empty value.",
|
|
351
|
+
expression: {
|
|
352
|
+
operator: "?:",
|
|
353
|
+
target: {
|
|
354
|
+
operator: "===",
|
|
355
|
+
target: {
|
|
356
|
+
operator: "??",
|
|
357
|
+
target: {
|
|
358
|
+
$ref: "$args/value",
|
|
359
|
+
},
|
|
360
|
+
value: "",
|
|
361
|
+
},
|
|
362
|
+
value: "",
|
|
363
|
+
},
|
|
364
|
+
value: "",
|
|
365
|
+
initial: {
|
|
366
|
+
operator: "call",
|
|
367
|
+
target: {
|
|
368
|
+
$ref: "window#/Intl/formatNumber",
|
|
369
|
+
},
|
|
370
|
+
value: [
|
|
371
|
+
{
|
|
372
|
+
$ref: "$args/value",
|
|
373
|
+
},
|
|
374
|
+
null,
|
|
375
|
+
{
|
|
376
|
+
$ref: "$args/options",
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
name: "formatNumber",
|
|
382
|
+
parameters: [
|
|
383
|
+
{
|
|
384
|
+
name: "value",
|
|
385
|
+
type: {
|
|
386
|
+
text: "number | string | null",
|
|
387
|
+
type: ["number", "string", "null"],
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
name: "options",
|
|
392
|
+
optional: true,
|
|
393
|
+
description: "How to write it: style, currency, digits, notation.",
|
|
394
|
+
type: {
|
|
395
|
+
text: "Intl.NumberFormatOptions",
|
|
396
|
+
type: "object",
|
|
397
|
+
properties: {
|
|
398
|
+
style: {
|
|
399
|
+
enum: ["decimal", "currency", "percent", "unit"],
|
|
400
|
+
},
|
|
401
|
+
currency: {
|
|
402
|
+
type: "string",
|
|
403
|
+
},
|
|
404
|
+
currencyDisplay: {
|
|
405
|
+
enum: ["symbol", "narrowSymbol", "code", "name"],
|
|
406
|
+
},
|
|
407
|
+
unit: {
|
|
408
|
+
type: "string",
|
|
409
|
+
},
|
|
410
|
+
unitDisplay: {
|
|
411
|
+
enum: ["long", "short", "narrow"],
|
|
412
|
+
},
|
|
413
|
+
notation: {
|
|
414
|
+
enum: ["standard", "compact", "scientific", "engineering"],
|
|
415
|
+
},
|
|
416
|
+
minimumFractionDigits: {
|
|
417
|
+
type: "integer",
|
|
418
|
+
minimum: 0,
|
|
419
|
+
maximum: 100,
|
|
420
|
+
},
|
|
421
|
+
maximumFractionDigits: {
|
|
422
|
+
type: "integer",
|
|
423
|
+
minimum: 0,
|
|
424
|
+
maximum: 100,
|
|
425
|
+
},
|
|
426
|
+
useGrouping: {
|
|
427
|
+
type: "boolean",
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
],
|
|
433
|
+
},
|
|
208
434
|
{
|
|
209
435
|
description:
|
|
210
436
|
'The uppercase first letters of each whitespace-separated word, joined (e.g. "ada lovelace" → "AL").',
|
|
@@ -357,6 +583,116 @@ export const catalog: FormulaCatalogEntry[] = [
|
|
|
357
583
|
},
|
|
358
584
|
],
|
|
359
585
|
},
|
|
586
|
+
{
|
|
587
|
+
description:
|
|
588
|
+
'True when a value has content: false for a missing value, "", "0", 0, false, NaN and an empty array (the test PHP\'s empty() makes), true for anything else.',
|
|
589
|
+
expression: {
|
|
590
|
+
operator: "&&",
|
|
591
|
+
target: {
|
|
592
|
+
operator: "&&",
|
|
593
|
+
target: {
|
|
594
|
+
operator: "!",
|
|
595
|
+
target: {
|
|
596
|
+
operator: "!",
|
|
597
|
+
target: {
|
|
598
|
+
$ref: "$args/value",
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
value: {
|
|
603
|
+
operator: "!==",
|
|
604
|
+
target: {
|
|
605
|
+
$ref: "$args/value",
|
|
606
|
+
},
|
|
607
|
+
value: "0",
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
value: {
|
|
611
|
+
operator: "!",
|
|
612
|
+
target: {
|
|
613
|
+
operator: "&&",
|
|
614
|
+
target: {
|
|
615
|
+
operator: "call",
|
|
616
|
+
target: {
|
|
617
|
+
$ref: "window#/Array/isArray",
|
|
618
|
+
},
|
|
619
|
+
value: [
|
|
620
|
+
{
|
|
621
|
+
$ref: "$args/value",
|
|
622
|
+
},
|
|
623
|
+
],
|
|
624
|
+
},
|
|
625
|
+
value: {
|
|
626
|
+
operator: "===",
|
|
627
|
+
target: {
|
|
628
|
+
$ref: "$args/value/length",
|
|
629
|
+
},
|
|
630
|
+
value: 0,
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
name: "notEmpty",
|
|
636
|
+
parameters: [
|
|
637
|
+
{
|
|
638
|
+
name: "value",
|
|
639
|
+
type: {
|
|
640
|
+
text: "unknown",
|
|
641
|
+
},
|
|
642
|
+
},
|
|
643
|
+
],
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
description:
|
|
647
|
+
'The value as given, or an empty string when it is missing, "0", 0 or false (what a PHP template prints for a field it reads as unset).',
|
|
648
|
+
expression: {
|
|
649
|
+
operator: "?:",
|
|
650
|
+
target: {
|
|
651
|
+
operator: "||",
|
|
652
|
+
target: {
|
|
653
|
+
operator: "||",
|
|
654
|
+
target: {
|
|
655
|
+
operator: "===",
|
|
656
|
+
target: {
|
|
657
|
+
$ref: "$args/value",
|
|
658
|
+
},
|
|
659
|
+
value: "0",
|
|
660
|
+
},
|
|
661
|
+
value: {
|
|
662
|
+
operator: "===",
|
|
663
|
+
target: {
|
|
664
|
+
$ref: "$args/value",
|
|
665
|
+
},
|
|
666
|
+
value: 0,
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
value: {
|
|
670
|
+
operator: "===",
|
|
671
|
+
target: {
|
|
672
|
+
$ref: "$args/value",
|
|
673
|
+
},
|
|
674
|
+
value: false,
|
|
675
|
+
},
|
|
676
|
+
},
|
|
677
|
+
value: "",
|
|
678
|
+
initial: {
|
|
679
|
+
operator: "??",
|
|
680
|
+
target: {
|
|
681
|
+
$ref: "$args/value",
|
|
682
|
+
},
|
|
683
|
+
value: "",
|
|
684
|
+
},
|
|
685
|
+
},
|
|
686
|
+
name: "orBlank",
|
|
687
|
+
parameters: [
|
|
688
|
+
{
|
|
689
|
+
name: "value",
|
|
690
|
+
type: {
|
|
691
|
+
text: "unknown",
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
],
|
|
695
|
+
},
|
|
360
696
|
{
|
|
361
697
|
description: "part / whole as a percentage (0 when the whole is 0 or missing).",
|
|
362
698
|
expression: {
|
|
@@ -395,6 +731,60 @@ export const catalog: FormulaCatalogEntry[] = [
|
|
|
395
731
|
},
|
|
396
732
|
],
|
|
397
733
|
},
|
|
734
|
+
{
|
|
735
|
+
description:
|
|
736
|
+
'A signed count of units as a relative time in the page\'s locale (Intl.RelativeTimeFormat): -3 and "day" give "3 days ago"; an empty string for a missing or empty value.',
|
|
737
|
+
expression: {
|
|
738
|
+
operator: "?:",
|
|
739
|
+
target: {
|
|
740
|
+
operator: "===",
|
|
741
|
+
target: {
|
|
742
|
+
operator: "??",
|
|
743
|
+
target: {
|
|
744
|
+
$ref: "$args/value",
|
|
745
|
+
},
|
|
746
|
+
value: "",
|
|
747
|
+
},
|
|
748
|
+
value: "",
|
|
749
|
+
},
|
|
750
|
+
value: "",
|
|
751
|
+
initial: {
|
|
752
|
+
operator: "call",
|
|
753
|
+
target: {
|
|
754
|
+
$ref: "window#/Intl/formatRelativeTime",
|
|
755
|
+
},
|
|
756
|
+
value: [
|
|
757
|
+
{
|
|
758
|
+
$ref: "$args/value",
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
$ref: "$args/unit",
|
|
762
|
+
},
|
|
763
|
+
null,
|
|
764
|
+
],
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
name: "relativeTime",
|
|
768
|
+
parameters: [
|
|
769
|
+
{
|
|
770
|
+
name: "value",
|
|
771
|
+
type: {
|
|
772
|
+
text: "number | null",
|
|
773
|
+
type: ["number", "null"],
|
|
774
|
+
},
|
|
775
|
+
description: "How many units away: negative for the past, positive for the future.",
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
name: "unit",
|
|
779
|
+
default: "day",
|
|
780
|
+
type: {
|
|
781
|
+
text: "Intl.RelativeTimeFormatUnit",
|
|
782
|
+
type: "string",
|
|
783
|
+
enum: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"],
|
|
784
|
+
},
|
|
785
|
+
},
|
|
786
|
+
],
|
|
787
|
+
},
|
|
398
788
|
{
|
|
399
789
|
description:
|
|
400
790
|
"Round a number to the given decimal places (Math.round against a Math.pow(10, digits) scale).",
|