mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-22 22:31:13 +00:00
* refactor(normalization): consolidate string helpers * refactor(normalization): consolidate agent ids * refactor(paths): consolidate user path resolution * refactor(gateway): preserve transcript helper facade * fix(normalization): align helper build aliases * fix(memory): keep helper import line neutral * chore(plugin-sdk): align consolidated helper surface * refactor(normalization): reuse lowercase string helper * refactor(normalization): reuse record guard * refactor(normalization): share surrogate boundary helper * refactor(agents): share token estimate constant * refactor(memory): distinguish standalone helper contracts * refactor(normalization): share error cause formatter * refactor(config): distinguish eligibility predicates * refactor(plugins): share registry state symbol * refactor(cli): reuse outbound dependency adapter * refactor(cron): distinguish positive duration parser * fix(gateway): keep transcript helper private * fix(paths): preserve public helper status * refactor(channels): reuse registry normalizer * refactor(agents): reuse agent core runtime facade * refactor(auth): reuse locked profile upsert * refactor(records): distinguish trap-safe guard * refactor(migrations): distinguish sync directory helper * test(plugins): drop stale duration alias expectations * fix(channels): remove stale registry import * chore(plugin-sdk): refresh helper API baseline * fix(memory): keep renamed helpers private * fix(plugins): keep registry state key private * fix(plugin-sdk): tighten wildcard surface budget * chore(plugin-sdk): refresh rebased helper API baseline
65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
// Surrogate-safe UTF-16 string slicing helpers.
|
|
//
|
|
// Kept dependency-free (no node: imports) so browser/UI bundles can import them
|
|
// without dragging in filesystem/runtime code. See utils.ts, which re-exports
|
|
// these for the broad runtime surface.
|
|
|
|
function isHighSurrogate(codeUnit: number): boolean {
|
|
return codeUnit >= 0xd800 && codeUnit <= 0xdbff;
|
|
}
|
|
|
|
function isLowSurrogate(codeUnit: number): boolean {
|
|
return codeUnit >= 0xdc00 && codeUnit <= 0xdfff;
|
|
}
|
|
|
|
/** Moves a chunk boundary away from the middle of a UTF-16 surrogate pair. */
|
|
export function avoidTrailingHighSurrogateBreak(text: string, start: number, end: number): number {
|
|
if (
|
|
end <= start ||
|
|
end >= text.length ||
|
|
!isHighSurrogate(text.charCodeAt(end - 1)) ||
|
|
!isLowSurrogate(text.charCodeAt(end))
|
|
) {
|
|
return end;
|
|
}
|
|
const adjusted = end - 1;
|
|
return adjusted > start ? adjusted : end + 1;
|
|
}
|
|
|
|
/** Slices a UTF-16 string without returning dangling surrogate halves at either edge. */
|
|
export function sliceUtf16Safe(input: string, start: number, end?: number): string {
|
|
const len = input.length;
|
|
|
|
let from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
|
|
let to = end === undefined ? len : end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
|
|
|
|
if (to <= from) {
|
|
return "";
|
|
}
|
|
|
|
if (from > 0 && from < len) {
|
|
const codeUnit = input.charCodeAt(from);
|
|
if (isLowSurrogate(codeUnit) && isHighSurrogate(input.charCodeAt(from - 1))) {
|
|
from += 1;
|
|
}
|
|
}
|
|
|
|
if (to > 0 && to < len) {
|
|
const codeUnit = input.charCodeAt(to - 1);
|
|
if (isHighSurrogate(codeUnit) && isLowSurrogate(input.charCodeAt(to))) {
|
|
to -= 1;
|
|
}
|
|
}
|
|
|
|
return input.slice(from, to);
|
|
}
|
|
|
|
/** Truncates a UTF-16 string without cutting a surrogate pair in half. */
|
|
export function truncateUtf16Safe(input: string, maxLen: number): string {
|
|
const limit = Math.max(0, Math.floor(maxLen));
|
|
if (input.length <= limit) {
|
|
return input;
|
|
}
|
|
return sliceUtf16Safe(input, 0, limit);
|
|
}
|