Skip to content

Fix multiline basic string patching tests and fix line handling#131

Draft
DecimalTurn wants to merge 7 commits intolatestfrom
dev-inline-tables-patching-mls_rebased
Draft

Fix multiline basic string patching tests and fix line handling#131
DecimalTurn wants to merge 7 commits intolatestfrom
dev-inline-tables-patching-mls_rebased

Conversation

@DecimalTurn
Copy link
Copy Markdown
Owner

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends multiline string format preservation during patch() so that TOML basic multiline strings using line-continuation backslashes (\<NL><ws>) can be edited while keeping their original structural formatting.

Changes:

  • Add rebuildLineContinuation() in generateString() to reconstruct multiline basic strings that use line-continuation backslashes.
  • Add/expand test coverage for editing multiline string values inside multiline inline tables when line continuations are present.
  • Add a one-off audit script to print actual patch() outputs for these cases.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
src/generate.ts Adds line-continuation detection and a reconstruction helper for multiline strings during format preservation.
src/tests/patch.test.ts Adds regression tests ensuring line-continuation backslashes + closing indent are preserved after edits.
scripts/audit-multiline-inline-outputs.cjs Adds an audit utility to print patch() outputs for multiline inline-table test cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

decodedValue: string,
delimiter: string,
newlineChar: string
): string {
}

let stripped = line;
const hasBackslash = stripped.endsWith('\\');
Comment on lines +231 to +255
const splitWords = (s: string): string[] => s.match(/\S+/g) || [];

const newWords = splitWords(decodedValue);

// Map content segments to word ranges: segmentWordRanges[i] = [startWordIdx, endWordIdx)
const segmentWordRanges: [number, number][] = [];
let wordIdx = 0;
for (const seg of contentSegments) {
const segWords = splitWords(seg.content);
const start = wordIdx;
wordIdx += segWords.length;
segmentWordRanges.push([start, wordIdx]);
}

// Redistribute new words across content segments using the same ranges.
const newContents: string[] = [];
for (let i = 0; i < contentSegments.length; i++) {
const [origStart, origEnd] = segmentWordRanges[i];
const origCount = origEnd - origStart;
const segNewWords =
i === contentSegments.length - 1
? newWords.slice(origStart)
: newWords.slice(origStart, origStart + origCount);
newContents.push(segNewWords.join(' '));
}
Comment on lines +233 to +257
const newWords = splitWords(decodedValue);

// Map content segments to word ranges: segmentWordRanges[i] = [startWordIdx, endWordIdx)
const segmentWordRanges: [number, number][] = [];
let wordIdx = 0;
for (const seg of contentSegments) {
const segWords = splitWords(seg.content);
const start = wordIdx;
wordIdx += segWords.length;
segmentWordRanges.push([start, wordIdx]);
}

// Redistribute new words across content segments using the same ranges.
const newContents: string[] = [];
for (let i = 0; i < contentSegments.length; i++) {
const [origStart, origEnd] = segmentWordRanges[i];
const origCount = origEnd - origStart;
const segNewWords =
i === contentSegments.length - 1
? newWords.slice(origStart)
: newWords.slice(origStart, origStart + origCount);
newContents.push(segNewWords.join(' '));
}

// Trim trailing empty content entries (when new value has fewer words)
Comment on lines +210 to +211
if (line.trim() === '') {
return { indent: '', content: '', trailingWs: '', hasBackslash: false, isBlank: true };
Comment on lines +334 to +347
// Detect line-continuation backslashes anywhere in the multiline string body.
// A line ending with an odd number of backslashes is a continuation line.
// Line-continuation is only meaningful in basic (""") strings, not literal (''').
const innerContent = existingRaw.slice(delimiter.length, existingRaw.length - delimiter.length);
const hasLineContinuation = !isLiteral && !escaped.includes(newlineChar) &&
innerContent.split(newlineChar).some(line => {
const m = line.match(/(\\+)$/);
return m !== null && m[1].length % 2 === 1;
});

// Generate the replacement raw string, preserving the structural format of the existing raw.
if (hasLineContinuation) {
raw = rebuildLineContinuation(existingRaw, escaped, value, delimiter, newlineChar);
} else if (hasLeadingNewline) {
@DecimalTurn DecimalTurn force-pushed the dev-inline-tables-patching-mls_rebased branch from 6f0ed0c to adcfa8f Compare March 18, 2026 14:42
@DecimalTurn DecimalTurn force-pushed the dev-inline-tables-patching-mls_rebased branch from adcfa8f to a4354e7 Compare March 18, 2026 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants