chore: 整理 third-party Dark Reader 目录并移除本地说明文件跟踪
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import type {MessageBGtoCS, MessageCStoBG} from '../../../src/definitions';
|
||||
import {MessageTypeBGtoCS, MessageTypeCStoBG} from '../../../src/utils/message';
|
||||
|
||||
let nativeSendMessage: typeof chrome.runtime.sendMessage;
|
||||
const bgResponses = new Map<string, string>();
|
||||
|
||||
export function stubChromeRuntimeMessage(): void {
|
||||
nativeSendMessage = chrome.runtime.sendMessage;
|
||||
const listeners: Array<(message: MessageBGtoCS) => void> = (chrome.runtime.onMessage as any)['__listeners__'];
|
||||
|
||||
(chrome.runtime as any).sendMessage = (message: MessageCStoBG) => {
|
||||
if (message.type === MessageTypeCStoBG.FETCH) {
|
||||
const {id, data: {url}} = message;
|
||||
setTimeout(() => {
|
||||
listeners.forEach((listener) => {
|
||||
if (!bgResponses.has(url)) {
|
||||
throw new Error('Response is missing, use `stubBackgroundFetchResponse()`');
|
||||
}
|
||||
const data = bgResponses.get(url);
|
||||
listener({type: MessageTypeBGtoCS.FETCH_RESPONSE, data, error: null, id});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function resetChromeRuntimeMessageStub(): void {
|
||||
chrome.runtime.sendMessage = nativeSendMessage;
|
||||
bgResponses.clear();
|
||||
}
|
||||
|
||||
export function stubBackgroundFetchResponse(url: string, content: string): void {
|
||||
bgResponses.set(url, content);
|
||||
}
|
||||
|
||||
const urlResponses = new Map<string, string>();
|
||||
export function stubChromeRuntimeGetURL(path: string, url: string): void {
|
||||
urlResponses.set(path, url);
|
||||
(chrome.runtime as any).getURL = (path: string) => {
|
||||
return urlResponses.get(path);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
(() => {
|
||||
if (window.top === window.self) {
|
||||
return;
|
||||
}
|
||||
const topDoc = window.top!.document;
|
||||
const style = topDoc.createElement('style');
|
||||
style.textContent = [
|
||||
'body { background-color: #222222; color: #dddddd; }',
|
||||
'#banner { background-color: #226644; }',
|
||||
'.executing { background-color: #662233; }',
|
||||
].join('\n');
|
||||
topDoc.head.append(style);
|
||||
})();
|
||||
@@ -0,0 +1,11 @@
|
||||
export function getEchoURL(content: string, type = 'text/plain'): string {
|
||||
return `http://localhost:9966/echo?${new URLSearchParams({type, content})}`;
|
||||
}
|
||||
|
||||
export function getCSSEchoURL(content: string): string {
|
||||
return getEchoURL(content, 'text/css');
|
||||
}
|
||||
|
||||
export function getJSEchoURL(script: string): string {
|
||||
return getEchoURL(script, 'application/javascript');
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// @ts-check
|
||||
import http from 'http';
|
||||
|
||||
export async function createEchoServer(/** @type {number} */port) {
|
||||
/** @type {import('http').Server | null} */
|
||||
let server;
|
||||
|
||||
/** @type {import('http').RequestListener} */
|
||||
function handleRequest(req, res) {
|
||||
const parsedURL = new URL(req.url ?? '', `http://${req.headers.host}`);
|
||||
const pathName = parsedURL.pathname;
|
||||
|
||||
if (pathName !== '/echo') {
|
||||
res.statusCode = 500;
|
||||
res.end('The URL path must be /echo');
|
||||
return;
|
||||
}
|
||||
|
||||
const {searchParams} = parsedURL;
|
||||
|
||||
const content = searchParams.get('content');
|
||||
if (!content) {
|
||||
res.statusCode = 500;
|
||||
res.end('Send content like /echo?type=text%2Fplain&content=XYZ');
|
||||
return;
|
||||
}
|
||||
|
||||
const contentType = searchParams.get('type') || 'text/plain';
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', contentType);
|
||||
res.end(content, 'utf8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
function start() {
|
||||
return new Promise((resolve) => {
|
||||
server = http
|
||||
.createServer(handleRequest)
|
||||
.listen(port, () => resolve());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void> | undefined}
|
||||
*/
|
||||
function close() {
|
||||
if (!server) {
|
||||
return;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
server?.close((err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
server = null;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
process.on('exit', close);
|
||||
process.on('SIGINT', close);
|
||||
|
||||
await start();
|
||||
|
||||
return {
|
||||
close,
|
||||
url: `http://localhost:${port}`,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
if (!window.hasOwnProperty('chrome')) {
|
||||
window.chrome = {} as any;
|
||||
}
|
||||
if (!chrome.hasOwnProperty('runtime')) {
|
||||
chrome.runtime = {} as any;
|
||||
}
|
||||
if (!chrome.runtime.hasOwnProperty('onMessage')) {
|
||||
type AnyFunction = () => void;
|
||||
const listeners = new Set<AnyFunction>();
|
||||
(chrome.runtime as any).onMessage = {
|
||||
addListener: (listener: AnyFunction) => {
|
||||
listeners.add(listener);
|
||||
},
|
||||
removeListener: (listener: AnyFunction) => {
|
||||
listeners.delete(listener);
|
||||
},
|
||||
} as any;
|
||||
(chrome.runtime.onMessage as any)['__listeners__'] = listeners;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Loaded with HTML/DOM only
|
||||
|
||||
export function multiline(...lines: string[]): string {
|
||||
if (lines.length < 1) {
|
||||
return '\n';
|
||||
}
|
||||
if (lines[lines.length - 1] !== '') {
|
||||
lines.push('');
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
export function timeout(delay: number): Promise<void> {
|
||||
return new Promise<void>((resolve) => setTimeout(resolve, delay));
|
||||
}
|
||||
|
||||
export function waitForEvent(eventName: string): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
document.addEventListener(eventName, () => resolve(), {once: true});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user