@terreno/blocks 57.12.0 → 57.14.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/dist/errors.d.ts +2 -0
- package/dist/errors.js +2 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +13 -1
- package/dist/interactive.d.ts +26 -0
- package/dist/interactive.js +62 -0
- package/dist/limits.d.ts +26 -0
- package/dist/limits.js +26 -0
- package/dist/lint.d.ts +18 -1
- package/dist/lint.js +186 -26
- package/dist/plainText.d.ts +17 -0
- package/dist/plainText.js +56 -0
- package/dist/prompt.d.ts +10 -1
- package/dist/prompt.js +73 -3
- package/dist/schema.d.ts +113 -2
- package/dist/schema.js +121 -5
- package/dist/validate.js +26 -2
- package/package.json +1 -1
- package/src/__snapshots__/prompt.test.ts.snap +530 -0
- package/src/errors.ts +4 -0
- package/src/fixtures/golden/sunday-roast.yaml +174 -0
- package/src/fixtures/invalid/card-eyebrow-empty.yaml +7 -0
- package/src/fixtures/invalid/card-eyebrow-too-long.yaml +7 -0
- package/src/fixtures/invalid/checklist-duplicate-item.yaml +9 -0
- package/src/fixtures/invalid/checklist-item-id-too-long.yaml +7 -0
- package/src/fixtures/invalid/checklist-reserved-id.yaml +16 -0
- package/src/fixtures/invalid/copy-missing-text-and-target.yaml +10 -0
- package/src/fixtures/invalid/copy-target.yaml +14 -0
- package/src/fixtures/invalid/gallery-caption-too-long.yaml +9 -0
- package/src/fixtures/invalid/gallery-image-host.yaml +10 -0
- package/src/fixtures/invalid/gallery-too-few.yaml +6 -0
- package/src/fixtures/invalid/list-image-host.yaml +12 -0
- package/src/fixtures/invalid/list-missing-title.yaml +6 -0
- package/src/fixtures/invalid/list-too-many.yaml +17 -0
- package/src/fixtures/invalid/stepper-decimals.yaml +14 -0
- package/src/fixtures/invalid/stepper-out-of-range.yaml +10 -0
- package/src/fixtures/invalid/stepper-reserved-id.yaml +19 -0
- package/src/fixtures/valid/card-eyebrow.yaml +8 -0
- package/src/fixtures/valid/checklist.yaml +29 -0
- package/src/fixtures/valid/copy.yaml +85 -0
- package/src/fixtures/valid/gallery.yaml +22 -0
- package/src/fixtures/valid/list.yaml +24 -0
- package/src/fixtures/valid/stepper.yaml +35 -0
- package/src/golden.test.ts +234 -0
- package/src/index.test.ts +9 -0
- package/src/index.ts +24 -0
- package/src/interactive.test.ts +141 -0
- package/src/interactive.ts +75 -0
- package/src/limits.ts +26 -0
- package/src/lint.test.ts +672 -0
- package/src/lint.ts +264 -33
- package/src/parse.test.ts +40 -0
- package/src/plainText.test.ts +158 -0
- package/src/plainText.ts +81 -0
- package/src/prompt.test.ts +325 -2
- package/src/prompt.ts +87 -2
- package/src/schema.ts +259 -6
- package/src/validate.ts +26 -2
package/dist/errors.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export declare const BLOCK_ERROR_CODES: {
|
|
3
3
|
readonly COLUMN_NOT_FOUND: "A chart or table names a column the dataset does not have.";
|
|
4
4
|
readonly COLUMN_TYPE_MISMATCH: "A column value does not match the column type.";
|
|
5
|
+
readonly COPY_TARGET_INVALID: "A copy action names a block that is not a stepper, checklist, list, table, or text block.";
|
|
5
6
|
readonly DATASET_NOT_FOUND: "A chart or table names a dataset the document does not define.";
|
|
6
7
|
readonly DATASET_TOO_LARGE: "A dataset has more rows or columns than allowed.";
|
|
7
8
|
readonly DEPTH_EXCEEDED: "A columns or card block is nested inside another columns or card block.";
|
|
@@ -15,6 +16,7 @@ export declare const BLOCK_ERROR_CODES: {
|
|
|
15
16
|
readonly KEY_ORDER: "Top-level keys are not in the order v, datasets, blocks.";
|
|
16
17
|
readonly MISSING_REQUIRED: "A required field is missing.";
|
|
17
18
|
readonly NOT_A_DOCUMENT: "The reply is not one YAML or JSON mapping with a v field.";
|
|
19
|
+
readonly OUT_OF_RANGE: "A number is outside its allowed range, such as a stepper value outside min and max.";
|
|
18
20
|
readonly ROW_ARITY_MISMATCH: "A dataset row does not have one value per column.";
|
|
19
21
|
readonly SELECT_TARGET_INVALID: "A select action names a block that is not a chart or table.";
|
|
20
22
|
readonly TABLE_TOO_WIDE: "A table lists more columns than allowed.";
|
package/dist/errors.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.sortBlockErrors = exports.formatBlockPath = exports.BLOCK_WARNING_CODES
|
|
|
5
5
|
exports.BLOCK_ERROR_CODES = {
|
|
6
6
|
COLUMN_NOT_FOUND: "A chart or table names a column the dataset does not have.",
|
|
7
7
|
COLUMN_TYPE_MISMATCH: "A column value does not match the column type.",
|
|
8
|
+
COPY_TARGET_INVALID: "A copy action names a block that is not a stepper, checklist, list, table, or text block.",
|
|
8
9
|
DATASET_NOT_FOUND: "A chart or table names a dataset the document does not define.",
|
|
9
10
|
DATASET_TOO_LARGE: "A dataset has more rows or columns than allowed.",
|
|
10
11
|
DEPTH_EXCEEDED: "A columns or card block is nested inside another columns or card block.",
|
|
@@ -18,6 +19,7 @@ exports.BLOCK_ERROR_CODES = {
|
|
|
18
19
|
KEY_ORDER: "Top-level keys are not in the order v, datasets, blocks.",
|
|
19
20
|
MISSING_REQUIRED: "A required field is missing.",
|
|
20
21
|
NOT_A_DOCUMENT: "The reply is not one YAML or JSON mapping with a v field.",
|
|
22
|
+
OUT_OF_RANGE: "A number is outside its allowed range, such as a stepper value outside min and max.",
|
|
21
23
|
ROW_ARITY_MISMATCH: "A dataset row does not have one value per column.",
|
|
22
24
|
SELECT_TARGET_INVALID: "A select action names a block that is not a chart or table.",
|
|
23
25
|
TABLE_TOO_WIDE: "A table lists more columns than allowed.",
|
package/dist/index.d.ts
CHANGED
|
@@ -17,15 +17,20 @@ export { validateAskInput } from "./asks/validateInput";
|
|
|
17
17
|
export { validateAskResponse } from "./asks/validateResponse";
|
|
18
18
|
export type { BlockError, BlockErrorCode, BlockWarningCode } from "./errors";
|
|
19
19
|
export { BLOCK_ERROR_CODES, BLOCK_WARNING_CODES } from "./errors";
|
|
20
|
+
export type { ChecklistTick } from "./interactive";
|
|
21
|
+
export { applyChecklistState, isStepperValueAllowed, scaleStepperBlock, unknownChecklistItemIds, } from "./interactive";
|
|
20
22
|
export { blocksJsonSchema } from "./jsonSchema";
|
|
21
23
|
export { BLOCK_LIMITS } from "./limits";
|
|
22
24
|
export type { KnownDataset, LintBlocksOptions } from "./lint";
|
|
25
|
+
export { checklistElementId, stepperElementIds } from "./lint";
|
|
23
26
|
export type { ParseBlocksResult } from "./parse";
|
|
24
27
|
export { parseBlocks } from "./parse";
|
|
25
28
|
export type { ParseBlocksPartialResult } from "./parsePartial";
|
|
26
29
|
export { parseBlocksPartial } from "./parsePartial";
|
|
30
|
+
export type { BlockPlainTextOptions } from "./plainText";
|
|
31
|
+
export { blockPlainText } from "./plainText";
|
|
27
32
|
export { blocksPromptSection } from "./prompt";
|
|
28
|
-
export type { ActionsBlock, BadgeBlock, Block, BlockAction, BlocksDocument, ButtonElement, CallbackAction, CalloutBlock, CardBlock, ChartBlock, ColumnsBlock, ContextBlock, Dataset, DatasetColumn, DetailsBlock, DividerBlock, HeadingBlock, HtmlBlock, ImageBlock, InlineDataset, LeafBlock, MetricBlock, OpenAction, RefDataset, ReplyAction, SegmentedElement, SelectAction, TableBlock, TextBlock, } from "./schema";
|
|
29
|
-
export { BADGE_STATUSES, BUTTON_VARIANTS, blocksSchema, CALLOUT_STATUSES, CHART_HEIGHTS, CHART_KINDS, DATASET_COLUMN_TYPES, DATASET_GRAINS, HEADING_SIZES, HTML_HEIGHTS, METRIC_TRENDS, wrapAsTextDocument, } from "./schema";
|
|
33
|
+
export type { ActionsBlock, BadgeBlock, Block, BlockAction, BlocksDocument, ButtonElement, CallbackAction, CalloutBlock, CardBlock, ChartBlock, ChecklistBlock, ChecklistCallback, ChecklistItem, ColumnsBlock, ContextBlock, CopyAction, Dataset, DatasetColumn, DetailsBlock, DividerBlock, GalleryBlock, GalleryImage, HeadingBlock, HtmlBlock, ImageBlock, InlineDataset, LeafBlock, ListBlock, ListItem, ListItemImage, MetricBlock, OpenAction, RefDataset, ReplyAction, SegmentedElement, SelectAction, StepperBlock, StepperCallback, StepperItem, TableBlock, TextBlock, } from "./schema";
|
|
34
|
+
export { BADGE_STATUSES, BUTTON_VARIANTS, blocksSchema, CALLOUT_STATUSES, CHART_HEIGHTS, CHART_KINDS, COPY_TARGET_TYPES, DATASET_COLUMN_TYPES, DATASET_GRAINS, HEADING_SIZES, HTML_HEIGHTS, METRIC_TRENDS, STEPPER_ROUNDING, wrapAsTextDocument, } from "./schema";
|
|
30
35
|
export type { ValidateBlocksResult } from "./validate";
|
|
31
36
|
export { validateBlocks } from "./validate";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.filesAskInputSchema = exports.filesAnswerSchema = exports.FORM_FIELD_TYPES = exports.confirmButtonLabels = exports.confirmAskResponseSchema = exports.confirmAskInputSchema = exports.confirmAnswerSchema = exports.compactChoiceAskInputSchema = exports.compactAskInputSchemas = exports.choiceSelectionBounds = exports.choiceOptionSchema = exports.choiceAskResponseSchema = exports.choiceAskInputSchema = exports.choiceAnswerSchema = exports.COMPACT_ASK_KINDS = exports.CHOICE_SELECT_MODES = exports.askResponseSchema = exports.askOutputSchemas = exports.askKindsForSurface = exports.askInputSchemas = exports.askInputSchemaFor = exports.askFileRefSchema = exports.askDeclineResponseSchema = exports.askCancelResponseSchema = exports.askAllowsDecline = exports.askAcceptResponseSchema = exports.ASK_SURFACES = exports.ASK_KINDS = exports.ASK_CANCEL_REASONS = exports.askPromptSection = exports.ASK_LIMITS = exports.askJsonSchemas = exports.turnResultSchema = exports.turnRequestSchema = exports.pendingAskSummarySchema = exports.pendingAskListSchema = exports.pendingAskListItemSchema = exports.askSurfaceSchema = exports.askResponseWithToolCallIdSchema = exports.formTextMaxLength = exports.formDefaultValues = exports.sniffFileBytes = exports.parseAskDataUrl = exports.isTextFileMimeType = exports.fileNotOwnedError = exports.checkAskFileBytes = exports.acceptedFileMimeTypes = exports.ASK_FILE_ACCEPT_MIME_TYPES = exports.ASK_FILE_ACCEPT = exports.ASK_ERROR_CODES = void 0;
|
|
4
|
-
exports.validateBlocks = exports.wrapAsTextDocument = exports.METRIC_TRENDS = exports.HTML_HEIGHTS = exports.HEADING_SIZES = exports.DATASET_GRAINS = exports.DATASET_COLUMN_TYPES = exports.CHART_KINDS = exports.CHART_HEIGHTS = exports.CALLOUT_STATUSES = exports.blocksSchema = exports.BUTTON_VARIANTS = exports.BADGE_STATUSES = exports.blocksPromptSection = exports.parseBlocksPartial = exports.parseBlocks = exports.BLOCK_LIMITS = exports.blocksJsonSchema = exports.BLOCK_WARNING_CODES = exports.BLOCK_ERROR_CODES = exports.validateAskResponse = exports.validateAskInput = exports.toSimpleCard = exports.simpleCardSchema = exports.simpleCardButtonSchema = exports.SIMPLE_CARD_BUTTON_STYLES = exports.resolveButtonAnswer = exports.markdownLengthBounds = exports.markdownAskResponseSchema = exports.markdownAskInputSchema = exports.markdownAnswerSchema = exports.isCompactAskKind = exports.formFieldSchema = exports.formAskResponseSchema = exports.formAskInputSchema = exports.formAnswerSchema = exports.filesCountBounds = exports.filesAskResponseSchema = void 0;
|
|
4
|
+
exports.validateBlocks = exports.wrapAsTextDocument = exports.STEPPER_ROUNDING = exports.METRIC_TRENDS = exports.HTML_HEIGHTS = exports.HEADING_SIZES = exports.DATASET_GRAINS = exports.DATASET_COLUMN_TYPES = exports.COPY_TARGET_TYPES = exports.CHART_KINDS = exports.CHART_HEIGHTS = exports.CALLOUT_STATUSES = exports.blocksSchema = exports.BUTTON_VARIANTS = exports.BADGE_STATUSES = exports.blocksPromptSection = exports.blockPlainText = exports.parseBlocksPartial = exports.parseBlocks = exports.stepperElementIds = exports.checklistElementId = exports.BLOCK_LIMITS = exports.blocksJsonSchema = exports.unknownChecklistItemIds = exports.scaleStepperBlock = exports.isStepperValueAllowed = exports.applyChecklistState = exports.BLOCK_WARNING_CODES = exports.BLOCK_ERROR_CODES = exports.validateAskResponse = exports.validateAskInput = exports.toSimpleCard = exports.simpleCardSchema = exports.simpleCardButtonSchema = exports.SIMPLE_CARD_BUTTON_STYLES = exports.resolveButtonAnswer = exports.markdownLengthBounds = exports.markdownAskResponseSchema = exports.markdownAskInputSchema = exports.markdownAnswerSchema = exports.isCompactAskKind = exports.formFieldSchema = exports.formAskResponseSchema = exports.formAskInputSchema = exports.formAnswerSchema = exports.filesCountBounds = exports.filesAskResponseSchema = void 0;
|
|
5
5
|
var errors_1 = require("./asks/errors");
|
|
6
6
|
Object.defineProperty(exports, "ASK_ERROR_CODES", { enumerable: true, get: function () { return errors_1.ASK_ERROR_CODES; } });
|
|
7
7
|
var files_1 = require("./asks/files");
|
|
@@ -84,14 +84,24 @@ Object.defineProperty(exports, "validateAskResponse", { enumerable: true, get: f
|
|
|
84
84
|
var errors_2 = require("./errors");
|
|
85
85
|
Object.defineProperty(exports, "BLOCK_ERROR_CODES", { enumerable: true, get: function () { return errors_2.BLOCK_ERROR_CODES; } });
|
|
86
86
|
Object.defineProperty(exports, "BLOCK_WARNING_CODES", { enumerable: true, get: function () { return errors_2.BLOCK_WARNING_CODES; } });
|
|
87
|
+
var interactive_1 = require("./interactive");
|
|
88
|
+
Object.defineProperty(exports, "applyChecklistState", { enumerable: true, get: function () { return interactive_1.applyChecklistState; } });
|
|
89
|
+
Object.defineProperty(exports, "isStepperValueAllowed", { enumerable: true, get: function () { return interactive_1.isStepperValueAllowed; } });
|
|
90
|
+
Object.defineProperty(exports, "scaleStepperBlock", { enumerable: true, get: function () { return interactive_1.scaleStepperBlock; } });
|
|
91
|
+
Object.defineProperty(exports, "unknownChecklistItemIds", { enumerable: true, get: function () { return interactive_1.unknownChecklistItemIds; } });
|
|
87
92
|
var jsonSchema_2 = require("./jsonSchema");
|
|
88
93
|
Object.defineProperty(exports, "blocksJsonSchema", { enumerable: true, get: function () { return jsonSchema_2.blocksJsonSchema; } });
|
|
89
94
|
var limits_2 = require("./limits");
|
|
90
95
|
Object.defineProperty(exports, "BLOCK_LIMITS", { enumerable: true, get: function () { return limits_2.BLOCK_LIMITS; } });
|
|
96
|
+
var lint_1 = require("./lint");
|
|
97
|
+
Object.defineProperty(exports, "checklistElementId", { enumerable: true, get: function () { return lint_1.checklistElementId; } });
|
|
98
|
+
Object.defineProperty(exports, "stepperElementIds", { enumerable: true, get: function () { return lint_1.stepperElementIds; } });
|
|
91
99
|
var parse_1 = require("./parse");
|
|
92
100
|
Object.defineProperty(exports, "parseBlocks", { enumerable: true, get: function () { return parse_1.parseBlocks; } });
|
|
93
101
|
var parsePartial_1 = require("./parsePartial");
|
|
94
102
|
Object.defineProperty(exports, "parseBlocksPartial", { enumerable: true, get: function () { return parsePartial_1.parseBlocksPartial; } });
|
|
103
|
+
var plainText_1 = require("./plainText");
|
|
104
|
+
Object.defineProperty(exports, "blockPlainText", { enumerable: true, get: function () { return plainText_1.blockPlainText; } });
|
|
95
105
|
var prompt_2 = require("./prompt");
|
|
96
106
|
Object.defineProperty(exports, "blocksPromptSection", { enumerable: true, get: function () { return prompt_2.blocksPromptSection; } });
|
|
97
107
|
var schema_2 = require("./schema");
|
|
@@ -101,11 +111,13 @@ Object.defineProperty(exports, "blocksSchema", { enumerable: true, get: function
|
|
|
101
111
|
Object.defineProperty(exports, "CALLOUT_STATUSES", { enumerable: true, get: function () { return schema_2.CALLOUT_STATUSES; } });
|
|
102
112
|
Object.defineProperty(exports, "CHART_HEIGHTS", { enumerable: true, get: function () { return schema_2.CHART_HEIGHTS; } });
|
|
103
113
|
Object.defineProperty(exports, "CHART_KINDS", { enumerable: true, get: function () { return schema_2.CHART_KINDS; } });
|
|
114
|
+
Object.defineProperty(exports, "COPY_TARGET_TYPES", { enumerable: true, get: function () { return schema_2.COPY_TARGET_TYPES; } });
|
|
104
115
|
Object.defineProperty(exports, "DATASET_COLUMN_TYPES", { enumerable: true, get: function () { return schema_2.DATASET_COLUMN_TYPES; } });
|
|
105
116
|
Object.defineProperty(exports, "DATASET_GRAINS", { enumerable: true, get: function () { return schema_2.DATASET_GRAINS; } });
|
|
106
117
|
Object.defineProperty(exports, "HEADING_SIZES", { enumerable: true, get: function () { return schema_2.HEADING_SIZES; } });
|
|
107
118
|
Object.defineProperty(exports, "HTML_HEIGHTS", { enumerable: true, get: function () { return schema_2.HTML_HEIGHTS; } });
|
|
108
119
|
Object.defineProperty(exports, "METRIC_TRENDS", { enumerable: true, get: function () { return schema_2.METRIC_TRENDS; } });
|
|
120
|
+
Object.defineProperty(exports, "STEPPER_ROUNDING", { enumerable: true, get: function () { return schema_2.STEPPER_ROUNDING; } });
|
|
109
121
|
Object.defineProperty(exports, "wrapAsTextDocument", { enumerable: true, get: function () { return schema_2.wrapAsTextDocument; } });
|
|
110
122
|
var validate_1 = require("./validate");
|
|
111
123
|
Object.defineProperty(exports, "validateBlocks", { enumerable: true, get: function () { return validate_1.validateBlocks; } });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChecklistBlock, StepperBlock } from "./schema";
|
|
2
|
+
/** A checklist tick as the renderer sends it: the ticked item and every item's state. */
|
|
3
|
+
export interface ChecklistTick {
|
|
4
|
+
checked: boolean;
|
|
5
|
+
itemId: string;
|
|
6
|
+
state: Record<string, boolean>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* True when `value` is finite, within `min`..`max`, and a whole number of `step`s from the
|
|
10
|
+
* stepper's own `value`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const isStepperValueAllowed: (stepper: StepperBlock, value: number) => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Returns `original` at `value` with every item scaled linearly from `original`, rounded by its
|
|
15
|
+
* `decimals` and `round`. Always scale from the block the agent wrote, not the last result, so
|
|
16
|
+
* rounding never drifts tap after tap. An original `value` of 0 keeps the amounts as written.
|
|
17
|
+
* Check the value with `isStepperValueAllowed` first.
|
|
18
|
+
*/
|
|
19
|
+
export declare const scaleStepperBlock: (original: StepperBlock, value: number) => StepperBlock;
|
|
20
|
+
/** The ids in a tick (its `itemId` and `state` keys) that `checklist` has no item for, once each. */
|
|
21
|
+
export declare const unknownChecklistItemIds: (checklist: ChecklistBlock, tick: ChecklistTick) => string[];
|
|
22
|
+
/**
|
|
23
|
+
* Returns `checklist` with every item's `checked` taken from `tick.state`. An item missing from
|
|
24
|
+
* `state` is unchecked, and the ticked item always takes `tick.checked`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const applyChecklistState: (checklist: ChecklistBlock, tick: ChecklistTick) => ChecklistBlock;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyChecklistState = exports.unknownChecklistItemIds = exports.scaleStepperBlock = exports.isStepperValueAllowed = void 0;
|
|
4
|
+
/** Tolerance for float noise when checking the step grid and rounding up. */
|
|
5
|
+
const EPSILON = 1e-9;
|
|
6
|
+
const roundAmount = (amount, item) => {
|
|
7
|
+
const factor = 10 ** (item.decimals ?? 0);
|
|
8
|
+
const scaled = amount * factor;
|
|
9
|
+
const rounded = item.round === "up" ? Math.ceil(scaled - EPSILON) : Math.round(scaled);
|
|
10
|
+
return Number((rounded / factor).toFixed(item.decimals ?? 0));
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* True when `value` is finite, within `min`..`max`, and a whole number of `step`s from the
|
|
14
|
+
* stepper's own `value`.
|
|
15
|
+
*/
|
|
16
|
+
const isStepperValueAllowed = (stepper, value) => {
|
|
17
|
+
if (!Number.isFinite(value) || value < stepper.min || value > stepper.max) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const steps = (value - stepper.value) / (stepper.step ?? 1);
|
|
21
|
+
return Math.abs(steps - Math.round(steps)) < EPSILON;
|
|
22
|
+
};
|
|
23
|
+
exports.isStepperValueAllowed = isStepperValueAllowed;
|
|
24
|
+
/**
|
|
25
|
+
* Returns `original` at `value` with every item scaled linearly from `original`, rounded by its
|
|
26
|
+
* `decimals` and `round`. Always scale from the block the agent wrote, not the last result, so
|
|
27
|
+
* rounding never drifts tap after tap. An original `value` of 0 keeps the amounts as written.
|
|
28
|
+
* Check the value with `isStepperValueAllowed` first.
|
|
29
|
+
*/
|
|
30
|
+
const scaleStepperBlock = (original, value) => {
|
|
31
|
+
if (original.items === undefined) {
|
|
32
|
+
return { ...original, value };
|
|
33
|
+
}
|
|
34
|
+
const ratio = original.value === 0 ? 1 : value / original.value;
|
|
35
|
+
return {
|
|
36
|
+
...original,
|
|
37
|
+
items: original.items.map((item) => ({
|
|
38
|
+
...item,
|
|
39
|
+
amount: roundAmount(item.amount * ratio, item),
|
|
40
|
+
})),
|
|
41
|
+
value,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
exports.scaleStepperBlock = scaleStepperBlock;
|
|
45
|
+
/** The ids in a tick (its `itemId` and `state` keys) that `checklist` has no item for, once each. */
|
|
46
|
+
const unknownChecklistItemIds = (checklist, tick) => {
|
|
47
|
+
const itemIds = new Set(checklist.items.map((item) => item.id));
|
|
48
|
+
return [...new Set([tick.itemId, ...Object.keys(tick.state)])].filter((id) => !itemIds.has(id));
|
|
49
|
+
};
|
|
50
|
+
exports.unknownChecklistItemIds = unknownChecklistItemIds;
|
|
51
|
+
/**
|
|
52
|
+
* Returns `checklist` with every item's `checked` taken from `tick.state`. An item missing from
|
|
53
|
+
* `state` is unchecked, and the ticked item always takes `tick.checked`.
|
|
54
|
+
*/
|
|
55
|
+
const applyChecklistState = (checklist, tick) => ({
|
|
56
|
+
...checklist,
|
|
57
|
+
items: checklist.items.map((item) => ({
|
|
58
|
+
...item,
|
|
59
|
+
checked: item.id === tick.itemId ? tick.checked : tick.state[item.id] === true,
|
|
60
|
+
})),
|
|
61
|
+
});
|
|
62
|
+
exports.applyChecklistState = applyChecklistState;
|
package/dist/limits.d.ts
CHANGED
|
@@ -6,16 +6,35 @@ export declare const BLOCK_LIMITS: {
|
|
|
6
6
|
readonly badgeTextMaxLength: 80;
|
|
7
7
|
readonly barCategoryWarning: 60;
|
|
8
8
|
readonly blockTextMaxLength: 4000;
|
|
9
|
+
readonly cardEyebrowMaxLength: 60;
|
|
9
10
|
readonly cardTitleMaxLength: 120;
|
|
11
|
+
readonly checklistIdMaxLength: 31;
|
|
12
|
+
readonly checklistItemDetailMaxLength: 280;
|
|
13
|
+
readonly checklistItemIdMaxLength: 32;
|
|
14
|
+
readonly checklistItemMetaMaxLength: 40;
|
|
15
|
+
readonly checklistItemsMax: 30;
|
|
16
|
+
readonly checklistItemsMin: 1;
|
|
17
|
+
readonly checklistItemTextMaxLength: 120;
|
|
18
|
+
readonly checklistTitleMaxLength: 120;
|
|
10
19
|
readonly columnsMax: 4;
|
|
11
20
|
readonly columnsMin: 2;
|
|
12
21
|
readonly contextTextMaxLength: 280;
|
|
22
|
+
readonly copyTextMaxLength: 4000;
|
|
13
23
|
readonly datasetColumnMax: 12;
|
|
14
24
|
readonly datasetRowMax: 500;
|
|
15
25
|
readonly documentTextMaxLength: 20000;
|
|
16
26
|
readonly donutSliceWarning: 8;
|
|
27
|
+
readonly galleryAltMaxLength: 200;
|
|
28
|
+
readonly galleryCaptionMaxLength: 120;
|
|
29
|
+
readonly galleryImagesMax: 6;
|
|
30
|
+
readonly galleryImagesMin: 2;
|
|
17
31
|
readonly headingTextMaxLength: 200;
|
|
18
32
|
readonly htmlMaxBytes: 100000;
|
|
33
|
+
readonly listItemMetaMaxLength: 40;
|
|
34
|
+
readonly listItemsMax: 12;
|
|
35
|
+
readonly listItemsMin: 1;
|
|
36
|
+
readonly listItemTextMaxLength: 500;
|
|
37
|
+
readonly listItemTitleMaxLength: 120;
|
|
19
38
|
readonly maxBlocks: 50;
|
|
20
39
|
readonly maxDatasets: 8;
|
|
21
40
|
readonly maxDepth: 2;
|
|
@@ -24,4 +43,11 @@ export declare const BLOCK_LIMITS: {
|
|
|
24
43
|
readonly metricLabelMaxLength: 80;
|
|
25
44
|
readonly metricValueMaxLength: 80;
|
|
26
45
|
readonly refLimitMax: 1000;
|
|
46
|
+
readonly stepperDecimalsMax: 3;
|
|
47
|
+
readonly stepperIdMaxLength: 54;
|
|
48
|
+
readonly stepperItemsMax: 12;
|
|
49
|
+
readonly stepperItemUnitMaxLength: 20;
|
|
50
|
+
readonly stepperLabelMaxLength: 80;
|
|
51
|
+
readonly stepperNoteMaxLength: 280;
|
|
52
|
+
readonly stepperUnitMaxLength: 40;
|
|
27
53
|
};
|
package/dist/limits.js
CHANGED
|
@@ -9,16 +9,35 @@ exports.BLOCK_LIMITS = {
|
|
|
9
9
|
badgeTextMaxLength: 80,
|
|
10
10
|
barCategoryWarning: 60,
|
|
11
11
|
blockTextMaxLength: 4_000,
|
|
12
|
+
cardEyebrowMaxLength: 60,
|
|
12
13
|
cardTitleMaxLength: 120,
|
|
14
|
+
checklistIdMaxLength: 31,
|
|
15
|
+
checklistItemDetailMaxLength: 280,
|
|
16
|
+
checklistItemIdMaxLength: 32,
|
|
17
|
+
checklistItemMetaMaxLength: 40,
|
|
18
|
+
checklistItemsMax: 30,
|
|
19
|
+
checklistItemsMin: 1,
|
|
20
|
+
checklistItemTextMaxLength: 120,
|
|
21
|
+
checklistTitleMaxLength: 120,
|
|
13
22
|
columnsMax: 4,
|
|
14
23
|
columnsMin: 2,
|
|
15
24
|
contextTextMaxLength: 280,
|
|
25
|
+
copyTextMaxLength: 4_000,
|
|
16
26
|
datasetColumnMax: 12,
|
|
17
27
|
datasetRowMax: 500,
|
|
18
28
|
documentTextMaxLength: 20_000,
|
|
19
29
|
donutSliceWarning: 8,
|
|
30
|
+
galleryAltMaxLength: 200,
|
|
31
|
+
galleryCaptionMaxLength: 120,
|
|
32
|
+
galleryImagesMax: 6,
|
|
33
|
+
galleryImagesMin: 2,
|
|
20
34
|
headingTextMaxLength: 200,
|
|
21
35
|
htmlMaxBytes: 100_000,
|
|
36
|
+
listItemMetaMaxLength: 40,
|
|
37
|
+
listItemsMax: 12,
|
|
38
|
+
listItemsMin: 1,
|
|
39
|
+
listItemTextMaxLength: 500,
|
|
40
|
+
listItemTitleMaxLength: 120,
|
|
22
41
|
maxBlocks: 50,
|
|
23
42
|
maxDatasets: 8,
|
|
24
43
|
maxDepth: 2,
|
|
@@ -27,4 +46,11 @@ exports.BLOCK_LIMITS = {
|
|
|
27
46
|
metricLabelMaxLength: 80,
|
|
28
47
|
metricValueMaxLength: 80,
|
|
29
48
|
refLimitMax: 1_000,
|
|
49
|
+
stepperDecimalsMax: 3,
|
|
50
|
+
stepperIdMaxLength: 54,
|
|
51
|
+
stepperItemsMax: 12,
|
|
52
|
+
stepperItemUnitMaxLength: 20,
|
|
53
|
+
stepperLabelMaxLength: 80,
|
|
54
|
+
stepperNoteMaxLength: 280,
|
|
55
|
+
stepperUnitMaxLength: 40,
|
|
30
56
|
};
|
package/dist/lint.d.ts
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
import { type BlockError } from "./errors";
|
|
2
|
-
import type
|
|
2
|
+
import { type BlocksDocument, type DatasetColumn } from "./schema";
|
|
3
3
|
export interface KnownDataset {
|
|
4
4
|
columns: DatasetColumn[];
|
|
5
5
|
}
|
|
6
6
|
export interface LintBlocksOptions {
|
|
7
7
|
/** When false or omitted, an `html` block fails with `HTML_DISABLED`. */
|
|
8
8
|
allowHtml?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Host actions that handle a checklist. When set, a checklist `callback.name` outside it fails
|
|
11
|
+
* with `UNKNOWN_HOST_ACTION`.
|
|
12
|
+
*/
|
|
13
|
+
checklistActions?: readonly string[];
|
|
9
14
|
hostActions?: readonly string[];
|
|
10
15
|
/** Hostnames allowed on `https` image `src` values. Empty means no https images. */
|
|
11
16
|
imageHosts?: readonly string[];
|
|
12
17
|
knownDatasets?: Record<string, KnownDataset>;
|
|
18
|
+
/**
|
|
19
|
+
* Host actions that handle a stepper. When set, a stepper `callback.name` outside it fails with
|
|
20
|
+
* `UNKNOWN_HOST_ACTION`, even when the name is in `hostActions`. Omitted, `hostActions` applies.
|
|
21
|
+
*/
|
|
22
|
+
stepperActions?: readonly string[];
|
|
13
23
|
}
|
|
24
|
+
/** The element ids a stepper's − and + buttons use in callback events. */
|
|
25
|
+
export declare const stepperElementIds: (stepperId: string) => {
|
|
26
|
+
decrease: string;
|
|
27
|
+
increase: string;
|
|
28
|
+
};
|
|
29
|
+
/** The element id a checklist item's tick uses in callback events. */
|
|
30
|
+
export declare const checklistElementId: (checklistId: string, itemId: string) => string;
|
|
14
31
|
/**
|
|
15
32
|
* Semantic checks for datasets, charts, and tables.
|
|
16
33
|
* Structural schema errors are handled before this runs.
|
package/dist/lint.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.lintDocument = void 0;
|
|
3
|
+
exports.lintDocument = exports.checklistElementId = exports.stepperElementIds = void 0;
|
|
4
4
|
const errors_1 = require("./errors");
|
|
5
5
|
const limits_1 = require("./limits");
|
|
6
|
+
const schema_1 = require("./schema");
|
|
6
7
|
const issue = ({ code, fix, message, path }) => ({ code, fix, message, path });
|
|
7
8
|
const imageSourceIssue = (src, hosts, path) => {
|
|
8
9
|
if (src.startsWith("file:") && src.slice("file:".length).trim().length > 0) {
|
|
@@ -32,6 +33,85 @@ const imageSourceIssue = (src, hosts, path) => {
|
|
|
32
33
|
path: `${path}.src`,
|
|
33
34
|
});
|
|
34
35
|
};
|
|
36
|
+
/** The element ids a stepper's − and + buttons use in callback events. */
|
|
37
|
+
const stepperElementIds = (stepperId) => ({
|
|
38
|
+
decrease: `${stepperId}_decrease`,
|
|
39
|
+
increase: `${stepperId}_increase`,
|
|
40
|
+
});
|
|
41
|
+
exports.stepperElementIds = stepperElementIds;
|
|
42
|
+
/** The element id a checklist item's tick uses in callback events. */
|
|
43
|
+
const checklistElementId = (checklistId, itemId) => `${checklistId}_${itemId}`;
|
|
44
|
+
exports.checklistElementId = checklistElementId;
|
|
45
|
+
const unknownHostActionIssue = (name, hostActions, path) => {
|
|
46
|
+
if (hostActions === undefined || hostActions.includes(name)) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return issue({
|
|
50
|
+
code: "UNKNOWN_HOST_ACTION",
|
|
51
|
+
fix: `Use one of: ${hostActions.join(", ") || "(none registered)"}.`,
|
|
52
|
+
message: errors_1.BLOCK_ERROR_CODES.UNKNOWN_HOST_ACTION,
|
|
53
|
+
path,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const stepperIssues = (block, path, options) => {
|
|
57
|
+
const found = [];
|
|
58
|
+
if (block.min >= block.max) {
|
|
59
|
+
found.push(issue({
|
|
60
|
+
code: "OUT_OF_RANGE",
|
|
61
|
+
fix: "Set max above min.",
|
|
62
|
+
message: errors_1.BLOCK_ERROR_CODES.OUT_OF_RANGE,
|
|
63
|
+
path: `${path}.max`,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
else if (block.value < block.min || block.value > block.max) {
|
|
67
|
+
found.push(issue({
|
|
68
|
+
code: "OUT_OF_RANGE",
|
|
69
|
+
fix: `Set value between ${block.min} and ${block.max}.`,
|
|
70
|
+
message: errors_1.BLOCK_ERROR_CODES.OUT_OF_RANGE,
|
|
71
|
+
path: `${path}.value`,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
if (block.step !== undefined && block.step <= 0) {
|
|
75
|
+
found.push(issue({
|
|
76
|
+
code: "OUT_OF_RANGE",
|
|
77
|
+
fix: "Set step above 0, or leave it out for 1.",
|
|
78
|
+
message: errors_1.BLOCK_ERROR_CODES.OUT_OF_RANGE,
|
|
79
|
+
path: `${path}.step`,
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
const unknown = unknownHostActionIssue(block.callback.name, options?.stepperActions ?? options?.hostActions, `${path}.callback.name`);
|
|
83
|
+
if (unknown) {
|
|
84
|
+
found.push(unknown);
|
|
85
|
+
}
|
|
86
|
+
return found;
|
|
87
|
+
};
|
|
88
|
+
const checklistIssues = (block, path, options) => {
|
|
89
|
+
const found = [];
|
|
90
|
+
const seenItemIds = new Set();
|
|
91
|
+
block.items.forEach((item, index) => {
|
|
92
|
+
if (seenItemIds.has(item.id)) {
|
|
93
|
+
found.push(issue({
|
|
94
|
+
code: "DUPLICATE_ID",
|
|
95
|
+
fix: `Give ${path}.items[${index}] an id no other item in this checklist uses.`,
|
|
96
|
+
message: errors_1.BLOCK_ERROR_CODES.DUPLICATE_ID,
|
|
97
|
+
path: `${path}.items[${index}].id`,
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
seenItemIds.add(item.id);
|
|
101
|
+
});
|
|
102
|
+
if (block.callback === undefined) {
|
|
103
|
+
return found;
|
|
104
|
+
}
|
|
105
|
+
const unknown = unknownHostActionIssue(block.callback.name, options?.checklistActions ?? options?.hostActions, `${path}.callback.name`);
|
|
106
|
+
if (unknown) {
|
|
107
|
+
found.push(unknown);
|
|
108
|
+
}
|
|
109
|
+
return found;
|
|
110
|
+
};
|
|
111
|
+
const STEPPER_RESERVED_FIX = "A stepper uses <id>_decrease and <id>_increase for its buttons.";
|
|
112
|
+
const CHECKLIST_RESERVED_FIX = "A checklist uses <id>_<item id> for each item's tick.";
|
|
113
|
+
const copyTargetTypes = new Set(schema_1.COPY_TARGET_TYPES);
|
|
114
|
+
const COPY_TARGET_FIX = `Set target to the id of a ${schema_1.COPY_TARGET_TYPES.slice(0, -1).join(", ")}, or ${schema_1.COPY_TARGET_TYPES.at(-1)} block in this document.`;
|
|
35
115
|
const isInline = (dataset) => dataset.source !== "ref";
|
|
36
116
|
const columnsFor = (dataset, options) => {
|
|
37
117
|
if (isInline(dataset)) {
|
|
@@ -154,12 +234,61 @@ const lintDocument = (doc, options) => {
|
|
|
154
234
|
}
|
|
155
235
|
const seenIds = new Set();
|
|
156
236
|
const selectableIds = new Set();
|
|
237
|
+
// Block ids a copy action may target, collected first so a target may sit before or after it.
|
|
238
|
+
const copyTargetIds = new Set();
|
|
239
|
+
// Element ids a renderer derives from a block id, mapped to the fix that explains the clash.
|
|
240
|
+
const reservedIds = new Map();
|
|
241
|
+
// Two blocks deriving the same element id would send ambiguous callback events. A clash within
|
|
242
|
+
// one block id is a repeated item or block id, which DUPLICATE_ID already reports elsewhere.
|
|
243
|
+
const reserve = ({ elementId, fix, ownerId, path, }) => {
|
|
244
|
+
const taken = reservedIds.get(elementId);
|
|
245
|
+
if (taken !== undefined && taken.ownerId !== ownerId) {
|
|
246
|
+
errors.push(issue({
|
|
247
|
+
code: "DUPLICATE_ID",
|
|
248
|
+
fix: `Rename ${path}. Its element id ${elementId} is already used. ${taken.fix}`,
|
|
249
|
+
message: errors_1.BLOCK_ERROR_CODES.DUPLICATE_ID,
|
|
250
|
+
path,
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
253
|
+
reservedIds.set(elementId, { fix, ownerId });
|
|
254
|
+
};
|
|
157
255
|
const walked = walk(doc.blocks, "blocks");
|
|
158
|
-
for (const { block } of walked) {
|
|
256
|
+
for (const { block, path } of walked) {
|
|
159
257
|
if ((block.type === "chart" || block.type === "table") && block.id !== undefined) {
|
|
160
258
|
selectableIds.add(block.id);
|
|
161
259
|
}
|
|
260
|
+
if (copyTargetTypes.has(block.type) && block.id !== undefined) {
|
|
261
|
+
copyTargetIds.add(block.id);
|
|
262
|
+
}
|
|
263
|
+
if (block.type === "stepper") {
|
|
264
|
+
const { decrease, increase } = (0, exports.stepperElementIds)(block.id);
|
|
265
|
+
for (const elementId of [decrease, increase]) {
|
|
266
|
+
reserve({ elementId, fix: STEPPER_RESERVED_FIX, ownerId: block.id, path: `${path}.id` });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (block.type === "checklist") {
|
|
270
|
+
block.items.forEach((item, index) => {
|
|
271
|
+
reserve({
|
|
272
|
+
elementId: (0, exports.checklistElementId)(block.id, item.id),
|
|
273
|
+
fix: CHECKLIST_RESERVED_FIX,
|
|
274
|
+
ownerId: block.id,
|
|
275
|
+
path: `${path}.items[${index}].id`,
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
162
279
|
}
|
|
280
|
+
const idIssue = (id, path) => {
|
|
281
|
+
const reservedFix = reservedIds.get(id)?.fix;
|
|
282
|
+
if (!seenIds.has(id) && reservedFix === undefined) {
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
return issue({
|
|
286
|
+
code: "DUPLICATE_ID",
|
|
287
|
+
fix: reservedFix === undefined ? `Give ${path} a unique id.` : `Rename ${path}. ${reservedFix}`,
|
|
288
|
+
message: errors_1.BLOCK_ERROR_CODES.DUPLICATE_ID,
|
|
289
|
+
path: `${path}.id`,
|
|
290
|
+
});
|
|
291
|
+
};
|
|
163
292
|
for (const { block, path } of walked) {
|
|
164
293
|
if (block.type === "html") {
|
|
165
294
|
if (options?.allowHtml !== true) {
|
|
@@ -186,17 +315,38 @@ const lintDocument = (doc, options) => {
|
|
|
186
315
|
errors.push(imageIssue);
|
|
187
316
|
}
|
|
188
317
|
}
|
|
318
|
+
if (block.type === "gallery") {
|
|
319
|
+
block.images.forEach((image, index) => {
|
|
320
|
+
const tileIssue = imageSourceIssue(image.src, options?.imageHosts, `${path}.images[${index}]`);
|
|
321
|
+
if (tileIssue) {
|
|
322
|
+
errors.push(tileIssue);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
if (block.type === "list") {
|
|
327
|
+
block.items.forEach((item, index) => {
|
|
328
|
+
if (item.image === undefined) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const thumbnailIssue = imageSourceIssue(item.image.src, options?.imageHosts, `${path}.items[${index}].image`);
|
|
332
|
+
if (thumbnailIssue) {
|
|
333
|
+
errors.push(thumbnailIssue);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
189
337
|
if (block.id !== undefined) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
fix: `Give ${path} a unique id.`,
|
|
194
|
-
message: errors_1.BLOCK_ERROR_CODES.DUPLICATE_ID,
|
|
195
|
-
path: `${path}.id`,
|
|
196
|
-
}));
|
|
338
|
+
const duplicate = idIssue(block.id, path);
|
|
339
|
+
if (duplicate) {
|
|
340
|
+
errors.push(duplicate);
|
|
197
341
|
}
|
|
198
342
|
seenIds.add(block.id);
|
|
199
343
|
}
|
|
344
|
+
if (block.type === "stepper") {
|
|
345
|
+
errors.push(...stepperIssues(block, path, options));
|
|
346
|
+
}
|
|
347
|
+
if (block.type === "checklist") {
|
|
348
|
+
errors.push(...checklistIssues(block, path, options));
|
|
349
|
+
}
|
|
200
350
|
if (block.type === "chart") {
|
|
201
351
|
const hasPoints = block.points !== undefined;
|
|
202
352
|
const hasData = block.data !== undefined || block.x !== undefined || block.y !== undefined;
|
|
@@ -295,13 +445,9 @@ const lintDocument = (doc, options) => {
|
|
|
295
445
|
if (block.type === "actions") {
|
|
296
446
|
block.elements.forEach((element, index) => {
|
|
297
447
|
const elementPath = `${path}.elements[${index}]`;
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
fix: `Give ${elementPath} a unique id.`,
|
|
302
|
-
message: errors_1.BLOCK_ERROR_CODES.DUPLICATE_ID,
|
|
303
|
-
path: `${elementPath}.id`,
|
|
304
|
-
}));
|
|
448
|
+
const duplicate = idIssue(element.id, elementPath);
|
|
449
|
+
if (duplicate) {
|
|
450
|
+
errors.push(duplicate);
|
|
305
451
|
}
|
|
306
452
|
seenIds.add(element.id);
|
|
307
453
|
if (element.type === "segmented" && !selectableIds.has(element.target)) {
|
|
@@ -322,16 +468,11 @@ const lintDocument = (doc, options) => {
|
|
|
322
468
|
path: `${elementPath}.action.target`,
|
|
323
469
|
}));
|
|
324
470
|
}
|
|
325
|
-
if (element.type === "button" &&
|
|
326
|
-
element.action.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
code: "UNKNOWN_HOST_ACTION",
|
|
331
|
-
fix: `Use one of: ${options.hostActions.join(", ") || "(none registered)"}.`,
|
|
332
|
-
message: errors_1.BLOCK_ERROR_CODES.UNKNOWN_HOST_ACTION,
|
|
333
|
-
path: `${elementPath}.action.name`,
|
|
334
|
-
}));
|
|
471
|
+
if (element.type === "button" && element.action.kind === "callback") {
|
|
472
|
+
const unknown = unknownHostActionIssue(element.action.name, options?.hostActions, `${elementPath}.action.name`);
|
|
473
|
+
if (unknown) {
|
|
474
|
+
errors.push(unknown);
|
|
475
|
+
}
|
|
335
476
|
}
|
|
336
477
|
if (element.type === "button" && element.action.kind === "open") {
|
|
337
478
|
const hasRoute = element.action.route !== undefined;
|
|
@@ -345,6 +486,25 @@ const lintDocument = (doc, options) => {
|
|
|
345
486
|
}));
|
|
346
487
|
}
|
|
347
488
|
}
|
|
489
|
+
if (element.type === "button" && element.action.kind === "copy") {
|
|
490
|
+
const { target, text } = element.action;
|
|
491
|
+
if ((target === undefined) === (text === undefined)) {
|
|
492
|
+
errors.push(issue({
|
|
493
|
+
code: "MISSING_REQUIRED",
|
|
494
|
+
fix: "Set either text or target on a copy action.",
|
|
495
|
+
message: errors_1.BLOCK_ERROR_CODES.MISSING_REQUIRED,
|
|
496
|
+
path: `${elementPath}.action`,
|
|
497
|
+
}));
|
|
498
|
+
}
|
|
499
|
+
else if (target !== undefined && !copyTargetIds.has(target)) {
|
|
500
|
+
errors.push(issue({
|
|
501
|
+
code: "COPY_TARGET_INVALID",
|
|
502
|
+
fix: COPY_TARGET_FIX,
|
|
503
|
+
message: errors_1.BLOCK_ERROR_CODES.COPY_TARGET_INVALID,
|
|
504
|
+
path: `${elementPath}.action.target`,
|
|
505
|
+
}));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
348
508
|
});
|
|
349
509
|
}
|
|
350
510
|
if (block.type === "table") {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Block, Dataset } from "./schema";
|
|
2
|
+
export interface BlockPlainTextOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Current ticks by checklist item id. An entry overrides that item's `checked`; ids the
|
|
5
|
+
* checklist does not have are ignored.
|
|
6
|
+
*/
|
|
7
|
+
checked?: Record<string, boolean>;
|
|
8
|
+
/** The document's datasets. A table copies only an inline dataset, so resolve refs first. */
|
|
9
|
+
datasets?: Record<string, Dataset>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The text a copy action writes to the clipboard for its target block. Pass the block as it is
|
|
13
|
+
* shown now (a host override applied) and the current checklist ticks in `checked`. Blocks a
|
|
14
|
+
* copy action cannot target return an empty string, as does a table whose dataset is missing or
|
|
15
|
+
* an unresolved ref.
|
|
16
|
+
*/
|
|
17
|
+
export declare const blockPlainText: (block: Block, options?: BlockPlainTextOptions) => string;
|