aiwrapper
Version:
A Universal AI Wrapper for JavaScript & TypeScript
284 lines (283 loc) • 8.75 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
function applyDiff_v4a(input, diff, mode = "default") {
const diffLines = normalizeDiffLines(diff);
if (mode === "create") {
return parseCreateDiff(diffLines);
}
const { chunks } = parseUpdateDiff(diffLines, input);
return applyChunks(input, chunks);
}
const END_PATCH = "*** End Patch";
const END_FILE = "*** End of File";
const END_SECTION_MARKERS = [
END_PATCH,
"*** Update File:",
"*** Delete File:",
"*** Add File:",
END_FILE
];
const SECTION_TERMINATORS = [
END_PATCH,
"*** Update File:",
"*** Delete File:",
"*** Add File:"
];
function normalizeDiffLines(diff) {
return diff.split(/\r?\n/).map((line) => line.replace(/\r$/, "")).filter((line, idx, arr) => !(idx === arr.length - 1 && line === ""));
}
function isDone(state, prefixes) {
if (state.index >= state.lines.length) return true;
if (prefixes.some((p) => {
var _a;
return (_a = state.lines[state.index]) == null ? void 0 : _a.startsWith(p);
}))
return true;
return false;
}
function readStr(state, prefix) {
const current = state.lines[state.index];
if (typeof current === "string" && current.startsWith(prefix)) {
state.index += 1;
return current.slice(prefix.length);
}
return "";
}
function parseCreateDiff(lines) {
const parser = {
lines: [...lines, END_PATCH],
index: 0,
fuzz: 0
};
const output = [];
while (!isDone(parser, SECTION_TERMINATORS)) {
const line = parser.lines[parser.index];
parser.index += 1;
if (!line.startsWith("+")) {
throw new Error(`Invalid Add File Line: ${line}`);
}
output.push(line.slice(1));
}
return output.join("\n");
}
function parseUpdateDiff(lines, input) {
const parser = {
lines: [...lines, END_PATCH],
index: 0,
fuzz: 0
};
const inputLines = input.split("\n");
const chunks = [];
let cursor = 0;
while (!isDone(parser, END_SECTION_MARKERS)) {
const anchor = readStr(parser, "@@ ");
const hasBareAnchor = !anchor && parser.lines[parser.index] === "@@";
if (hasBareAnchor) parser.index += 1;
if (!(anchor || hasBareAnchor || cursor === 0)) {
throw new Error(`Invalid Line:
${parser.lines[parser.index]}`);
}
if (anchor.trim()) {
cursor = advanceCursorToAnchor(anchor, inputLines, cursor, parser);
}
const { nextContext, sectionChunks, endIndex, eof } = readSection(
parser.lines,
parser.index
);
const nextContextText = nextContext.join("\n");
const { newIndex, fuzz } = findContext(
inputLines,
nextContext,
cursor,
eof
);
if (newIndex === -1) {
if (eof) {
throw new Error(`Invalid EOF Context ${cursor}:
${nextContextText}`);
}
throw new Error(`Invalid Context ${cursor}:
${nextContextText}`);
}
parser.fuzz += fuzz;
for (const ch of sectionChunks) {
chunks.push(__spreadProps(__spreadValues({}, ch), { origIndex: ch.origIndex + newIndex }));
}
cursor = newIndex + nextContext.length;
parser.index = endIndex;
}
return { chunks, fuzz: parser.fuzz };
}
function advanceCursorToAnchor(anchor, inputLines, cursor, parser) {
let found = false;
if (!inputLines.slice(0, cursor).some((s) => s === anchor)) {
for (let i = cursor; i < inputLines.length; i += 1) {
if (inputLines[i] === anchor) {
cursor = i + 1;
found = true;
break;
}
}
}
if (!found && !inputLines.slice(0, cursor).some((s) => s.trim() === anchor.trim())) {
for (let i = cursor; i < inputLines.length; i += 1) {
if (inputLines[i].trim() === anchor.trim()) {
cursor = i + 1;
parser.fuzz += 1;
found = true;
break;
}
}
}
return cursor;
}
function readSection(lines, startIndex) {
const context = [];
let delLines = [];
let insLines = [];
const sectionChunks = [];
let mode = "keep";
let index = startIndex;
const origIndex = index;
while (index < lines.length) {
const raw = lines[index];
if (raw.startsWith("@@") || raw.startsWith(END_PATCH) || raw.startsWith("*** Update File:") || raw.startsWith("*** Delete File:") || raw.startsWith("*** Add File:") || raw.startsWith(END_FILE)) {
break;
}
if (raw === "***") break;
if (raw.startsWith("***")) {
throw new Error(`Invalid Line: ${raw}`);
}
index += 1;
const lastMode = mode;
let line = raw;
if (line === "") line = " ";
if (line[0] === "+") {
mode = "add";
} else if (line[0] === "-") {
mode = "delete";
} else if (line[0] === " ") {
mode = "keep";
} else {
throw new Error(`Invalid Line: ${line}`);
}
line = line.slice(1);
const switchingToContext = mode === "keep" && lastMode !== mode;
if (switchingToContext && (insLines.length || delLines.length)) {
sectionChunks.push({
origIndex: context.length - delLines.length,
delLines,
insLines
});
delLines = [];
insLines = [];
}
if (mode === "delete") {
delLines.push(line);
context.push(line);
} else if (mode === "add") {
insLines.push(line);
} else {
context.push(line);
}
}
if (insLines.length || delLines.length) {
sectionChunks.push({
origIndex: context.length - delLines.length,
delLines,
insLines
});
delLines = [];
insLines = [];
}
if (index < lines.length && lines[index] === END_FILE) {
index += 1;
return { nextContext: context, sectionChunks, endIndex: index, eof: true };
}
if (index === origIndex) {
throw new Error(`Nothing in this section - index=${index} ${lines[index]}`);
}
return { nextContext: context, sectionChunks, endIndex: index, eof: false };
}
function findContext(lines, context, start, eof) {
if (eof) {
const endStart = Math.max(0, lines.length - context.length);
const endMatch = findContextCore(lines, context, endStart);
if (endMatch.newIndex !== -1) return endMatch;
const fallback = findContextCore(lines, context, start);
return { newIndex: fallback.newIndex, fuzz: fallback.fuzz + 1e4 };
}
return findContextCore(lines, context, start);
}
function findContextCore(lines, context, start) {
if (!context.length) {
return { newIndex: start, fuzz: 0 };
}
for (let i = start; i < lines.length; i += 1) {
if (equalsSlice(lines, context, i, (s) => s))
return { newIndex: i, fuzz: 0 };
}
for (let i = start; i < lines.length; i += 1) {
if (equalsSlice(lines, context, i, (s) => s.trimEnd()))
return { newIndex: i, fuzz: 1 };
}
for (let i = start; i < lines.length; i += 1) {
if (equalsSlice(lines, context, i, (s) => s.trim()))
return { newIndex: i, fuzz: 100 };
}
return { newIndex: -1, fuzz: 0 };
}
function equalsSlice(source, target, start, mapFn) {
if (start + target.length > source.length) return false;
for (let i = 0; i < target.length; i += 1) {
if (mapFn(source[start + i]) !== mapFn(target[i])) return false;
}
return true;
}
function applyChunks(input, chunks) {
const origLines = input.split("\n");
const destLines = [];
let origIndex = 0;
for (const chunk of chunks) {
if (chunk.origIndex > origLines.length) {
throw new Error(
`applyDiff: chunk.origIndex ${chunk.origIndex} > input length ${origLines.length}`
);
}
if (origIndex > chunk.origIndex) {
throw new Error(
`applyDiff: overlapping chunk at ${chunk.origIndex} (cursor ${origIndex})`
);
}
destLines.push(...origLines.slice(origIndex, chunk.origIndex));
origIndex = chunk.origIndex;
if (chunk.insLines.length) {
destLines.push(...chunk.insLines);
}
origIndex += chunk.delLines.length;
}
destLines.push(...origLines.slice(origIndex));
const result = destLines.join("\n");
return result;
}
export {
applyDiff_v4a
};
//# sourceMappingURL=applyDiff-v4a.js.map