Skip to content

Commit a4e7ee5

Browse files
committed
fix(diff-flat): merge all changes
Avoids additions/deletions when a file is split up.
1 parent ba36e07 commit a4e7ee5

File tree

1 file changed

+167
-120
lines changed

1 file changed

+167
-120
lines changed

scripts/diff-flat.ts

Lines changed: 167 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,41 @@ const diffKeys = (
224224
.join('.');
225225
};
226226

227+
/**
228+
* Deeply merges a source object into a target object.
229+
* @param target The target object to merge into.
230+
* @param source The source object to merge.
231+
* @returns the target object with source merged.
232+
*/
233+
const deepMerge = (target: any, source: any): any => {
234+
if (typeof target !== 'object' || target === null) {
235+
return source;
236+
}
237+
if (typeof source !== 'object' || source === null) {
238+
return source;
239+
}
240+
241+
for (const key of Object.keys(source)) {
242+
const sourceValue = source[key];
243+
const targetValue = target[key];
244+
245+
if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
246+
target[key] = targetValue.concat(sourceValue);
247+
} else if (
248+
typeof sourceValue === 'object' &&
249+
typeof targetValue === 'object' &&
250+
sourceValue !== null &&
251+
targetValue !== null
252+
) {
253+
target[key] = deepMerge({ ...targetValue }, sourceValue);
254+
} else {
255+
target[key] = sourceValue;
256+
}
257+
}
258+
259+
return target;
260+
};
261+
227262
/**
228263
* Print diffs
229264
* @param base Base ref
@@ -250,6 +285,9 @@ const printDiffs = (
250285

251286
const groups = new Map<string, Set<string>>();
252287

288+
const baseContents = {};
289+
const headContents = {};
290+
253291
for (const status of getGitDiffStatuses(base, head)) {
254292
if (
255293
!(
@@ -260,157 +298,166 @@ const printDiffs = (
260298
continue;
261299
}
262300

263-
const baseContents = (
301+
const baseFileContents = (
264302
status.value !== 'A'
265303
? JSON.parse(getFileContent(base, status.basePath))
266304
: {}
267305
) as CompatData;
268-
const headContents = (
306+
const headFileContents = (
269307
status.value !== 'D'
270308
? JSON.parse(getFileContent(head, status.headPath))
271309
: {}
272310
) as CompatData;
273311

274-
if (options.mirror) {
275-
for (const feature of walk(undefined, baseContents)) {
276-
applyMirroring(feature);
277-
}
278-
for (const feature of walk(undefined, headContents)) {
279-
applyMirroring(feature);
280-
}
281-
}
312+
deepMerge(baseContents, baseFileContents);
313+
deepMerge(headContents, headFileContents);
314+
}
315+
316+
if (options.mirror) {
282317
for (const feature of walk(undefined, baseContents)) {
283-
addVersionLast(feature);
318+
applyMirroring(feature);
284319
}
285320
for (const feature of walk(undefined, headContents)) {
286-
addVersionLast(feature);
321+
applyMirroring(feature);
287322
}
288-
if (options.transform) {
289-
for (const feature of walk(undefined, baseContents)) {
290-
transformMD(feature);
291-
}
292-
for (const feature of walk(undefined, headContents)) {
293-
transformMD(feature);
294-
}
323+
}
324+
for (const feature of walk(undefined, baseContents)) {
325+
addVersionLast(feature);
326+
}
327+
for (const feature of walk(undefined, headContents)) {
328+
addVersionLast(feature);
329+
}
330+
if (options.transform) {
331+
for (const feature of walk(undefined, baseContents)) {
332+
transformMD(feature);
333+
}
334+
for (const feature of walk(undefined, headContents)) {
335+
transformMD(feature);
295336
}
337+
}
296338

297-
const baseData = flattenObject(baseContents);
298-
const headData = flattenObject(headContents);
339+
const baseData = flattenObject(baseContents);
340+
const headData = flattenObject(headContents);
299341

300-
const keys = [
301-
...new Set<string>([
302-
...Object.keys(baseData),
303-
...Object.keys(headData),
304-
]).values(),
305-
].sort();
342+
const keys = [
343+
...new Set<string>([
344+
...Object.keys(baseData),
345+
...Object.keys(headData),
346+
]).values(),
347+
].sort();
306348

307-
if (!keys.length) {
308-
continue;
309-
}
349+
if (!keys.length) {
350+
console.log('✔ No data file changed.');
351+
return;
352+
}
310353

311-
const prefix = diffArrays(
312-
keys.at(0)?.split('.') ?? [],
313-
keys.at(-1)?.split('.') ?? [],
314-
)[0]?.value.join('.');
354+
const prefix = diffArrays(
355+
keys.at(0)?.split('.') ?? [],
356+
keys.at(-1)?.split('.') ?? [],
357+
)[0]?.value.join('.');
315358

316-
const commonName =
317-
options.format === 'html' ? `<h3>${prefix}</h3>` : `${prefix}`;
359+
const commonName =
360+
options.format === 'html' ? `<h3>${prefix}</h3>` : `${prefix}`;
318361

319-
let lastKey = '';
362+
let lastKey = '';
320363

321-
for (const key of keys) {
322-
const baseValue = JSON.stringify(baseData[key] ?? null);
323-
const headValue = JSON.stringify(headData[key] ?? null);
324-
if (baseValue === headValue) {
325-
continue;
326-
}
327-
if (!lastKey) {
328-
lastKey = key;
329-
}
330-
const keyDiff = diffKeys(
331-
key.slice(prefix.length),
332-
lastKey.slice(prefix.length),
333-
options,
334-
);
364+
for (const key of keys) {
365+
const baseValue = JSON.stringify(baseData[key] ?? null);
366+
const headValue = JSON.stringify(headData[key] ?? null);
367+
if (baseValue === headValue) {
368+
continue;
369+
}
370+
if (!lastKey) {
371+
lastKey = key;
372+
}
373+
const keyDiff = diffKeys(
374+
key.slice(prefix.length),
375+
lastKey.slice(prefix.length),
376+
options,
377+
);
335378

336-
const splitRegexp =
337-
/(?<=^")|(?<=[\],/ ])|(?=[[,/ ])|(?="$)|(?<=\d)(?=)|(?<=)(?=\d)|(?=#)/;
338-
let headValueForDiff = headValue;
339-
let baseValueForDiff = baseValue;
379+
const splitRegexp =
380+
/(?<=^")|(?<=[\],/ ])|(?=[[,/ ])|(?="$)|(?<=\d)(?=)|(?<=)(?=\d)|(?=#)/;
381+
let headValueForDiff = headValue;
382+
let baseValueForDiff = baseValue;
340383

341-
if (baseValue == 'null') {
342-
baseValueForDiff = '';
343-
if (headValue == '"mirror"' || headValue == '"false"') {
344-
// Ignore initial "mirror"/"false" values.
345-
headValueForDiff = '';
346-
}
347-
} else if (headValue == 'null') {
384+
if (baseValue == 'null') {
385+
baseValueForDiff = '';
386+
if (headValue == '"mirror"' || headValue == '"false"') {
387+
// Ignore initial "mirror"/"false" values.
348388
headValueForDiff = '';
349389
}
390+
} else if (headValue == 'null') {
391+
headValueForDiff = '';
392+
}
350393

351-
const valueDiff = diffArrays(
352-
headValueForDiff.split(splitRegexp),
353-
baseValueForDiff.split(splitRegexp),
354-
)
355-
.map((part) => {
356-
// Note: removed/added is deliberately inversed here, to have additions first.
357-
const value = part.value.join('');
358-
if (part.removed) {
359-
return options.format == 'html'
360-
? `<ins style="color: green">${value}</ins>`
361-
: chalk`{green ${value}}`;
362-
} else if (part.added) {
363-
return options.format == 'html'
364-
? `<del style="color: red">${value}</del>`
365-
: chalk`{red ${value}}`;
366-
}
394+
const valueDiff = diffArrays(
395+
headValueForDiff.split(splitRegexp),
396+
baseValueForDiff.split(splitRegexp),
397+
)
398+
.map((part) => {
399+
// Note: removed/added is deliberately inversed here, to have additions first.
400+
const value = part.value.join('');
401+
if (part.removed) {
402+
return options.format == 'html'
403+
? `<ins style="color: green">${value}</ins>`
404+
: chalk`{green ${value}}`;
405+
} else if (part.added) {
406+
return options.format == 'html'
407+
? `<del style="color: red">${value}</del>`
408+
: chalk`{red ${value}}`;
409+
}
367410

368-
return value;
369-
})
370-
.join('');
411+
return value;
412+
})
413+
.join('');
371414

372-
const value = valueDiff;
415+
const value = valueDiff;
373416

374-
if (!value.length) {
375-
// e.g. null => "mirror"
376-
continue;
377-
}
417+
if (!value.length) {
418+
// e.g. null => "mirror"
419+
continue;
420+
}
378421

379-
if (options.group) {
380-
const reverseKeyParts = key.split('.').reverse();
381-
const browser = reverseKeyParts.find((part) =>
382-
BROWSER_NAMES.includes(part),
383-
);
384-
const field = reverseKeyParts.find((part) => !/^\d+$/.test(part));
385-
const groupKey = `${!browser ? '' : options.format == 'html' ? `<strong>${browser}</strong>.` : chalk`{cyan ${browser}}.`}${field} = ${value}`;
386-
const groupValue = key
387-
.split('.')
388-
.map((part) => (part !== browser && part !== field ? part : '{}'))
389-
.reverse()
390-
.filter((value, index) => index > 0 || value !== '{}')
391-
.reverse()
392-
.map((value) =>
393-
value !== '{}'
394-
? value
395-
: options.format == 'html'
396-
? '<small>{}</small>'
397-
: chalk`{dim \{\}}`,
398-
)
399-
.join('.');
400-
const group = groups.get(groupKey) ?? new Set();
401-
group.add(groupValue);
402-
groups.set(groupKey, group);
403-
} else {
404-
const change =
405-
options.format == 'html'
406-
? `${keyDiff} = ${value}`
407-
: chalk`${keyDiff} = ${value}`;
408-
const group = groups.get(commonName) ?? new Set();
409-
group.add(change);
410-
groups.set(commonName, group);
411-
}
412-
lastKey = key;
422+
if (options.group) {
423+
const reverseKeyParts = key.split('.').reverse();
424+
const browser = reverseKeyParts.find((part) =>
425+
BROWSER_NAMES.includes(part),
426+
);
427+
const field = reverseKeyParts.find((part) => !/^\d+$/.test(part));
428+
const groupKey = `${!browser ? '' : options.format == 'html' ? `<strong>${browser}</strong>.` : chalk`{cyan ${browser}}.`}${field} = ${value}`;
429+
const groupValue = key
430+
.split('.')
431+
.map((part) => (part !== browser && part !== field ? part : '{}'))
432+
.reverse()
433+
.filter((value, index) => index > 0 || value !== '{}')
434+
.reverse()
435+
.map((value) =>
436+
value !== '{}'
437+
? value
438+
: options.format == 'html'
439+
? '<small>{}</small>'
440+
: chalk`{dim \{\}}`,
441+
)
442+
.join('.');
443+
const group = groups.get(groupKey) ?? new Set();
444+
group.add(groupValue);
445+
groups.set(groupKey, group);
446+
} else {
447+
const change =
448+
options.format == 'html'
449+
? `${keyDiff} = ${value}`
450+
: chalk`${keyDiff} = ${value}`;
451+
const group = groups.get(commonName) ?? new Set();
452+
group.add(change);
453+
groups.set(commonName, group);
413454
}
455+
lastKey = key;
456+
}
457+
458+
if (groups.size === 0) {
459+
console.log('✔ No changes.');
460+
return;
414461
}
415462

416463
const originalEntries: [string, string[]][] = [...groups.entries()].map(

0 commit comments

Comments
 (0)