mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
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;
|
||
|
}
|
||
|
}
|