iikanji
This commit is contained in:
parent
c7902feb49
commit
71783d8f06
|
@ -13,6 +13,30 @@ export function correctAcct(acct: Acct, localHostname?: string): Acct {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parse(acct: string): Acct {
|
||||||
|
let acctWithNoPrefix = acct;
|
||||||
|
|
||||||
|
if (acct.startsWith('@')) {
|
||||||
|
acctWithNoPrefix = acct.substring(1);
|
||||||
|
} else if (acct.startsWith('acct:')) {
|
||||||
|
acctWithNoPrefix = acct.substring(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
const split = acctWithNoPrefix.split('@', 2);
|
||||||
|
|
||||||
|
return { username: split[0], host: split[1] || null };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseUrl(str: string): Acct {
|
||||||
|
const url = new URL(str);
|
||||||
|
const path = url.pathname.split('/').find((p) => p.startsWith('@') && p.length >= 2);
|
||||||
|
if (!path) throw new Error('This url is not acct like.');
|
||||||
|
|
||||||
|
const split = path.split('@', 3); // ['', 'username', 'other.example.com']
|
||||||
|
|
||||||
|
return { username: split[1], host: split[2] || url.hostname };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a string and returns an Acct object.
|
* Parses a string and returns an Acct object.
|
||||||
* @param acct String to parse
|
* @param acct String to parse
|
||||||
|
@ -23,30 +47,14 @@ export function correctAcct(acct: Acct, localHostname?: string): Acct {
|
||||||
* @param localHostname If provided and matches the host found in acct, the returned `host` will be set to `null`.
|
* @param localHostname If provided and matches the host found in acct, the returned `host` will be set to `null`.
|
||||||
* @returns Acct object
|
* @returns Acct object
|
||||||
*/
|
*/
|
||||||
export function parse(acct: string, localHostname?: string): Acct {
|
export function parseAcctOrUrl(acct: string, localHostname?: string): Acct {
|
||||||
//#region url style
|
|
||||||
if (acct.startsWith('https://') || acct.startsWith('http://')) {
|
if (acct.startsWith('https://') || acct.startsWith('http://')) {
|
||||||
const url = new URL(acct);
|
// url style
|
||||||
const path = url.pathname.split('/').find((p) => p.startsWith('@') && p.length >= 2);
|
return correctAcct(parseUrl(acct), localHostname);
|
||||||
if (!path) throw new Error('This url is not acct like.');
|
|
||||||
|
|
||||||
const split = path.split('@', 3); // ['', 'username', 'other.example.com']
|
|
||||||
|
|
||||||
return correctAcct({ username: split[1], host: split[2] || url.hostname }, localHostname);
|
|
||||||
}
|
}
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region at-mark and acct: style
|
// acct style
|
||||||
let acctWithNoPrefix = acct;
|
return correctAcct(parse(acct), localHostname);
|
||||||
if (acct.startsWith('@')) {
|
|
||||||
acctWithNoPrefix = acct.substring(1);
|
|
||||||
} else if (acct.startsWith('acct:')) {
|
|
||||||
acctWithNoPrefix = acct.substring(5);
|
|
||||||
}
|
|
||||||
const split = acctWithNoPrefix.split('@', 2);
|
|
||||||
|
|
||||||
return correctAcct({ username: split[0], host: split[1] || null }, localHostname);
|
|
||||||
//#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toString(acct: Acct): string {
|
export function toString(acct: Acct): string {
|
||||||
|
|
|
@ -1,64 +1,96 @@
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import * as acct from '../src/acct.js';
|
import * as acct from '../src/acct.js';
|
||||||
|
|
||||||
describe('acct.parse', () => {
|
function testParseAcct(fn: (acct: string) => acct.Acct) {
|
||||||
it('parses plain username', () => {
|
it('parses plain username', () => {
|
||||||
const res = acct.parse('alice');
|
const res = fn('alice');
|
||||||
expect(res).toEqual({ username: 'alice', host: null });
|
expect(res).toEqual({ username: 'alice', host: null });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses at-mark style without host', () => {
|
it('parses at-mark style without host', () => {
|
||||||
const res = acct.parse('@alice');
|
const res = fn('@alice');
|
||||||
expect(res).toEqual({ username: 'alice', host: null });
|
expect(res).toEqual({ username: 'alice', host: null });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses at-mark style with host', () => {
|
it('parses at-mark style with host', () => {
|
||||||
const res = acct.parse('@alice@example.com');
|
const res = fn('@alice@example.com');
|
||||||
expect(res).toEqual({ username: 'alice', host: 'example.com' });
|
expect(res).toEqual({ username: 'alice', host: 'example.com' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nulls host for at-mark style when localHostname matches', () => {
|
|
||||||
const res = acct.parse('@alice@example.com', 'example.com');
|
|
||||||
expect(res).toEqual({ username: 'alice', host: null });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('parses acct: style', () => {
|
it('parses acct: style', () => {
|
||||||
const res = acct.parse('acct:alice@example.com');
|
const res = fn('acct:alice@example.com');
|
||||||
expect(res).toEqual({ username: 'alice', host: 'example.com' });
|
expect(res).toEqual({ username: 'alice', host: 'example.com' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nulls host for acct: style when localHostname matches', () => {
|
it('parse Mr.http', () => {
|
||||||
const res = acct.parse('acct:alice@example.com', 'example.com');
|
const res = fn('http');
|
||||||
expect(res).toEqual({ username: 'alice', host: null });
|
expect(res).toEqual({ username: 'http', host: null });
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function testParseUrl(fn: (acct: string) => acct.Acct) {
|
||||||
it('parses url style https with same host -> host kept when localHostname not provided', () => {
|
it('parses url style https with same host -> host kept when localHostname not provided', () => {
|
||||||
const res = acct.parse('https://example.com/@alice');
|
const res = fn('https://example.com/@alice');
|
||||||
expect(res).toEqual({ username: 'alice', host: 'example.com' });
|
expect(res).toEqual({ username: 'alice', host: 'example.com' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses url style http with same host and nulls host when localHostname matches', () => {
|
|
||||||
const res = acct.parse('http://example.com/@alice', 'example.com');
|
|
||||||
expect(res).toEqual({ username: 'alice', host: null });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('parses url style with remote host contained in path', () => {
|
it('parses url style with remote host contained in path', () => {
|
||||||
const res = acct.parse('https://self.example.com/@alice@other.example.com');
|
const res = fn('https://self.example.com/@alice@other.example.com');
|
||||||
expect(res).toEqual({ username: 'alice', host: 'other.example.com' });
|
expect(res).toEqual({ username: 'alice', host: 'other.example.com' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('nulls host when localHostname matches the remote host in path', () => {
|
it('throws on non-acct-like url path', () => {
|
||||||
const res = acct.parse('https://self.example.com/@alice@other.example.com', 'other.example.com');
|
expect(() => fn('https://example.com/users/alice')).toThrowError();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('acct.parse', () => {
|
||||||
|
testParseAcct(acct.parse);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('acct.parseUrl', () => {
|
||||||
|
testParseUrl(acct.parseUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('acct.parseAcctOrUrl', () => {
|
||||||
|
testParseAcct(acct.parseAcctOrUrl);
|
||||||
|
testParseUrl(acct.parseAcctOrUrl);
|
||||||
|
|
||||||
|
it('parse url with localHostname', () => {
|
||||||
|
const res = acct.parseAcctOrUrl('https://example.com/@alice', 'example.com');
|
||||||
expect(res).toEqual({ username: 'alice', host: null });
|
expect(res).toEqual({ username: 'alice', host: null });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws on non-acct-like url path', () => {
|
it('parse @username with localHostname', () => {
|
||||||
expect(() => acct.parse('https://example.com/users/alice')).toThrowError();
|
const res = acct.parseAcctOrUrl('@alice', 'example.com');
|
||||||
|
expect(res).toEqual({ username: 'alice', host: null });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses correctly Mr.http', () => {
|
describe('acct.correctAcct', () => {
|
||||||
const res = acct.parse('http');
|
it('returns host=null when acct.host is null', () => {
|
||||||
expect(res).toEqual({ username: 'http', host: null });
|
const input: acct.Acct = { username: 'alice', host: null };
|
||||||
|
const out = acct.correctAcct(input);
|
||||||
|
expect(out).toEqual({ username: 'alice', host: null });
|
||||||
|
expect(out).not.toBe(input); // immutability
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps host when localHostname not provided', () => {
|
||||||
|
const input: acct.Acct = { username: 'bob', host: 'example.com' };
|
||||||
|
const out = acct.correctAcct(input);
|
||||||
|
expect(out).toEqual({ username: 'bob', host: 'example.com' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('nulls host when it matches localHostname', () => {
|
||||||
|
const input: acct.Acct = { username: 'carol', host: 'example.com' };
|
||||||
|
const out = acct.correctAcct(input, 'example.com');
|
||||||
|
expect(out).toEqual({ username: 'carol', host: null });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps host when it differs from localHostname', () => {
|
||||||
|
const input: acct.Acct = { username: 'dave', host: 'other.example.com' };
|
||||||
|
const out = acct.correctAcct(input, 'example.com');
|
||||||
|
expect(out).toEqual({ username: 'dave', host: 'other.example.com' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue