@tightknitai/slack-block-kit-validator 0.1.7-alpha.1 → 0.1.8
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 +4 -2
- package/dist/helpers/check-data-visualization-consistency.d.ts +22 -0
- package/dist/helpers/check-data-visualization-consistency.d.ts.map +1 -0
- package/dist/helpers/check-data-visualization-consistency.js +75 -0
- package/dist/helpers/check-data-visualization-consistency.js.map +1 -0
- package/dist/helpers/check-data-visualization-max.d.ts +16 -0
- package/dist/helpers/check-data-visualization-max.d.ts.map +1 -0
- package/dist/helpers/check-data-visualization-max.js +27 -0
- package/dist/helpers/check-data-visualization-max.js.map +1 -0
- package/dist/helpers/check-surface-compatibility.d.ts.map +1 -1
- package/dist/helpers/check-surface-compatibility.js +6 -0
- package/dist/helpers/check-surface-compatibility.js.map +1 -1
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +2 -0
- package/dist/helpers.js.map +1 -1
- package/dist/slack-block-kit.schema.json +107 -2
- package/dist/standalone-validator.js +1165 -315
- package/dist/types.generated.d.ts +306 -2
- package/dist/types.generated.d.ts.map +1 -1
- package/dist/validate-block-kit.d.ts.map +1 -1
- package/dist/validate-block-kit.js +5 -0
- package/dist/validate-block-kit.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -123,6 +123,8 @@ The schema uses `$defs` for every block, element, composition object, rich-text
|
|
|
123
123
|
| `findDuplicateBlockIds` | `(blocks) => string[]` | Duplicate `block_id` values in a blocks array. |
|
|
124
124
|
| `checkCumulativeMarkdownLength` | `(blocks) => string[]` | Sum of all `markdown` block text > 12,000 chars. |
|
|
125
125
|
| `checkSingleTableBlock` | `(blocks) => string[]` | More than one `table` block per payload. |
|
|
126
|
+
| `checkDataVisualizationMax` | `(blocks) => string[]` | More than two `data_visualization` blocks per message. |
|
|
127
|
+
| `checkDataVisualizationConsistency` | `(blocks) => string[]` | Chart series with duplicate names, or data points that don't line up with `axis_config.categories`. |
|
|
126
128
|
| `checkFocusOnLoadUniqueness` | `(blocks) => string[]` | More than one element with `focus_on_load: true` in a view (walks nested elements + accessories). |
|
|
127
129
|
| `checkSurfaceCompatibility` | `(blocks, surface) => string[]` | Blocks not allowed on the target surface (e.g. `alert` on message, `markdown` on modal, `file_input` outside modals). |
|
|
128
130
|
| `checkCardActionsMax` | `(blocks) => string[]` | More than `CARD_ACTIONS_MAX` action buttons on a card block. |
|
|
@@ -139,12 +141,12 @@ Each returns an array of human-readable error strings — empty when valid.
|
|
|
139
141
|
|
|
140
142
|
## Coverage
|
|
141
143
|
|
|
142
|
-
- **
|
|
144
|
+
- **19 blocks**: actions, alert, card, carousel, context, context_actions, data_visualization, divider, file, header, image, input, markdown, plan, rich_text, section, table, task_card, video.
|
|
143
145
|
- **All block elements**: button, icon_button, workflow_button, feedback_buttons, plain_text / email / url / number inputs, datepicker, datetimepicker, timepicker, file_input, rich_text_input, checkboxes, radio_buttons, image, overflow, url source, and all 5 single + 5 multi-select menu variants.
|
|
144
146
|
- **All 9 composition objects**: text (plain_text + mrkdwn), confirm, option (3 contextual variants), option_group, slack_file, dispatch_action_config, conversation_filter, trigger, workflow.
|
|
145
147
|
- **Rich text**: 4 container kinds (section, list, preformatted, quote) + 10 leaf kinds (text, link, user, usergroup, team, channel, emoji, broadcast, color, date) with style flags.
|
|
146
148
|
- **View envelopes**: `modal_view` + `home_view` under `$defs`.
|
|
147
|
-
- **Cross-payload rules** (via helpers): dup `block_id`, cumulative markdown, single-table, `focus_on_load` uniqueness, surface compatibility.
|
|
149
|
+
- **Cross-payload rules** (via helpers): dup `block_id`, cumulative markdown, single-table, two-data-visualization-per-message, chart series/category consistency, `focus_on_load` uniqueness, surface compatibility.
|
|
148
150
|
|
|
149
151
|
Every documented `maxLength`, regex (date / time / user ID / channel ID / team ID format), enum value, and array cardinality limit is enforced structurally.
|
|
150
152
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enforces the two `data_visualization` rules Slack applies at runtime that
|
|
3
|
+
* JSON Schema can't express, because each depends on the values of sibling
|
|
4
|
+
* fields:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Unique series names** — every series in a chart must have a distinct
|
|
7
|
+
* `name`.
|
|
8
|
+
* 2. **Label ↔ category matching** — each series must contain exactly one
|
|
9
|
+
* data point for every label in `axis_config.categories`, and no data
|
|
10
|
+
* point may use a label outside `categories`.
|
|
11
|
+
*
|
|
12
|
+
* Only cartesian (line/bar/area) charts have `series` + `axis_config`; pie
|
|
13
|
+
* charts (segments only) carry no categories and are skipped. Structurally
|
|
14
|
+
* malformed charts are skipped too — the schema reports those.
|
|
15
|
+
*
|
|
16
|
+
* @param blocks - array of Block Kit blocks
|
|
17
|
+
* @returns array of error messages (empty when every chart is internally consistent)
|
|
18
|
+
*/
|
|
19
|
+
export declare function checkDataVisualizationConsistency(blocks: readonly {
|
|
20
|
+
type?: string;
|
|
21
|
+
}[]): string[];
|
|
22
|
+
//# sourceMappingURL=check-data-visualization-consistency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-data-visualization-consistency.d.ts","sourceRoot":"","sources":["../../src/helpers/check-data-visualization-consistency.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,EAAE,CAmEhG"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enforces the two `data_visualization` rules Slack applies at runtime that
|
|
3
|
+
* JSON Schema can't express, because each depends on the values of sibling
|
|
4
|
+
* fields:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Unique series names** — every series in a chart must have a distinct
|
|
7
|
+
* `name`.
|
|
8
|
+
* 2. **Label ↔ category matching** — each series must contain exactly one
|
|
9
|
+
* data point for every label in `axis_config.categories`, and no data
|
|
10
|
+
* point may use a label outside `categories`.
|
|
11
|
+
*
|
|
12
|
+
* Only cartesian (line/bar/area) charts have `series` + `axis_config`; pie
|
|
13
|
+
* charts (segments only) carry no categories and are skipped. Structurally
|
|
14
|
+
* malformed charts are skipped too — the schema reports those.
|
|
15
|
+
*
|
|
16
|
+
* @param blocks - array of Block Kit blocks
|
|
17
|
+
* @returns array of error messages (empty when every chart is internally consistent)
|
|
18
|
+
*/
|
|
19
|
+
export function checkDataVisualizationConsistency(blocks) {
|
|
20
|
+
const errors = [];
|
|
21
|
+
blocks.forEach((block, i) => {
|
|
22
|
+
if (block?.type !== "data_visualization") {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const chart = block.chart;
|
|
26
|
+
const series = chart?.series;
|
|
27
|
+
if (!Array.isArray(series)) {
|
|
28
|
+
// Pie chart or malformed cartesian — nothing to cross-check here.
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// 1. Series names must be unique within the chart.
|
|
32
|
+
const seenNames = new Set();
|
|
33
|
+
series.forEach((entry) => {
|
|
34
|
+
const name = entry?.name;
|
|
35
|
+
if (typeof name !== "string") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (seenNames.has(name)) {
|
|
39
|
+
errors.push(`blocks[${i}].chart.series has a duplicate series name '${name}' — series names must be unique within a chart`);
|
|
40
|
+
}
|
|
41
|
+
seenNames.add(name);
|
|
42
|
+
});
|
|
43
|
+
// 2. Every series' data points must line up exactly with the categories.
|
|
44
|
+
const categories = chart?.axis_config?.categories;
|
|
45
|
+
if (!Array.isArray(categories)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const categorySet = new Set(categories.filter((c) => typeof c === "string"));
|
|
49
|
+
series.forEach((entry, si) => {
|
|
50
|
+
const data = entry?.data;
|
|
51
|
+
if (!Array.isArray(data)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const labels = data.map((d) => d?.label).filter((l) => typeof l === "string");
|
|
55
|
+
// Labels that aren't a declared category.
|
|
56
|
+
for (const label of labels) {
|
|
57
|
+
if (!categorySet.has(label)) {
|
|
58
|
+
errors.push(`blocks[${i}].chart.series[${si}] has a data point labeled '${label}' that is not in axis_config.categories`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Each category must be covered by exactly one data point.
|
|
62
|
+
for (const category of categorySet) {
|
|
63
|
+
const count = labels.filter((l) => l === category).length;
|
|
64
|
+
if (count === 0) {
|
|
65
|
+
errors.push(`blocks[${i}].chart.series[${si}] is missing a data point for category '${category}'`);
|
|
66
|
+
}
|
|
67
|
+
else if (count > 1) {
|
|
68
|
+
errors.push(`blocks[${i}].chart.series[${si}] has ${count} data points for category '${category}' — expected exactly one`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
return errors;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=check-data-visualization-consistency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-data-visualization-consistency.js","sourceRoot":"","sources":["../../src/helpers/check-data-visualization-consistency.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum number of `data_visualization` blocks Slack renders in a single
|
|
3
|
+
* message. Additional ones beyond this cap are dropped.
|
|
4
|
+
*/
|
|
5
|
+
export declare const DATA_VISUALIZATION_MAX = 2;
|
|
6
|
+
/**
|
|
7
|
+
* Checks that a payload contains at most {@link DATA_VISUALIZATION_MAX}
|
|
8
|
+
* `data_visualization` blocks. Slack renders only the first two data
|
|
9
|
+
* visualization blocks per message; any beyond that are silently dropped.
|
|
10
|
+
* @param blocks - array of Block Kit blocks
|
|
11
|
+
* @returns array of error messages (empty when within the limit)
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkDataVisualizationMax(blocks: readonly {
|
|
14
|
+
type?: string;
|
|
15
|
+
}[]): string[];
|
|
16
|
+
//# sourceMappingURL=check-data-visualization-max.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-data-visualization-max.d.ts","sourceRoot":"","sources":["../../src/helpers/check-data-visualization-max.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,EAAE,CAaxF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum number of `data_visualization` blocks Slack renders in a single
|
|
3
|
+
* message. Additional ones beyond this cap are dropped.
|
|
4
|
+
*/
|
|
5
|
+
export const DATA_VISUALIZATION_MAX = 2;
|
|
6
|
+
/**
|
|
7
|
+
* Checks that a payload contains at most {@link DATA_VISUALIZATION_MAX}
|
|
8
|
+
* `data_visualization` blocks. Slack renders only the first two data
|
|
9
|
+
* visualization blocks per message; any beyond that are silently dropped.
|
|
10
|
+
* @param blocks - array of Block Kit blocks
|
|
11
|
+
* @returns array of error messages (empty when within the limit)
|
|
12
|
+
*/
|
|
13
|
+
export function checkDataVisualizationMax(blocks) {
|
|
14
|
+
const indices = [];
|
|
15
|
+
blocks.forEach((block, i) => {
|
|
16
|
+
if (block?.type === "data_visualization") {
|
|
17
|
+
indices.push(i);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
if (indices.length > DATA_VISUALIZATION_MAX) {
|
|
21
|
+
return [
|
|
22
|
+
`at most ${DATA_VISUALIZATION_MAX} 'data_visualization' blocks are allowed per message — found ${indices.length} at indices ${indices.join(", ")}`,
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=check-data-visualization-max.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-data-visualization-max.js","sourceRoot":"","sources":["../../src/helpers/check-data-visualization-max.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAoC;IAC5E,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,KAAK,EAAE,IAAI,KAAK,oBAAoB,EAAE,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,MAAM,GAAG,sBAAsB,EAAE,CAAC;QAC5C,OAAO;YACL,WAAW,sBAAsB,gEAAgE,OAAO,CAAC,MAAM,eAAe,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;SACnJ,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-surface-compatibility.d.ts","sourceRoot":"","sources":["../../src/helpers/check-surface-compatibility.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"check-surface-compatibility.d.ts","sourceRoot":"","sources":["../../src/helpers/check-surface-compatibility.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AA+DnD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAAE,EACjE,OAAO,EAAE,OAAO,GACf,MAAM,EAAE,CAsBV"}
|
|
@@ -11,10 +11,15 @@ const BLOCKS_NOT_ALLOWED_IN_MESSAGE = new Set(["alert", "file"]);
|
|
|
11
11
|
// carousel/card are listed as modal-available in Slack's blocks.json but
|
|
12
12
|
// empirically fail to render inside modal views — confirmed by the PR author
|
|
13
13
|
// against the live API. They work in messages and home tabs.
|
|
14
|
+
// `data_visualization` is a messages-only block — its reference page lists
|
|
15
|
+
// "Available in Surfaces: Messages" only
|
|
16
|
+
// (https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block).
|
|
17
|
+
// Forbidden in both modals and home tabs.
|
|
14
18
|
const BLOCKS_NOT_ALLOWED_IN_MODAL = new Set([
|
|
15
19
|
"card",
|
|
16
20
|
"carousel",
|
|
17
21
|
"context_actions",
|
|
22
|
+
"data_visualization",
|
|
18
23
|
"file",
|
|
19
24
|
"markdown",
|
|
20
25
|
"plan",
|
|
@@ -24,6 +29,7 @@ const BLOCKS_NOT_ALLOWED_IN_MODAL = new Set([
|
|
|
24
29
|
const BLOCKS_NOT_ALLOWED_IN_HOME = new Set([
|
|
25
30
|
"alert",
|
|
26
31
|
"context_actions",
|
|
32
|
+
"data_visualization",
|
|
27
33
|
"file",
|
|
28
34
|
"markdown",
|
|
29
35
|
"plan",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-surface-compatibility.js","sourceRoot":"","sources":["../../src/helpers/check-surface-compatibility.ts"],"names":[],"mappings":"AAMA,2EAA2E;AAC3E,0EAA0E;AAC1E,0EAA0E;AAC1E,yEAAyE;AACzE,qCAAqC;AACrC,yEAAyE;AACzE,4DAA4D;AAC5D,iEAAiE;AACjE,2DAA2D;AAC3D,MAAM,6BAA6B,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAEjE,yEAAyE;AACzE,6EAA6E;AAC7E,6DAA6D;AAC7D,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC;IAC1C,MAAM;IACN,UAAU;IACV,iBAAiB;IACjB,MAAM;IACN,UAAU;IACV,MAAM;IACN,OAAO;IACP,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,OAAO;IACP,iBAAiB;IACjB,MAAM;IACN,UAAU;IACV,MAAM;IACN,OAAO;IACP,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAiC;IACzD,OAAO,EAAE,6BAA6B;IACtC,KAAK,EAAE,2BAA2B;IAClC,IAAI,EAAE,0BAA0B;CACjC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,qBAAqB,GAA4B;IACrD,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,GAAG;CACV,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAiE,EACjE,OAAgB;IAEhB,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,SAAS,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,YAAY,OAAO,oBAAoB,SAAS,gBAAgB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAChG,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,KAAK,EAAE,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,CAAC,IAAI,gCAAgC,OAAO,GAAG,CAAC,CAAC;YACxF,mEAAmE;YACnE,uCAAuC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,KAAK,EAAE,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,KAAK,YAAY,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YAC3F,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,uEAAuE,OAAO,IAAI,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"check-surface-compatibility.js","sourceRoot":"","sources":["../../src/helpers/check-surface-compatibility.ts"],"names":[],"mappings":"AAMA,2EAA2E;AAC3E,0EAA0E;AAC1E,0EAA0E;AAC1E,yEAAyE;AACzE,qCAAqC;AACrC,yEAAyE;AACzE,4DAA4D;AAC5D,iEAAiE;AACjE,2DAA2D;AAC3D,MAAM,6BAA6B,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAEjE,yEAAyE;AACzE,6EAA6E;AAC7E,6DAA6D;AAC7D,2EAA2E;AAC3E,yCAAyC;AACzC,gFAAgF;AAChF,0CAA0C;AAC1C,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC;IAC1C,MAAM;IACN,UAAU;IACV,iBAAiB;IACjB,oBAAoB;IACpB,MAAM;IACN,UAAU;IACV,MAAM;IACN,OAAO;IACP,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,OAAO;IACP,iBAAiB;IACjB,oBAAoB;IACpB,MAAM;IACN,UAAU;IACV,MAAM;IACN,OAAO;IACP,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAiC;IACzD,OAAO,EAAE,6BAA6B;IACtC,KAAK,EAAE,2BAA2B;IAClC,IAAI,EAAE,0BAA0B;CACjC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,qBAAqB,GAA4B;IACrD,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,GAAG;CACV,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAiE,EACjE,OAAgB;IAEhB,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,SAAS,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,YAAY,OAAO,oBAAoB,SAAS,gBAAgB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAChG,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,KAAK,EAAE,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,CAAC,IAAI,gCAAgC,OAAO,GAAG,CAAC,CAAC;YACxF,mEAAmE;YACnE,uCAAuC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,KAAK,EAAE,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,KAAK,YAAY,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YAC3F,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,uEAAuE,OAAO,IAAI,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from "./helpers/check-card-actions-max.js";
|
|
2
2
|
export * from "./helpers/check-cumulative-markdown-length.js";
|
|
3
|
+
export * from "./helpers/check-data-visualization-consistency.js";
|
|
4
|
+
export * from "./helpers/check-data-visualization-max.js";
|
|
3
5
|
export * from "./helpers/check-focus-on-load-uniqueness.js";
|
|
4
6
|
export * from "./helpers/check-number-input-bounds.js";
|
|
5
7
|
export * from "./helpers/check-response-url-enabled-context.js";
|
package/dist/helpers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAIA,cAAc,qCAAqC,CAAC;AACpD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,6CAA6C,CAAC;AAC5D,cAAc,wCAAwC,CAAC;AACvD,cAAc,iDAAiD,CAAC;AAChE,cAAc,uCAAuC,CAAC;AACtD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAIA,cAAc,qCAAqC,CAAC;AACpD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mDAAmD,CAAC;AAClE,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6CAA6C,CAAC;AAC5D,cAAc,wCAAwC,CAAC;AACvD,cAAc,iDAAiD,CAAC;AAChE,cAAc,uCAAuC,CAAC;AACtD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC"}
|
package/dist/helpers.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
// can't express, and can be composed with any other validator.
|
|
4
4
|
export * from "./helpers/check-card-actions-max.js";
|
|
5
5
|
export * from "./helpers/check-cumulative-markdown-length.js";
|
|
6
|
+
export * from "./helpers/check-data-visualization-consistency.js";
|
|
7
|
+
export * from "./helpers/check-data-visualization-max.js";
|
|
6
8
|
export * from "./helpers/check-focus-on-load-uniqueness.js";
|
|
7
9
|
export * from "./helpers/check-number-input-bounds.js";
|
|
8
10
|
export * from "./helpers/check-response-url-enabled-context.js";
|
package/dist/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,+DAA+D;AAE/D,cAAc,qCAAqC,CAAC;AACpD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,6CAA6C,CAAC;AAC5D,cAAc,wCAAwC,CAAC;AACvD,cAAc,iDAAiD,CAAC;AAChE,cAAc,uCAAuC,CAAC;AACtD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC"}
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,+DAA+D;AAE/D,cAAc,qCAAqC,CAAC;AACpD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mDAAmD,CAAC;AAClE,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6CAA6C,CAAC;AAC5D,cAAc,wCAAwC,CAAC;AACvD,cAAc,iDAAiD,CAAC;AAChE,cAAc,uCAAuC,CAAC;AACtD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://tightknit.com/schemas/slack-block-kit.schema.json",
|
|
4
4
|
"title": "Slack Block Kit",
|
|
5
|
-
"description": "JSON Schema (draft 2020-12) for Slack Block Kit payloads. Validates a top-level array of blocks. Individual block, element, and composition object schemas are exposed via $defs for re-use. Compiled from https://docs.slack.dev/reference/block-kit (fetched 2026-04-16). Surface restrictions (messages vs modals vs home) and payload-level rules (e.g. cumulative 12k char markdown limit, single-table-per-message) are documented in $defs descriptions but not enforced at the per-block level.",
|
|
5
|
+
"description": "JSON Schema (draft 2020-12) for Slack Block Kit payloads. Validates a top-level array of blocks. Individual block, element, and composition object schemas are exposed via $defs for re-use. Compiled from https://docs.slack.dev/reference/block-kit (fetched 2026-04-16). Surface restrictions (messages vs modals vs home) and payload-level rules (e.g. cumulative 12k char markdown limit, single-table-per-message, max two data-visualization blocks per message) are documented in $defs descriptions but not enforced at the per-block level.",
|
|
6
6
|
"type": "array",
|
|
7
7
|
"minItems": 1,
|
|
8
8
|
"maxItems": 100,
|
|
@@ -1210,6 +1210,109 @@
|
|
|
1210
1210
|
}
|
|
1211
1211
|
},
|
|
1212
1212
|
|
|
1213
|
+
"data_visualization_data_point": {
|
|
1214
|
+
"description": "A single point in a chart series: an x-axis label and its numeric value. The label must match one of axis_config.categories (enforced via checkDataVisualizationConsistency). Negative values are permitted — line/bar/area charts render against a zero baseline.",
|
|
1215
|
+
"type": "object",
|
|
1216
|
+
"additionalProperties": false,
|
|
1217
|
+
"required": ["label", "value"],
|
|
1218
|
+
"properties": {
|
|
1219
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 20 },
|
|
1220
|
+
"value": { "type": "number" }
|
|
1221
|
+
}
|
|
1222
|
+
},
|
|
1223
|
+
|
|
1224
|
+
"data_visualization_series": {
|
|
1225
|
+
"description": "A named series of data points plotted on a line/bar/area chart. The name drives the chart legend and must be unique across all series in the same chart (enforced via checkDataVisualizationConsistency).",
|
|
1226
|
+
"type": "object",
|
|
1227
|
+
"additionalProperties": false,
|
|
1228
|
+
"required": ["name", "data"],
|
|
1229
|
+
"properties": {
|
|
1230
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 20 },
|
|
1231
|
+
"data": {
|
|
1232
|
+
"type": "array",
|
|
1233
|
+
"minItems": 1,
|
|
1234
|
+
"maxItems": 20,
|
|
1235
|
+
"items": { "$ref": "#/$defs/data_visualization_data_point" }
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
},
|
|
1239
|
+
|
|
1240
|
+
"data_visualization_axis_config": {
|
|
1241
|
+
"description": "Axis configuration for cartesian (line/bar/area) charts. categories define the valid x-axis labels and their left-to-right display order.",
|
|
1242
|
+
"type": "object",
|
|
1243
|
+
"additionalProperties": false,
|
|
1244
|
+
"required": ["categories"],
|
|
1245
|
+
"properties": {
|
|
1246
|
+
"categories": {
|
|
1247
|
+
"type": "array",
|
|
1248
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 20 }
|
|
1249
|
+
},
|
|
1250
|
+
"x_label": { "type": "string", "maxLength": 50 },
|
|
1251
|
+
"y_label": { "type": "string", "maxLength": 50 }
|
|
1252
|
+
}
|
|
1253
|
+
},
|
|
1254
|
+
|
|
1255
|
+
"data_visualization_segment": {
|
|
1256
|
+
"description": "A single slice of a pie chart. value must be greater than 0; Slack derives the displayed percentage from each segment's value as a share of the total.",
|
|
1257
|
+
"type": "object",
|
|
1258
|
+
"additionalProperties": false,
|
|
1259
|
+
"required": ["label", "value"],
|
|
1260
|
+
"properties": {
|
|
1261
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 20 },
|
|
1262
|
+
"value": { "type": "number", "exclusiveMinimum": 0 }
|
|
1263
|
+
}
|
|
1264
|
+
},
|
|
1265
|
+
|
|
1266
|
+
"data_visualization_chart": {
|
|
1267
|
+
"description": "The chart rendered by a data_visualization block. line/bar/area charts use series + axis_config; pie charts use segments.",
|
|
1268
|
+
"oneOf": [
|
|
1269
|
+
{
|
|
1270
|
+
"description": "Cartesian chart — line, bar, or area. 1–6 series; axis_config required.",
|
|
1271
|
+
"type": "object",
|
|
1272
|
+
"additionalProperties": false,
|
|
1273
|
+
"required": ["type", "series", "axis_config"],
|
|
1274
|
+
"properties": {
|
|
1275
|
+
"type": { "enum": ["line", "bar", "area"] },
|
|
1276
|
+
"series": {
|
|
1277
|
+
"type": "array",
|
|
1278
|
+
"minItems": 1,
|
|
1279
|
+
"maxItems": 6,
|
|
1280
|
+
"items": { "$ref": "#/$defs/data_visualization_series" }
|
|
1281
|
+
},
|
|
1282
|
+
"axis_config": { "$ref": "#/$defs/data_visualization_axis_config" }
|
|
1283
|
+
}
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
"description": "Pie chart. 1–6 segments.",
|
|
1287
|
+
"type": "object",
|
|
1288
|
+
"additionalProperties": false,
|
|
1289
|
+
"required": ["type", "segments"],
|
|
1290
|
+
"properties": {
|
|
1291
|
+
"type": { "const": "pie" },
|
|
1292
|
+
"segments": {
|
|
1293
|
+
"type": "array",
|
|
1294
|
+
"minItems": 1,
|
|
1295
|
+
"maxItems": 6,
|
|
1296
|
+
"items": { "$ref": "#/$defs/data_visualization_segment" }
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
]
|
|
1301
|
+
},
|
|
1302
|
+
|
|
1303
|
+
"data_visualization_block": {
|
|
1304
|
+
"description": "Renders data as a line, bar, area, or pie chart. Messages only (https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block). Slack renders at most two data_visualization blocks per message (enforced via the checkDataVisualizationMax helper, since JSON Schema can't count sibling blocks). Two further runtime rules are enforced via checkDataVisualizationConsistency, since they depend on sibling-field values JSON Schema can't compare: series names must be unique within a chart, and each series must contain exactly one data point per axis_config.categories label.",
|
|
1305
|
+
"type": "object",
|
|
1306
|
+
"additionalProperties": false,
|
|
1307
|
+
"required": ["type", "title", "chart"],
|
|
1308
|
+
"properties": {
|
|
1309
|
+
"type": { "const": "data_visualization" },
|
|
1310
|
+
"block_id": { "$ref": "#/$defs/block_id" },
|
|
1311
|
+
"title": { "type": "string", "minLength": 1, "maxLength": 50 },
|
|
1312
|
+
"chart": { "$ref": "#/$defs/data_visualization_chart" }
|
|
1313
|
+
}
|
|
1314
|
+
},
|
|
1315
|
+
|
|
1213
1316
|
"divider_block": {
|
|
1214
1317
|
"type": "object",
|
|
1215
1318
|
"additionalProperties": false,
|
|
@@ -1242,7 +1345,8 @@
|
|
|
1242
1345
|
"text": {
|
|
1243
1346
|
"allOf": [{ "$ref": "#/$defs/plain_text_object" }, { "properties": { "text": { "maxLength": 150 } } }]
|
|
1244
1347
|
},
|
|
1245
|
-
"block_id": { "$ref": "#/$defs/block_id" }
|
|
1348
|
+
"block_id": { "$ref": "#/$defs/block_id" },
|
|
1349
|
+
"level": { "type": "integer", "minimum": 1, "maximum": 4 }
|
|
1246
1350
|
}
|
|
1247
1351
|
},
|
|
1248
1352
|
|
|
@@ -1521,6 +1625,7 @@
|
|
|
1521
1625
|
{ "$ref": "#/$defs/carousel_block" },
|
|
1522
1626
|
{ "$ref": "#/$defs/context_actions_block" },
|
|
1523
1627
|
{ "$ref": "#/$defs/context_block" },
|
|
1628
|
+
{ "$ref": "#/$defs/data_visualization_block" },
|
|
1524
1629
|
{ "$ref": "#/$defs/divider_block" },
|
|
1525
1630
|
{ "$ref": "#/$defs/file_block" },
|
|
1526
1631
|
{ "$ref": "#/$defs/header_block" },
|