refactor(domain): add FeedId, EmailAddress and Domain value objects
Encapsulate the email/domain/feed-id parsing that was scattered as ad-hoc
regexes and split("@") calls into three small immutable value objects under
src/domain/value-objects/. EmailParser.extractFeedId and generateFeedId now
delegate to FeedId; the sender policy, favicon domain extraction and the admin
SenderField parse through EmailAddress/Domain.
Left as-is on purpose: forwardemail's multi-address free-text extraction and the
admin allow/block list normaliser, which operate on mixed email-or-domain input
that the single-address value objects would reject.
Behaviour-preserving; adds unit tests for each value object.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
8f036cf223
commit
c65aabe7f4
11 files changed
+198
-35
No files matched your search
@@ -1,10 +1,10 @@
|
||||
import { EmailData } from "../types";
|
||||
import { FeedId } from "../domain/value-objects/feed-id";
|
||||
|
||||
export class EmailParser {
|
||||
// Matches noun1.noun2.XY (the feed ID format) before the @ symbol
|
||||
static extractFeedId(emailAddress: string): string | null {
|
||||
const match = emailAddress.match(/^([a-z]+\.[a-z]+\.\d{2})@/i);
|
||||
return match ? match[1] : null;
|
||||
return FeedId.parse(emailAddress)?.value ?? null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
MAX_ICON_BYTES,
|
||||
} from "../config/constants";
|
||||
import { FeedRepository } from "../domain/feed-repository";
|
||||
import { EmailAddress } from "../domain/value-objects/email-address";
|
||||
import { logger } from "../lib/logger";
|
||||
|
||||
interface IconRecord {
|
||||
@@ -18,10 +19,7 @@ interface IconRecord {
|
||||
* no plausible address can be parsed.
|
||||
*/
|
||||
export function extractEmailDomain(from: string): string | null {
|
||||
const match = from.match(/[^\s<>@]+@([^\s<>@]+\.[^\s<>@]+)/);
|
||||
if (!match) return null;
|
||||
const domain = match[1].trim().toLowerCase().replace(/\.+$/, "");
|
||||
return domain || null;
|
||||
return EmailAddress.parse(from)?.domain.value ?? null;
|
||||
}
|
||||
|
||||
function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
import { nouns } from "../data/nouns";
|
||||
import { FeedId } from "../domain/value-objects/feed-id";
|
||||
|
||||
/**
|
||||
* Generates a random feed ID in the format noun1.noun2.XY
|
||||
* @returns A random feed ID string
|
||||
*/
|
||||
export function generateFeedId(): string {
|
||||
// Select two random nouns
|
||||
const noun1 = nouns[Math.floor(Math.random() * nouns.length)];
|
||||
const noun2 = nouns[Math.floor(Math.random() * nouns.length)];
|
||||
|
||||
// Generate a random 2-digit number between 10 and 99
|
||||
const number = Math.floor(Math.random() * 90) + 10;
|
||||
|
||||
// Combine to create the ID with dots as separators
|
||||
return `${noun1}.${noun2}.${number}`;
|
||||
return FeedId.generate().value;
|
||||
}
|
||||
Reference in new issue
Block a user