@supernova-studio/model 0.48.27 → 0.48.29

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@supernova-studio/model",
3
- "version": "0.48.27",
3
+ "version": "0.48.29",
4
4
  "description": "Supernova Data Models",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -32,9 +32,11 @@
32
32
  "dependencies": {
33
33
  "@sindresorhus/slugify": "1.1.2",
34
34
  "ip-cidr": "3.1.0",
35
- "zod": "3.23.6"
35
+ "zod": "3.23.6",
36
+ "deep-equal": "2.2.3"
36
37
  },
37
38
  "devDependencies": {
39
+ "@types/deep-equal": "1.0.4",
38
40
  "fs": "0.0.1-security",
39
41
  "tsup": "8.0.2",
40
42
  "typescript": "5.0.4"
@@ -1,5 +1,7 @@
1
+ import deepEqual from "deep-equal";
1
2
  import { z } from "zod";
2
3
  import { nullishToOptional } from "../../../helpers";
4
+ import { mapByUnique } from "../../../utils";
3
5
  import { ColorTokenInlineData } from "../../properties";
4
6
  import { Size } from "../primitives";
5
7
  import { DesignTokenType } from "../raw-element";
@@ -210,14 +212,20 @@ export const PageBlockTableProperties = z.object({
210
212
  columns: z.array(PageBlockTableColumn),
211
213
  });
212
214
 
213
- export const PageBlockTextSpanAttributeType = z.enum(["Bold", "Italic", "Link", "Strikethrough", "Code"]);
215
+ export const PageBlockTextSpanAttributeType = z.enum(["Bold", "Italic", "Link", "Strikethrough", "Code", "Comment"]);
214
216
 
215
217
  export const PageBlockTextSpanAttribute = z.object({
216
218
  type: PageBlockTextSpanAttributeType,
219
+
220
+ // Link attributes
217
221
  link: nullishToOptional(z.string()),
218
222
  documentationItemId: nullishToOptional(z.string()),
219
223
  openInNewWindow: nullishToOptional(z.boolean()), // deprecated. use openInNewTab
220
224
  openInNewTab: nullishToOptional(z.boolean()),
225
+
226
+ // Comment attributes
227
+ commentHighlightId: nullishToOptional(z.string()),
228
+ commentIsResolved: nullishToOptional(z.boolean()),
221
229
  });
222
230
 
223
231
  export const PageBlockTextSpan = z.object({
@@ -353,3 +361,109 @@ export function traversePageBlocksV1(blocks: PageBlockV1[], action: (block: Page
353
361
  traversePageBlocksV1(block.children, action);
354
362
  }
355
363
  }
364
+
365
+ export function removeCommentSpans(text: PageBlockText): PageBlockText {
366
+ const { spans, ...rest } = text;
367
+
368
+ const newSpans = spans.map(s => {
369
+ return {
370
+ ...s,
371
+ attributes: s.attributes.filter(a => a.type !== "Comment"),
372
+ };
373
+ });
374
+
375
+ const updatedRichText = {
376
+ ...rest,
377
+ spans: newSpans,
378
+ };
379
+
380
+ return joinRepeatingSpans(updatedRichText);
381
+ }
382
+
383
+ export function joinRepeatingSpans(text: PageBlockText): PageBlockText {
384
+ if (text.spans.length < 2) return text;
385
+
386
+ // Make sure spans are clean before comparing them
387
+ text = sanitizeSpans(text);
388
+ const { spans, ...rest } = text;
389
+
390
+ let previousSpan = { ...spans[0] };
391
+ const newSpans = [previousSpan];
392
+
393
+ for (let i = 1; i < spans.length; i++) {
394
+ const span = spans[i];
395
+ if (areAttributesEqual(span.attributes, previousSpan.attributes)) {
396
+ previousSpan.text += span.text;
397
+ } else {
398
+ previousSpan = { ...span };
399
+ newSpans.push(previousSpan);
400
+ }
401
+ }
402
+
403
+ return {
404
+ ...rest,
405
+ spans: newSpans,
406
+ };
407
+ }
408
+
409
+ function areAttributesEqual(lhs: PageBlockTextSpanAttribute[], rhs: PageBlockTextSpanAttribute[]) {
410
+ if (lhs.length !== rhs.length) return false;
411
+
412
+ const lhsMap = mapByUnique(lhs, i => i.type);
413
+ for (const rhsAttribute of rhs) {
414
+ const lhsAttribute = lhsMap.get(rhsAttribute.type);
415
+ if (!deepEqual(lhsAttribute, rhsAttribute)) return false;
416
+ }
417
+
418
+ return true;
419
+ }
420
+
421
+ function sanitizeSpans(text: PageBlockText): PageBlockText {
422
+ const { spans, ...rest } = text;
423
+
424
+ return {
425
+ ...rest,
426
+ spans: spans.map(s => {
427
+ const { attributes, ...rest } = s;
428
+
429
+ return {
430
+ ...rest,
431
+ attributes: attributes.map(sanitizeSpanAttribute),
432
+ };
433
+ }),
434
+ };
435
+ }
436
+
437
+ function sanitizeSpanAttribute(attribute: PageBlockTextSpanAttribute): PageBlockTextSpanAttribute {
438
+ switch (attribute.type) {
439
+ case "Bold":
440
+ return { type: "Bold" };
441
+ case "Code":
442
+ return { type: "Code" };
443
+ case "Strikethrough":
444
+ return { type: "Strikethrough" };
445
+ case "Italic":
446
+ return { type: "Italic" };
447
+ case "Comment":
448
+ const { commentHighlightId, commentIsResolved } = attribute;
449
+ const isCommentIsResolvedDefined = commentIsResolved !== undefined && commentIsResolved !== null;
450
+
451
+ return {
452
+ type: "Comment",
453
+ ...(isCommentIsResolvedDefined && { commentIsResolved }),
454
+ ...(commentHighlightId && { commentHighlightId }),
455
+ };
456
+ case "Link":
457
+ const { documentationItemId, link, openInNewTab, openInNewWindow } = attribute;
458
+ const isOpenInNewTabDefined = openInNewTab !== undefined && openInNewTab !== null;
459
+ const isOpenInNewWindowDefined = openInNewWindow !== undefined && openInNewWindow !== null;
460
+
461
+ return {
462
+ type: "Link",
463
+ ...(isOpenInNewTabDefined && { openInNewTab }),
464
+ ...(isOpenInNewWindowDefined && { openInNewWindow }),
465
+ ...(documentationItemId && { documentationItemId }),
466
+ ...(link && { link }),
467
+ };
468
+ }
469
+ }