mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-21 03:56:23 +08:00
feat(nbstore): improve nbstore (#9512)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`parseUniversalId > should parse universal id > @peer(@name);@type(userspace);@id(@id); 1`] = `
|
||||
{
|
||||
"id": "@id",
|
||||
"peer": "@name",
|
||||
"type": "userspace",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseUniversalId > should parse universal id > @peer(@peer(name);@type(userspace);@id(@id); 1`] = `
|
||||
{
|
||||
"id": "@id",
|
||||
"peer": "@peer(name",
|
||||
"type": "userspace",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseUniversalId > should parse universal id > @peer(123);@type(userspace);@id(456); 1`] = `
|
||||
{
|
||||
"id": "456",
|
||||
"peer": "123",
|
||||
"type": "userspace",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseUniversalId > should parse universal id > @peer(123);@type(workspace);@id(456); 1`] = `
|
||||
{
|
||||
"id": "456",
|
||||
"peer": "123",
|
||||
"type": "workspace",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseUniversalId > should parse universal id > @peer(https://app.affine.pro);@type(userspace);@id(hello:world); 1`] = `
|
||||
{
|
||||
"id": "hello:world",
|
||||
"peer": "https://app.affine.pro",
|
||||
"type": "userspace",
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { parseUniversalId, universalId } from '../universal-id';
|
||||
|
||||
describe('parseUniversalId', () => {
|
||||
it('should generate universal id', () => {
|
||||
expect(universalId({ peer: '123', type: 'workspace', id: '456' })).toEqual(
|
||||
'@peer(123);@type(workspace);@id(456);'
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse universal id', () => {
|
||||
const testcases = [
|
||||
'@peer(123);@type(userspace);@id(456);',
|
||||
'@peer(123);@type(workspace);@id(456);',
|
||||
'@peer(https://app.affine.pro);@type(userspace);@id(hello:world);',
|
||||
'@peer(@name);@type(userspace);@id(@id);',
|
||||
'@peer(@peer(name);@type(userspace);@id(@id);',
|
||||
];
|
||||
|
||||
testcases.forEach(id => {
|
||||
expect(parseUniversalId(id)).toMatchSnapshot(id);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw invalid universal id', () => {
|
||||
const testcases = [
|
||||
'@peer(123);@type(anyspace);@id(456);', // invalid space type
|
||||
'@peer(@peer(name););@type(userspace);@id(@id);', // invalid peer
|
||||
];
|
||||
|
||||
testcases.forEach(id => {
|
||||
expect(() => parseUniversalId(id)).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
export type SpaceType = 'workspace' | 'userspace';
|
||||
|
||||
export function universalId({
|
||||
peer,
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
peer: string;
|
||||
type: SpaceType;
|
||||
id: string;
|
||||
}) {
|
||||
return `@peer(${peer});@type(${type});@id(${id});`;
|
||||
}
|
||||
|
||||
export function isValidSpaceType(type: string): type is SpaceType {
|
||||
return type === 'workspace' || type === 'userspace';
|
||||
}
|
||||
|
||||
export function isValidUniversalId(opts: Record<string, string>): boolean {
|
||||
const requiredKeys = ['peer', 'type', 'id'] as const;
|
||||
|
||||
for (const key of requiredKeys) {
|
||||
if (!opts[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return isValidSpaceType(opts.type);
|
||||
}
|
||||
|
||||
export function parseUniversalId(id: string): {
|
||||
peer: string;
|
||||
type: SpaceType;
|
||||
id: string;
|
||||
} {
|
||||
const result: Partial<{
|
||||
peer: string;
|
||||
type: SpaceType;
|
||||
id: string;
|
||||
}> = {};
|
||||
let key = '';
|
||||
let value = '';
|
||||
let isInValue = false;
|
||||
|
||||
let i = -1;
|
||||
|
||||
while (++i < id.length) {
|
||||
const ch = id[i];
|
||||
const nextCh = id[i + 1];
|
||||
|
||||
// when we are in value string, we only care about ch and next char to be [')', ';'] to end the id part
|
||||
if (isInValue) {
|
||||
if (ch === ')' && nextCh === ';') {
|
||||
// @ts-expect-error we know the key is valid
|
||||
result[key] = value;
|
||||
key = '';
|
||||
value = '';
|
||||
isInValue = false;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
value += ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '@') {
|
||||
const keyEnd = id.indexOf('(', i);
|
||||
// we find '@' but no '(' in lookahead or '(' is immediately after '@', invalid id
|
||||
if (keyEnd === -1 || keyEnd === i + 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
key = id.slice(i + 1, keyEnd);
|
||||
i = keyEnd;
|
||||
isInValue = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValidUniversalId(result)) {
|
||||
throw new Error(
|
||||
`Invalid universal storage id: ${id}. It should be in format of @peer(\${peer});@type(\${type});@id(\${id});`
|
||||
);
|
||||
}
|
||||
|
||||
return result as {
|
||||
peer: string;
|
||||
type: SpaceType;
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user