mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-13 05:33:43 +01:00
* [editor-core] share the pieces the editor, real-time and history-v1 all need Project-level history-OT has the browser, real-time and history-v1 all reason about the same changes, so the rules they reason with move into the shared library rather than being reimplemented on each side. - `origin/editor_origin.js` plus `EDITOR_ORIGIN_KIND` and its schema entry: the origin an editor client's change carries, holding the editorId that scopes a change's timestamp. - `change_identity.js`: how a submission is recognised when it comes back, so a resend of a change that already landed is deduplicated rather than applied twice. - `rebase.js`: transforming a change onto concurrent ones, in the same order on both sides, which is what lets the server acknowledge a change with only the version it landed at. - `text_file_defaults.js`: the doc-vs-file extension lists, now read from here by web's settings instead of being spelled out again. - `blob_string_length.js`: the string length of a blob, used by history-v1's blob store and by web when it writes an uploaded file into history. - `file_tree_diff.js`: file-tree operations to a diff, used by project-history's FileTreeDiffGenerator. - `Blob.EMPTY_HASH`, so callers can answer for the empty blob without storing it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [project-history] build the file-tree diff with the shared helper FileTreeDiffGenerator's hand-rolled walk over add/edit/move/delete operations becomes a call to `buildFileTreeDiff` from overleaf-editor-core, so the editor and project-history read a file-tree change the same way. Adds the unit tests the decaffeinated original never had. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [web] read the editable-file lists from overleaf-editor-core web's settings spelled out the text extensions and editable filenames that decide whether a file becomes a doc, and every other service that has to make that call carried its own copy. The lists now live in overleaf-editor-core and web builds settings.textExtensions and settings.editableFilenames from them, keeping the ADDITIONAL_TEXT_EXTENSIONS override for Server CE/Pro on top. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [history-v1] read a blob's string length from overleaf-editor-core Two copies of getStringLengthOfFile lived here, the one in recover_zip.js carrying a TODO asking for exactly this. Both now import the shared implementation, which the blob store keeps re-exporting for backupArchiver. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> GitOrigin-RevId: 31948332f416f56848e3b0dfb5142a4c9f93f508
122 lines
3.2 KiB
JavaScript
122 lines
3.2 KiB
JavaScript
'use strict'
|
|
|
|
const assert = require('check-types').assert
|
|
const OError = require('@overleaf/o-error')
|
|
|
|
const TextOperation = require('./operation/text_operation')
|
|
|
|
class NotFoundError extends OError {
|
|
constructor(hash) {
|
|
super(`blob ${hash} not found`, { hash })
|
|
this.hash = hash
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Metadata record for the content of a file.
|
|
*/
|
|
class Blob {
|
|
static HEX_HASH_RX_STRING = '^[0-9a-f]{40,40}$'
|
|
static HEX_HASH_RX = new RegExp(Blob.HEX_HASH_RX_STRING)
|
|
|
|
/**
|
|
* Size of the largest file that we'll read to determine whether we can edit it
|
|
* or not, in bytes. The final decision on whether a file is editable or not is
|
|
* based on the number of characters it contains, but we need to read the file
|
|
* in to determine that; so it is useful to have an upper bound on the byte
|
|
* length of a file that might be editable.
|
|
*
|
|
* The reason for the factor of 3 is as follows. We cannot currently edit files
|
|
* that contain characters outside of the basic multilingual plane, so we're
|
|
* limited to characters that can be represented in a single, two-byte UCS-2
|
|
* code unit. Encoding the largest such value, 0xFFFF (which is not actually
|
|
* a valid character), takes three bytes in UTF-8: 0xEF 0xBF 0xBF. A file
|
|
* composed entirely of three-byte UTF-8 codepoints is the worst case; in
|
|
* practice, this is a very conservative upper bound.
|
|
*
|
|
* @type {number}
|
|
*/
|
|
static MAX_EDITABLE_BYTE_LENGTH_BOUND = 3 * TextOperation.MAX_STRING_LENGTH
|
|
|
|
/**
|
|
* The hash of empty content, which is the same for every project.
|
|
*
|
|
* git's hash of an empty blob, as `blobHash` computes it: it is a property of the
|
|
* content rather than of anything stored, so it can be recognised without looking
|
|
* anything up. `File.EMPTY_FILE_HASH` is the same value under the name a file's
|
|
* content goes by.
|
|
*
|
|
* @type {string}
|
|
*/
|
|
static EMPTY_HASH = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'
|
|
|
|
static NotFoundError = NotFoundError
|
|
|
|
/**
|
|
* @param {string} hash
|
|
* @param {number} byteLength
|
|
* @param {number} [stringLength]
|
|
*/
|
|
constructor(hash, byteLength, stringLength) {
|
|
this.setHash(hash)
|
|
this.setByteLength(byteLength)
|
|
this.setStringLength(stringLength)
|
|
}
|
|
|
|
static fromRaw(raw) {
|
|
if (raw) {
|
|
return new Blob(raw.hash, raw.byteLength, raw.stringLength)
|
|
}
|
|
return null
|
|
}
|
|
|
|
toRaw() {
|
|
return {
|
|
hash: this.hash,
|
|
byteLength: this.byteLength,
|
|
stringLength: this.stringLength,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hex hash.
|
|
* @return {String}
|
|
*/
|
|
getHash() {
|
|
return this.hash
|
|
}
|
|
|
|
setHash(hash) {
|
|
assert.match(hash, Blob.HEX_HASH_RX, 'bad hash')
|
|
this.hash = hash
|
|
}
|
|
|
|
/**
|
|
* Length of the blob in bytes.
|
|
* @return {number}
|
|
*/
|
|
getByteLength() {
|
|
return this.byteLength
|
|
}
|
|
|
|
setByteLength(byteLength) {
|
|
assert.integer(byteLength, 'bad byteLength')
|
|
this.byteLength = byteLength
|
|
}
|
|
|
|
/**
|
|
* Utf-8 length of the blob content, if it appears to be valid UTF-8.
|
|
* @return {number|undefined}
|
|
*/
|
|
getStringLength() {
|
|
return this.stringLength
|
|
}
|
|
|
|
setStringLength(stringLength) {
|
|
assert.maybe.integer(stringLength, 'bad stringLength')
|
|
this.stringLength = stringLength
|
|
}
|
|
}
|
|
|
|
module.exports = Blob
|