gt-sanity 0.0.5 → 1.0.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.
Files changed (108) hide show
  1. package/LICENSE.md +1 -8
  2. package/README.md +5 -5
  3. package/dist/index.d.mts +122 -95
  4. package/dist/index.d.ts +122 -95
  5. package/dist/index.js +9089 -1119
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +9099 -1100
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +11 -4
  10. package/src/adapter/core.ts +111 -9
  11. package/src/adapter/createTask.ts +1 -1
  12. package/src/adapter/getLocales.ts +2 -2
  13. package/src/adapter/types.ts +9 -0
  14. package/src/components/TranslationsProvider.tsx +942 -0
  15. package/src/components/page/BatchProgress.tsx +27 -0
  16. package/src/components/page/ImportAllDialog.tsx +51 -0
  17. package/src/components/page/ImportMissingDialog.tsx +55 -0
  18. package/src/components/page/TranslateAllDialog.tsx +55 -0
  19. package/src/components/page/TranslationsTable.tsx +81 -0
  20. package/src/components/page/TranslationsTool.tsx +338 -0
  21. package/src/components/shared/BaseTranslationWrapper.tsx +82 -0
  22. package/src/components/{LanguageStatus.tsx → shared/LanguageStatus.tsx} +2 -0
  23. package/src/components/shared/LocaleCheckbox.tsx +47 -0
  24. package/src/components/{ProgressBar.tsx → shared/ProgressBar.tsx} +2 -0
  25. package/src/components/shared/SingleDocumentView.tsx +108 -0
  26. package/src/components/tab/TranslationView.tsx +379 -0
  27. package/src/components/tab/TranslationsTab.tsx +25 -0
  28. package/src/configuration/baseDocumentLevelConfig/documentLevelPatch.ts +21 -11
  29. package/src/configuration/baseDocumentLevelConfig/helpers/createI18nDocAndPatchMetadata.ts +57 -23
  30. package/src/configuration/baseDocumentLevelConfig/helpers/createTranslationMetadata.ts +2 -0
  31. package/src/configuration/baseDocumentLevelConfig/helpers/getOrCreateTranslationMetadata.ts +2 -0
  32. package/src/configuration/baseDocumentLevelConfig/helpers/getTranslationMetadata.ts +2 -0
  33. package/src/configuration/baseDocumentLevelConfig/helpers/patchI18nDoc.ts +31 -8
  34. package/src/configuration/baseDocumentLevelConfig/index.ts +18 -101
  35. package/src/configuration/baseFieldLevelConfig.ts +19 -51
  36. package/src/configuration/utils/checkSerializationVersion.ts +2 -0
  37. package/src/configuration/utils/findDocumentAtRevision.ts +2 -0
  38. package/src/configuration/utils/findLatestDraft.ts +2 -0
  39. package/src/hooks/useClient.ts +3 -1
  40. package/src/hooks/useSecrets.ts +2 -0
  41. package/src/index.ts +91 -67
  42. package/src/sanity-api/findDocuments.ts +44 -0
  43. package/src/sanity-api/publishDocuments.ts +49 -0
  44. package/src/sanity-api/resolveRefs.ts +146 -0
  45. package/src/serialization/BaseDocumentMerger.ts +138 -0
  46. package/src/serialization/BaseSerializationConfig.ts +220 -0
  47. package/src/serialization/__tests__/BaseDocumentDeserializer/__snapshots__/documentLevelDeserialization.test.ts.snap +189 -0
  48. package/src/serialization/__tests__/BaseDocumentDeserializer/__snapshots__/fieldLevelDeserialization.test.ts.snap +107 -0
  49. package/src/serialization/__tests__/BaseDocumentDeserializer/baseDeserialization.test.ts +397 -0
  50. package/src/serialization/__tests__/BaseDocumentDeserializer/documentLevelDeserialization.test.ts +107 -0
  51. package/src/serialization/__tests__/BaseDocumentDeserializer/fieldLevelDeserialization.test.ts +107 -0
  52. package/src/serialization/__tests__/BaseDocumentMerger/__snapshots__/documentLevelMerge.test.ts.snap +193 -0
  53. package/src/serialization/__tests__/BaseDocumentMerger/__snapshots__/fieldLevelMerge.test.ts.snap +97 -0
  54. package/src/serialization/__tests__/BaseDocumentMerger/baseMerge.test.ts +36 -0
  55. package/src/serialization/__tests__/BaseDocumentMerger/documentLevelMerge.test.ts +96 -0
  56. package/src/serialization/__tests__/BaseDocumentMerger/fieldLevelMerge.test.ts +142 -0
  57. package/src/serialization/__tests__/BaseDocumentMerger/utils.ts +52 -0
  58. package/src/serialization/__tests__/BaseDocumentSerializer/__snapshots__/documentInlineMarks.test.ts.snap +39 -0
  59. package/src/serialization/__tests__/BaseDocumentSerializer/__snapshots__/documentLevelSerialization.test.ts.snap +8 -0
  60. package/src/serialization/__tests__/BaseDocumentSerializer/__snapshots__/fieldLevelSerialization.test.ts.snap +8 -0
  61. package/src/serialization/__tests__/BaseDocumentSerializer/baseSerialization.test.ts +345 -0
  62. package/src/serialization/__tests__/BaseDocumentSerializer/documentInlineMarks.test.ts +53 -0
  63. package/src/serialization/__tests__/BaseDocumentSerializer/documentLevelSerialization.test.ts +120 -0
  64. package/src/serialization/__tests__/BaseDocumentSerializer/fieldLevelSerialization.test.ts +153 -0
  65. package/src/serialization/__tests__/BaseDocumentSerializer/utils.ts +27 -0
  66. package/src/serialization/__tests__/README +2 -0
  67. package/src/serialization/__tests__/__fixtures__/annotationAndInlineBlocks.json +140 -0
  68. package/src/serialization/__tests__/__fixtures__/customStyles.json +62 -0
  69. package/src/serialization/__tests__/__fixtures__/documentInlineMarks.json +70 -0
  70. package/src/serialization/__tests__/__fixtures__/documentLevelArticle.json +185 -0
  71. package/src/serialization/__tests__/__fixtures__/fieldLevelArticle.json +107 -0
  72. package/src/serialization/__tests__/__fixtures__/inlineDocumentLevelArticle.json +134 -0
  73. package/src/serialization/__tests__/__fixtures__/inlineSchema.ts +270 -0
  74. package/src/serialization/__tests__/__fixtures__/messy-html.html +26 -0
  75. package/src/serialization/__tests__/__fixtures__/nestedLanguageFields.json +54 -0
  76. package/src/serialization/__tests__/__fixtures__/schema.ts +310 -0
  77. package/src/serialization/__tests__/global.setup.ts +40 -0
  78. package/src/serialization/__tests__/helpers.ts +132 -0
  79. package/src/serialization/data.ts +82 -0
  80. package/src/serialization/deserialize/BaseDocumentDeserializer.ts +171 -0
  81. package/src/serialization/deserialize/helpers.ts +42 -0
  82. package/src/serialization/helpers.ts +18 -0
  83. package/src/serialization/index.ts +11 -0
  84. package/src/serialization/serialize/fieldFilters.ts +124 -0
  85. package/src/serialization/serialize/index.ts +284 -0
  86. package/src/serialization/types.ts +41 -0
  87. package/src/translation/checkTranslationStatus.ts +42 -0
  88. package/src/translation/createJobs.ts +16 -0
  89. package/src/translation/downloadTranslations.ts +68 -0
  90. package/src/translation/importDocument.ts +23 -0
  91. package/src/translation/initProject.ts +61 -0
  92. package/src/translation/uploadFiles.ts +32 -0
  93. package/src/types.ts +7 -20
  94. package/src/utils/applyDocuments.ts +72 -0
  95. package/src/utils/batchProcessor.ts +111 -0
  96. package/src/utils/importUtils.ts +95 -0
  97. package/src/utils/serialize.ts +52 -0
  98. package/src/utils/shared.ts +1 -0
  99. package/src/adapter/index.ts +0 -13
  100. package/src/components/NewTask.tsx +0 -249
  101. package/src/components/TaskView.tsx +0 -255
  102. package/src/components/TranslationContext.tsx +0 -19
  103. package/src/components/TranslationView.tsx +0 -82
  104. package/src/components/TranslationsTab.tsx +0 -177
  105. package/src/configuration/baseDocumentLevelConfig/helpers/index.ts +0 -5
  106. package/src/configuration/baseDocumentLevelConfig/legacyDocumentLevelPatch.ts +0 -69
  107. package/src/configuration/index.ts +0 -18
  108. package/src/configuration/utils/index.ts +0 -3
