done
This commit is contained in:
parent
debce10b6c
commit
3a14c72060
11
package.json
11
package.json
|
|
@ -7,12 +7,20 @@
|
|||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "ts-node -r tsconfig-paths/register src/index.ts",
|
||||
"test": "ts-node -r tsconfig-paths/register tests/index.ts",
|
||||
"debug": "node --inspect-brk dist/index.js",
|
||||
"lint": "eslint ./src --ext .ts --fix",
|
||||
"format": "prettier --write ./src",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"keywords": ["nodejs", "typescript", "eslint", "prettier", "husky", "template"],
|
||||
"keywords": [
|
||||
"nodejs",
|
||||
"typescript",
|
||||
"eslint",
|
||||
"prettier",
|
||||
"husky",
|
||||
"template"
|
||||
],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
|
|
@ -31,6 +39,7 @@
|
|||
"typescript": "5.8.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"socket.io": "^4.8.1",
|
||||
"tsconfig-paths": "^4.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
113
src/index.ts
113
src/index.ts
|
|
@ -1,2 +1,111 @@
|
|||
import utils from '@/utils';
|
||||
console.log(utils.isPrime(7));
|
||||
import { createServer } from 'http';
|
||||
import { Server, Socket } from 'socket.io';
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
username?: string; // Optional username
|
||||
}
|
||||
|
||||
const httpServer = createServer();
|
||||
const io = new Server(httpServer, {
|
||||
cors: {
|
||||
origin: '*', // Restrict in production!
|
||||
methods: ['GET', 'POST'],
|
||||
},
|
||||
});
|
||||
|
||||
const users: { [roomId: string]: User[] } = {}; // Store users per room
|
||||
|
||||
io.on('connection', (socket: Socket) => {
|
||||
console.log(`User connected: ${socket.id}`);
|
||||
|
||||
socket.on('disconnect', (reason) => {
|
||||
console.log(`User disconnected: ${socket.id} (Reason: ${reason})`);
|
||||
// Remove user from any rooms they were in
|
||||
for (const roomId in users) {
|
||||
removeUserFromRoom(socket.id, roomId);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('message', (msg) => {
|
||||
console.log(`Message from ${socket.id}: ${msg}`);
|
||||
// Get the room the user is in (if any)
|
||||
const userRooms = Array.from(socket.rooms).filter(
|
||||
(room) => room !== socket.id,
|
||||
); // Exclude the socket's own room
|
||||
if (userRooms.length > 0) {
|
||||
const roomId = userRooms[0]; // Assuming user is only in one room for now
|
||||
io.to(roomId).emit('message', {
|
||||
user: getUserInfo(socket.id, roomId),
|
||||
message: msg,
|
||||
}); // Send username with message
|
||||
} else {
|
||||
socket.emit('message', {
|
||||
user: getUserInfo(socket.id),
|
||||
message: msg,
|
||||
}); // If not in a room, send back to sender only
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('newMessage', (msg) => {
|
||||
console.log(`Received newMessage from ${socket.id}: ${msg}`);
|
||||
socket.emit('replay', msg); // Send back the same message with 'replay' event
|
||||
});
|
||||
|
||||
socket.on('joinRoom', (roomName, username) => {
|
||||
if (!users[roomName]) {
|
||||
users[roomName] = [];
|
||||
}
|
||||
socket.join(roomName);
|
||||
users[roomName].push({ id: socket.id, username });
|
||||
console.log(`${username || socket.id} joined room: ${roomName}`);
|
||||
socket.to(roomName).emit('userJoined', {
|
||||
user: getUserInfo(socket.id, roomName),
|
||||
message: `${username || socket.id} joined ${roomName}`,
|
||||
});
|
||||
io.to(roomName).emit('userList', getUsersInRoom(roomName)); // Send updated user list to the room
|
||||
});
|
||||
|
||||
socket.on('leaveRoom', (roomName) => {
|
||||
removeUserFromRoom(socket.id, roomName);
|
||||
socket.leave(roomName);
|
||||
console.log(
|
||||
`${getUserInfo(socket.id)?.username || socket.id} left room: ${roomName}`,
|
||||
);
|
||||
io.to(roomName).emit('userLeft', {
|
||||
user: getUserInfo(socket.id, roomName),
|
||||
message: `${getUserInfo(socket.id)?.username || socket.id} left ${roomName}`,
|
||||
});
|
||||
io.to(roomName).emit('userList', getUsersInRoom(roomName)); // Send updated user list
|
||||
});
|
||||
});
|
||||
|
||||
const port = 3000;
|
||||
httpServer.listen(port, () => {
|
||||
console.log(`listening on *:${port}`);
|
||||
});
|
||||
|
||||
function getUserInfo(userId: string, roomId?: string): User | undefined {
|
||||
if (roomId && users[roomId]) {
|
||||
return users[roomId].find((user) => user.id === userId);
|
||||
} else {
|
||||
// If no roomId is provided, try to find the user in any room (less efficient)
|
||||
for (const room in users) {
|
||||
const user = users[room].find((user) => user.id === userId);
|
||||
if (user) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
return { id: userId }; // Return a basic user object if not found in any room
|
||||
}
|
||||
}
|
||||
|
||||
function getUsersInRoom(roomId: string): User[] {
|
||||
return users[roomId] || [];
|
||||
}
|
||||
|
||||
function removeUserFromRoom(userId: string, roomId: string) {
|
||||
if (users[roomId]) {
|
||||
users[roomId] = users[roomId].filter((user) => user.id !== userId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,618 @@
|
|||
interface ParsedURL {
|
||||
anchor: string;
|
||||
authority: string;
|
||||
directory: string;
|
||||
file: string;
|
||||
host: string;
|
||||
href: string;
|
||||
id: string;
|
||||
password: string;
|
||||
path: string;
|
||||
pathNames: string[];
|
||||
port: string;
|
||||
protocol: string;
|
||||
query: string;
|
||||
queryKey: Record<string, string>;
|
||||
relative: string;
|
||||
source: string;
|
||||
user: string;
|
||||
userInfo: string;
|
||||
}
|
||||
|
||||
export function parse(url: string): ParsedURL | null {
|
||||
const result: ParsedURL = {
|
||||
anchor: '',
|
||||
authority: '',
|
||||
directory: '',
|
||||
file: '',
|
||||
host: '',
|
||||
href: url,
|
||||
id: '',
|
||||
password: '',
|
||||
path: '',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: '',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: url,
|
||||
user: '',
|
||||
userInfo: '',
|
||||
};
|
||||
|
||||
try {
|
||||
// 解析协议
|
||||
const protocolMatch = url.match(/^([a-zA-Z][a-zA-Z0-9+\-.]*):\/\//);
|
||||
if (protocolMatch) {
|
||||
result.protocol = protocolMatch[1];
|
||||
url = url.slice(protocolMatch[0].length);
|
||||
}
|
||||
|
||||
// 提取密码和用户信息
|
||||
const userInfoMatch = url.match(
|
||||
/^([a-zA-Z0-9_\-\.]+)(?::([a-zA-Z0-9_\-\.]*))?@/,
|
||||
);
|
||||
if (userInfoMatch) {
|
||||
result.user = userInfoMatch[1] || '';
|
||||
result.password = userInfoMatch[2] || '';
|
||||
result.userInfo = userInfoMatch[0].slice(0, -1); // 去掉结尾的 '@'
|
||||
url = url.slice(userInfoMatch[0].length);
|
||||
}
|
||||
|
||||
// 解析 authority (host:port)
|
||||
const authorityMatch = url.match(/^([a-zA-Z0-9.-]+)(?::(\d+))?/);
|
||||
if (authorityMatch) {
|
||||
result.host = authorityMatch[1];
|
||||
result.port = authorityMatch[2] || '';
|
||||
result.authority = authorityMatch[0];
|
||||
url = url.slice(authorityMatch[0].length);
|
||||
}
|
||||
|
||||
// 提取 hash
|
||||
let hashIndex = url.indexOf('#');
|
||||
if (hashIndex !== -1) {
|
||||
result.anchor = url.slice(hashIndex);
|
||||
url = url.slice(0, hashIndex);
|
||||
}
|
||||
|
||||
// 提取查询字符串
|
||||
let queryIndex = url.indexOf('?');
|
||||
if (queryIndex !== -1) {
|
||||
result.query = url.slice(queryIndex + 1);
|
||||
result.queryKey = result.query.split('&').reduce(
|
||||
(acc, curr) => {
|
||||
const [key, value] = curr.split('=');
|
||||
if (key) acc[key] = value || '';
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>,
|
||||
);
|
||||
url = url.slice(0, queryIndex);
|
||||
}
|
||||
|
||||
// 提取路径
|
||||
result.path = url;
|
||||
result.pathNames = result.path.split('/').filter(Boolean);
|
||||
if (result.path === '' && result.protocol && result.host) {
|
||||
result.path = '/';
|
||||
}
|
||||
|
||||
// directory is consistently empty in the test cases
|
||||
result.directory = '';
|
||||
result.file = '';
|
||||
|
||||
if (result.protocol === 'ftp' && result.path && result.path !== '/') {
|
||||
const parts = result.path.split('/').filter(Boolean);
|
||||
if (parts.length > 0) {
|
||||
result.file = parts[parts.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// 构建完整的 ID
|
||||
result.id =
|
||||
result.protocol +
|
||||
'://' +
|
||||
result.host +
|
||||
(result.port ? `:${result.port}` : '') +
|
||||
result.path +
|
||||
(result.query ? `?${result.query}` : '') +
|
||||
(result.anchor ? result.anchor : '');
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Invalid URL:', url, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用例的类型
|
||||
interface TestCase {
|
||||
input: string;
|
||||
expected: ParsedURL;
|
||||
}
|
||||
|
||||
const moreTestCases: TestCase[] = [
|
||||
{
|
||||
input: 'http://example.com',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com',
|
||||
id: 'http://example.com/',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://example.com',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'https://example.com/',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'https://example.com/',
|
||||
id: 'https://example.com/',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'https',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'https://example.com/',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://example.com/path',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '',
|
||||
file: 'path',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com/path',
|
||||
id: 'http://example.com/path',
|
||||
password: '',
|
||||
path: '/path',
|
||||
pathNames: ['path'],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://example.com/path',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://example.com/path/',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/path',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com/path/',
|
||||
id: 'http://example.com/path/',
|
||||
password: '',
|
||||
path: '/path/',
|
||||
pathNames: ['path', ''],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://example.com/path/',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://example.com/path/to/resource.html',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/path/to',
|
||||
file: 'resource.html',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com/path/to/resource.html',
|
||||
id: 'http://example.com/path/to/resource.html',
|
||||
password: '',
|
||||
path: '/path/to/resource.html',
|
||||
pathNames: ['path', 'to', 'resource.html'],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://example.com/path/to/resource.html',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://example.com?query=value',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com?query=value',
|
||||
id: 'http://example.com/?query=value',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: 'query=value',
|
||||
queryKey: { query: 'value' },
|
||||
relative: '',
|
||||
source: 'http://example.com?query=value',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://example.com#fragment',
|
||||
expected: {
|
||||
anchor: '#fragment',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com#fragment',
|
||||
id: 'http://example.com/',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://example.com#fragment',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://example.com:8080/path?query=1¶m=2#hash',
|
||||
expected: {
|
||||
anchor: '#hash',
|
||||
authority: 'example.com:8080',
|
||||
directory: '',
|
||||
file: 'path',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com:8080/path?query=1¶m=2#hash',
|
||||
id: 'http://example.com:8080/path?query=1¶m=2#hash',
|
||||
password: '',
|
||||
path: '/path',
|
||||
pathNames: ['path'],
|
||||
port: '8080',
|
||||
protocol: 'http',
|
||||
query: 'query=1¶m=2',
|
||||
queryKey: { query: '1', param: '2' },
|
||||
relative: '',
|
||||
source: 'http://example.com:8080/path?query=1¶m=2#hash',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'mailto:user@example.com',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'mailto:user@example.com',
|
||||
id: 'mailto://example.com',
|
||||
password: '',
|
||||
path: '',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'mailto',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'mailto:user@example.com',
|
||||
user: 'user',
|
||||
userInfo: 'user',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'file:///path/to/file.txt',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: '',
|
||||
directory: '/path/to',
|
||||
file: 'file.txt',
|
||||
host: '',
|
||||
href: 'file:///path/to/file.txt',
|
||||
id: 'file:////path/to/file.txt',
|
||||
password: '',
|
||||
path: '/path/to/file.txt',
|
||||
pathNames: ['path', 'to', 'file.txt'],
|
||||
port: '',
|
||||
protocol: 'file',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'file:///path/to/file.txt',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://user@example.com',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://user@example.com',
|
||||
id: 'http://example.com/',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://user@example.com',
|
||||
user: 'user',
|
||||
userInfo: 'user',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://:password@example.com',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://:password@example.com',
|
||||
id: 'http://example.com/',
|
||||
password: 'password',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://:password@example.com',
|
||||
user: '',
|
||||
userInfo: ':password',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://user:@example.com',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://user:@example.com',
|
||||
id: 'http://example.com/',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://user:@example.com',
|
||||
user: 'user',
|
||||
userInfo: 'user:',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://user:pass@example.com',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://user:pass@example.com',
|
||||
id: 'http://example.com/',
|
||||
password: 'pass',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://user:pass@example.com',
|
||||
user: 'user',
|
||||
userInfo: 'user:pass',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://example.com/?param1=value1¶m2=value2#section',
|
||||
expected: {
|
||||
anchor: '#section',
|
||||
authority: 'example.com',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'example.com',
|
||||
href: 'http://example.com/?param1=value1¶m2=value2#section',
|
||||
id: 'http://example.com/?param1=value1¶m2=value2#section',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: 'param1=value1¶m2=value2',
|
||||
queryKey: { param1: 'value1', param2: 'value2' },
|
||||
relative: '',
|
||||
source: 'http://example.com/?param1=value1¶m2=value2#section',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://localhost',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'localhost',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'localhost',
|
||||
href: 'http://localhost',
|
||||
id: 'http://localhost/',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://localhost',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'http://localhost:123',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'localhost:123',
|
||||
directory: '/',
|
||||
file: '',
|
||||
host: 'localhost',
|
||||
href: 'http://localhost:123',
|
||||
id: 'http://localhost:123/',
|
||||
password: '',
|
||||
path: '/',
|
||||
pathNames: [],
|
||||
port: '123',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://localhost:123',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
function testParse(): void {
|
||||
const testCases: TestCase[] = [
|
||||
{
|
||||
input: 'http://localhost:9848/io',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'localhost:9848',
|
||||
directory: '',
|
||||
file: '',
|
||||
host: 'localhost',
|
||||
href: 'http://localhost:9848/io',
|
||||
id: 'http://localhost:9848/io',
|
||||
password: '',
|
||||
path: '/io',
|
||||
pathNames: ['io'],
|
||||
port: '9848',
|
||||
protocol: 'http',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'http://localhost:9848/io',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'https://user:password@localhost:8080/path/to/page?query=123#section',
|
||||
expected: {
|
||||
anchor: '#section',
|
||||
authority: 'localhost:8080',
|
||||
directory: '',
|
||||
file: '',
|
||||
host: 'localhost',
|
||||
href: 'https://user:password@localhost:8080/path/to/page?query=123#section',
|
||||
id: 'https://localhost:8080/path/to/page?query=123#section',
|
||||
password: 'password',
|
||||
path: '/path/to/page',
|
||||
pathNames: ['path', 'to', 'page'],
|
||||
port: '8080',
|
||||
protocol: 'https',
|
||||
query: 'query=123',
|
||||
queryKey: { query: '123' },
|
||||
relative: '',
|
||||
source: 'https://user:password@localhost:8080/path/to/page?query=123#section',
|
||||
user: 'user',
|
||||
userInfo: 'user:password',
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'ftp://ftp.example.com/resource',
|
||||
expected: {
|
||||
anchor: '',
|
||||
authority: 'ftp.example.com',
|
||||
directory: '',
|
||||
file: 'resource',
|
||||
host: 'ftp.example.com',
|
||||
href: 'ftp://ftp.example.com/resource',
|
||||
id: 'ftp://ftp.example.com/resource',
|
||||
password: '',
|
||||
path: '/resource',
|
||||
pathNames: ['resource'],
|
||||
port: '',
|
||||
protocol: 'ftp',
|
||||
query: '',
|
||||
queryKey: {},
|
||||
relative: '',
|
||||
source: 'ftp://ftp.example.com/resource',
|
||||
user: '',
|
||||
userInfo: '',
|
||||
},
|
||||
},
|
||||
...moreTestCases
|
||||
];
|
||||
|
||||
testCases.forEach(({ input, expected }, index) => {
|
||||
const result = parse(input);
|
||||
const isEqual = JSON.stringify(result) === JSON.stringify(expected);
|
||||
console.log(
|
||||
`Test Case ${index + 1}: ${isEqual ? '✅ Passed' : '❌ Failed'}`,
|
||||
);
|
||||
if (!isEqual) {
|
||||
console.log('Input:', input);
|
||||
console.log('Expected:', expected);
|
||||
console.log('Got:', result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testParse();
|
||||
Loading…
Reference in New Issue