branch:
utils.ts
3477 bytesRaw
const JS_RESERVED = new Set([
"abstract",
"arguments",
"await",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"double",
"else",
"enum",
"eval",
"export",
"extends",
"false",
"final",
"finally",
"float",
"for",
"function",
"goto",
"if",
"implements",
"import",
"in",
"instanceof",
"int",
"interface",
"let",
"long",
"native",
"new",
"null",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"true",
"try",
"typeof",
"undefined",
"var",
"void",
"volatile",
"while",
"with",
"yield"
]);
/**
* Sanitize a tool name into a valid JavaScript identifier.
* Replaces hyphens, dots, and spaces with `_`, strips other invalid chars,
* prefixes digit-leading names with `_`, and appends `_` to JS reserved words.
*/
export function sanitizeToolName(name: string): string {
if (!name) return "_";
// Replace common separators with underscores
let sanitized = name.replace(/[-.\s]/g, "_");
// Strip any remaining non-identifier characters
sanitized = sanitized.replace(/[^a-zA-Z0-9_$]/g, "");
if (!sanitized) return "_";
// Prefix with _ if starts with a digit
if (/^[0-9]/.test(sanitized)) {
sanitized = "_" + sanitized;
}
// Append _ to reserved words
if (JS_RESERVED.has(sanitized)) {
sanitized = sanitized + "_";
}
return sanitized;
}
export function toPascalCase(str: string) {
return str
.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
.replace(/^[a-z]/, (letter) => letter.toUpperCase());
}
/**
* Escape a character as a unicode escape sequence if it is a control character.
*/
function escapeControlChar(ch: string): string {
const code = ch.charCodeAt(0);
if (code <= 0x1f || code === 0x7f) {
return "\\u" + code.toString(16).padStart(4, "0");
}
return ch;
}
/**
* Quote a property name if needed.
* Escapes backslashes, quotes, and control characters.
*/
export function quoteProp(name: string): string {
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) {
let escaped = "";
for (const ch of name) {
if (ch === "\\") escaped += "\\\\";
else if (ch === '"') escaped += '\\"';
else if (ch === "\n") escaped += "\\n";
else if (ch === "\r") escaped += "\\r";
else if (ch === "\t") escaped += "\\t";
else if (ch === "\u2028") escaped += "\\u2028";
else if (ch === "\u2029") escaped += "\\u2029";
else escaped += escapeControlChar(ch);
}
return `"${escaped}"`;
}
return name;
}
/**
* Escape a string for use inside a double-quoted TypeScript string literal.
*/
export function escapeStringLiteral(s: string): string {
let out = "";
for (const ch of s) {
if (ch === "\\") out += "\\\\";
else if (ch === '"') out += '\\"';
else if (ch === "\n") out += "\\n";
else if (ch === "\r") out += "\\r";
else if (ch === "\t") out += "\\t";
else if (ch === "\u2028") out += "\\u2028";
else if (ch === "\u2029") out += "\\u2029";
else out += escapeControlChar(ch);
}
return out;
}
/**
* Escape a string for use inside a JSDoc comment.
* Prevents premature comment closure from star-slash sequences.
*/
export function escapeJsDoc(text: string): string {
return text.replace(/\*\//g, "*\\/");
}