@tldraw/tlschema 4.2.1 → 4.2.2

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 (117) hide show
  1. package/dist-cjs/bindings/TLBaseBinding.js.map +2 -2
  2. package/dist-cjs/createTLSchema.js.map +2 -2
  3. package/dist-cjs/index.d.ts +242 -71
  4. package/dist-cjs/index.js +4 -1
  5. package/dist-cjs/index.js.map +2 -2
  6. package/dist-cjs/misc/TLOpacity.js +1 -5
  7. package/dist-cjs/misc/TLOpacity.js.map +2 -2
  8. package/dist-cjs/misc/TLRichText.js +5 -1
  9. package/dist-cjs/misc/TLRichText.js.map +2 -2
  10. package/dist-cjs/misc/b64Vecs.js +224 -0
  11. package/dist-cjs/misc/b64Vecs.js.map +7 -0
  12. package/dist-cjs/records/TLAsset.js.map +1 -1
  13. package/dist-cjs/records/TLBinding.js.map +2 -2
  14. package/dist-cjs/records/TLShape.js.map +2 -2
  15. package/dist-cjs/shapes/ShapeWithCrop.js.map +1 -1
  16. package/dist-cjs/shapes/TLArrowShape.js +26 -13
  17. package/dist-cjs/shapes/TLArrowShape.js.map +2 -2
  18. package/dist-cjs/shapes/TLBaseShape.js.map +2 -2
  19. package/dist-cjs/shapes/TLDrawShape.js +37 -4
  20. package/dist-cjs/shapes/TLDrawShape.js.map +2 -2
  21. package/dist-cjs/shapes/TLEmbedShape.js +17 -0
  22. package/dist-cjs/shapes/TLEmbedShape.js.map +2 -2
  23. package/dist-cjs/shapes/TLGeoShape.js +12 -1
  24. package/dist-cjs/shapes/TLGeoShape.js.map +2 -2
  25. package/dist-cjs/shapes/TLHighlightShape.js +29 -2
  26. package/dist-cjs/shapes/TLHighlightShape.js.map +2 -2
  27. package/dist-cjs/shapes/TLNoteShape.js +12 -1
  28. package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
  29. package/dist-cjs/shapes/TLTextShape.js +12 -1
  30. package/dist-cjs/shapes/TLTextShape.js.map +2 -2
  31. package/dist-cjs/store-migrations.js +15 -15
  32. package/dist-cjs/store-migrations.js.map +2 -2
  33. package/dist-esm/bindings/TLBaseBinding.mjs.map +2 -2
  34. package/dist-esm/createTLSchema.mjs.map +2 -2
  35. package/dist-esm/index.d.mts +242 -71
  36. package/dist-esm/index.mjs +5 -1
  37. package/dist-esm/index.mjs.map +2 -2
  38. package/dist-esm/misc/TLOpacity.mjs +1 -5
  39. package/dist-esm/misc/TLOpacity.mjs.map +2 -2
  40. package/dist-esm/misc/TLRichText.mjs +5 -1
  41. package/dist-esm/misc/TLRichText.mjs.map +2 -2
  42. package/dist-esm/misc/b64Vecs.mjs +204 -0
  43. package/dist-esm/misc/b64Vecs.mjs.map +7 -0
  44. package/dist-esm/records/TLAsset.mjs.map +1 -1
  45. package/dist-esm/records/TLBinding.mjs.map +2 -2
  46. package/dist-esm/records/TLShape.mjs.map +2 -2
  47. package/dist-esm/shapes/TLArrowShape.mjs +26 -13
  48. package/dist-esm/shapes/TLArrowShape.mjs.map +2 -2
  49. package/dist-esm/shapes/TLBaseShape.mjs.map +2 -2
  50. package/dist-esm/shapes/TLDrawShape.mjs +37 -4
  51. package/dist-esm/shapes/TLDrawShape.mjs.map +2 -2
  52. package/dist-esm/shapes/TLEmbedShape.mjs +17 -0
  53. package/dist-esm/shapes/TLEmbedShape.mjs.map +2 -2
  54. package/dist-esm/shapes/TLGeoShape.mjs +12 -1
  55. package/dist-esm/shapes/TLGeoShape.mjs.map +2 -2
  56. package/dist-esm/shapes/TLHighlightShape.mjs +29 -2
  57. package/dist-esm/shapes/TLHighlightShape.mjs.map +2 -2
  58. package/dist-esm/shapes/TLNoteShape.mjs +12 -1
  59. package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
  60. package/dist-esm/shapes/TLTextShape.mjs +12 -1
  61. package/dist-esm/shapes/TLTextShape.mjs.map +2 -2
  62. package/dist-esm/store-migrations.mjs +15 -15
  63. package/dist-esm/store-migrations.mjs.map +2 -2
  64. package/package.json +8 -8
  65. package/src/__tests__/migrationTestUtils.ts +9 -3
  66. package/src/bindings/TLBaseBinding.ts +25 -14
  67. package/src/createTLSchema.ts +8 -2
  68. package/src/index.ts +9 -0
  69. package/src/migrations.test.ts +149 -1
  70. package/src/misc/TLOpacity.ts +1 -5
  71. package/src/misc/TLRichText.ts +6 -1
  72. package/src/misc/b64Vecs.ts +308 -0
  73. package/src/records/TLAsset.ts +2 -2
  74. package/src/records/TLBinding.ts +65 -23
  75. package/src/records/TLShape.ts +100 -5
  76. package/src/shapes/ShapeWithCrop.ts +2 -2
  77. package/src/shapes/TLArrowShape.ts +28 -14
  78. package/src/shapes/TLBaseShape.ts +34 -10
  79. package/src/shapes/TLDrawShape.ts +59 -12
  80. package/src/shapes/TLEmbedShape.ts +17 -0
  81. package/src/shapes/TLGeoShape.ts +14 -1
  82. package/src/shapes/TLHighlightShape.ts +37 -0
  83. package/src/shapes/TLNoteShape.ts +15 -1
  84. package/src/shapes/TLTextShape.ts +16 -2
  85. package/src/store-migrations.ts +17 -16
  86. package/src/assets/TLBookmarkAsset.test.ts +0 -96
  87. package/src/assets/TLImageAsset.test.ts +0 -213
  88. package/src/assets/TLVideoAsset.test.ts +0 -105
  89. package/src/bindings/TLArrowBinding.test.ts +0 -55
  90. package/src/misc/id-validator.test.ts +0 -50
  91. package/src/records/TLAsset.test.ts +0 -234
  92. package/src/records/TLBinding.test.ts +0 -22
  93. package/src/records/TLCamera.test.ts +0 -19
  94. package/src/records/TLDocument.test.ts +0 -35
  95. package/src/records/TLInstance.test.ts +0 -201
  96. package/src/records/TLPage.test.ts +0 -110
  97. package/src/records/TLPageState.test.ts +0 -228
  98. package/src/records/TLPointer.test.ts +0 -63
  99. package/src/records/TLPresence.test.ts +0 -190
  100. package/src/records/TLRecord.test.ts +0 -70
  101. package/src/records/TLShape.test.ts +0 -232
  102. package/src/shapes/ShapeWithCrop.test.ts +0 -18
  103. package/src/shapes/TLArrowShape.test.ts +0 -505
  104. package/src/shapes/TLBaseShape.test.ts +0 -142
  105. package/src/shapes/TLBookmarkShape.test.ts +0 -122
  106. package/src/shapes/TLDrawShape.test.ts +0 -177
  107. package/src/shapes/TLEmbedShape.test.ts +0 -286
  108. package/src/shapes/TLFrameShape.test.ts +0 -71
  109. package/src/shapes/TLGeoShape.test.ts +0 -247
  110. package/src/shapes/TLGroupShape.test.ts +0 -59
  111. package/src/shapes/TLHighlightShape.test.ts +0 -325
  112. package/src/shapes/TLImageShape.test.ts +0 -534
  113. package/src/shapes/TLLineShape.test.ts +0 -269
  114. package/src/shapes/TLNoteShape.test.ts +0 -1568
  115. package/src/shapes/TLTextShape.test.ts +0 -407
  116. package/src/shapes/TLVideoShape.test.ts +0 -112
  117. package/src/styles/TLColorStyle.test.ts +0 -439
@@ -1,234 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { getTestMigration } from '../__tests__/migrationTestUtils'
3
- import {
4
- assetMigrations,
5
- AssetRecordType,
6
- assetValidator,
7
- assetVersions,
8
- TLAssetId,
9
- } from './TLAsset'
10
-
11
- describe('TLAsset', () => {
12
- describe('assetValidator', () => {
13
- it('should validate different asset types using discriminated union', () => {
14
- const imageAsset = {
15
- id: 'asset:test_image',
16
- typeName: 'asset' as const,
17
- type: 'image' as const,
18
- props: {
19
- w: 100,
20
- h: 100,
21
- name: 'test.jpg',
22
- isAnimated: false,
23
- mimeType: 'image/jpeg',
24
- src: 'https://example.com/test.jpg',
25
- },
26
- meta: {},
27
- }
28
-
29
- const videoAsset = {
30
- id: 'asset:test_video',
31
- typeName: 'asset' as const,
32
- type: 'video' as const,
33
- props: {
34
- w: 640,
35
- h: 480,
36
- name: 'test.mp4',
37
- isAnimated: true,
38
- mimeType: 'video/mp4',
39
- src: 'https://example.com/test.mp4',
40
- },
41
- meta: {},
42
- }
43
-
44
- const bookmarkAsset = {
45
- id: 'asset:test_bookmark',
46
- typeName: 'asset' as const,
47
- type: 'bookmark' as const,
48
- props: {
49
- title: 'Test Site',
50
- description: 'A test bookmark',
51
- image: 'https://example.com/image.png',
52
- favicon: 'https://example.com/favicon.ico',
53
- src: 'https://example.com',
54
- },
55
- meta: {},
56
- }
57
-
58
- expect(() => assetValidator.validate(imageAsset)).not.toThrow()
59
- expect(() => assetValidator.validate(videoAsset)).not.toThrow()
60
- expect(() => assetValidator.validate(bookmarkAsset)).not.toThrow()
61
-
62
- expect(assetValidator.validate(imageAsset).type).toBe('image')
63
- expect(assetValidator.validate(videoAsset).type).toBe('video')
64
- expect(assetValidator.validate(bookmarkAsset).type).toBe('bookmark')
65
- })
66
-
67
- it('should reject invalid asset types', () => {
68
- const invalidAsset = {
69
- id: 'asset:invalid',
70
- typeName: 'asset' as const,
71
- type: 'invalid_type' as any,
72
- props: {
73
- w: 100,
74
- h: 100,
75
- name: 'test.jpg',
76
- },
77
- meta: {},
78
- }
79
-
80
- expect(() => assetValidator.validate(invalidAsset)).toThrow()
81
- })
82
-
83
- it('should require valid asset structure', () => {
84
- // Wrong typeName
85
- const wrongTypeName = {
86
- id: 'asset:wrong_typename',
87
- typeName: 'shape' as const,
88
- type: 'image' as const,
89
- props: {
90
- w: 100,
91
- h: 100,
92
- name: 'test.jpg',
93
- isAnimated: false,
94
- mimeType: 'image/jpeg',
95
- src: 'https://example.com/test.jpg',
96
- },
97
- meta: {},
98
- }
99
- expect(() => assetValidator.validate(wrongTypeName)).toThrow()
100
-
101
- // Missing meta
102
- const noMeta = {
103
- id: 'asset:no_meta',
104
- typeName: 'asset' as const,
105
- type: 'image' as const,
106
- props: {
107
- w: 100,
108
- h: 100,
109
- name: 'test.jpg',
110
- isAnimated: false,
111
- mimeType: 'image/jpeg',
112
- src: 'https://example.com/test.jpg',
113
- },
114
- }
115
- expect(() => assetValidator.validate(noMeta)).toThrow()
116
-
117
- // Wrong ID prefix
118
- const wrongId = {
119
- id: 'shape:wrong_prefix',
120
- typeName: 'asset' as const,
121
- type: 'image' as const,
122
- props: {
123
- w: 100,
124
- h: 100,
125
- name: 'test.jpg',
126
- isAnimated: false,
127
- mimeType: 'image/jpeg',
128
- src: 'https://example.com/test.jpg',
129
- },
130
- meta: {},
131
- }
132
- expect(() => assetValidator.validate(wrongId)).toThrow()
133
- })
134
- })
135
-
136
- describe('assetMigrations', () => {
137
- it('should have correct migration structure', () => {
138
- expect(assetMigrations.sequenceId).toBe('com.tldraw.asset')
139
- expect(assetMigrations.sequence).toHaveLength(1)
140
- expect(assetMigrations.sequence[0].id).toBe(assetVersions.AddMeta)
141
- })
142
- })
143
-
144
- describe('AddMeta migration', () => {
145
- const { up } = getTestMigration(assetVersions.AddMeta)
146
-
147
- it('should add empty meta property', () => {
148
- const assetWithoutMeta = {
149
- id: 'asset:test',
150
- typeName: 'asset',
151
- type: 'image',
152
- props: {
153
- w: 100,
154
- h: 100,
155
- name: 'test.jpg',
156
- isAnimated: false,
157
- mimeType: 'image/jpeg',
158
- src: 'https://example.com/test.jpg',
159
- },
160
- }
161
-
162
- const result = up(assetWithoutMeta)
163
- expect(result.meta).toEqual({})
164
- expect(result.props).toEqual(assetWithoutMeta.props)
165
- })
166
-
167
- it('should overwrite existing meta property', () => {
168
- const assetWithMeta = {
169
- id: 'asset:test',
170
- typeName: 'asset',
171
- type: 'image',
172
- props: {
173
- w: 100,
174
- h: 100,
175
- name: 'test.jpg',
176
- isAnimated: false,
177
- mimeType: 'image/jpeg',
178
- src: 'https://example.com/test.jpg',
179
- },
180
- meta: { existing: 'data' },
181
- }
182
-
183
- const result = up(assetWithMeta)
184
- expect(result.meta).toEqual({}) // Migration always sets to empty object
185
- })
186
-
187
- it('should preserve other properties during migration', () => {
188
- const assetWithExtraProps = {
189
- id: 'asset:extra_props',
190
- typeName: 'asset',
191
- type: 'image',
192
- props: {
193
- w: 200,
194
- h: 150,
195
- name: 'extra.png',
196
- isAnimated: false,
197
- mimeType: 'image/png',
198
- src: 'https://example.com/extra.png',
199
- },
200
- customProperty: 'should be preserved',
201
- }
202
-
203
- const result = up(assetWithExtraProps)
204
- expect(result.meta).toEqual({})
205
- expect(result.customProperty).toBe('should be preserved')
206
- })
207
- })
208
-
209
- describe('AssetRecordType', () => {
210
- it('should have correct configuration', () => {
211
- expect(AssetRecordType.typeName).toBe('asset')
212
- expect(AssetRecordType.scope).toBe('document')
213
- expect(AssetRecordType.validator).toBe(assetValidator)
214
- })
215
-
216
- it('should create records with default meta property', () => {
217
- const assetRecord = AssetRecordType.create({
218
- id: 'asset:test' as TLAssetId,
219
- type: 'image',
220
- props: {
221
- w: 100,
222
- h: 100,
223
- name: 'test.jpg',
224
- isAnimated: false,
225
- mimeType: 'image/jpeg',
226
- src: 'https://example.com/test.jpg',
227
- },
228
- })
229
-
230
- expect(assetRecord.meta).toEqual({})
231
- expect(assetRecord.typeName).toBe('asset')
232
- })
233
- })
234
- })
@@ -1,22 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { createBindingId, rootBindingMigrations } from './TLBinding'
3
-
4
- describe('TLBinding', () => {
5
- describe('createBindingId function', () => {
6
- it('should generate IDs starting with binding:', () => {
7
- const id = createBindingId()
8
- expect(id.startsWith('binding:')).toBe(true)
9
- })
10
-
11
- it('should use custom ID when provided', () => {
12
- expect(createBindingId('test')).toBe('binding:test')
13
- })
14
- })
15
-
16
- describe('rootBindingMigrations', () => {
17
- it('should have correct structure', () => {
18
- expect(rootBindingMigrations.sequenceId).toBe('com.tldraw.binding')
19
- expect(Array.isArray(rootBindingMigrations.sequence)).toBe(true)
20
- })
21
- })
22
- })
@@ -1,19 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { cameraMigrations, cameraVersions } from './TLCamera'
3
-
4
- describe('cameraMigrations', () => {
5
- it('should apply AddMeta migration correctly', () => {
6
- const addMetaMigration = cameraMigrations.sequence.find((m) => m.id === cameraVersions.AddMeta)!
7
-
8
- const oldRecord: any = {
9
- typeName: 'camera',
10
- id: 'camera:test',
11
- x: 100,
12
- y: 200,
13
- z: 0.5,
14
- }
15
-
16
- addMetaMigration.up(oldRecord)
17
- expect(oldRecord.meta).toEqual({})
18
- })
19
- })
@@ -1,35 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { documentMigrations, documentVersions, TLDOCUMENT_ID } from './TLDocument'
3
-
4
- describe('documentMigrations', () => {
5
- it('should apply AddName migration correctly', () => {
6
- const addNameMigration = documentMigrations.sequence.find(
7
- (m) => m.id === documentVersions.AddName
8
- )!
9
-
10
- const oldRecord: any = {
11
- typeName: 'document',
12
- id: TLDOCUMENT_ID,
13
- gridSize: 10,
14
- }
15
-
16
- addNameMigration.up(oldRecord)
17
- expect(oldRecord.name).toBe('')
18
- })
19
-
20
- it('should apply AddMeta migration correctly', () => {
21
- const addMetaMigration = documentMigrations.sequence.find(
22
- (m) => m.id === documentVersions.AddMeta
23
- )!
24
-
25
- const oldRecord: any = {
26
- typeName: 'document',
27
- id: TLDOCUMENT_ID,
28
- gridSize: 10,
29
- name: 'Test',
30
- }
31
-
32
- addMetaMigration.up(oldRecord)
33
- expect(oldRecord.meta).toEqual({})
34
- })
35
- })
@@ -1,201 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { StyleProp } from '../styles/StyleProp'
3
- import {
4
- createInstanceRecordType,
5
- instanceIdValidator,
6
- instanceMigrations,
7
- instanceVersions,
8
- pluckPreservingValues,
9
- shouldKeyBePreservedBetweenSessions,
10
- TLInstance,
11
- TLINSTANCE_ID,
12
- } from './TLInstance'
13
-
14
- // Mock style prop for testing
15
- const mockColorStyle = {
16
- type: 'color',
17
- defaultValue: 'black',
18
- getDefaultValue: () => 'black',
19
- } as unknown as StyleProp<string>
20
-
21
- const mockStylesMap = new Map([['color', mockColorStyle]])
22
- createInstanceRecordType(mockStylesMap)
23
-
24
- describe('shouldKeyBePreservedBetweenSessions', () => {
25
- it('should preserve user preferences', () => {
26
- const userPreferences = [
27
- 'isFocusMode',
28
- 'isDebugMode',
29
- 'isToolLocked',
30
- 'exportBackground',
31
- 'isGridMode',
32
- 'isReadonly',
33
- ]
34
-
35
- userPreferences.forEach((key) => {
36
- expect(
37
- shouldKeyBePreservedBetweenSessions[key as keyof typeof shouldKeyBePreservedBetweenSessions]
38
- ).toBe(true)
39
- })
40
- })
41
-
42
- it('should not preserve temporary state', () => {
43
- const temporaryState = [
44
- 'currentPageId',
45
- 'opacityForNextShape',
46
- 'stylesForNextShape',
47
- 'followingUserId',
48
- 'brush',
49
- 'cursor',
50
- 'scribbles',
51
- 'zoomBrush',
52
- 'chatMessage',
53
- 'isChatting',
54
- 'isPenMode',
55
- 'isHoveringCanvas',
56
- 'openMenus',
57
- 'isChangingStyle',
58
- 'duplicateProps',
59
- ]
60
-
61
- temporaryState.forEach((key) => {
62
- expect(
63
- shouldKeyBePreservedBetweenSessions[key as keyof typeof shouldKeyBePreservedBetweenSessions]
64
- ).toBe(false)
65
- })
66
- })
67
- })
68
-
69
- describe('pluckPreservingValues', () => {
70
- it('should return null for null or undefined input', () => {
71
- expect(pluckPreservingValues(null)).toBe(null)
72
- expect(pluckPreservingValues(undefined)).toBe(null)
73
- })
74
-
75
- it('should filter properties according to preservation rules', () => {
76
- const fullInstance: TLInstance = {
77
- id: TLINSTANCE_ID,
78
- typeName: 'instance',
79
- currentPageId: 'page:page1' as any,
80
- opacityForNextShape: 0.5,
81
- stylesForNextShape: {},
82
- followingUserId: null,
83
- highlightedUserIds: [],
84
- brush: null,
85
- cursor: { type: 'default', rotation: 0 },
86
- scribbles: [],
87
- isFocusMode: true,
88
- isDebugMode: false,
89
- isToolLocked: true,
90
- exportBackground: true,
91
- screenBounds: { x: 0, y: 0, w: 1920, h: 1080 },
92
- insets: [false, false, false, false],
93
- zoomBrush: null,
94
- chatMessage: '',
95
- isChatting: false,
96
- isPenMode: false,
97
- isGridMode: true,
98
- isFocused: true,
99
- devicePixelRatio: 2,
100
- isCoarsePointer: false,
101
- isHoveringCanvas: null,
102
- openMenus: [],
103
- isChangingStyle: false,
104
- isReadonly: false,
105
- meta: {},
106
- duplicateProps: null,
107
- }
108
-
109
- const preserved = pluckPreservingValues(fullInstance)
110
-
111
- // Should preserve user preferences
112
- expect(preserved?.isFocusMode).toBe(true)
113
- expect(preserved?.isDebugMode).toBe(false)
114
- expect(preserved?.isToolLocked).toBe(true)
115
- expect(preserved?.exportBackground).toBe(true)
116
- expect(preserved?.isGridMode).toBe(true)
117
-
118
- // Should not preserve temporary state
119
- expect(preserved?.currentPageId).toBeUndefined()
120
- expect(preserved?.opacityForNextShape).toBeUndefined()
121
- expect(preserved?.brush).toBeUndefined()
122
- expect(preserved?.cursor).toBeUndefined()
123
- expect(preserved?.chatMessage).toBeUndefined()
124
- expect(preserved?.openMenus).toBeUndefined()
125
- })
126
- })
127
-
128
- describe('instanceIdValidator', () => {
129
- it('should validate correct instance IDs and reject invalid ones', () => {
130
- expect(() => instanceIdValidator.validate('instance:instance')).not.toThrow()
131
- expect(() => instanceIdValidator.validate('instance:test')).not.toThrow()
132
- expect(() => instanceIdValidator.validate(TLINSTANCE_ID)).not.toThrow()
133
-
134
- expect(() => instanceIdValidator.validate('invalid')).toThrow()
135
- expect(() => instanceIdValidator.validate('page:instance')).toThrow()
136
- expect(() => instanceIdValidator.validate('')).toThrow()
137
- })
138
- })
139
-
140
- describe('createInstanceRecordType', () => {
141
- it('should create a valid record type with correct configuration', () => {
142
- const recordType = createInstanceRecordType(mockStylesMap)
143
- expect(recordType.typeName).toBe('instance')
144
- expect(recordType.scope).toBe('session')
145
- })
146
- })
147
-
148
- describe('instanceMigrations', () => {
149
- it('should have correct migration configuration', () => {
150
- expect(instanceMigrations.sequenceId).toBe('com.tldraw.instance')
151
- expect(Array.isArray(instanceMigrations.sequence)).toBe(true)
152
- expect(instanceMigrations.sequence.length).toBe(25)
153
- })
154
-
155
- it('should migrate HoistOpacity correctly', () => {
156
- const migration = instanceMigrations.sequence.find(
157
- (m) => m.id === instanceVersions.HoistOpacity
158
- )!
159
- const oldRecord: any = {
160
- id: TLINSTANCE_ID,
161
- typeName: 'instance',
162
- propsForNextShape: {
163
- opacity: '0.5',
164
- color: 'red',
165
- },
166
- }
167
- const result = migration.up(oldRecord)
168
-
169
- expect((result as any).opacityForNextShape).toBe(0.5)
170
- expect((result as any).propsForNextShape.opacity).toBeUndefined()
171
- expect((result as any).propsForNextShape.color).toBe('red')
172
- })
173
-
174
- it('should migrate RemoveDialog correctly', () => {
175
- const migration = instanceMigrations.sequence.find(
176
- (m) => m.id === instanceVersions.RemoveDialog
177
- )!
178
- const oldRecord: any = {
179
- id: TLINSTANCE_ID,
180
- typeName: 'instance',
181
- dialog: 'some-dialog',
182
- otherProp: 'keep-me',
183
- }
184
- const result = migration.up(oldRecord)
185
-
186
- expect((result as any).dialog).toBeUndefined()
187
- expect((result as any).otherProp).toBe('keep-me')
188
- })
189
-
190
- it('should have bidirectional migrations where applicable', () => {
191
- const addInsetMigration = instanceMigrations.sequence.find(
192
- (m) => m.id === instanceVersions.AddInset
193
- )!
194
- expect(addInsetMigration.down).toBeDefined()
195
-
196
- const removeCameraMigration = instanceMigrations.sequence.find(
197
- (m) => m.id === instanceVersions.RemoveCanMoveCamera
198
- )!
199
- expect(removeCameraMigration.down).toBeDefined()
200
- })
201
- })
@@ -1,110 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import {
3
- isPageId,
4
- pageIdValidator,
5
- pageMigrations,
6
- PageRecordType,
7
- pageValidator,
8
- pageVersions,
9
- TLPageId,
10
- } from './TLPage'
11
-
12
- describe('pageIdValidator', () => {
13
- it('should validate correct page IDs', () => {
14
- expect(() => pageIdValidator.validate('page:main')).not.toThrow()
15
- expect(() => pageIdValidator.validate('page:page1')).not.toThrow()
16
- })
17
-
18
- it('should reject invalid page IDs', () => {
19
- expect(() => pageIdValidator.validate('invalid')).toThrow()
20
- expect(() => pageIdValidator.validate('shape:page1')).toThrow()
21
- expect(() => pageIdValidator.validate('')).toThrow()
22
- })
23
- })
24
-
25
- describe('pageValidator', () => {
26
- it('should validate valid page records', () => {
27
- const validPage = {
28
- typeName: 'page',
29
- id: 'page:test' as TLPageId,
30
- name: 'Test Page',
31
- index: 'a1' as any,
32
- meta: {},
33
- }
34
-
35
- expect(() => pageValidator.validate(validPage)).not.toThrow()
36
- })
37
-
38
- it('should reject pages with invalid typeName', () => {
39
- const invalidPage = {
40
- typeName: 'not-page',
41
- id: 'page:test' as TLPageId,
42
- name: 'Test',
43
- index: 'a1' as any,
44
- meta: {},
45
- }
46
-
47
- expect(() => pageValidator.validate(invalidPage)).toThrow()
48
- })
49
-
50
- it('should reject pages with missing required fields', () => {
51
- const incompletePages = [
52
- {
53
- typeName: 'page',
54
- id: 'page:test' as TLPageId,
55
- // missing name, index, meta
56
- },
57
- {
58
- typeName: 'page',
59
- id: 'page:test' as TLPageId,
60
- name: 'Test',
61
- // missing index, meta
62
- },
63
- ]
64
-
65
- incompletePages.forEach((page) => {
66
- expect(() => pageValidator.validate(page)).toThrow()
67
- })
68
- })
69
- })
70
-
71
- describe('pageMigrations', () => {
72
- it('should apply AddMeta migration correctly', () => {
73
- const addMetaMigration = pageMigrations.sequence.find((m) => m.id === pageVersions.AddMeta)!
74
-
75
- const oldRecord: any = {
76
- typeName: 'page',
77
- id: 'page:test',
78
- name: 'Test Page',
79
- index: 'a1',
80
- }
81
-
82
- addMetaMigration.up(oldRecord)
83
- expect(oldRecord.meta).toEqual({})
84
- })
85
- })
86
-
87
- describe('PageRecordType', () => {
88
- it('should create page records with defaults', () => {
89
- const page = PageRecordType.create({
90
- id: 'page:test' as TLPageId,
91
- name: 'Test Page',
92
- index: 'a1' as any,
93
- })
94
-
95
- expect(page.meta).toEqual({})
96
- })
97
- })
98
-
99
- describe('isPageId', () => {
100
- it('should return true for valid page IDs', () => {
101
- expect(isPageId('page:main')).toBe(true)
102
- expect(isPageId('page:page1')).toBe(true)
103
- })
104
-
105
- it('should return false for invalid page IDs', () => {
106
- expect(isPageId('shape:main')).toBe(false)
107
- expect(isPageId('invalid')).toBe(false)
108
- expect(isPageId('')).toBe(false)
109
- })
110
- })