@terreno/blocks 57.10.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.
Files changed (237) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/biome.jsonc +18 -0
  4. package/bunfig.toml +6 -0
  5. package/dist/asks/errors.d.ts +77 -0
  6. package/dist/asks/errors.js +364 -0
  7. package/dist/asks/files.d.ts +53 -0
  8. package/dist/asks/files.js +171 -0
  9. package/dist/asks/formValues.d.ts +32 -0
  10. package/dist/asks/formValues.js +229 -0
  11. package/dist/asks/headless.d.ts +227 -0
  12. package/dist/asks/headless.js +94 -0
  13. package/dist/asks/jsonSchema.d.ts +6 -0
  14. package/dist/asks/jsonSchema.js +62 -0
  15. package/dist/asks/limits.d.ts +58 -0
  16. package/dist/asks/limits.js +61 -0
  17. package/dist/asks/prompt.d.ts +10 -0
  18. package/dist/asks/prompt.js +144 -0
  19. package/dist/asks/schema.d.ts +826 -0
  20. package/dist/asks/schema.js +864 -0
  21. package/dist/asks/simpleCard.d.ts +85 -0
  22. package/dist/asks/simpleCard.js +279 -0
  23. package/dist/asks/validateInput.d.ts +13 -0
  24. package/dist/asks/validateInput.js +19 -0
  25. package/dist/asks/validateResponse.d.ts +13 -0
  26. package/dist/asks/validateResponse.js +278 -0
  27. package/dist/cli.d.ts +11 -0
  28. package/dist/cli.js +58 -0
  29. package/dist/errors.d.ts +51 -0
  30. package/dist/errors.js +106 -0
  31. package/dist/index.d.ts +31 -0
  32. package/dist/index.js +111 -0
  33. package/dist/jsonSchema.d.ts +5 -0
  34. package/dist/jsonSchema.js +12 -0
  35. package/dist/limits.d.ts +27 -0
  36. package/dist/limits.js +30 -0
  37. package/dist/lint.d.ts +21 -0
  38. package/dist/lint.js +388 -0
  39. package/dist/parse.d.ts +16 -0
  40. package/dist/parse.js +95 -0
  41. package/dist/parsePartial.d.ts +12 -0
  42. package/dist/parsePartial.js +105 -0
  43. package/dist/prompt.d.ts +9 -0
  44. package/dist/prompt.js +95 -0
  45. package/dist/schema.d.ts +199 -0
  46. package/dist/schema.js +277 -0
  47. package/dist/validate.d.ts +17 -0
  48. package/dist/validate.js +331 -0
  49. package/package.json +60 -0
  50. package/schemas/pendingAsksResponse.schema.json +195 -0
  51. package/schemas/simpleCard.schema.json +135 -0
  52. package/schemas/turnRequest.schema.json +108 -0
  53. package/schemas/turnResponse.schema.json +204 -0
  54. package/scripts/writeJsonSchemas.ts +11 -0
  55. package/src/asks/docParity.test.ts +65 -0
  56. package/src/asks/errors.test.ts +250 -0
  57. package/src/asks/errors.ts +449 -0
  58. package/src/asks/files.test.ts +294 -0
  59. package/src/asks/files.ts +216 -0
  60. package/src/asks/fixtures/invalid/choice-blank-text.json +20 -0
  61. package/src/asks/fixtures/invalid/choice-default-not-in-options.json +13 -0
  62. package/src/asks/fixtures/invalid/choice-default-selects-two.json +16 -0
  63. package/src/asks/fixtures/invalid/choice-description-too-long.json +24 -0
  64. package/src/asks/fixtures/invalid/choice-duplicate-ids.json +17 -0
  65. package/src/asks/fixtures/invalid/choice-label-too-long.json +23 -0
  66. package/src/asks/fixtures/invalid/choice-many-bounds-not-whole.json +17 -0
  67. package/src/asks/fixtures/invalid/choice-many-bounds-out-of-range.json +17 -0
  68. package/src/asks/fixtures/invalid/choice-many-default-duplicate.json +17 -0
  69. package/src/asks/fixtures/invalid/choice-many-default-too-many.json +15 -0
  70. package/src/asks/fixtures/invalid/choice-many-max-above-options.json +14 -0
  71. package/src/asks/fixtures/invalid/choice-many-min-above-choices.json +13 -0
  72. package/src/asks/fixtures/invalid/choice-many-min-above-max.json +15 -0
  73. package/src/asks/fixtures/invalid/choice-missing-required.json +14 -0
  74. package/src/asks/fixtures/invalid/choice-mixed-errors.json +19 -0
  75. package/src/asks/fixtures/invalid/choice-not-an-object.json +5 -0
  76. package/src/asks/fixtures/invalid/choice-one-with-many-fields.json +19 -0
  77. package/src/asks/fixtures/invalid/choice-option-id-format.json +35 -0
  78. package/src/asks/fixtures/invalid/choice-options-not-objects.json +12 -0
  79. package/src/asks/fixtures/invalid/choice-other-label-too-long.json +25 -0
  80. package/src/asks/fixtures/invalid/choice-other-label-without-allow-other.json +14 -0
  81. package/src/asks/fixtures/invalid/choice-prompt-empty.json +12 -0
  82. package/src/asks/fixtures/invalid/choice-prompt-too-long.json +23 -0
  83. package/src/asks/fixtures/invalid/choice-select-unknown.json +12 -0
  84. package/src/asks/fixtures/invalid/choice-submit-label-too-long.json +13 -0
  85. package/src/asks/fixtures/invalid/choice-title-too-long.json +24 -0
  86. package/src/asks/fixtures/invalid/choice-too-few-options.json +9 -0
  87. package/src/asks/fixtures/invalid/choice-too-many-options.json +219 -0
  88. package/src/asks/fixtures/invalid/choice-unknown-key-option.json +15 -0
  89. package/src/asks/fixtures/invalid/choice-unknown-key-root.json +13 -0
  90. package/src/asks/fixtures/invalid/choice-wrong-types.json +16 -0
  91. package/src/asks/fixtures/invalid/confirm-emoji-label-too-long.json +13 -0
  92. package/src/asks/fixtures/invalid/confirm-label-too-long.json +14 -0
  93. package/src/asks/fixtures/invalid/confirm-labels-alike-after-trim.json +14 -0
  94. package/src/asks/fixtures/invalid/confirm-labels-alike.json +13 -0
  95. package/src/asks/fixtures/invalid/confirm-missing-prompt-blank-label.json +16 -0
  96. package/src/asks/fixtures/invalid/confirm-unknown-keys.json +23 -0
  97. package/src/asks/fixtures/invalid/confirm-wrong-types.json +18 -0
  98. package/src/asks/fixtures/invalid/files-accept-duplicate.json +13 -0
  99. package/src/asks/fixtures/invalid/files-accept-empty.json +13 -0
  100. package/src/asks/fixtures/invalid/files-accept-unknown.json +13 -0
  101. package/src/asks/fixtures/invalid/files-counts-out-of-range.json +19 -0
  102. package/src/asks/fixtures/invalid/files-min-above-max.json +15 -0
  103. package/src/asks/fixtures/invalid/files-missing-accept-unknown-key.json +17 -0
  104. package/src/asks/fixtures/invalid/form-default-bad-format.json +40 -0
  105. package/src/asks/fixtures/invalid/form-default-invalid-date.json +40 -0
  106. package/src/asks/fixtures/invalid/form-default-not-in-options.json +58 -0
  107. package/src/asks/fixtures/invalid/form-default-out-of-range.json +33 -0
  108. package/src/asks/fixtures/invalid/form-default-text-bounds.json +42 -0
  109. package/src/asks/fixtures/invalid/form-default-wrong-type.json +30 -0
  110. package/src/asks/fixtures/invalid/form-duplicate-field-ids.json +24 -0
  111. package/src/asks/fixtures/invalid/form-field-id-format.json +19 -0
  112. package/src/asks/fixtures/invalid/form-field-text-limits.json +33 -0
  113. package/src/asks/fixtures/invalid/form-keys-of-another-type.json +39 -0
  114. package/src/asks/fixtures/invalid/form-length-above-cap.json +30 -0
  115. package/src/asks/fixtures/invalid/form-min-above-max.json +32 -0
  116. package/src/asks/fixtures/invalid/form-no-fields.json +13 -0
  117. package/src/asks/fixtures/invalid/form-select-options.json +44 -0
  118. package/src/asks/fixtures/invalid/form-too-many-fields.json +59 -0
  119. package/src/asks/fixtures/invalid/form-unknown-field-type.json +27 -0
  120. package/src/asks/fixtures/invalid/markdown-bounds-out-of-range.json +18 -0
  121. package/src/asks/fixtures/invalid/markdown-initial-above-cap.json +13 -0
  122. package/src/asks/fixtures/invalid/markdown-max-above-cap.json +13 -0
  123. package/src/asks/fixtures/invalid/markdown-min-above-cap.json +13 -0
  124. package/src/asks/fixtures/invalid/markdown-min-above-max.json +14 -0
  125. package/src/asks/fixtures/invalid/markdown-placeholder-too-long.json +13 -0
  126. package/src/asks/fixtures/invalid/markdown-wrong-types-unknown-key.json +27 -0
  127. package/src/asks/fixtures/valid/choice-emoji-label-cut.json +32 -0
  128. package/src/asks/fixtures/valid/choice-labels-collide-after-cut.json +21 -0
  129. package/src/asks/fixtures/valid/choice-long-text-cut.json +41 -0
  130. package/src/asks/fixtures/valid/choice-many-default-below-min.json +24 -0
  131. package/src/asks/fixtures/valid/choice-many-every-choice-with-other.json +24 -0
  132. package/src/asks/fixtures/valid/choice-many-no-default.json +21 -0
  133. package/src/asks/fixtures/valid/choice-many-optional-no-buttons.json +20 -0
  134. package/src/asks/fixtures/valid/choice-many-options-default-label-collides.json +23 -0
  135. package/src/asks/fixtures/valid/choice-many-options-no-buttons.json +21 -0
  136. package/src/asks/fixtures/valid/choice-many-options-no-default.json +22 -0
  137. package/src/asks/fixtures/valid/choice-many-options-with-default.json +30 -0
  138. package/src/asks/fixtures/valid/choice-many-required-with-default.json +29 -0
  139. package/src/asks/fixtures/valid/choice-many-single-pick-or-other.json +29 -0
  140. package/src/asks/fixtures/valid/choice-many-toppings-with-default.json +36 -0
  141. package/src/asks/fixtures/valid/choice-max-limits.json +245 -0
  142. package/src/asks/fixtures/valid/choice-plan-with-default.json +42 -0
  143. package/src/asks/fixtures/valid/choice-two-options-no-decline.json +32 -0
  144. package/src/asks/fixtures/valid/choice-two-options.json +32 -0
  145. package/src/asks/fixtures/valid/confirm-allow-decline.json +40 -0
  146. package/src/asks/fixtures/valid/confirm-default-labels.json +36 -0
  147. package/src/asks/fixtures/valid/confirm-destructive-delete.json +41 -0
  148. package/src/asks/fixtures/valid/confirm-emoji-labels.json +38 -0
  149. package/src/asks/fixtures/valid/confirm-long-text-cut.json +40 -0
  150. package/src/asks/fixtures/valid/files-every-type.json +28 -0
  151. package/src/asks/fixtures/valid/files-one-csv-no-decline.json +16 -0
  152. package/src/asks/fixtures/valid/files-receipt-photos.json +24 -0
  153. package/src/asks/fixtures/valid/form-boolean-newsletter.json +30 -0
  154. package/src/asks/fixtures/valid/form-date-due.json +44 -0
  155. package/src/asks/fixtures/valid/form-datetime-meeting.json +44 -0
  156. package/src/asks/fixtures/valid/form-datetime-minutes-offset.json +44 -0
  157. package/src/asks/fixtures/valid/form-eight-fields.json +71 -0
  158. package/src/asks/fixtures/valid/form-email-contact.json +44 -0
  159. package/src/asks/fixtures/valid/form-invoice-details.json +68 -0
  160. package/src/asks/fixtures/valid/form-multiselect-channels.json +64 -0
  161. package/src/asks/fixtures/valid/form-number-budget.json +45 -0
  162. package/src/asks/fixtures/valid/form-phone-callback.json +44 -0
  163. package/src/asks/fixtures/valid/form-select-shipping.json +58 -0
  164. package/src/asks/fixtures/valid/form-text-required-default.json +47 -0
  165. package/src/asks/fixtures/valid/form-textarea-notes.json +23 -0
  166. package/src/asks/fixtures/valid/form-time-reminder.json +44 -0
  167. package/src/asks/fixtures/valid/form-url-website.json +30 -0
  168. package/src/asks/fixtures/valid/markdown-announcement-draft.json +39 -0
  169. package/src/asks/fixtures/valid/markdown-empty-draft.json +34 -0
  170. package/src/asks/fixtures/valid/markdown-initial-blank-below-min.json +24 -0
  171. package/src/asks/fixtures/valid/markdown-initial-over-max.json +24 -0
  172. package/src/asks/fixtures/valid/markdown-long-text-cut.json +37 -0
  173. package/src/asks/fixtures/valid/markdown-no-decline.json +28 -0
  174. package/src/asks/fixtures/valid/markdown-no-initial-with-min.json +25 -0
  175. package/src/asks/formValues.ts +320 -0
  176. package/src/asks/headless.test.ts +146 -0
  177. package/src/asks/headless.ts +130 -0
  178. package/src/asks/jsonSchema.test.ts +171 -0
  179. package/src/asks/jsonSchema.ts +89 -0
  180. package/src/asks/limits.ts +58 -0
  181. package/src/asks/prompt.test.ts +200 -0
  182. package/src/asks/prompt.ts +173 -0
  183. package/src/asks/schema.test.ts +198 -0
  184. package/src/asks/schema.ts +1203 -0
  185. package/src/asks/simpleCard.test.ts +998 -0
  186. package/src/asks/simpleCard.ts +341 -0
  187. package/src/asks/validateInput.test.ts +875 -0
  188. package/src/asks/validateInput.ts +24 -0
  189. package/src/asks/validateResponse.test.ts +740 -0
  190. package/src/asks/validateResponse.ts +341 -0
  191. package/src/blocksDocParity.test.ts +21 -0
  192. package/src/cli.test.ts +134 -0
  193. package/src/cli.ts +65 -0
  194. package/src/display.test.ts +68 -0
  195. package/src/errors.test.ts +29 -0
  196. package/src/errors.ts +125 -0
  197. package/src/fixtures/invalid/column-not-found.yaml +14 -0
  198. package/src/fixtures/invalid/column-type.yaml +14 -0
  199. package/src/fixtures/invalid/dataset-not-found.yaml +7 -0
  200. package/src/fixtures/invalid/dataset-too-large.yaml +20 -0
  201. package/src/fixtures/invalid/depth-exceeded.yaml +10 -0
  202. package/src/fixtures/invalid/duplicate-id.yaml +6 -0
  203. package/src/fixtures/invalid/invalid-enum.yaml +5 -0
  204. package/src/fixtures/invalid/key-order.yaml +4 -0
  205. package/src/fixtures/invalid/missing-required.yaml +3 -0
  206. package/src/fixtures/invalid/not-a-document.txt +1 -0
  207. package/src/fixtures/invalid/row-arity.yaml +11 -0
  208. package/src/fixtures/invalid/select-target.yaml +12 -0
  209. package/src/fixtures/invalid/table-too-wide.yaml +9 -0
  210. package/src/fixtures/invalid/too-many-points.yaml +8 -0
  211. package/src/fixtures/invalid/unknown-key.yaml +5 -0
  212. package/src/fixtures/invalid/unsupported-version.yaml +4 -0
  213. package/src/fixtures/invalid/yaml-anchor.yaml +6 -0
  214. package/src/fixtures/partial/cut-after-divider.yaml +5 -0
  215. package/src/fixtures/valid/actions.yaml +32 -0
  216. package/src/fixtures/valid/chart.yaml +20 -0
  217. package/src/fixtures/valid/layout.yaml +26 -0
  218. package/src/fixtures/valid/prose.yaml +4 -0
  219. package/src/html.test.ts +52 -0
  220. package/src/index.test.ts +114 -0
  221. package/src/index.ts +175 -0
  222. package/src/jsonSchema.test.ts +33 -0
  223. package/src/jsonSchema.ts +11 -0
  224. package/src/limits.ts +27 -0
  225. package/src/lint.test.ts +289 -0
  226. package/src/lint.ts +484 -0
  227. package/src/parse.test.ts +281 -0
  228. package/src/parse.ts +104 -0
  229. package/src/parsePartial.test.ts +53 -0
  230. package/src/parsePartial.ts +116 -0
  231. package/src/prompt.test.ts +24 -0
  232. package/src/prompt.ts +104 -0
  233. package/src/schema.ts +509 -0
  234. package/src/tests/askFixtures.ts +40 -0
  235. package/src/validate.perf.test.ts +43 -0
  236. package/src/validate.ts +369 -0
  237. package/tsconfig.json +18 -0
