feat(misskey-js): acct.parseがURLを受け付けるように, acct.tsのテストを追加
This commit is contained in:
parent
76beac41d2
commit
14f5456ef0
|
@ -3,11 +3,50 @@ export type Acct = {
|
|||
host: string | null;
|
||||
};
|
||||
|
||||
export function parse(_acct: string): Acct {
|
||||
let acct = _acct;
|
||||
if (acct.startsWith('@')) acct = acct.substring(1);
|
||||
const split = acct.split('@', 2);
|
||||
return { username: split[0], host: split[1] || null };
|
||||
/**
|
||||
* Parses a string and returns an Acct object.
|
||||
* @param acct String to parse
|
||||
* The string should be in one of the following formats:
|
||||
* * At-mark style: `@username@example.com`
|
||||
* * Starts with `acct:`: `acct:username@example.com`
|
||||
* * URL style: `https://example.com/@username`, `https://self.example.com/@username@other.example.com`
|
||||
* @param localHostname If provided and matches the host found in acct, the returned `host` will be set to `null`.
|
||||
* @returns Acct object
|
||||
*/
|
||||
export function parse(acct: string, localHostname?: string): Acct {
|
||||
//#region url style
|
||||
if (acct.startsWith('https://') || acct.startsWith('http://')) {
|
||||
const url = new URL(acct);
|
||||
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']
|
||||
|
||||
let host: string | null = split[2] || url.hostname;
|
||||
if (localHostname && host === localHostname) {
|
||||
host = null;
|
||||
}
|
||||
|
||||
return { username: split[1], host: host };
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region at-mark and acct: style
|
||||
let acctWithNoPrefix = acct;
|
||||
if (acct.startsWith('@')) {
|
||||
acctWithNoPrefix = acct.substring(1);
|
||||
} else if (acct.startsWith('acct:')) {
|
||||
acctWithNoPrefix = acct.substring(5);
|
||||
}
|
||||
const split = acctWithNoPrefix.split('@', 2);
|
||||
|
||||
let host: string | null = split[1] || null;
|
||||
if (localHostname && host === localHostname) {
|
||||
host = null;
|
||||
}
|
||||
|
||||
return { username: split[0], host };
|
||||
//#endregion
|
||||
}
|
||||
|
||||
export function toString(acct: Acct): string {
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import * as acct from '../src/acct.js';
|
||||
|
||||
describe('acct.parse', () => {
|
||||
it('parses plain username', () => {
|
||||
const res = acct.parse('alice');
|
||||
expect(res).toEqual({ username: 'alice', host: null });
|
||||
});
|
||||
|
||||
it('parses at-mark style without host', () => {
|
||||
const res = acct.parse('@alice');
|
||||
expect(res).toEqual({ username: 'alice', host: null });
|
||||
});
|
||||
|
||||
it('parses at-mark style with host', () => {
|
||||
const res = acct.parse('@alice@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', () => {
|
||||
const res = acct.parse('acct:alice@example.com');
|
||||
expect(res).toEqual({ username: 'alice', host: 'example.com' });
|
||||
});
|
||||
|
||||
it('nulls host for acct: style when localHostname matches', () => {
|
||||
const res = acct.parse('acct:alice@example.com', 'example.com');
|
||||
expect(res).toEqual({ username: 'alice', host: null });
|
||||
});
|
||||
|
||||
it('parses url style https with same host -> host kept when localHostname not provided', () => {
|
||||
const res = acct.parse('https://example.com/@alice');
|
||||
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', () => {
|
||||
const res = acct.parse('https://self.example.com/@alice@other.example.com');
|
||||
expect(res).toEqual({ username: 'alice', host: 'other.example.com' });
|
||||
});
|
||||
|
||||
it('nulls host when localHostname matches the remote host in path', () => {
|
||||
const res = acct.parse('https://self.example.com/@alice@other.example.com', 'other.example.com');
|
||||
expect(res).toEqual({ username: 'alice', host: null });
|
||||
});
|
||||
|
||||
it('throws on non-acct-like url path', () => {
|
||||
expect(() => acct.parse('https://example.com/users/alice')).toThrowError();
|
||||
});
|
||||
|
||||
it('parses correctly Mr.http', () => {
|
||||
const res = acct.parse('http');
|
||||
expect(res).toEqual({ username: 'http', host: null });
|
||||
});
|
||||
});
|
||||
|
||||
describe('acct.toString', () => {
|
||||
it('returns username when host is null', () => {
|
||||
expect(acct.toString({ username: 'alice', host: null })).toBe('alice');
|
||||
});
|
||||
|
||||
it('returns username@host when host exists', () => {
|
||||
expect(acct.toString({ username: 'alice', host: 'example.com' })).toBe('alice@example.com');
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue