@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
89 lines • 3.69 kB
JavaScript
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import { decodeText } from "../../../../shell/bytes.js";
import { readOptional } from "./io.js";
const MAILMAP_LINE = /^\s*([^<>]*?)\s*<([^<>]+)>(?:\s*([^<>]*?)\s*<([^<>]*)>)?/;
const IDENTITY = /(.*?)\s*<([^<>]*)>/;
/**
* Read Git's four mailmap identity forms.
*
* Pinned against git 2.47.3 (Debian stable) and 2.50.1: only a `#` in the
* first column starts a comment, and the second email may be empty (`<>`)
* while the first may not.
*/
export function parseMailmap(text) {
const entries = [];
for (const line of text.split('\n')) {
if (line.startsWith('#'))
continue;
const match = MAILMAP_LINE.exec(line);
if (!match)
continue;
const [, name = '', email = '', oldName, oldEmail] = match;
entries.push({
email: (oldEmail ?? email).toLowerCase(),
name: oldName ? oldName.toLowerCase() : null,
mappedName: name || null,
mappedEmail: oldEmail === undefined ? null : email,
});
}
return entries;
}
/**
* Map one `Name <email>` identity the way git's mailmap does.
*
* An entry naming both the recorded name and email wins outright, the last
* such line replacing any earlier one. Without one, the entries naming the
* email alone apply, each later line overriding the part it spells.
*/
export function mappedIdentity(identity, entries) {
const match = IDENTITY.exec(identity);
if (!match)
return identity;
const [, name = '', email = ''] = match;
let simpleName = null;
let simpleEmail = null;
let specific = null;
for (const entry of entries) {
if (entry.email !== email.toLowerCase())
continue;
if (entry.name === null) {
simpleName = entry.mappedName ?? simpleName;
simpleEmail = entry.mappedEmail ?? simpleEmail;
}
else if (entry.name === name.toLowerCase()) {
specific = entry;
}
}
if (specific !== null) {
simpleName = specific.mappedName;
simpleEmail = specific.mappedEmail;
}
return `${simpleName ?? name} <${simpleEmail ?? email}>`;
}
/** Read the worktree mailmap through the workspace data plane. */
export async function loadMailmap(vfs, location, exact = false) {
const data = (await readOptional(vfs, location.worktree.join(`.mailmap`))) ?? new Uint8Array();
// `exact` keeps every byte, as decodeText reads object headers, so a name
// that is not UTF-8 matches byte for byte as git's does; otherwise such a
// byte reads as U+FFFD, as the log family reads identities.
return parseMailmap(exact ? decodeText(data) : new TextDecoder().decode(data));
}
/** Apply explicit mailmap switches in command-line order. */
export function useMailmap(fl, enabled) {
for (const [key] of fl.occurrences('mailmap', 'use_mailmap', 'no_mailmap', 'no_use_mailmap'))
enabled = !key.startsWith('no_');
return enabled;
}
//# sourceMappingURL=mailmap.js.map