Skip to content

Commit 4a88ab5

Browse files
authored
JSON normalization followup (#241)
* z = normaliZe JSON * consistent style for JSON normalization control * refactor DiffOptions * pass down update function * rename * confused myself; it works * Add a normalize toggle under the gear * add note * add "identical after normalization" banner * safety check for minified files * fix encoding bug * bump versions
1 parent 0c86feb commit 4a88ab5

File tree

18 files changed

+344
-124
lines changed

18 files changed

+344
-124
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "webdiff"
7-
version = "1.3.0b1"
7+
version = "1.3.0b2"
88
description = "Two-column web-based git difftool"
99
license = "Apache-2.0"
1010
readme = "README.md"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"id":8503055,"num_reps":5505497728300038000000,"elapsed_s":27775981.582439058,"failures":["sredetiltnapsres","stngeiaedrlpsdes","gresenapdtilsres","dresenalstipares","gresenalstipares","gresenalstipores","dresenilstapares","dresenilstapores","dresenilstapures","gressnaletipdres","gntseaieslrdopes","sttseiaenrlpsges","plsdeaiertnrsges","plsteaiertnrsges","psldeaiertnrsges","spldeaiertnrsges","spldeiaetrntsges","splseaiertnrsdes","splseaiertnrsges","slpseaierntrsdes","slpseaierntrsges","slpseaiertnrsges","slpseiaerntrsdes","dresenapstilares","gresenapstilares","gresenapstilores","dplcseainrtngies","dresenilgtapsres","stndeiaenrlpsges","stngeiaenrlpsges","gsedtnileratspes","slpseaierntrgdes","gntseaieplrdseas","gntseaieplrdsees","plcdeaiertnrsges","dplseaiertnrsges","mplseaiertnrsges","sresetipdnalsges","plcseaiertnrsges","dlpseaiertnrsges","gredenalstipares","gredenalstipores","hsebetalsripgnes","hsedetalsripgnes","tsebetalsripgnes","tsedetalsripgnes"],"elim_level":[0,15455,177058,5063716,76688548,461765945,746413471,1341313341,1163044169,683351596,332798842,146849412,75414967,51931121],"secs_by_level":[3674055.3433500067,410511.63218999945,1173934.825350049,3012839.132659852,5235705.436329976,4241101.513749921,4354658.159489981,2102788.1823800365,669439.2463199788,109737.61249999885,25531.954199997952,4647.2012399998175,1373.4651100000929],"bounds":[17529004948,13770052786,11002135202,8716185865,6917888192,5476876187,4192563351,3051811248,2128082619,1431049972,956438815,668040946,500412197],"depth":[0,19950,615593,14344534,148852615,670318189,1798495841,2584907222,2213849795,1122244756,511943456,205264471,96606475,62028585],"boards_to_test":16527857205,"init_nodes":21169090330328,"total_nodes":216126848966789,"tree_bytes":426388045692928,"total_bytes":574688434585600,"n_bound":9429491482,"n_force":2101423756,"max_multi":1312378509,"bound_secs":[0,26.31909999999997,762.3841000000707,13895.171989995355,96300.35142999486,278184.6050899924,509398.4086700136,489545.5812600387,261858.04687000782,96741.63683000114,42098.825499994186,16502.548799997923,8129.411579999221,6838.873439999473],"test_secs":859209.9650399276,"best_board":[3827,"splseaiertnrsges"]}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
{
2+
"id": 8503055,
3+
"num_reps": 5505497728300038000000,
4+
"elapsed_s": 27775981.582439058,
5+
"failures": [
6+
"sredetiltnapsres",
7+
"stngeiaedrlpsdes",
8+
"gresenapdtilsres",
9+
"dresenalstipares",
10+
"gresenalstipares",
11+
"gresenalstipores",
12+
"dresenilstapares",
13+
"dresenilstapores",
14+
"dresenilstapures",
15+
"gressnaletipdres",
16+
"gntseaieslrdopes",
17+
"sttseiaenrlpsges",
18+
"plsdeaiertnrsges",
19+
"plsteaiertnrsges",
20+
"psldeaiertnrsges",
21+
"spldeaiertnrsges",
22+
"spldeiaetrntsges",
23+
"splseaiertnrsdes",
24+
"splseaiertnrsges",
25+
"slpseaierntrsdes",
26+
"slpseaierntrsges",
27+
"slpseaiertnrsges",
28+
"slpseiaerntrsdes",
29+
"dresenapstilares",
30+
"gresenapstilares",
31+
"gresenapstilores",
32+
"dplcseainrtngies",
33+
"dresenilgtapsres",
34+
"stndeiaenrlpsges",
35+
"stngeiaenrlpsges",
36+
"gsedtnileratspes",
37+
"slpseaierntrgdes",
38+
"gntseaieplrdseas",
39+
"gntseaieplrdsees",
40+
"plcdeaiertnrsges",
41+
"dplseaiertnrsges",
42+
"mplseaiertnrsges",
43+
"sresetipdnalsges",
44+
"plcseaiertnrsges",
45+
"dlpseaiertnrsges",
46+
"gredenalstipares",
47+
"gredenalstipores",
48+
"hsebetalsripgnes",
49+
"hsedetalsripgnes",
50+
"tsebetalsripgnes",
51+
"tsedetalsripgnes"
52+
],
53+
"elim_level": [
54+
0,
55+
15455,
56+
177058,
57+
5063716,
58+
76688548,
59+
461765945,
60+
746413471,
61+
1341313341,
62+
1163044169,
63+
683351596,
64+
332798842,
65+
146849412,
66+
75414967,
67+
51931121
68+
],
69+
"secs_by_level": [
70+
3674055.3433500067,
71+
410511.63218999945,
72+
1173934.825350049,
73+
3012839.132659852,
74+
5235705.436329976,
75+
4241101.513749921,
76+
4354658.159489981,
77+
2102788.1823800365,
78+
669439.2463199788,
79+
109737.61249999885,
80+
25531.954199997952,
81+
4647.2012399998175,
82+
1373.4651100000929
83+
],
84+
"bounds": [
85+
17529004948,
86+
13770052786,
87+
11002135202,
88+
8716185865,
89+
6917888192,
90+
5476876187,
91+
4192563351,
92+
3051811248,
93+
2128082619,
94+
1431049972,
95+
956438815,
96+
668040946,
97+
500412197
98+
],
99+
"depth": [
100+
0,
101+
19950,
102+
615593,
103+
14344534,
104+
148852615,
105+
670318189,
106+
1798495841,
107+
2584907222,
108+
2213849795,
109+
1122244756,
110+
511943456,
111+
205264471,
112+
96606475,
113+
62028585
114+
],
115+
"boards_to_test": 16527857205,
116+
"init_nodes": 21169090330328,
117+
"total_nodes": 216126848966789,
118+
"tree_bytes": 426388045692928,
119+
"total_bytes": 574688434585600,
120+
"n_bound": 9429491482,
121+
"n_force": 2101423756,
122+
"max_multi": 1312378509,
123+
"bound_secs": [
124+
0,
125+
26.31909999999997,
126+
762.3841000000707,
127+
13895.171989995355,
128+
96300.35142999486,
129+
278184.6050899924,
130+
509398.4086700136,
131+
489545.5812600387,
132+
261858.04687000782,
133+
96741.63683000114,
134+
42098.825499994186,
135+
16502.548799997923,
136+
8129.411579999221,
137+
6838.873439999473
138+
],
139+
"test_secs": 859209.9650399276,
140+
"best_board": [
141+
3827,
142+
"splseaiertnrsges"
143+
]
144+
}

