mirror of
https://github.com/samsonjs/spirit-tracker.git
synced 2026-04-27 15:07:43 +00:00
fix: PR JS
This commit is contained in:
parent
a29c3920e5
commit
3ba5658149
1 changed files with 56 additions and 90 deletions
|
|
@ -216,104 +216,70 @@ function makePrettyObjBlock(objIndent, obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyInsertionsToArrayText({
|
function applyInsertionsToArrayText({
|
||||||
src,
|
src,
|
||||||
propName,
|
propName,
|
||||||
incoming,
|
incoming,
|
||||||
keyFn,
|
keyFn,
|
||||||
normalizeFn,
|
normalizeFn,
|
||||||
}) {
|
}) {
|
||||||
const span = findJsonArraySpan(src, propName);
|
const span = findJsonArraySpan(src, propName);
|
||||||
if (!span) die(`Could not find "${propName}" array in ${filePath}`);
|
if (!span) die(`Could not find "${propName}" array in ${filePath}`);
|
||||||
|
|
||||||
const before = src.slice(0, span.open + 1); // includes '['
|
const before = src.slice(0, span.open + 1); // includes '['
|
||||||
const inner = src.slice(span.open + 1, span.close); // between [ and ]
|
const inner = src.slice(span.open + 1, span.close); // between [ and ]
|
||||||
const after = src.slice(span.close); // starts with ']'
|
const after = src.slice(span.close); // starts with ']'
|
||||||
|
|
||||||
const itemIndent = detectItemIndent(inner, span.fieldIndent);
|
const itemIndent = detectItemIndent(inner, span.fieldIndent);
|
||||||
|
|
||||||
const rawBlocks = splitArrayObjectBlocks(inner);
|
// Parse existing objects to build a dedupe set (does NOT modify inner text)
|
||||||
|
const rawBlocks = splitArrayObjectBlocks(inner);
|
||||||
const existing = [];
|
const seen = new Set();
|
||||||
const seen = new Set();
|
for (const raw of rawBlocks) {
|
||||||
|
try {
|
||||||
for (const raw of rawBlocks) {
|
const obj = JSON.parse(raw);
|
||||||
try {
|
const k = keyFn(obj);
|
||||||
const obj = JSON.parse(raw);
|
if (k) seen.add(k);
|
||||||
const k = keyFn(obj);
|
} catch {
|
||||||
existing.push({ raw, obj, key: k });
|
// ignore unparsable blocks for dedupe purposes
|
||||||
if (k) seen.add(k);
|
}
|
||||||
} catch {
|
|
||||||
// If parsing fails, keep the raw block as-is, but don't use it for keying
|
|
||||||
existing.push({ raw, obj: null, key: "" });
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const toAdd = [];
|
||||||
const toAdd = [];
|
for (const x of incoming) {
|
||||||
for (const x of incoming) {
|
const nx = normalizeFn(x);
|
||||||
const nx = normalizeFn(x);
|
const k = keyFn(nx);
|
||||||
const k = keyFn(nx);
|
if (!k || seen.has(k)) continue;
|
||||||
if (!k || seen.has(k)) continue;
|
seen.add(k);
|
||||||
seen.add(k);
|
toAdd.push(nx);
|
||||||
toAdd.push({ obj: nx, key: k });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!toAdd.length) return src; // nothing to do
|
|
||||||
|
|
||||||
// Insert each new item into sorted position by key (lex)
|
|
||||||
// We rebuild the list of raw blocks but preserve existing raw blocks untouched.
|
|
||||||
const outBlocks = existing.slice(); // keep {raw,obj,key}
|
|
||||||
|
|
||||||
function findInsertIndex(k) {
|
|
||||||
for (let i = 0; i < outBlocks.length; i++) {
|
|
||||||
const kk = outBlocks[i]?.key || "";
|
|
||||||
if (!kk) continue; // unknown blocks: keep them where they are
|
|
||||||
if (kk > k) return i;
|
|
||||||
}
|
}
|
||||||
return outBlocks.length;
|
|
||||||
}
|
if (!toAdd.length) return src;
|
||||||
|
|
||||||
// Sort additions so results are deterministic
|
// Deterministic order for new items only (doesn't reorder existing)
|
||||||
toAdd.sort((a, b) => a.key.localeCompare(b.key));
|
const addBlocks = toAdd
|
||||||
|
.map((obj) => ({ obj, key: keyFn(obj) }))
|
||||||
for (const add of toAdd) {
|
.sort((a, b) => String(a.key).localeCompare(String(b.key)))
|
||||||
const idx = findInsertIndex(add.key);
|
.map((x) => makePrettyObjBlock(itemIndent, x.obj));
|
||||||
const raw = makePrettyObjBlock(itemIndent, add.obj);
|
|
||||||
outBlocks.splice(idx, 0, { raw, obj: add.obj, key: add.key });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rebuild inner text, preserving inline-empty formatting if it was empty
|
|
||||||
let newInner = "";
|
|
||||||
if (outBlocks.length === 0) {
|
|
||||||
newInner = inner; // shouldn't happen, but keep original
|
|
||||||
} else {
|
|
||||||
// Determine if original was inline empty: "links": []
|
|
||||||
const wasInlineEmpty = /^\s*$/.test(inner);
|
const wasInlineEmpty = /^\s*$/.test(inner);
|
||||||
|
|
||||||
|
let newInner;
|
||||||
if (wasInlineEmpty) {
|
if (wasInlineEmpty) {
|
||||||
// Convert to pretty multi-line on first insert (minimal and stable)
|
// "links": [] -> pretty multiline
|
||||||
newInner =
|
newInner =
|
||||||
"\n" +
|
"\n" + addBlocks.join(",\n") + "\n" + span.fieldIndent;
|
||||||
outBlocks.map((x) => x.raw).join(",\n") +
|
|
||||||
"\n" +
|
|
||||||
span.fieldIndent;
|
|
||||||
} else {
|
} else {
|
||||||
// Keep pretty multi-line (same join style as JSON.stringify)
|
// Keep existing whitespace EXACTLY; append before trailing whitespace
|
||||||
// Ensure leading/trailing newlines similar to original
|
const m = inner.match(/\s*$/);
|
||||||
const trimmed = inner.replace(/^\s+|\s+$/g, "");
|
const tail = m ? m[0] : "";
|
||||||
const hadLeadingNL = /^\s*\n/.test(inner);
|
const body = inner.slice(0, inner.length - tail.length).replace(/\s*$/, ""); // end at last non-ws
|
||||||
const hadTrailingNL = /\n\s*$/.test(inner);
|
|
||||||
|
newInner = body + ",\n" + addBlocks.join(",\n") + tail;
|
||||||
const body = outBlocks.map((x) => x.raw).join(",\n");
|
|
||||||
newInner =
|
|
||||||
(hadLeadingNL ? "\n" : "") +
|
|
||||||
body +
|
|
||||||
(hadTrailingNL ? "\n" + span.fieldIndent : "");
|
|
||||||
// If original didn't have trailing newline before ']', keep it tight
|
|
||||||
if (!hadTrailingNL) newInner = "\n" + body + "\n" + span.fieldIndent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return before + newInner + after;
|
||||||
}
|
}
|
||||||
|
|
||||||
return before + newInner + after;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------- Apply edits ---------------- */
|
/* ---------------- Apply edits ---------------- */
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue