@konemono/nostr-content-parser
Version:
Parse Nostr content into tokens
191 lines • 7.38 kB
JavaScript
// patterns.ts
// 既存の TokenType 定義に加えて型も作成
export const TokenType = {
TEXT: "text",
// NPUB: "npub",
// NPROFILE: "nprofile",
// NOTE: "note",
// NEVENT: "nevent",
// NADDR: "naddr",
// NSEC: "nsec",
NIP19: "nip19", // 統合されたNIP19タイプ
RELAY: "relay",
URL: "url",
CUSTOM_EMOJI: "custom_emoji",
HASHTAG: "hashtag",
LN_ADDRESS: "ln_address",
LN_URL: "ln_url",
LNBC: "lnbc",
EMAIL: "email",
CASHU_TOKEN: "cashu_token",
BITCOIN_ADDRESS: "bitcoin_address",
NIP_IDENTIFIER: "nip_identifier",
LEGACY_REFERENCE: "legacy_reference", // 旧タイプ引用 #[3]
};
// NIP19のサブタイプ定義
export const NIP19SubType = {
NPUB: "npub",
NPROFILE: "nprofile",
NOTE: "note",
NEVENT: "nevent",
NADDR: "naddr",
NSEC: "nsec",
};
// NIP19サブタイプマッピング
export const NIP19_TYPE_MAP = {
[NIP19SubType.NPUB]: NIP19SubType.NPUB,
[NIP19SubType.NPROFILE]: NIP19SubType.NPROFILE,
[NIP19SubType.NOTE]: NIP19SubType.NOTE,
[NIP19SubType.NEVENT]: NIP19SubType.NEVENT,
[NIP19SubType.NADDR]: NIP19SubType.NADDR,
[NIP19SubType.NSEC]: NIP19SubType.NSEC,
};
// 必要なパターンをエクスポート
export const LN_ADDRESS_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
// ヘルパー関数もエクスポート
export function isLightningAddress(emailLike) {
const commonEmailDomains = [
"gmail.com",
"yahoo.com",
"hotmail.com",
"outlook.com",
"icloud.com",
"protonmail.com",
"aol.com",
"live.com",
];
const domain = emailLike.split("@")[1]?.toLowerCase();
return !!domain && !commonEmailDomains.includes(domain);
}
export function findCustomEmojiMetadata(emojiName, tags) {
if (!tags)
return null;
const emojiTag = tags.find((tag) => tag[0] === "emoji" && tag[1] === emojiName);
return emojiTag ? { url: emojiTag[2] } : null;
}
export const NIP19_PATTERNS = {
npub: /nostr:npub1[023456789acdefghjklmnpqrstuvwxyz]{58}/g,
nprofile: /nostr:nprofile1[023456789acdefghjklmnpqrstuvwxyz]+/g,
note: /nostr:note1[023456789acdefghjklmnpqrstuvwxyz]{58}/g,
nevent: /nostr:nevent1[023456789acdefghjklmnpqrstuvwxyz]+/g,
naddr: /nostr:naddr1[023456789acdefghjklmnpqrstuvwxyz]+/g,
nsec: /nostr:nsec1[023456789acdefghjklmnpqrstuvwxyz]{58}/g,
};
export const NIP19_PLAIN_PATTERNS = {
npub: /(? {
let cleanedUrl = url;
// 末尾から不要な文字を除去(句点、記号、括弧など)
const trailingChars = /[。..、,,;;::!!??→←)」』】〉》〕\)\]}>]$/;
while (trailingChars.test(cleanedUrl)) {
const lastChar = cleanedUrl.slice(-1);
// 閉じ括弧の場合は対応する開き括弧があるかチェック
if (lastChar === ")") {
const openCount = (cleanedUrl.match(/\(/g) || []).length;
const closeCount = (cleanedUrl.match(/\)/g) || []).length;
if (openCount >= closeCount)
break; // ペアになっている場合は除去しない
}
else if (lastChar === ")") {
const openCount = (cleanedUrl.match(/(/g) || []).length;
const closeCount = (cleanedUrl.match(/)/g) || []).length;
if (openCount >= closeCount)
break;
}
else if (lastChar === "」") {
const openCount = (cleanedUrl.match(/「/g) || []).length;
const closeCount = (cleanedUrl.match(/」/g) || []).length;
if (openCount >= closeCount)
break;
}
else if (lastChar === "]") {
const openCount = (cleanedUrl.match(/\[/g) || []).length;
const closeCount = (cleanedUrl.match(/\]/g) || []).length;
if (openCount >= closeCount)
break;
}
else if (lastChar === "}") {
const openCount = (cleanedUrl.match(/\{/g) || []).length;
const closeCount = (cleanedUrl.match(/\}/g) || []).length;
if (openCount >= closeCount)
break;
}
cleanedUrl = cleanedUrl.slice(0, -1);
}
return cleanedUrl;
};
// 旧タイプ引用のメタデータを取得する関数
export function findLegacyReferenceMetadata(referenceMatch, tags) {
// #[3] から数字部分を抽出
const indexMatch = referenceMatch.match(/#\[(\d+)\]/);
if (!indexMatch)
return null;
const tagIndex = parseInt(indexMatch[1], 10);
if (!tags || tagIndex >= tags.length) {
return { tagIndex };
}
const tag = tags[tagIndex];
if (!tag || tag.length < 2) {
return { tagIndex };
}
const tagType = tag[0];
const referenceId = tag[1];
// tagTypeに基づいて参照タイプを判定
let referenceType = "unknown";
if (tagType === "p") {
referenceType = "npub";
}
else if (tagType === "e") {
referenceType = "note";
}
else if (tagType === "a") {
referenceType = "naddr";
}
return {
tagIndex,
tagType,
referenceId,
referenceType,
};
}
//# sourceMappingURL=patterns.js.map