diff --git a/libraries/overleaf-editor-core/lib/schemas.js b/libraries/overleaf-editor-core/lib/schemas.js index c6912d9c6c..765312aa1d 100644 --- a/libraries/overleaf-editor-core/lib/schemas.js +++ b/libraries/overleaf-editor-core/lib/schemas.js @@ -38,7 +38,7 @@ const rawRetainOp = z.union([ const rawScanOp = z.union([rawInsertOp, rawRemoveOp, rawRetainOp]) const rawTextOperation = z.strictObject({ - textOperation: z.array(rawScanOp).min(1), + textOperation: z.array(rawScanOp), contentHash: z.string().optional(), }) @@ -151,19 +151,27 @@ const rawBlobHash = z.string().regex(/^[0-9a-f]{40}$/, { message: 'invalid blob hash', }) -// file metadata is the linked-file metadata written by web, the main-file -// marker written by the v1 history import, regular file with importedAt, -// or an empty object (metadata cleared) const rawFileMetadata = z.union([ + // doc/clear metadata + z.strictObject({}), + // regular file v2 + z.strictObject({ + importedAt: z.iso.datetime(), + }), + // linked-file v2 rawLinkedFileData, + + // main-file v1 z.strictObject({ main: z.boolean(), importedAt: z.iso.datetime().optional(), }), + // url import v1 z.strictObject({ - importedAt: z.iso.datetime(), + agent: z.literal('url'), + agentDataId: z.number(), + importedAt: z.iso.datetime().optional(), }), - z.strictObject({}), ]) const rawHashFileData = z.strictObject({ diff --git a/libraries/overleaf-editor-core/test/unit/schemas.test.js b/libraries/overleaf-editor-core/test/unit/schemas.test.js index 4936e0a33f..94f8a9fbb6 100644 --- a/libraries/overleaf-editor-core/test/unit/schemas.test.js +++ b/libraries/overleaf-editor-core/test/unit/schemas.test.js @@ -3,9 +3,19 @@ const { rawLinkedFileData, rawFileMetadata, rawRetainOp, + rawTextOperation, } = require('../../lib/schemas') describe('schemas', function () { + describe('rawTextOperation', function () { + it('accepts a no-op TextOperation', function () { + const result = rawTextOperation.safeParse({ + textOperation: [], + }) + expect(result.success).to.equal(true) + }) + }) + describe('rawRetainOp', function () { it('accepts a bare retain length', function () { const result = rawRetainOp.safeParse(5) @@ -203,6 +213,14 @@ describe('schemas', function () { expect(result.success).to.equal(true) }) + it('accepts a legacy v1 url import', function () { + const result = rawFileMetadata.safeParse({ + agent: 'url', + agentDataId: 42, + }) + expect(result.success).to.equal(true) + }) + it('accepts a legacy v1 main flag with an importedAt timestamp', function () { const result = rawFileMetadata.safeParse({ main: true,