@@ -0,0 +1,189 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Global test of working doc-level functionality and snapshot match 1`] = `
4
+ {
5
+ "_id": "drafts.d8ffc675-ce86-4f60-9ac8-da164cde3b0a",
6
+ "_rev": "fxcnqj-uew-gr7-v6r-z965tfm69",
7
+ "_type": "documentLevelArticle",
8
+ "config": {
9
+ "_type": "objectField",
10
+ "nestedArrayField": [
11
+ {
12
+ "_key": "4a58adc7c507",
13
+ "_type": "block",
14
+ "children": [
15
+ {
16
+ "_key": "randomKey-16",
17
+ "_type": "span",
18
+ "marks": [],
19
+ "text": "This is block text 1 level deep",
20
+ },
21
+ ],
22
+ "markDefs": [],
23
+ "style": "normal",
24
+ },
25
+ ],
26
+ "objectAsField": {
27
+ "_type": "childObjectField",
28
+ "content": [
29
+ {
30
+ "_key": "1aa228ac848b",
31
+ "_type": "block",
32
+ "children": [
33
+ {
34
+ "_key": "randomKey-14",
35
+ "_type": "span",
36
+ "marks": [],
37
+ "text": "This is a block text 2 levels deep",
38
+ },
39
+ ],
40
+ "markDefs": [],
41
+ "style": "normal",
42
+ },
43
+ ],
44
+ "title": "This is one level deeper",
45
+ },
46
+ "title": "This is an object nested in a document",
47
+ },
48
+ "content": [
49
+ {
50
+ "_key": "a4d177e92666",
51
+ "_type": "block",
52
+ "children": [
53
+ {
54
+ "_key": "randomKey-18",
55
+ "_type": "span",
56
+ "marks": [],
57
+ "text": "This is block text at the top level.",
58
+ },
59
+ ],
60
+ "markDefs": [],
61
+ "style": "normal",
62
+ },
63
+ {
64
+ "_key": "c0313627775e",
65
+ "_type": "objectField",
66
+ "objectAsField": {
67
+ "_type": "childObjectField",
68
+ "content": [
69
+ {
70
+ "_key": "4f24f6fbfae7",
71
+ "_type": "block",
72
+ "children": [
73
+ {
74
+ "_key": "randomKey-24",
75
+ "_type": "span",
76
+ "marks": [],
77
+ "text": "This is block text in a nested object in an object in top-level block text.",
78
+ },
79
+ ],
80
+ "markDefs": [],
81
+ "style": "normal",
82
+ },
83
+ ],
84
+ "title": "This is a nested object in an object in top-level block text.",
85
+ },
86
+ "title": "This is an object in top-level block text.",
87
+ },
88
+ {
89
+ "_key": "9e2ab13c6d63",
90
+ "_type": "block",
91
+ "children": [
92
+ {
93
+ "_key": "randomKey-26",
94
+ "_type": "span",
95
+ "marks": [],
96
+ "text": "This is h1 text",
97
+ },
98
+ ],
99
+ "markDefs": [],
100
+ "style": "h1",
101
+ },
102
+ {
103
+ "_key": "297142fbaf21",
104
+ "_type": "block",
105
+ "children": [
106
+ {
107
+ "_key": "randomKey-28",
108
+ "_type": "span",
109
+ "marks": [],
110
+ "text": "This is h2 text",
111
+ },
112
+ ],
113
+ "markDefs": [],
114
+ "style": "h2",
115
+ },
116
+ {
117
+ "_key": "76e648fc3845",
118
+ "_type": "block",
119
+ "children": [
120
+ {
121
+ "_key": "randomKey-32",
122
+ "_type": "span",
123
+ "marks": [],
124
+ "text": "Bullet 1",
125
+ },
126
+ ],
127
+ "level": 1,
128
+ "listItem": "bullet",
129
+ "markDefs": [],
130
+ "style": "normal",
131
+ },
132
+ {
133
+ "_key": "d090cd8b27d2",
134
+ "_type": "block",
135
+ "children": [
136
+ {
137
+ "_key": "randomKey-36",
138
+ "_type": "span",
139
+ "marks": [],
140
+ "text": "nested bullet a",
141
+ },
142
+ ],
143
+ "level": 2,
144
+ "listItem": "bullet",
145
+ "markDefs": [],
146
+ "style": "normal",
147
+ },
148
+ {
149
+ "_key": "1cdffa5d50f5",
150
+ "_type": "block",
151
+ "children": [
152
+ {
153
+ "_key": "randomKey-42",
154
+ "_type": "span",
155
+ "marks": [],
156
+ "text": "Styled bullet 2",
157
+ },
158
+ ],
159
+ "level": 1,
160
+ "listItem": "bullet",
161
+ "markDefs": [],
162
+ "style": "h2",
163
+ },
164
+ {
165
+ "_key": "da29f5063059",
166
+ "_type": "block",
167
+ "children": [
168
+ {
169
+ "_key": "randomKey-48",
170
+ "_type": "span",
171
+ "marks": [],
172
+ "text": "Number 1",
173
+ },
174
+ ],
175
+ "level": 1,
176
+ "listItem": "number",
177
+ "markDefs": [],
178
+ "style": "h3",
179
+ },
180
+ ],
181
+ "snippet": "This is text in my text field.",
182
+ "tags": [
183
+ "tag 1",
184
+ "tag 2",
185
+ "tag 3",
186
+ ],
187
+ "title": "My Document-Level Article",
188
+ }
189
+ `;
@@ -0,0 +1,107 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Global test of working field-level functionality and snapshot match 1`] = `
4
+ {
5
+ "_id": "drafts.2947533e-1ea5-4116-955b-339608d3445d",
6
+ "_rev": "l58oha-n06-1s4-f6i-74g6cuakl",
7
+ "_type": "fieldLevelArticle",
8
+ "config": {
9
+ "en": {
10
+ "_type": "objectField",
11
+ "nestedArrayField": [
12
+ {
13
+ "_key": "f49b4d7e3e51",
14
+ "_type": "block",
15
+ "children": [
16
+ {
17
+ "_key": "randomKey-16",
18
+ "_type": "span",
19
+ "marks": [],
20
+ "text": "This is block text 1 level deep",
21
+ },
22
+ ],
23
+ "markDefs": [],
24
+ "style": "normal",
25
+ },
26
+ ],
27
+ "objectAsField": {
28
+ "_type": "childObjectField",
29
+ "content": [
30
+ {
31
+ "_key": "869168fe3a2a",
32
+ "_type": "block",
33
+ "children": [
34
+ {
35
+ "_key": "randomKey-14",
36
+ "_type": "span",
37
+ "marks": [],
38
+ "text": "This is block text 2 levels deep",
39
+ },
40
+ ],
41
+ "markDefs": [],
42
+ "style": "normal",
43
+ },
44
+ ],
45
+ "title": "This is one level deeper",
46
+ },
47
+ "title": "This is an object nested in a document",
48
+ },
49
+ },
50
+ "content": {
51
+ "en": [
52
+ {
53
+ "_key": "e2a39d768ff8",
54
+ "_type": "block",
55
+ "children": [
56
+ {
57
+ "_key": "randomKey-18",
58
+ "_type": "span",
59
+ "marks": [],
60
+ "text": "This is block text at the top level.",
61
+ },
62
+ ],
63
+ "markDefs": [],
64
+ "style": "normal",
65
+ },
66
+ {
67
+ "_key": "271b0c6ee984",
68
+ "_type": "objectField",
69
+ "objectAsField": {
70
+ "_type": "childObjectField",
71
+ "content": [
72
+ {
73
+ "_key": "4f24f6fbfae7",
74
+ "_type": "block",
75
+ "children": [
76
+ {
77
+ "_key": "randomKey-24",
78
+ "_type": "span",
79
+ "marks": [],
80
+ "text": "This is block text in a nested object in an object in top-level block text.",
81
+ },
82
+ ],
83
+ "markDefs": [],
84
+ "style": "normal",
85
+ },
86
+ ],
87
+ "title": "This is a nested object in an object in top-level block text.",
88
+ },
89
+ "title": "This is an object in top-level block text.",
90
+ },
91
+ ],
92
+ },
93
+ "snippet": {
94
+ "en": "This is text in my text field",
95
+ },
96
+ "tags": {
97
+ "en": [
98
+ "tag 1",
99
+ "tag 2",
100
+ "tag 3",
101
+ ],
102
+ },
103
+ "title": {
104
+ "en": "My Field-Level Article",
105
+ },
106
+ }
107
+ `;
@@ -0,0 +1,397 @@
1
+ import { readFileSync } from 'fs';
2
+ import {
3
+ PortableTextBlock,
4
+ PortableTextObject,
5
+ PortableTextSpan,
6
+ PortableTextTextBlock,
7
+ } from 'sanity';
8
+ import { beforeEach, expect, test, vi } from 'vitest';
9
+ import {
10
+ BaseDocumentDeserializer,
11
+ BaseDocumentSerializer,
12
+ customBlockDeserializers,
13
+ defaultStopTypes,
14
+ } from '../../index';
15
+ import {
16
+ annotationAndInlineBlocks,
17
+ documentLevelArticle,
18
+ inlineDocumentLevelArticle,
19
+ inlineSchema,
20
+ schema,
21
+ } from '../BaseDocumentSerializer/utils';
22
+ import {
23
+ addedBlockDeserializers,
24
+ addedCustomDeserializers,
25
+ addedCustomSerializers,
26
+ getDeserialized,
27
+ } from '../helpers';
28
+
29
+ const customStyles = require('../__fixtures__/customStyles');
30
+
31
+ let mockTestKey = 0;
32
+
33
+ vi.mock('@sanity/block-tools', async () => {
34
+ const originalModule = await vi.importActual<
35
+ typeof import('@sanity/block-tools')
36
+ >('@sanity/block-tools');
37
+ return {
38
+ ...originalModule,
39
+ //not ideal but vi.mock('@sanity/block-tools/src/util/randomKey.ts' is not working
40
+ htmlToBlocks: (html: string, blockContentType: any, options: any) => {
41
+ const blocks = originalModule.htmlToBlocks(
42
+ html,
43
+ blockContentType,
44
+ options
45
+ );
46
+ const newBlocks = blocks.map((block) => {
47
+ const newChildren = (
48
+ block as unknown as PortableTextTextBlock<
49
+ PortableTextSpan | PortableTextObject
50
+ >
51
+ ).children.map((child) => {
52
+ return { ...child, _key: `randomKey-${mockTestKey++}` };
53
+ });
54
+ return {
55
+ ...block,
56
+ children: newChildren,
57
+ _key: `randomKey-${mockTestKey++}`,
58
+ };
59
+ });
60
+ return newBlocks;
61
+ },
62
+ };
63
+ });
64
+
65
+ beforeEach(() => {
66
+ mockTestKey = 0;
67
+ });
68
+
69
+ test('Contains id of original document', () => {
70
+ const deserialized = getDeserialized(documentLevelArticle, 'document');
71
+ const id = deserialized._id;
72
+ expect(id).toEqual(documentLevelArticle._id);
73
+ });
74
+
75
+ test('Contains rev of original document', () => {
76
+ const deserialized = getDeserialized(documentLevelArticle, 'document');
77
+ const rev = deserialized._rev;
78
+ expect(rev).toEqual(documentLevelArticle._rev);
79
+ });
80
+
81
+ test('Contains type of original document', () => {
82
+ const deserialized = getDeserialized(documentLevelArticle, 'document');
83
+ const type = deserialized._type;
84
+ expect(type).toEqual(documentLevelArticle._type);
85
+ });
86
+
87
+ /*
88
+ * CUSTOM SETTINGS
89
+ */
90
+
91
+ test('Custom deserialization should manifest at all levels', () => {
92
+ const serialized = BaseDocumentSerializer(schema).serializeDocument(
93
+ documentLevelArticle,
94
+ 'document',
95
+ 'en',
96
+ defaultStopTypes,
97
+ addedCustomSerializers
98
+ );
99
+
100
+ const deserialized = BaseDocumentDeserializer.deserializeDocument(
101
+ serialized.content,
102
+ addedCustomDeserializers,
103
+ customBlockDeserializers
104
+ );
105
+ expect(deserialized.config.title).toEqual(documentLevelArticle.config.title);
106
+ expect(deserialized.config._type).toEqual(documentLevelArticle.config._type);
107
+
108
+ const origArrayObj = documentLevelArticle.content.find(
109
+ (b: Record<string, any>) => b._type === 'objectField'
110
+ );
111
+ const deserializedArrayObj = deserialized.content.find(
112
+ (b: Record<string, any>) => b._type === 'objectField'
113
+ );
114
+
115
+ expect(deserializedArrayObj.title).toEqual(origArrayObj.title);
116
+ expect(deserializedArrayObj._key).toEqual(origArrayObj._key);
117
+ });
118
+
119
+ test('Content with custom styles deserializes correctly and maintains style', () => {
120
+ vi.spyOn(console, 'warn').mockImplementation(() => {});
121
+
122
+ const customStyledDocument = {
123
+ ...documentLevelArticle,
124
+ ...customStyles,
125
+ };
126
+
127
+ const serialized = BaseDocumentSerializer(schema).serializeDocument(
128
+ customStyledDocument,
129
+ 'document'
130
+ );
131
+
132
+ const deserialized = BaseDocumentDeserializer.deserializeDocument(
133
+ serialized.content
134
+ );
135
+ const origCustomStyleBlock = customStyledDocument.content.find(
136
+ (b: Record<string, any>) => b._type === 'block' && b.style === 'custom1'
137
+ );
138
+ const origCustomStyleListItem = customStyledDocument.content.find(
139
+ (b: Record<string, any>) =>
140
+ b._type === 'block' && b.listItem === 'number' && b.style === 'custom1'
141
+ );
142
+ const deserializedCustomStyleBlock = deserialized.content.find(
143
+ (b: Record<string, any>) => b._type === 'block' && b.style === 'custom1'
144
+ );
145
+ const deserializedCustomStyleListItem = deserialized.content.find(
146
+ (b: Record<string, any>) =>
147
+ b._type === 'block' && b.listItem === 'number' && b.style === 'custom1'
148
+ );
149
+
150
+ expect(deserializedCustomStyleBlock.children[0].text).toEqual(
151
+ origCustomStyleBlock.children[0].text
152
+ );
153
+
154
+ expect(deserializedCustomStyleListItem.children[0].text).toEqual(
155
+ origCustomStyleListItem.children[0].text
156
+ );
157
+ });
158
+
159
+ //test -- unhandled annotations and inlines don't break when they get deserialized back
160
+ test('Handled inline objects should be accurately deserialized', () => {
161
+ const inlineDocument = {
162
+ ...documentLevelArticle,
163
+ ...annotationAndInlineBlocks,
164
+ };
165
+
166
+ const serialized = BaseDocumentSerializer(schema).serializeDocument(
167
+ inlineDocument,
168
+ 'document',
169
+ 'en',
170
+ defaultStopTypes,
171
+ addedCustomSerializers
172
+ );
173
+
174
+ const deserialized = BaseDocumentDeserializer.deserializeDocument(
175
+ serialized.content,
176
+ addedCustomDeserializers,
177
+ addedBlockDeserializers
178
+ );
179
+
180
+ const getInlineObj = (
181
+ content: PortableTextBlock[],
182
+ level: number | undefined = undefined
183
+ ) => {
184
+ let child: Record<string, any> = {};
185
+ const blocks = content.filter((block: PortableTextBlock) => {
186
+ if (level) {
187
+ return block.level === level;
188
+ }
189
+ return !block.level;
190
+ });
191
+
192
+ blocks.forEach((block: PortableTextBlock) => {
193
+ if (block.children && Array.isArray(block.children)) {
194
+ child = block.children.find((span: Record<string, any>) => {
195
+ if (level) {
196
+ return span._type === 'childObjectField' && block.level === level;
197
+ }
198
+ return span._type === 'childObjectField' && !block.level;
199
+ });
200
+ }
201
+ });
202
+
203
+ return child;
204
+ };
205
+ const origInlineObject = getInlineObj(inlineDocument.content);
206
+ const origInlineListObject = getInlineObj(inlineDocument.content, 1);
207
+
208
+ const deserializedInlineObject = getInlineObj(deserialized.content);
209
+ const deserializedInlineListObject = getInlineObj(deserialized.content, 1);
210
+
211
+ expect(deserializedInlineObject.title).toEqual(origInlineObject.title);
212
+ expect(deserializedInlineObject._type).toEqual(origInlineObject._type);
213
+
214
+ expect(deserializedInlineListObject.title).toEqual(
215
+ origInlineListObject.title
216
+ );
217
+ expect(deserializedInlineListObject._type).toEqual(
218
+ origInlineListObject._type
219
+ );
220
+ });
221
+
222
+ test('Handled annotations should be accurately deserialized', () => {
223
+ const inlineDocument = {
224
+ ...documentLevelArticle,
225
+ ...annotationAndInlineBlocks,
226
+ };
227
+
228
+ const serialized = BaseDocumentSerializer(schema).serializeDocument(
229
+ inlineDocument,
230
+ 'document',
231
+ 'en',
232
+ defaultStopTypes,
233
+ addedCustomSerializers
234
+ );
235
+
236
+ const deserialized = BaseDocumentDeserializer.deserializeDocument(
237
+ serialized.content,
238
+ addedCustomDeserializers,
239
+ addedBlockDeserializers
240
+ );
241
+
242
+ let origAnnotation: Record<string, any> | null = null;
243
+ let deserializedAnnotation: Record<string, any> | null = null;
244
+
245
+ inlineDocument.content.forEach((block: PortableTextBlock) => {
246
+ if (block.children && Array.isArray(block.children)) {
247
+ block.children.forEach((span: Record<string, any>) => {
248
+ if (span.marks && span.marks.length) {
249
+ origAnnotation = span;
250
+ }
251
+ });
252
+ }
253
+ });
254
+
255
+ deserialized.content.forEach((block: PortableTextBlock) => {
256
+ if (block.children && Array.isArray(block.children)) {
257
+ block.children.forEach((span: Record<string, any>) => {
258
+ if (span.marks && span.marks.length) {
259
+ deserializedAnnotation = span;
260
+ }
261
+ });
262
+ }
263
+ });
264
+
265
+ expect(deserializedAnnotation!.text).toEqual(origAnnotation!.text);
266
+ });
267
+
268
+ /*
269
+ * STYLE TAGS
270
+ */
271
+ test('Deserialized content should preserve style tags', () => {
272
+ const deserialized = getDeserialized(documentLevelArticle, 'document');
273
+ const origH1 = documentLevelArticle.content.find(
274
+ (block: PortableTextBlock) => block.style === 'h1'
275
+ );
276
+ const deserializedH1 = deserialized.content.find(
277
+ (block: PortableTextBlock) => block.style === 'h1'
278
+ );
279
+ const origH2 = documentLevelArticle.content.find(
280
+ (block: PortableTextBlock) => block.style === 'h2'
281
+ );
282
+ const deserializedH2 = deserialized.content.find(
283
+ (block: PortableTextBlock) => block.style === 'h2'
284
+ );
285
+ expect(deserializedH1).toBeDefined();
286
+ expect(deserializedH2).toBeDefined();
287
+ expect(deserializedH1._key).toEqual(origH1._key);
288
+ expect(deserializedH2._key).toEqual(origH2._key);
289
+ expect(deserializedH1.children[0].text).toEqual(origH1.children[0].text);
290
+ expect(deserializedH2.children[0].text).toEqual(origH2.children[0].text);
291
+ });
292
+
293
+ /*
294
+ * LIST ITEMS
295
+ */
296
+ test('Deserialized list items should preserve level, style and tag', () => {
297
+ const deserialized = getDeserialized(documentLevelArticle, 'document');
298
+ const origListItem = documentLevelArticle.content.find(
299
+ (block: PortableTextBlock) =>
300
+ block.listItem === 'bullet' && block.style === 'h2'
301
+ );
302
+ const deserializedListItem = deserialized.content.find(
303
+ (block: PortableTextBlock) =>
304
+ block.listItem === 'bullet' && block.style === 'h2'
305
+ );
306
+ const origNestedListItem = documentLevelArticle.content.find(
307
+ (block: PortableTextBlock) =>
308
+ block.listItem === 'bullet' && block.level === 2
309
+ );
310
+ const deserializedNestedListItem = deserialized.content.find(
311
+ (block: PortableTextBlock) =>
312
+ block.listItem === 'bullet' && block.level === 2
313
+ );
314
+ expect(deserializedListItem).toBeDefined();
315
+ expect(deserializedNestedListItem).toBeDefined();
316
+ expect(deserializedListItem._key).toEqual(origListItem._key);
317
+ expect(deserializedNestedListItem._key).toEqual(origNestedListItem._key);
318
+ expect(deserializedListItem.children[0].text).toEqual(
319
+ origListItem.children[0].text
320
+ );
321
+ expect(deserializedNestedListItem.children[0].text).toEqual(
322
+ origNestedListItem.children[0].text
323
+ );
324
+ });
325
+
326
+ /*
327
+ * MESSY INPUT
328
+ */
329
+ test('&nbsp; whitespace should not be escaped', () => {
330
+ vi.spyOn(console, 'debug').mockImplementation(() => {});
331
+
332
+ const content = readFileSync(
333
+ 'src/serialization/__tests__/__fixtures__/messy-html.html',
334
+ {
335
+ encoding: 'utf-8',
336
+ }
337
+ );
338
+ const result = BaseDocumentDeserializer.deserializeDocument(content);
339
+ expect(result.title).toEqual('Här är artikel titeln');
340
+ expect(result.content[1].nestedArrayField[0].title).toEqual(
341
+ 'Det här är en dragspels titeln'
342
+ );
343
+ });
344
+
345
+ /*
346
+ * V2 functionality -- be able to operate without a strict schema
347
+ */
348
+ test('Content with anonymous inline objects deserializes all fields, at any depth', () => {
349
+ vi.spyOn(console, 'debug').mockImplementation(() => {});
350
+
351
+ const serialized = BaseDocumentSerializer(inlineSchema).serializeDocument(
352
+ inlineDocumentLevelArticle,
353
+ 'document'
354
+ );
355
+
356
+ const deserialized = BaseDocumentDeserializer.deserializeDocument(
357
+ serialized.content
358
+ );
359
+ //object in field
360
+ expect(deserialized.tabs.config.title).toEqual(
361
+ inlineDocumentLevelArticle.tabs.config.title
362
+ );
363
+
364
+ //array in object in object
365
+ expect(
366
+ deserialized.tabs.config.objectAsField.content[0].children[0].text
367
+ ).toEqual(
368
+ inlineDocumentLevelArticle.tabs.config.objectAsField.content[0].children[0]
369
+ .text
370
+ );
371
+
372
+ //arrays
373
+ expect(deserialized.tabs.content).toBeInstanceOf(Array);
374
+ expect(deserialized.tabs.content.map((block: any) => block._key)).toEqual(
375
+ inlineDocumentLevelArticle.tabs.content.map((block: any) => block._key)
376
+ );
377
+
378
+ //object in array
379
+ const origObj = inlineDocumentLevelArticle.tabs.content.find(
380
+ (block: any) => block._type === 'objectField'
381
+ );
382
+ const deserializedObj = deserialized.tabs.content.find(
383
+ (block: any) => block._type === 'objectField'
384
+ );
385
+
386
+ expect(deserializedObj.title).toEqual(origObj.title);
387
+ expect(deserializedObj.objectAsField.content[0].children[0].text).toEqual(
388
+ origObj.objectAsField.content[0].children[0].text
389
+ );
390
+
391
+ //anonymous object in array
392
+ const origArray = inlineDocumentLevelArticle.tabs.arrayWithAnonymousObjects;
393
+ const deserializedArray = deserialized.tabs.arrayWithAnonymousObjects;
394
+ expect(deserializedArray.length).toEqual(origArray.length);
395
+ expect(deserializedArray[0]._key).toEqual(origArray[0]._key);
396
+ expect(Object.keys(deserializedArray[0])).not.toContain('span');
397
+ });