testdata/jsondiffs/right/tsconfig.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
2+
/* Note that this file isn't really JSON! It's JSONC. */
23
"compilerOptions": {
3-
/* Note that this file isn't really JSON! */
44

55
/* Basic Options */
66
// "incremental": true, /* Enable incremental compilation */
77
"target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
88
"module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
99
/* Specify library files to be included in the compilation. */
1010
"lib": [
11-
"es2021",
11+
"es2021",
1212
"dom"
1313
] ,
1414
// "allowJs": true, /* Allow javascript files to be compiled. */

ts/CodeDiffContainer.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import {DiffOptions, encodeDiffOptions} from './diff-options';
2+
import {GitDiffOptions, gitDiffOptionsToFlags} from './diff-options';
33
import {CodeDiff, PatchOptions} from './codediff/codediff';
44
import {guessLanguageUsingContents, guessLanguageUsingFileName} from './codediff/language';
55
import {GitConfig} from './options';
@@ -53,18 +53,19 @@ export interface ImageDiffData {
5353
}
5454

5555
// A "no changes" sign which only appears when applicable.
56-
export function NoChanges(props: {filePair: FilePair}) {
57-
const {filePair} = props;
56+
export function NoChanges(props: {filePair: FilePair; isEqualAfterNormalization: boolean}) {
57+
const {filePair, isEqualAfterNormalization} = props;
58+
let msg = null;
5859
if (filePair.no_changes) {
59-
return <div className="no-changes">(File content is identical)</div>;
60+
msg = <>(File content is identical)</>;
61+
} else if (isEqualAfterNormalization) {
62+
msg = <>(File content is identical after normalization)</>;
6063
} else if (filePair.is_image_diff && filePair.are_same_pixels) {
61-
return (
62-
<div className="no-changes">
63-
Pixels are the same, though file content differs (perhaps the headers are different?)
64-
</div>
64+
msg = (
65+
<>Pixels are the same, though file content differs (perhaps the headers are different?)</>
6566
);
6667
}
67-
return null;
68+
return msg ? <div className="no-changes">{msg}</div> : null;
6869
}
6970

7071
// Either side can be empty (i.e. an add or a delete), in which case getOrNull resolves to null.
@@ -84,7 +85,7 @@ async function getOrNull(side: string, path: string, normalizeJSON: boolean) {
8485

8586
export interface CodeDiffContainerProps {
8687
filePair: FilePair;
87-
diffOptions: Partial<DiffOptions>;
88+
diffOptions: Partial<GitDiffOptions>;
8889
normalizeJSON: boolean;
8990
}
9091

@@ -96,6 +97,8 @@ export function CodeDiffContainer(props: CodeDiffContainerProps) {
9697
>();
9798

9899
React.useEffect(() => {
100+
// It would be more correct to set contents=undefined here to get a loading state,
101+
// but this produces an unnecessary flash for rapid transitions.
99102
const getDiff = async () => {
100103
const response = await fetch(`/diff/${filePair.idx}`, {
101104
method: 'POST',
@@ -104,7 +107,7 @@ export function CodeDiffContainer(props: CodeDiffContainerProps) {
104107
'Content-Type': 'application/json',
105108
},
106109
body: JSON.stringify({
107-
options: encodeDiffOptions(diffOptions),
110+
options: gitDiffOptionsToFlags(diffOptions),
108111
normalize_json: normalizeJSON,
109112
}),
110113
});
@@ -127,6 +130,10 @@ export function CodeDiffContainer(props: CodeDiffContainerProps) {
127130
});
128131
}, [filePair, diffOptions, normalizeJSON]);
129132

133+
const isEqualAfterNormalization = React.useMemo(() => {
134+
return !filePair.no_changes && normalizeJSON && contents && contents.before == contents.after;
135+
}, [contents, filePair.no_changes, normalizeJSON]);
136+
130137
return (
131138
<div>
132139
<div key={filePair.idx}>
@@ -136,6 +143,7 @@ export function CodeDiffContainer(props: CodeDiffContainerProps) {
136143
contentsBefore={contents.before}
137144
contentsAfter={contents.after}
138145
diffOps={contents.diffOps}
146+
isEqualAfterNormalization={!!isEqualAfterNormalization}
139147
/>
140148
) : (
141149
'Loading…'
@@ -150,6 +158,7 @@ interface FileDiffProps {
150158
contentsBefore: string | null;
151159
contentsAfter: string | null;
152160
diffOps: DiffRange[];
161+
isEqualAfterNormalization: boolean;
153162
}
154163

155164
function extractFilename(path: string) {
@@ -164,7 +173,7 @@ function lengthOrZero(data: unknown[] | string | null | undefined) {
164173
}
165174

166175
function FileDiff(props: FileDiffProps) {
167-
const {filePair, contentsBefore, contentsAfter, diffOps} = props;
176+
const {filePair, contentsBefore, contentsAfter, diffOps, isEqualAfterNormalization} = props;
168177
const pathBefore = filePair.a;
169178
const pathAfter = filePair.b;
170179
// build the diff view and add it to the current DOM
@@ -201,7 +210,7 @@ function FileDiff(props: FileDiffProps) {
201210

202211
return (
203212
<div className="diff">
204-
<NoChanges filePair={filePair} />
213+
<NoChanges filePair={filePair} isEqualAfterNormalization={isEqualAfterNormalization} />
205214
<CodeDiff
206215
beforeText={contentsBefore}
207216
afterText={contentsAfter}

0 commit comments

Comments
 (0)