refactor: dedupe core string reader helpers

This commit is contained in:
Peter Steinberger
2026-04-07 07:01:22 +01:00
parent ad0c4309e6
commit 997a16fa50
12 changed files with 31 additions and 58 deletions

View File

@@ -2,6 +2,7 @@ import type { TSchema } from "@sinclair/typebox";
import type { OpenClawConfig } from "../../config/config.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { defaultRuntime } from "../../runtime.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { normalizeAnyChannelId } from "../registry.js";
import { getChannelPlugin, listChannelPlugins } from "./index.js";
import type { ChannelMessageCapability } from "./message-capabilities.js";
@@ -35,8 +36,7 @@ export function resolveMessageActionDiscoveryChannelId(raw?: string | null): str
if (normalized) {
return normalized;
}
const trimmed = raw?.trim();
return trimmed || undefined;
return normalizeOptionalString(raw);
}
export function createMessageActionDiscoveryContext(

View File

@@ -1,3 +1,4 @@
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import type { ChatType } from "../chat-type.js";
import { normalizeChatChannelId } from "../registry.js";
import { getChannelPlugin, getLoadedChannelPlugin, normalizeChannelId } from "./index.js";
@@ -24,8 +25,7 @@ function normalizeComparableThreadId(
if (typeof threadId !== "string") {
return undefined;
}
const trimmed = threadId.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(threadId);
}
function parseWithPlugin(
@@ -59,7 +59,7 @@ export function resolveComparableTargetForChannel(params: {
rawTarget?: string | null;
fallbackThreadId?: string | number | null;
}): ComparableChannelTarget | null {
const rawTo = params.rawTarget?.trim();
const rawTo = normalizeOptionalString(params.rawTarget);
if (!rawTo) {
return null;
}
@@ -78,7 +78,7 @@ export function resolveComparableTargetForLoadedChannel(params: {
rawTarget?: string | null;
fallbackThreadId?: string | number | null;
}): ComparableChannelTarget | null {
const rawTo = params.rawTarget?.trim();
const rawTo = normalizeOptionalString(params.rawTarget);
if (!rawTo) {
return null;
}

View File

@@ -1,4 +1,5 @@
import type { CronFailureDestinationConfig } from "../config/types.cron.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import type { CronDelivery, CronDeliveryMode, CronJob, CronMessageChannel } from "./types.js";
export type CronDeliveryPlan = {
@@ -24,19 +25,11 @@ function normalizeChannel(value: unknown): CronMessageChannel | undefined {
}
function normalizeTo(value: unknown): string | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
function normalizeAccountId(value: unknown): string | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
function normalizeThreadId(value: unknown): string | number | undefined {
@@ -46,8 +39,7 @@ function normalizeThreadId(value: unknown): string | number | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
export function resolveCronDeliveryPlan(job: CronJob): CronDeliveryPlan {

View File

@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
import path from "node:path";
import { parseByteSize } from "../cli/parse-bytes.js";
import type { CronConfig } from "../config/types.cron.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import type { CronDeliveryStatus, CronRunStatus, CronRunTelemetry } from "./types.js";
export type CronRunLogEntry = {
@@ -239,7 +240,7 @@ function normalizeDeliveryStatuses(opts?: {
}
function parseAllRunLogEntries(raw: string, opts?: { jobId?: string }): CronRunLogEntry[] {
const jobId = opts?.jobId?.trim() || undefined;
const jobId = normalizeOptionalString(opts?.jobId);
if (!raw.trim()) {
return [];
}

View File

@@ -1,5 +1,6 @@
import crypto from "node:crypto";
import { normalizeAgentId } from "../../routing/session-key.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { parseAbsoluteTimeMs } from "../parse.js";
import {
coerceFiniteScheduleNumber,
@@ -717,8 +718,7 @@ function buildPayloadFromPatch(patch: CronPayloadPatch): CronPayload {
}
function normalizeOptionalTrimmedString(value: unknown): string | undefined {
const trimmed = typeof value === "string" ? value.trim() : "";
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
function normalizeOptionalThreadId(value: unknown): string | number | undefined {

View File

@@ -1,4 +1,5 @@
import { normalizeAgentId } from "../../routing/session-key.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { truncateUtf16Safe } from "../../utils.js";
import type { CronPayload } from "../types.js";
@@ -14,11 +15,7 @@ export function normalizeRequiredName(raw: unknown) {
}
export function normalizeOptionalText(raw: unknown) {
if (typeof raw !== "string") {
return undefined;
}
const trimmed = raw.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(raw);
}
function truncateText(input: string, maxLen: number) {
@@ -29,10 +26,7 @@ function truncateText(input: string, maxLen: number) {
}
export function normalizeOptionalAgentId(raw: unknown) {
if (typeof raw !== "string") {
return undefined;
}
const trimmed = raw.trim();
const trimmed = normalizeOptionalString(raw);
if (!trimmed) {
return undefined;
}
@@ -40,11 +34,7 @@ export function normalizeOptionalAgentId(raw: unknown) {
}
export function normalizeOptionalSessionKey(raw: unknown) {
if (typeof raw !== "string") {
return undefined;
}
const trimmed = raw.trim();
return trimmed || undefined;
return normalizeOptionalString(raw);
}
export function inferLegacyName(job: {

View File

@@ -1,6 +1,8 @@
import fs from "node:fs";
import path from "node:path";
import type { OpenClawConfig } from "../config/config.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { normalizeOptionalTrimmedStringList } from "../shared/string-normalization.js";
import { resolveUserPath } from "../utils.js";
import { resolveCompatibilityHostVersion } from "../version.js";
import { loadBundleManifest } from "./bundle-manifest.js";
@@ -221,18 +223,11 @@ function safeStatMtimeMs(filePath: string): number | null {
}
function normalizeManifestLabel(raw: string | undefined): string | undefined {
const trimmed = raw?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(raw);
}
function normalizePreferredPluginIds(raw: unknown): string[] | undefined {
if (!Array.isArray(raw)) {
return undefined;
}
const values = raw
.map((entry) => (typeof entry === "string" ? entry.trim() : ""))
.filter(Boolean);
return values.length > 0 ? values : undefined;
return normalizeOptionalTrimmedStringList(raw);
}
function mergePackageChannelMetaIntoChannelConfigs(params: {

View File

@@ -1,8 +1,7 @@
import { normalizeOptionalString } from "../shared/string-coerce.js";
export function normalizeCapabilityProviderId(providerId: string | undefined): string | undefined {
const trimmed = normalizeOptionalString(providerId)?.toLowerCase();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(providerId)?.toLowerCase();
}
export function buildCapabilityProviderMaps<T extends { id: string; aliases?: readonly string[] }>(

View File

@@ -1,3 +1,4 @@
import { normalizeOptionalString } from "../shared/string-coerce.js";
import {
findLatestTaskFlowForOwnerKey,
getTaskFlowById,
@@ -6,8 +7,7 @@ import {
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
function normalizeOwnerKey(ownerKey?: string): string | undefined {
const trimmed = ownerKey?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(ownerKey);
}
function canOwnerAccessFlow(flow: TaskFlowRecord, callerOwnerKey: string): boolean {

View File

@@ -137,13 +137,11 @@ function ensureNotifyPolicy(notifyPolicy?: TaskNotifyPolicy): TaskNotifyPolicy {
}
function normalizeOwnerKey(ownerKey?: string): string | undefined {
const trimmed = ownerKey?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(ownerKey);
}
function normalizeText(value?: string | null): string | undefined {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(value);
}
function normalizeJsonBlob(value: JsonValue | null | undefined): JsonValue | undefined {

View File

@@ -1,3 +1,4 @@
import { normalizeOptionalString } from "../shared/string-coerce.js";
import {
findTaskByRunId,
getTaskById,
@@ -8,8 +9,7 @@ import type { TaskRecord } from "./task-registry.types.js";
import { buildTaskStatusSnapshot } from "./task-status.js";
function normalizeOwnerKey(ownerKey?: string): string | undefined {
const trimmed = ownerKey?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(ownerKey);
}
function canOwnerAccessTask(task: TaskRecord, callerOwnerKey: string): boolean {

View File

@@ -123,8 +123,7 @@ function assertTaskOwner(params: { ownerKey: string; scopeKind: TaskScopeKind })
}
function normalizeOwnerKey(ownerKey?: string): string | undefined {
const trimmed = ownerKey?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(ownerKey);
}
function assertParentFlowLinkAllowed(params: {
@@ -404,8 +403,7 @@ function addRunIdIndex(taskId: string, runId?: string) {
}
function normalizeSessionIndexKey(sessionKey?: string): string | undefined {
const trimmed = sessionKey?.trim();
return trimmed ? trimmed : undefined;
return normalizeOptionalString(sessionKey);
}
function addIndexedKey(index: Map<string, Set<string>>, key: string, taskId: string) {