mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
87f2fd15fb
Summary: * Extends `/api/docs/docId1/compare/docId2` endpoint with a `detail=1` option to include details of what changed in the document content. * Adds an `/api/docs/docId/compare?left=HASH&right=HASH` endpoint for comparing two versions of a single document. This is needed to implement the extension to `/api/docs/docId1/compare/docId2`. * Adds a `HashUtil` class to allow hash aliases like `HEAD` and `HEAD~`. Everything is a bit crude: * Changes are expressed as ActionSummary objects, which aren't fully fleshed out. * Extra data about formula columns is inserted in an inflexible way. This is extracted and cleaned up from https://phab.getgrist.com/D2600. Test Plan: added tests Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2614
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { DocState } from 'app/common/UserAPI';
|
|
|
|
/**
|
|
*
|
|
* Helper class to support a small subset of git-style references for state hashes:
|
|
* HEAD = the most recent state
|
|
* [HASH]^1 = the parent of [HASH]
|
|
* [HASH]~1 = the parent of [HASH]
|
|
* [HASH]~2 = the grandparent of [HASH]
|
|
* [HASH]^1^1 = the grandparent of [HASH]
|
|
* [HASH]~3 = the great grandparent of [HASH]
|
|
* For git, where commits have multiple parents, "~" refers to the first parent,
|
|
* and "^1" also refers to the first parent. For grist, there are only first parents
|
|
* (unless/until we start tracking history across merges).
|
|
*
|
|
*/
|
|
export class HashUtil {
|
|
|
|
/**
|
|
* To construct, provide a list of states, most recent first.
|
|
*/
|
|
constructor(private _state: DocState[]) {}
|
|
|
|
/**
|
|
* Find the named hash in the list of states, allowing for aliases.
|
|
* Returns an index into the list of states provided in constructor.
|
|
*/
|
|
public hashToOffset(hash: string): number {
|
|
const parts = hash.split(/([~^][0-9]*)/);
|
|
hash = parts.shift() || '';
|
|
let offset = hash === 'HEAD' ? 0 : this._state.findIndex(state => state.h === hash);
|
|
if (offset < 0) { throw new Error('Cannot read hash'); }
|
|
for (const part of parts) {
|
|
if (part === '^' || part === '^1') {
|
|
offset++;
|
|
} else if (part.startsWith('~')) {
|
|
offset += parseInt(part.slice(1) || '1', 10);
|
|
} else if (part === '') {
|
|
// pass
|
|
} else {
|
|
throw new Error('cannot parse hash');
|
|
}
|
|
}
|
|
return offset;
|
|
}
|
|
}
|