advanced-related-pages-2
外部projectを自分のprojectとみなしてリンク構造を計算するUserScript
old version:
このscriptでやること
リンク情報の格納
リンク情報の更新
指定したページの逆リンクを取得
このscriptでやらないこと
リンク情報のfetch
link networkの計算方法
全て同じprojectのリンクだとして計算する
大文字小文字の違いは無視する
全角半角スペースとアンダーバーの違いも無視する
data構造
リンク情報
各ページのリンク先ページタイトルを入れておく
tsinterface LinkCache {
project: string,
title: string,
links: {
title: string,
}[];
}
逆リンク情報
各ページを参照しているページタイトルを保存する
LinkCache
から必要な分だけ計算する
計算処理が重いので、一度に計算するようなことはしない
参照元のproject nameは保持しておく
tsinterface BackLinksData {
title: string,
backLinks: {
project: string,
title: string,
}[];
}
script.jsexport class RelatedPageManager {
constructor() {
this._worker = new Worker('/api/code/takker/advanced-related-pages-2/link-calc-worker.js');
}
リンク情報の追加と削除
script.js push(...linkCache) {
this._worker.postMessage({type: 'push', linkCache: linkCache});
}
clear() {
this._worker.postMessage({type: 'clear'});
}
指定したページの逆リンク情報を取得する
既に backLinksData
にあればそれを返す
なければ計算して返す
script.js async getBackLinks(title) {
// workerに処理を委託して待つ
const result = new Promise((resolve, reject) =>
this._worker.addEventListener('message', message => {
resolve(message.data);
}, {once: true}));
this._worker.postMessage({type: 'get', title: title});
return await result;
}
// debug用
_log(msg, ...objects) {
console.log(`[RelatedPageManager] ${msg}`, objects);
}
}
WebWorkerのコード
やること
データの格納
大文字小文字の変換とスペースをタブにする変換を行っておく
逆リンクの計算
link-calc-worker.jslet linkCache = [];
let backLinksData = [];
self.addEventListener('message', async message => {
switch (message.data.type) {
case 'push':
push(...message.data.linkCache);
break;
case 'clear':
clear();
break;
case 'get':
self.postMessage(getBackLinks(message.data.title));
break;
}
});
function push(...links) {
// 文字列の変換
const format = title => title.toLowerCase().replace(/\s/g,'_');
const temp = links.map(data => {
return {
project: data.project,
title: format(data.title),
links: data.links
.map(link => format(link)),
};});
linkCache.push(...temp);
backLinksData = [];
_log(`Pushed link cache: %o`,linkCache);
}
function clear() {
linkCache = [];
backLinksData = [];
}
function getBackLinks(title) {
// 計算済みの逆リンク情報があればそれを返す
const backLinksCache = backLinksData.find(data => data.title === title)?.backLinks;
if (backLinksCache) return backLinksCache;
// なければ新たに計算し直す
_log('Start calculating back links...')
const backLinks = linkCache
.flatMap(cache => cache.links.includes(title) ?
[{project: cache.project, title: cache.title}] : []);
_log(`Finish calculating ${backLinks.length} back links.`);
return {
title: title,
backLinks: backLinks,
};
}
// debug用
function _log(msg, ...objects) {
if (objects.length === 0) {
console.log(`[link-calc-worker] ${msg}`);
return;
}
console.log(`[link-calc-worker] ${msg} %o`, ...objects);
}