@shurizma/discord-message-contract 0.4.0 → 0.6.0
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 +218 -169
- package/dist/grammar.d.ts +25 -0
- package/dist/grammar.d.ts.map +1 -1
- package/dist/grammar.js +1 -1
- package/dist/grammar.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate.d.ts +9 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +139 -0
- package/dist/validate.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,169 +1,218 @@
|
|
|
1
|
-
# @shurizma/discord-message-contract
|
|
2
|
-
|
|
3
|
-
The template engine shared by the [shuri.gg](https://shuri.gg) Discord Message Builder and the bots
|
|
4
|
-
that implement its compatibility contract.
|
|
5
|
-
|
|
6
|
-
The builder lets you compose a Discord [Components V2](https://discord.com/developers/docs/components/reference)
|
|
7
|
-
message in the browser and hand it to a bot to send. Templates let that message carry placeholders
|
|
8
|
-
(`{{guild.name}}`) that the bot fills in at send time, so a stored message can re-render itself
|
|
9
|
-
against fresh data.
|
|
10
|
-
|
|
11
|
-
That only works if the website's live preview and the bot's actual send agree on the grammar, down
|
|
12
|
-
to the character. This package is that agreement, extracted so there is exactly one implementation
|
|
13
|
-
instead of one per participant.
|
|
14
|
-
|
|
15
|
-
## Install
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
pnpm add @shurizma/discord-message-contract
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Zero runtime dependencies. Works in Node and in a browser bundle.
|
|
22
|
-
|
|
23
|
-
## A working implementation
|
|
24
|
-
|
|
25
|
-
If you are here because you want to build a bot the message builder can talk to, start from
|
|
26
|
-
[discord-message-bot](https://git.shuri.gg/ShuriZma/discord-message-bot) instead of from this
|
|
27
|
-
package. It is a complete, runnable reference implementation of the whole contract, multi-server out
|
|
28
|
-
of the box, and it uses everything documented below. Clone it and run it, or read it and write your
|
|
29
|
-
own.
|
|
30
|
-
|
|
31
|
-
This package is the part both sides have to agree on. The bot is what that agreement is for.
|
|
32
|
-
|
|
33
|
-
## API
|
|
34
|
-
|
|
35
|
-
### `renderTemplate(value, data, placeholders)`
|
|
36
|
-
|
|
37
|
-
Walks any JSON-shaped value and substitutes every template tag found in its strings. Arrays and
|
|
38
|
-
objects recurse; non-strings pass through untouched.
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
import { renderTemplate } from '@shurizma/discord-message-contract';
|
|
42
|
-
|
|
43
|
-
const placeholders = [
|
|
44
|
-
{ name: 'guild.name', description: 'Server name', kind: 'scalar' },
|
|
45
|
-
{ name: 'roles', description: 'Server roles', kind: 'list', itemAlias: 'role' },
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
const data = {
|
|
49
|
-
guild: { name: 'Skadi' },
|
|
50
|
-
roles: [{ name: 'Admin' }, { name: 'Mod' }],
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
renderTemplate(
|
|
54
|
-
{ components: [{ type: 10, content: '# {{guild.name}}\n{{#foreach:roles:, }}{{role.name}}{{/foreach}}' }] },
|
|
55
|
-
data,
|
|
56
|
-
placeholders,
|
|
57
|
-
);
|
|
58
|
-
// { components: [{ type: 10, content: '# Skadi\nAdmin, Mod' }] }
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### `applyConditionalButtons(components, rules, data)`
|
|
62
|
-
|
|
63
|
-
Removes buttons whose declared condition does not hold, and drops any action row left empty. A
|
|
64
|
-
button matches a rule when its `custom_id` starts with the rule's `customIdPrefix`. Buttons matching
|
|
65
|
-
no rule are always kept.
|
|
66
|
-
|
|
67
|
-
Link buttons with an empty `url` are always removed, because Discord rejects them outright.
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
import { applyConditionalButtons } from '@shurizma/discord-message-contract';
|
|
71
|
-
|
|
72
|
-
const rules = [{ customIdPrefix: 'boost:', condition: 'guild.boostCount', negate: true }];
|
|
73
|
-
|
|
74
|
-
applyConditionalButtons(components, rules, { guild: { boostCount: 0 } });
|
|
75
|
-
// the boost: button survives, because boostCount is falsy and the rule is negated
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
A bot must apply these rules on **every** render that reaches Discord, not only on scheduled
|
|
79
|
-
refreshes. If it does not, the website's preview and the message people actually see will disagree.
|
|
80
|
-
|
|
81
|
-
### `resolveNowTimestamps(value)`
|
|
82
|
-
|
|
83
|
-
Replaces `<t:now>` and `<t:now:R>` with a real Unix timestamp, recursing the same way
|
|
84
|
-
`renderTemplate` does. Call it last, immediately before handing the payload to Discord, and keep the
|
|
85
|
-
literal `<t:now>` in storage so it re-resolves on every future send or edit rather than freezing to
|
|
86
|
-
whenever the message was composed.
|
|
87
|
-
|
|
88
|
-
Supported format suffixes are Discord's own: `t`, `T`, `d`, `D`, `f`, `F`, `R`. Anything else is
|
|
89
|
-
left alone.
|
|
90
|
-
|
|
91
|
-
###
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
| `{{
|
|
110
|
-
| `{{#if
|
|
111
|
-
| `{{else}}` |
|
|
112
|
-
| `
|
|
113
|
-
| `{{
|
|
114
|
-
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
`
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
1
|
+
# @shurizma/discord-message-contract
|
|
2
|
+
|
|
3
|
+
The template engine shared by the [shuri.gg](https://shuri.gg) Discord Message Builder and the bots
|
|
4
|
+
that implement its compatibility contract.
|
|
5
|
+
|
|
6
|
+
The builder lets you compose a Discord [Components V2](https://discord.com/developers/docs/components/reference)
|
|
7
|
+
message in the browser and hand it to a bot to send. Templates let that message carry placeholders
|
|
8
|
+
(`{{guild.name}}`) that the bot fills in at send time, so a stored message can re-render itself
|
|
9
|
+
against fresh data.
|
|
10
|
+
|
|
11
|
+
That only works if the website's live preview and the bot's actual send agree on the grammar, down
|
|
12
|
+
to the character. This package is that agreement, extracted so there is exactly one implementation
|
|
13
|
+
instead of one per participant.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
pnpm add @shurizma/discord-message-contract
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Zero runtime dependencies. Works in Node and in a browser bundle.
|
|
22
|
+
|
|
23
|
+
## A working implementation
|
|
24
|
+
|
|
25
|
+
If you are here because you want to build a bot the message builder can talk to, start from
|
|
26
|
+
[discord-message-bot](https://git.shuri.gg/ShuriZma/discord-message-bot) instead of from this
|
|
27
|
+
package. It is a complete, runnable reference implementation of the whole contract, multi-server out
|
|
28
|
+
of the box, and it uses everything documented below. Clone it and run it, or read it and write your
|
|
29
|
+
own.
|
|
30
|
+
|
|
31
|
+
This package is the part both sides have to agree on. The bot is what that agreement is for.
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### `renderTemplate(value, data, placeholders)`
|
|
36
|
+
|
|
37
|
+
Walks any JSON-shaped value and substitutes every template tag found in its strings. Arrays and
|
|
38
|
+
objects recurse; non-strings pass through untouched.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { renderTemplate } from '@shurizma/discord-message-contract';
|
|
42
|
+
|
|
43
|
+
const placeholders = [
|
|
44
|
+
{ name: 'guild.name', description: 'Server name', kind: 'scalar' },
|
|
45
|
+
{ name: 'roles', description: 'Server roles', kind: 'list', itemAlias: 'role' },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const data = {
|
|
49
|
+
guild: { name: 'Skadi' },
|
|
50
|
+
roles: [{ name: 'Admin' }, { name: 'Mod' }],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
renderTemplate(
|
|
54
|
+
{ components: [{ type: 10, content: '# {{guild.name}}\n{{#foreach:roles:, }}{{role.name}}{{/foreach}}' }] },
|
|
55
|
+
data,
|
|
56
|
+
placeholders,
|
|
57
|
+
);
|
|
58
|
+
// { components: [{ type: 10, content: '# Skadi\nAdmin, Mod' }] }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `applyConditionalButtons(components, rules, data)`
|
|
62
|
+
|
|
63
|
+
Removes buttons whose declared condition does not hold, and drops any action row left empty. A
|
|
64
|
+
button matches a rule when its `custom_id` starts with the rule's `customIdPrefix`. Buttons matching
|
|
65
|
+
no rule are always kept.
|
|
66
|
+
|
|
67
|
+
Link buttons with an empty `url` are always removed, because Discord rejects them outright.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { applyConditionalButtons } from '@shurizma/discord-message-contract';
|
|
71
|
+
|
|
72
|
+
const rules = [{ customIdPrefix: 'boost:', condition: 'guild.boostCount', negate: true }];
|
|
73
|
+
|
|
74
|
+
applyConditionalButtons(components, rules, { guild: { boostCount: 0 } });
|
|
75
|
+
// the boost: button survives, because boostCount is falsy and the rule is negated
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A bot must apply these rules on **every** render that reaches Discord, not only on scheduled
|
|
79
|
+
refreshes. If it does not, the website's preview and the message people actually see will disagree.
|
|
80
|
+
|
|
81
|
+
### `resolveNowTimestamps(value)`
|
|
82
|
+
|
|
83
|
+
Replaces `<t:now>` and `<t:now:R>` with a real Unix timestamp, recursing the same way
|
|
84
|
+
`renderTemplate` does. Call it last, immediately before handing the payload to Discord, and keep the
|
|
85
|
+
literal `<t:now>` in storage so it re-resolves on every future send or edit rather than freezing to
|
|
86
|
+
whenever the message was composed.
|
|
87
|
+
|
|
88
|
+
Supported format suffixes are Discord's own: `t`, `T`, `d`, `D`, `f`, `F`, `R`. Anything else is
|
|
89
|
+
left alone.
|
|
90
|
+
|
|
91
|
+
### `validateTemplate(value, placeholders)`
|
|
92
|
+
|
|
93
|
+
Returns diagnostics for a template without rendering it, so an editor can show problems before
|
|
94
|
+
anyone saves. Every check below is silent at render time, which is why this exists.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { validateTemplate } from '@shurizma/discord-message-contract';
|
|
98
|
+
|
|
99
|
+
validateTemplate({ components: [{ type: 10, content: 'a{{/if}}b' }] }, placeholders);
|
|
100
|
+
// [{
|
|
101
|
+
// severity: 'error',
|
|
102
|
+
// message: '{{/if}} has no matching {{#if}}, and everything after it is discarded',
|
|
103
|
+
// path: 'components.0.content',
|
|
104
|
+
// }]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| Reported | Severity | Why it matters |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `{{/if}}` or `{{/foreach}}` with no opener | error | Everything after it is silently dropped |
|
|
110
|
+
| `{{#if}}` or `{{#foreach}}` never closed | error | The block renders anyway, which is rarely intended |
|
|
111
|
+
| `{{else}}` outside an if, or twice in one if | error | Only the first is used |
|
|
112
|
+
| `foreach` over a list with no registered `itemAlias` | error | Rendering throws |
|
|
113
|
+
| `{{@index}}` outside a `foreach` | error | Renders empty |
|
|
114
|
+
| A placeholder you never declared | warning | Renders as empty text |
|
|
115
|
+
|
|
116
|
+
`path` locates the offending string inside the payload, so `components.0.components.1.content`
|
|
117
|
+
points at exactly the text field to fix.
|
|
118
|
+
|
|
119
|
+
### Order of operations
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const rendered = renderTemplate(stored.payload, data, definition.placeholders);
|
|
123
|
+
const filtered = { ...rendered, components: applyConditionalButtons(rendered.components, definition.conditionalButtons, data) };
|
|
124
|
+
const payload = resolveNowTimestamps(filtered);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Substitute, then filter, then resolve timestamps. Filtering before substitution would test
|
|
128
|
+
conditions against unrendered placeholder text; resolving timestamps early would freeze them.
|
|
129
|
+
|
|
130
|
+
## Grammar
|
|
131
|
+
|
|
132
|
+
| Tag | Meaning |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| `{{path}}` | Insert a value. Dotted paths walk objects. A missing or null value renders as the empty string. |
|
|
135
|
+
| `{{#if:path}}` | Truthy test. An empty array is falsy; every other value follows JavaScript truthiness. |
|
|
136
|
+
| `{{#if:empty:path}}` | True when the value is `null`, `undefined`, `0` or `""`. |
|
|
137
|
+
| `{{#if:isset:path}}` | True when the value is neither `null` nor `undefined`. `0` and `""` count as set. |
|
|
138
|
+
| `{{#if:eq:path:value}}` | String comparison against a literal. `{{#if:eq:count:0}}` matches the number `0`. |
|
|
139
|
+
| `{{else}}` | Optional alternate branch. |
|
|
140
|
+
| `{{/if}}` | Closes the nearest open `if`. |
|
|
141
|
+
| `{{#foreach:list}}` | Iterate a list placeholder. |
|
|
142
|
+
| `{{#foreach:list:separator}}` | Same, joining iterations with the literal separator. `{{#foreach:roles:, }}` gives `Admin, Mod`. |
|
|
143
|
+
| `{{/foreach}}` | Closes the nearest open `foreach`. |
|
|
144
|
+
| `{{#if:ne:path:value}}` | String inequality, the counterpart to `eq`. |
|
|
145
|
+
| `{{@index}}` / `{{@index0}}` | Position in the current `foreach`, 1-based and 0-based. An inner loop shadows an outer one. |
|
|
146
|
+
|
|
147
|
+
Inside a `foreach` body, the current item is bound to the list placeholder's `itemAlias`, so a
|
|
148
|
+
placeholder declared as `{ name: 'roles', kind: 'list', itemAlias: 'role' }` exposes `{{role.name}}`.
|
|
149
|
+
The enclosing scope stays visible, so `{{guild.name}}` still resolves inside the loop.
|
|
150
|
+
|
|
151
|
+
Both `if` and `foreach` blocks nest. To iterate a list that lives inside the current item, declare
|
|
152
|
+
it as a list placeholder named after the loop alias and give it its own `itemAlias`:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
placeholders: [
|
|
156
|
+
{ name: 'teams', kind: 'list', itemAlias: 'team', ... },
|
|
157
|
+
{ name: 'team.members', kind: 'list', itemAlias: 'member', ... },
|
|
158
|
+
]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
{{#foreach:teams:; }}{{team.name}}: {{#foreach:team.members:, }}{{member.n}}{{/foreach}}{{/foreach}}
|
|
163
|
+
-> "Red: a, b; Blue: c"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The outer alias stays visible inside the inner loop. Iterating a list with no registered
|
|
167
|
+
`itemAlias` throws, which `validateTemplate` catches first.
|
|
168
|
+
|
|
169
|
+
Dotted paths reach into anything the data holds, including array length: `{{roles.length}}` and
|
|
170
|
+
`{{team.members.length}}` both work, declared or not. Declaring placeholders is what makes them
|
|
171
|
+
appear in an editor's toolbar; it is not required for them to resolve.
|
|
172
|
+
|
|
173
|
+
Unrecognised tags pass through as literal text.
|
|
174
|
+
|
|
175
|
+
### Known malformed-input behaviour
|
|
176
|
+
|
|
177
|
+
Malformed blocks fail quietly rather than raising:
|
|
178
|
+
|
|
179
|
+
- An unclosed `{{#if:x}}` renders its body when the condition holds.
|
|
180
|
+
- Text after an unmatched `{{/if}}` is discarded. `a{{/if}}b` renders as `a`.
|
|
181
|
+
|
|
182
|
+
These are frozen as-is because three live implementations already agreed on them. Treat them as
|
|
183
|
+
behaviour to preserve, not as intent.
|
|
184
|
+
|
|
185
|
+
## Conforming in another language
|
|
186
|
+
|
|
187
|
+
`fixtures/grammar.json` is the language-agnostic definition of the grammar. Passing every fixture is
|
|
188
|
+
what conformance means. Each entry is:
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"name": "foreach-separator",
|
|
193
|
+
"template": "{{#foreach:roles:, }}{{role.name}}{{/foreach}}",
|
|
194
|
+
"placeholders": [{ "name": "roles", "description": "roles", "kind": "list", "itemAlias": "role" }],
|
|
195
|
+
"data": { "roles": [{ "name": "Admin" }, { "name": "Mod" }] },
|
|
196
|
+
"expected": "Admin, Mod"
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`template` is any JSON value, not only a string, since substitution recurses through objects and
|
|
201
|
+
arrays. An entry carrying `throws` instead of `expected` must raise an error containing that text.
|
|
202
|
+
|
|
203
|
+
The fixtures were generated by running a shared corpus through the two implementations that existed
|
|
204
|
+
before this package (the shuri.gg frontend and the dallas bot) and recording only the cases where
|
|
205
|
+
both agreed, so they describe behaviour that was already in production rather than a fresh
|
|
206
|
+
specification.
|
|
207
|
+
|
|
208
|
+
## See also
|
|
209
|
+
|
|
210
|
+
- [discord-message-bot](https://git.shuri.gg/ShuriZma/discord-message-bot), a complete reference bot
|
|
211
|
+
built on this package.
|
|
212
|
+
- [The bot compatibility contract](https://shuri.gg/tools/discord/bots/compatibility), the HTTP
|
|
213
|
+
endpoints a bot implements.
|
|
214
|
+
- [The message builder](https://shuri.gg/tools/discord/message-builder) itself.
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|
package/dist/grammar.d.ts
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
1
|
import type { TemplatePlaceholder } from './types.js';
|
|
2
|
+
type IfMode = 'plain' | 'empty' | 'isset' | 'eq' | 'ne';
|
|
3
|
+
export type Token = {
|
|
4
|
+
kind: 'text';
|
|
5
|
+
value: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'if';
|
|
8
|
+
mode: IfMode;
|
|
9
|
+
path: string;
|
|
10
|
+
value?: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'else';
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'endif';
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'foreach';
|
|
17
|
+
name: string;
|
|
18
|
+
separator?: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'endforeach';
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'scalar';
|
|
23
|
+
path: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function tokenize(template: string): Token[];
|
|
2
26
|
export declare function renderTemplate(value: unknown, data: Record<string, unknown>, placeholders: TemplatePlaceholder[]): unknown;
|
|
27
|
+
export {};
|
|
3
28
|
//# sourceMappingURL=grammar.d.ts.map
|
package/dist/grammar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grammar.d.ts","sourceRoot":"","sources":["../src/grammar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"grammar.d.ts","sourceRoot":"","sources":["../src/grammar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,KAAK,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AAExD,MAAM,MAAM,KAAK,GACX;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAWvC,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,CAiClD;AA2HD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAe1H"}
|
package/dist/grammar.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const TAG_PATTERN = /\{\{(?:#if:(?:(?<ifMode>empty|isset):(?<ifPath>[\w.]+)|(?<cmpOp>eq|ne):(?<cmpPath>[\w.]+):(?<cmpValue>[^}]*)|(?<plainPath>[\w.]+))|(?<elseTag>else)|(?<endifTag>\/if)|#foreach:(?<foreachName>[\w.]+)(?::(?<foreachSep>[^}]*))?|(?<endforeachTag>\/foreach)|(?<scalarPath>@?[\w.]+))\}\}/g;
|
|
2
|
-
function tokenize(template) {
|
|
2
|
+
export function tokenize(template) {
|
|
3
3
|
const tokens = [];
|
|
4
4
|
let lastIndex = 0;
|
|
5
5
|
let match;
|
package/dist/grammar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grammar.js","sourceRoot":"","sources":["../src/grammar.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,GACb,2RAA2R,CAAC;AAEhS,
|
|
1
|
+
{"version":3,"file":"grammar.js","sourceRoot":"","sources":["../src/grammar.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { applyConditionalButtons } from './conditional-buttons.js';
|
|
2
2
|
export { renderTemplate } from './grammar.js';
|
|
3
3
|
export { resolveNowTimestamps } from './timestamps.js';
|
|
4
|
+
export { validateTemplate } from './validate.js';
|
|
5
|
+
export type { TemplateDiagnostic, TemplateDiagnosticSeverity } from './validate.js';
|
|
4
6
|
export type { MessageStore, NewSavedMessage, SavedMessage, SavedMessagePatch } from './store.js';
|
|
5
7
|
export type { ChannelSummary, ConditionalButtonRule, ContractCapabilities, ContractError, DiscordMessagePayload, GuildSummary, RoleSummary, TemplateDefinition, TemplatePlaceholder, TemplatePlaceholderKind, TemplatePreviewParam, TemplatePreviewSpec, UserSummary, } from './types.js';
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACjG,YAAY,EACR,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,GACd,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AACpF,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACjG,YAAY,EACR,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,GACd,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,uBAAuB,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,qBAAqB,EAAE,CAAC;IAC5C,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,cAAc,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE;QACN,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,OAAO,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC;QACf,KAAK,EAAE,OAAO,CAAC;QACf,mBAAmB,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,uBAAuB,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,qBAAqB,EAAE,CAAC;IAC5C,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,cAAc,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE;QACN,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,OAAO,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC;QACf,KAAK,EAAE,OAAO,CAAC;QACf,mBAAmB,EAAE,OAAO,CAAC;QAC7B,QAAQ,EAAE,OAAO,CAAC;KACrB,CAAC;CACL;AAED,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IAClC,UAAU,EAAE,OAAO,EAAE,CAAC;CACzB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TemplatePlaceholder } from './types.js';
|
|
2
|
+
export type TemplateDiagnosticSeverity = 'error' | 'warning';
|
|
3
|
+
export interface TemplateDiagnostic {
|
|
4
|
+
severity: TemplateDiagnosticSeverity;
|
|
5
|
+
message: string;
|
|
6
|
+
path: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function validateTemplate(value: unknown, placeholders: TemplatePlaceholder[], path?: string): TemplateDiagnostic[];
|
|
9
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,MAAM,0BAA0B,GAAG,OAAO,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,0BAA0B,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CAChB;AA0ID,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,EAAE,IAAI,SAAK,GAAG,kBAAkB,EAAE,CAarH"}
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { tokenize } from './grammar.js';
|
|
2
|
+
function aliasesByListName(placeholders) {
|
|
3
|
+
const map = new Map();
|
|
4
|
+
for (const placeholder of placeholders) {
|
|
5
|
+
if (placeholder.kind === 'list' && placeholder.itemAlias) {
|
|
6
|
+
map.set(placeholder.name, placeholder.itemAlias);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return map;
|
|
10
|
+
}
|
|
11
|
+
function declaredRoots(placeholders) {
|
|
12
|
+
const roots = new Set();
|
|
13
|
+
for (const placeholder of placeholders) {
|
|
14
|
+
roots.add(placeholder.name.split('.')[0]);
|
|
15
|
+
if (placeholder.kind === 'list' && placeholder.itemAlias) {
|
|
16
|
+
roots.add(placeholder.itemAlias);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return roots;
|
|
20
|
+
}
|
|
21
|
+
function checkPath(path, roots, openBlocks, where, diagnostics) {
|
|
22
|
+
const head = path.split('.')[0];
|
|
23
|
+
if (head === '@index' || head === '@index0') {
|
|
24
|
+
if (!openBlocks.some((block) => block.kind === 'foreach')) {
|
|
25
|
+
diagnostics.push({
|
|
26
|
+
severity: 'error',
|
|
27
|
+
message: `{{${path}}} only works inside a {{#foreach}} block`,
|
|
28
|
+
path: where,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (roots.has(head))
|
|
34
|
+
return;
|
|
35
|
+
diagnostics.push({
|
|
36
|
+
severity: 'warning',
|
|
37
|
+
message: `{{${path}}} is not a declared placeholder, so it renders as empty text`,
|
|
38
|
+
path: where,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function validateString(template, placeholders, where) {
|
|
42
|
+
const diagnostics = [];
|
|
43
|
+
const aliases = aliasesByListName(placeholders);
|
|
44
|
+
const roots = declaredRoots(placeholders);
|
|
45
|
+
const open = [];
|
|
46
|
+
const activeRoots = () => {
|
|
47
|
+
const set = new Set(roots);
|
|
48
|
+
for (const block of open) {
|
|
49
|
+
if (block.alias)
|
|
50
|
+
set.add(block.alias);
|
|
51
|
+
}
|
|
52
|
+
return set;
|
|
53
|
+
};
|
|
54
|
+
for (const token of tokenize(template)) {
|
|
55
|
+
if (token.kind === 'scalar') {
|
|
56
|
+
checkPath(token.path, activeRoots(), open, where, diagnostics);
|
|
57
|
+
}
|
|
58
|
+
else if (token.kind === 'if') {
|
|
59
|
+
checkPath(token.path, activeRoots(), open, where, diagnostics);
|
|
60
|
+
open.push({ kind: 'if', name: token.path, sawElse: false });
|
|
61
|
+
}
|
|
62
|
+
else if (token.kind === 'else') {
|
|
63
|
+
const current = open[open.length - 1];
|
|
64
|
+
if (!current || current.kind !== 'if') {
|
|
65
|
+
diagnostics.push({ severity: 'error', message: '{{else}} has no matching {{#if}}', path: where });
|
|
66
|
+
}
|
|
67
|
+
else if (current.sawElse) {
|
|
68
|
+
diagnostics.push({
|
|
69
|
+
severity: 'error',
|
|
70
|
+
message: `{{#if:${current.name}}} has more than one {{else}}; only the first is used`,
|
|
71
|
+
path: where,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
current.sawElse = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (token.kind === 'endif') {
|
|
79
|
+
const current = open[open.length - 1];
|
|
80
|
+
if (!current || current.kind !== 'if') {
|
|
81
|
+
diagnostics.push({
|
|
82
|
+
severity: 'error',
|
|
83
|
+
message: '{{/if}} has no matching {{#if}}, and everything after it is discarded',
|
|
84
|
+
path: where,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
open.pop();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (token.kind === 'foreach') {
|
|
92
|
+
checkPath(token.name, activeRoots(), open, where, diagnostics);
|
|
93
|
+
const alias = aliases.get(token.name);
|
|
94
|
+
if (!alias) {
|
|
95
|
+
diagnostics.push({
|
|
96
|
+
severity: 'error',
|
|
97
|
+
message: `{{#foreach:${token.name}}} needs a list placeholder named "${token.name}" with an itemAlias, or rendering throws`,
|
|
98
|
+
path: where,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
open.push({ kind: 'foreach', name: token.name, sawElse: false, alias });
|
|
102
|
+
}
|
|
103
|
+
else if (token.kind === 'endforeach') {
|
|
104
|
+
const current = open[open.length - 1];
|
|
105
|
+
if (!current || current.kind !== 'foreach') {
|
|
106
|
+
diagnostics.push({
|
|
107
|
+
severity: 'error',
|
|
108
|
+
message: '{{/foreach}} has no matching {{#foreach}}, and everything after it is discarded',
|
|
109
|
+
path: where,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
open.pop();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
for (const block of open) {
|
|
118
|
+
const opener = block.kind === 'if' ? `{{#if:${block.name}}}` : `{{#foreach:${block.name}}}`;
|
|
119
|
+
diagnostics.push({
|
|
120
|
+
severity: 'error',
|
|
121
|
+
message: `${opener} is never closed with {{/${block.kind}}}`,
|
|
122
|
+
path: where,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return diagnostics;
|
|
126
|
+
}
|
|
127
|
+
export function validateTemplate(value, placeholders, path = '') {
|
|
128
|
+
if (typeof value === 'string') {
|
|
129
|
+
return validateString(value, placeholders, path);
|
|
130
|
+
}
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
return value.flatMap((entry, index) => validateTemplate(entry, placeholders, path ? `${path}.${index}` : String(index)));
|
|
133
|
+
}
|
|
134
|
+
if (value !== null && typeof value === 'object') {
|
|
135
|
+
return Object.entries(value).flatMap(([key, entry]) => validateTemplate(entry, placeholders, path ? `${path}.${key}` : key));
|
|
136
|
+
}
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED