@platecms/delta-cast 0.8.0 → 0.9.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@platecms/delta-cast",
3
3
  "description": "Package containing the definition of CAST",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -22,6 +22,6 @@
22
22
  "tslib": "2.8.1"
23
23
  },
24
24
  "peerDependencies": {
25
- "@platecms/delta-plate-resource-notation": "0.8.0"
25
+ "@platecms/delta-plate-resource-notation": "0.9.0"
26
26
  }
27
27
  }
@@ -52,6 +52,47 @@
52
52
  },
53
53
  "type": "object"
54
54
  },
55
+ "CasSuggestion": {
56
+ "description": "A CAS suggestion node.",
57
+ "properties": {
58
+ "data": {
59
+ "$ref": "#/definitions/Data",
60
+ "description": "Info from the ecosystem."
61
+ },
62
+ "message": {
63
+ "description": "A message explaining the suggestion.",
64
+ "type": "string"
65
+ },
66
+ "method": {
67
+ "description": "The method or algorithm that created the suggestion (e.g. \"database; reusable\")",
68
+ "type": "string"
69
+ },
70
+ "original": {
71
+ "description": "The original content that is suggested to be replaced.",
72
+ "items": {
73
+ "$ref": "#/definitions/Content"
74
+ },
75
+ "type": "array"
76
+ },
77
+ "position": {
78
+ "$ref": "#/definitions/Position",
79
+ "description": "Position of a node in a source document.\n\nNodes that are generated (not in the original source document) must not\nhave a position."
80
+ },
81
+ "suggested": {
82
+ "description": "The suggested replacement content.",
83
+ "items": {
84
+ "$ref": "#/definitions/Content"
85
+ },
86
+ "type": "array"
87
+ },
88
+ "type": {
89
+ "const": "casSuggestion",
90
+ "description": "Node type.",
91
+ "type": "string"
92
+ }
93
+ },
94
+ "type": "object"
95
+ },
55
96
  "Code": {
56
97
  "properties": {
57
98
  "children": {
@@ -101,6 +142,9 @@
101
142
  {
102
143
  "$ref": "#/definitions/ListItem"
103
144
  },
145
+ {
146
+ "$ref": "#/definitions/CasSuggestion"
147
+ },
104
148
  {
105
149
  "$ref": "#/definitions/Bold"
106
150
  },
@@ -1,6 +1,6 @@
1
1
  import { Node, Literal as UnistLiteral, Parent as UnistParent } from "unist";
2
2
 
3
- export type Content = BlockContent | InlineContent;
3
+ export type Content = BlockContent | CasSuggestion | InlineContent;
4
4
 
5
5
  export type BlockContent = BlockContentMap[keyof BlockContentMap];
6
6
  export type InlineContent = InlineContentMap[keyof InlineContentMap];
@@ -232,3 +232,30 @@ export interface InternalLink extends Parent {
232
232
 
233
233
  target?: "_parent" | "_top" | "blank" | "self";
234
234
  }
235
+
236
+ /**
237
+ * A CAS suggestion node.
238
+ */
239
+ export interface CasSuggestion extends Node {
240
+ type: "casSuggestion";
241
+
242
+ /**
243
+ * The original content that is suggested to be replaced.
244
+ */
245
+ original: Content[];
246
+
247
+ /**
248
+ * The suggested replacement content.
249
+ */
250
+ suggested: Content[];
251
+
252
+ /**
253
+ * A message explaining the suggestion.
254
+ */
255
+ message: string;
256
+
257
+ /**
258
+ * The method or algorithm that created the suggestion (e.g. "database; reusable")
259
+ */
260
+ method: string;
261
+ }
@@ -2,6 +2,7 @@ import { validateCast } from "./validate-cast";
2
2
  import {
3
3
  Blockquote,
4
4
  Bold,
5
+ CasSuggestion,
5
6
  Code,
6
7
  Content,
7
8
  ExternalLink,
@@ -99,6 +100,16 @@ describe("validateCast", () => {
99
100
  "valid blockquote",
100
101
  { type: "blockquote", children: [{ type: "text", value: "Blockquote text" }] } satisfies Blockquote,
101
102
  ],
103
+ [
104
+ "valid cas suggestion",
105
+ {
106
+ type: "casSuggestion",
107
+ original: [{ type: "text", value: "Original text" }],
108
+ suggested: [{ type: "text", value: "Suggested text" }],
109
+ message: "This is a suggestion",
110
+ method: "database; reusable",
111
+ } satisfies CasSuggestion,
112
+ ],
102
113
  ])("validates a %s", (_, input) => {
103
114
  const root: Root = { type: "root", children: [input as Content] };
104
115
  expect(() => validateCast(root)).not.toThrow();
@@ -317,6 +328,66 @@ describe("validateCast", () => {
317
328
  children: [{ type: "listItem", children: "notAnArray" as unknown as InlineContent[] }],
318
329
  } satisfies Root,
319
330
  ],
331
+ [
332
+ "invalid cas suggestion - original not an array",
333
+ {
334
+ type: "root",
335
+ children: [
336
+ {
337
+ type: "casSuggestion",
338
+ original: "notAnArray" as unknown as InlineContent[],
339
+ suggested: [{ type: "text", value: "Suggested text" }],
340
+ message: "This is a suggestion",
341
+ method: "database; reusable",
342
+ },
343
+ ],
344
+ } satisfies Root,
345
+ ],
346
+ [
347
+ "invalid cas suggestion - suggested not an array",
348
+ {
349
+ type: "root",
350
+ children: [
351
+ {
352
+ type: "casSuggestion",
353
+ original: [{ type: "text", value: "Original text" }],
354
+ suggested: "notAnArray" as unknown as InlineContent[],
355
+ message: "This is a suggestion",
356
+ method: "database; reusable",
357
+ },
358
+ ],
359
+ } satisfies Root,
360
+ ],
361
+ [
362
+ "invalid cas suggestion - message not a string",
363
+ {
364
+ type: "root",
365
+ children: [
366
+ {
367
+ type: "casSuggestion",
368
+ original: [{ type: "text", value: "Original text" }],
369
+ suggested: [{ type: "text", value: "Suggested text" }],
370
+ message: null as unknown as string,
371
+ method: "database; reusable",
372
+ },
373
+ ],
374
+ } satisfies Root,
375
+ ],
376
+ [
377
+ "invalid cas suggestion - method not a string",
378
+ {
379
+ type: "root",
380
+ children: [
381
+ {
382
+ type: "casSuggestion",
383
+ original: [{ type: "text", value: "Original text" }],
384
+ suggested: [{ type: "text", value: "Suggested text" }],
385
+ message: "This is a suggestion",
386
+ method: 123 as unknown as string,
387
+ },
388
+ ],
389
+ } satisfies Root,
390
+ ],
320
391
  ])("throws an error for %s", (_, input) => {
321
392
  expect(() => validateCast(input)).toThrow(InvalidCastError);
322
393
  });
@@ -1,4 +1,5 @@
1
1
  import {
2
+ CasSuggestion,
2
3
  Code,
3
4
  Content,
4
5
  ExternalLink,
@@ -137,6 +138,35 @@ function assertValidInternalLink(value: unknown): asserts value is InternalLink
137
138
  link.children.forEach(assertTextNode);
138
139
  }
139
140
 
141
+ function assertValidCasSuggestion(value: unknown): asserts value is CasSuggestion {
142
+ assertNonNullObject(value);
143
+
144
+ const suggestion = value as CasSuggestion;
145
+
146
+ // Validate required fields
147
+ if (!Array.isArray(suggestion.original)) {
148
+ throw new InvalidCastError("Invalid casSuggestion: original must be an array");
149
+ }
150
+
151
+ if (!Array.isArray(suggestion.suggested)) {
152
+ throw new InvalidCastError("Invalid casSuggestion: suggested must be an array");
153
+ }
154
+
155
+ if (typeof suggestion.message !== "string") {
156
+ throw new InvalidCastError("Invalid casSuggestion: message must be a string");
157
+ }
158
+
159
+ if (typeof suggestion.method !== "string") {
160
+ throw new InvalidCastError("Invalid casSuggestion: method must be a string");
161
+ }
162
+
163
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
164
+ suggestion.original.forEach(assertValidContent);
165
+
166
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
167
+ suggestion.suggested.forEach(assertValidContent);
168
+ }
169
+
140
170
  function assertValidContent(value: unknown): asserts value is Content {
141
171
  assertNonNullObject(value);
142
172
  const content = value as Content;
@@ -157,6 +187,9 @@ function assertValidContent(value: unknown): asserts value is Content {
157
187
  case "internalLink":
158
188
  assertValidInternalLink(content);
159
189
  break;
190
+ case "casSuggestion":
191
+ assertValidCasSuggestion(content);
192
+ break;
160
193
  case "heading":
161
194
  assertValidHeading(content);
162
195
  break;