package/src/errors.ts ADDED
@@ -0,0 +1,125 @@
1
+ /** Error codes for whole-reply documents. Warnings never block rendering. */
2
+ export const BLOCK_ERROR_CODES = {
3
+ COLUMN_NOT_FOUND: "A chart or table names a column the dataset does not have.",
4
+ COLUMN_TYPE_MISMATCH: "A column value does not match the column type.",
5
+ DATASET_NOT_FOUND: "A chart or table names a dataset the document does not define.",
6
+ DATASET_TOO_LARGE: "A dataset has more rows or columns than allowed.",
7
+ DEPTH_EXCEEDED: "A columns or card block is nested inside another columns or card block.",
8
+ DUPLICATE_ID: "An id or a column name is used more than once.",
9
+ HTML_DISABLED: "An html block is present and this host has not turned HTML on.",
10
+ HTML_TOO_LARGE: "An html block is larger than 100,000 bytes.",
11
+ IMAGE_HOST_NOT_ALLOWED:
12
+ "An image URL is not a data:image URL, a file: ref, or an https URL on an allowed host.",
13
+ INVALID_ENUM: "A value is not one of the allowed values.",
14
+ INVALID_FORMAT: "A string does not match its required format.",
15
+ INVALID_TYPE: "A value has the wrong type.",
16
+ KEY_ORDER: "Top-level keys are not in the order v, datasets, blocks.",
17
+ MISSING_REQUIRED: "A required field is missing.",
18
+ NOT_A_DOCUMENT: "The reply is not one YAML or JSON mapping with a v field.",
19
+ ROW_ARITY_MISMATCH: "A dataset row does not have one value per column.",
20
+ SELECT_TARGET_INVALID: "A select action names a block that is not a chart or table.",
21
+ TABLE_TOO_WIDE: "A table lists more columns than allowed.",
22
+ TOO_FEW: "A list has fewer items than allowed.",
23
+ TOO_LONG: "A string is longer than allowed.",
24
+ TOO_MANY: "A list has more items than allowed.",
25
+ TOO_MANY_BLOCKS: "The document has more than the maximum number of blocks.",
26
+ TOO_MANY_POINTS: "A ref dataset asks for more rendered rows than allowed.",
27
+ TOO_SHORT: "A string is empty or only whitespace.",
28
+ UNKNOWN_HOST_ACTION: "A callback names a host action that is not registered.",
29
+ UNKNOWN_KEY: "An object has a field that its schema does not define.",
30
+ UNSUPPORTED_VERSION: "The document version is not 1.",
31
+ YAML_FEATURE_DISALLOWED: "The document uses a YAML anchor, alias, or custom tag.",
32
+ } as const;
33
+
34
+ /** Chart heuristics. They ride along on a valid document and do not block rendering. */
35
+ export const BLOCK_WARNING_CODES = {
36
+ BAR_TOO_MANY_CATEGORIES: "A bar chart has more categories than fit comfortably.",
37
+ DONUT_TOO_MANY_SLICES: "A donut chart has more slices than fit comfortably.",
38
+ LINE_SINGLE_POINT: "A line chart has only one point.",
39
+ } as const;
40
+
41
+ export type BlockWarningCode = keyof typeof BLOCK_WARNING_CODES;
42
+
43
+ export type BlockErrorCode = keyof typeof BLOCK_ERROR_CODES;
44
+
45
+ export interface BlockError {
46
+ /** A key of `BLOCK_ERROR_CODES` or `BLOCK_WARNING_CODES`. */
47
+ code: BlockErrorCode | BlockWarningCode;
48
+ /** One instruction that fixes the error. */
49
+ fix: string;
50
+ /** What is wrong, in one sentence. */
51
+ message: string;
52
+ /** Where the error is, such as `blocks[0].text`. The root is an empty string. */
53
+ path: string;
54
+ }
55
+
56
+ export const formatBlockPath = (segments: readonly PropertyKey[]): string =>
57
+ segments.reduce<string>((path, segment) => {
58
+ if (typeof segment === "number") {
59
+ return `${path}[${segment}]`;
60
+ }
61
+ const key = String(segment);
62
+ if (path === "") {
63
+ return key;
64
+ }
65
+ return `${path}.${key}`;
66
+ }, "");
67
+
68
+ const pathIndex = (segment: string): number | string => {
69
+ const index = Number(segment);
70
+ if (segment !== "" && String(index) === segment) {
71
+ return index;
72
+ }
73
+ return segment;
74
+ };
75
+
76
+ /** Splits `blocks[0].text` into comparable pieces so indexes sort numerically. */
77
+ const blockPathSegments = (path: string): readonly (string | number)[] => {
78
+ const parts: (string | number)[] = [];
79
+ const pattern = /([^[\].]+)|\[(\d+)\]/g;
80
+ for (const match of path.matchAll(pattern)) {
81
+ const index = match[2];
82
+ if (index !== undefined) {
83
+ parts.push(pathIndex(index));
84
+ continue;
85
+ }
86
+ const key = match[1];
87
+ if (key !== undefined) {
88
+ parts.push(key);
89
+ }
90
+ }
91
+ return parts;
92
+ };
93
+
94
+ const compareBlockPaths = (left: string, right: string): number => {
95
+ const leftParts = blockPathSegments(left);
96
+ const rightParts = blockPathSegments(right);
97
+ const length = Math.max(leftParts.length, rightParts.length);
98
+ for (let index = 0; index < length; index += 1) {
99
+ const leftPart = leftParts[index];
100
+ const rightPart = rightParts[index];
101
+ if (leftPart === undefined) {
102
+ return -1;
103
+ }
104
+ if (rightPart === undefined) {
105
+ return 1;
106
+ }
107
+ if (leftPart === rightPart) {
108
+ continue;
109
+ }
110
+ if (typeof leftPart === "number" && typeof rightPart === "number") {
111
+ return leftPart - rightPart;
112
+ }
113
+ return String(leftPart) < String(rightPart) ? -1 : 1;
114
+ }
115
+ return 0;
116
+ };
117
+
118
+ export const sortBlockErrors = (errors: readonly BlockError[]): BlockError[] =>
119
+ [...errors].sort((left, right) => {
120
+ const byPath = compareBlockPaths(left.path, right.path);
121
+ if (byPath !== 0) {
122
+ return byPath;
123
+ }
124
+ return left.code < right.code ? -1 : 1;
125
+ });
@@ -0,0 +1,14 @@
1
+ v: 1
2
+ datasets:
3
+ signups:
4
+ columns:
5
+ - {name: month, type: string}
6
+ - {name: count, type: number}
7
+ rows:
8
+ - [Jan, 120]
9
+ blocks:
10
+ - type: chart
11
+ kind: bar
12
+ data: signups
13
+ x: day
14
+ y: count
@@ -0,0 +1,14 @@
1
+ v: 1
2
+ datasets:
3
+ signups:
4
+ columns:
5
+ - {name: month, type: string}
6
+ - {name: count, type: number}
7
+ rows:
8
+ - [Jan, 120]
9
+ blocks:
10
+ - type: chart
11
+ kind: bar
12
+ data: signups
13
+ x: month
14
+ y: month
@@ -0,0 +1,7 @@
1
+ v: 1
2
+ blocks:
3
+ - type: chart
4
+ kind: bar
5
+ data: missing
6
+ x: month
7
+ y: count
@@ -0,0 +1,20 @@
1
+ v: 1
2
+ datasets:
3
+ signups:
4
+ columns:
5
+ - {name: a, type: string}
6
+ - {name: b, type: string}
7
+ - {name: c, type: string}
8
+ - {name: d, type: string}
9
+ - {name: e, type: string}
10
+ - {name: f, type: string}
11
+ - {name: g, type: string}
12
+ - {name: h, type: string}
13
+ - {name: i, type: string}
14
+ - {name: j, type: string}
15
+ - {name: k, type: string}
16
+ - {name: l, type: string}
17
+ - {name: m, type: string}
18
+ rows: []
19
+ blocks:
20
+ - type: divider
@@ -0,0 +1,10 @@
1
+ v: 1
2
+ blocks:
3
+ - type: columns
4
+ children:
5
+ - type: card
6
+ children:
7
+ - type: text
8
+ markdown: Nested
9
+ - type: text
10
+ markdown: Beside
@@ -0,0 +1,6 @@
1
+ v: 1
2
+ blocks:
3
+ - type: divider
4
+ id: twice
5
+ - type: divider
6
+ id: twice
@@ -0,0 +1,5 @@
1
+ v: 1
2
+ blocks:
3
+ - type: heading
4
+ text: Hello
5
+ size: huge
@@ -0,0 +1,4 @@
1
+ blocks:
2
+ - type: text
3
+ markdown: Hello
4
+ v: 1
@@ -0,0 +1,3 @@
1
+ v: 1
2
+ blocks:
3
+ - type: text
@@ -0,0 +1 @@
1
+ Just a sentence, not a document.
@@ -0,0 +1,11 @@
1
+ v: 1
2
+ datasets:
3
+ signups:
4
+ columns:
5
+ - {name: month, type: string}
6
+ - {name: count, type: number}
7
+ rows:
8
+ - [Jan]
9
+ blocks:
10
+ - type: table
11
+ data: signups
@@ -0,0 +1,12 @@
1
+ v: 1
2
+ blocks:
3
+ - type: actions
4
+ id: followups
5
+ elements:
6
+ - type: button
7
+ id: weekly
8
+ text: Show weekly
9
+ action:
10
+ kind: select
11
+ target: missing_chart
12
+ data: signups
@@ -0,0 +1,9 @@
1
+ v: 1
2
+ datasets:
3
+ signups:
4
+ source: ref
5
+ id: ds_1
6
+ blocks:
7
+ - type: table
8
+ data: signups
9
+ columns: [a, b, c, d, e, f, g, h, i, j, k, l, m]
@@ -0,0 +1,8 @@
1
+ v: 1
2
+ datasets:
3
+ signups:
4
+ source: ref
5
+ id: ds_1
6
+ limit: 1001
7
+ blocks:
8
+ - type: divider
@@ -0,0 +1,5 @@
1
+ v: 1
2
+ blocks:
3
+ - type: heading
4
+ text: Hello
5
+ color: primary
@@ -0,0 +1,4 @@
1
+ v: 2
2
+ blocks:
3
+ - type: text
4
+ markdown: Hello
@@ -0,0 +1,6 @@
1
+ v: 1
2
+ blocks:
3
+ - &item
4
+ type: text
5
+ markdown: Hello
6
+ - *item
@@ -0,0 +1,5 @@
1
+ v: 1
2
+ blocks:
3
+ - type: divider
4
+ - type: text
5
+ markdown: "hello
@@ -0,0 +1,32 @@
1
+ v: 1
2
+ blocks:
3
+ - type: chart
4
+ id: signups_chart
5
+ kind: bar
6
+ points:
7
+ - label: Jan
8
+ value: 120
9
+ - type: actions
10
+ id: followups
11
+ elements:
12
+ - type: button
13
+ id: weekly
14
+ text: Show weekly
15
+ action:
16
+ kind: reply
17
+ text: Show weekly signups for this quarter
18
+ - type: button
19
+ id: open_report
20
+ text: Open report
21
+ variant: outline
22
+ action:
23
+ kind: open
24
+ route: /reports
25
+ - type: segmented
26
+ id: grain
27
+ target: signups_chart
28
+ options:
29
+ - label: Month
30
+ data: signups
31
+ - label: Week
32
+ data: signups_weekly
@@ -0,0 +1,20 @@
1
+ v: 1
2
+ datasets:
3
+ signups:
4
+ columns:
5
+ - {name: month, type: string}
6
+ - {name: count, type: number}
7
+ rows:
8
+ - [Jan, 120]
9
+ - [Feb, 145]
10
+ blocks:
11
+ - type: chart
12
+ id: signups_chart
13
+ kind: bar
14
+ data: signups
15
+ x: month
16
+ y: count
17
+ title: Signups by month
18
+ - type: table
19
+ data: signups
20
+ columns: [month, count]
@@ -0,0 +1,26 @@
1
+ v: 1
2
+ blocks:
3
+ - type: heading
4
+ text: Signups this quarter
5
+ size: lg
6
+ - type: text
7
+ markdown: Signups grew **12%** quarter over quarter.
8
+ - type: columns
9
+ children:
10
+ - type: metric
11
+ label: Total
12
+ value: "403"
13
+ delta: "+12%"
14
+ trend: up
15
+ - type: metric
16
+ label: Best month
17
+ value: Feb
18
+ - type: card
19
+ title: Notes
20
+ children:
21
+ - type: badge
22
+ text: Draft
23
+ status: info
24
+ - type: context
25
+ text: February was the strongest month.
26
+ - type: divider
@@ -0,0 +1,4 @@
1
+ v: 1
2
+ blocks:
3
+ - type: text
4
+ markdown: I could not find any signups for that range.
@@ -0,0 +1,52 @@
1
+ import {describe, expect, it} from "bun:test";
2
+
3
+ import {BLOCK_LIMITS} from "./limits";
4
+ import {blocksPromptSection} from "./prompt";
5
+ import {validateBlocks} from "./validate";
6
+
7
+ const htmlDocument = (html: string): unknown => {
8
+ const block: Record<string, unknown> = {};
9
+ block.type = "html";
10
+ block.title = "Invoice preview";
11
+ block.height = "md";
12
+ block.html = html;
13
+ const doc: Record<string, unknown> = {};
14
+ doc.v = 1;
15
+ doc.blocks = [block];
16
+ return doc;
17
+ };
18
+
19
+ describe("html blocks", () => {
20
+ it("rejects html unless the host turns it on", () => {
21
+ const result = validateBlocks(htmlDocument("<p>Invoice</p>"));
22
+
23
+ expect(result.ok).toBe(false);
24
+ if (!result.ok) {
25
+ expect(result.errors.map((error) => error.code)).toContain("HTML_DISABLED");
26
+ }
27
+ });
28
+
29
+ it("accepts a short html block when HTML is on", () => {
30
+ const result = validateBlocks(htmlDocument("<h1>Invoice #1042</h1>"), {allowHtml: true});
31
+
32
+ expect(result.ok).toBe(true);
33
+ });
34
+
35
+ it("accepts html at 100,000 bytes and rejects one more byte", () => {
36
+ const atLimit = "a".repeat(BLOCK_LIMITS.htmlMaxBytes);
37
+ const over = `${atLimit}b`;
38
+
39
+ expect(validateBlocks(htmlDocument(atLimit), {allowHtml: true}).ok).toBe(true);
40
+ const result = validateBlocks(htmlDocument(over), {allowHtml: true});
41
+ expect(result.ok).toBe(false);
42
+ if (!result.ok) {
43
+ expect(result.errors.map((error) => error.code)).toContain("HTML_TOO_LARGE");
44
+ }
45
+ });
46
+
47
+ it("mentions html in the prompt only when it is allowed", () => {
48
+ expect(blocksPromptSection()).toContain("Do not emit type html");
49
+ expect(blocksPromptSection({allowHtml: true})).toContain("card, html");
50
+ expect(blocksPromptSection({allowHtml: true})).toContain(String(BLOCK_LIMITS.htmlMaxBytes));
51
+ });
52
+ });
@@ -0,0 +1,114 @@
1
+ import {describe, expect, it} from "bun:test";
2
+
3
+ import * as terrenoBlocks from "./index";
4
+
5
+ /**
6
+ * Guards the public entrypoint of @terreno/blocks: a missing or renamed export here breaks
7
+ * @terreno/ai, @terreno/ui, and apps, and the per-module tests import the modules directly.
8
+ */
9
+ describe("@terreno/blocks public exports", () => {
10
+ const expectedExports = [
11
+ "BADGE_STATUSES",
12
+ "BLOCK_ERROR_CODES",
13
+ "BLOCK_LIMITS",
14
+ "BLOCK_WARNING_CODES",
15
+ "BUTTON_VARIANTS",
16
+ "CALLOUT_STATUSES",
17
+ "CHART_HEIGHTS",
18
+ "CHART_KINDS",
19
+ "DATASET_COLUMN_TYPES",
20
+ "DATASET_GRAINS",
21
+ "HEADING_SIZES",
22
+ "HTML_HEIGHTS",
23
+ "METRIC_TRENDS",
24
+ "blocksJsonSchema",
25
+ "blocksPromptSection",
26
+ "blocksSchema",
27
+ "parseBlocks",
28
+ "parseBlocksPartial",
29
+ "validateBlocks",
30
+ "wrapAsTextDocument",
31
+
32
+ "ASK_ERROR_CODES",
33
+
34
+ "ASK_FILE_ACCEPT",
35
+ "ASK_FILE_ACCEPT_MIME_TYPES",
36
+ "acceptedFileMimeTypes",
37
+ "checkAskFileBytes",
38
+ "fileNotOwnedError",
39
+ "isTextFileMimeType",
40
+ "parseAskDataUrl",
41
+ "sniffFileBytes",
42
+
43
+ "askResponseWithToolCallIdSchema",
44
+ "askSurfaceSchema",
45
+ "pendingAskListItemSchema",
46
+ "pendingAskListSchema",
47
+ "pendingAskSummarySchema",
48
+ "turnRequestSchema",
49
+ "turnResultSchema",
50
+
51
+ "askJsonSchemas",
52
+
53
+ "formDefaultValues",
54
+ "formTextMaxLength",
55
+
56
+ "ASK_LIMITS",
57
+
58
+ "askPromptSection",
59
+
60
+ "ASK_CANCEL_REASONS",
61
+ "ASK_KINDS",
62
+ "ASK_SURFACES",
63
+ "CHOICE_SELECT_MODES",
64
+ "COMPACT_ASK_KINDS",
65
+ "askAcceptResponseSchema",
66
+ "askAllowsDecline",
67
+ "askCancelResponseSchema",
68
+ "askDeclineResponseSchema",
69
+ "askInputSchemaFor",
70
+ "askInputSchemas",
71
+ "askKindsForSurface",
72
+ "askOutputSchemas",
73
+ "askResponseSchema",
74
+ "choiceAnswerSchema",
75
+ "choiceAskInputSchema",
76
+ "choiceAskResponseSchema",
77
+ "choiceOptionSchema",
78
+ "choiceSelectionBounds",
79
+ "compactAskInputSchemas",
80
+ "compactChoiceAskInputSchema",
81
+ "confirmAnswerSchema",
82
+ "confirmAskInputSchema",
83
+ "confirmAskResponseSchema",
84
+ "confirmButtonLabels",
85
+ "FORM_FIELD_TYPES",
86
+ "askFileRefSchema",
87
+ "filesAnswerSchema",
88
+ "filesAskInputSchema",
89
+ "filesAskResponseSchema",
90
+ "filesCountBounds",
91
+ "formAnswerSchema",
92
+ "formAskInputSchema",
93
+ "formAskResponseSchema",
94
+ "formFieldSchema",
95
+ "isCompactAskKind",
96
+ "markdownAnswerSchema",
97
+ "markdownAskInputSchema",
98
+ "markdownAskResponseSchema",
99
+ "markdownLengthBounds",
100
+
101
+ "SIMPLE_CARD_BUTTON_STYLES",
102
+ "resolveButtonAnswer",
103
+ "simpleCardButtonSchema",
104
+ "simpleCardSchema",
105
+ "toSimpleCard",
106
+
107
+ "validateAskInput",
108
+ "validateAskResponse",
109
+ ];
110
+
111
+ it("exports exactly the public runtime API", () => {
112
+ expect(Object.keys(terrenoBlocks).sort()).toEqual([...expectedExports].sort());
113
+ });
114
+ });