@astryxdesign/lab 0.7.1-canary.fb02ee9 → 0.7.1-canary.fc89798
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DiffViewer/diffTypes.d.ts +65 -0
- package/dist/DiffViewer/diffTypes.d.ts.map +1 -0
- package/dist/DiffViewer/diffTypes.js +1 -0
- package/dist/DiffViewer/index.d.ts +10 -0
- package/dist/DiffViewer/index.d.ts.map +1 -0
- package/dist/DiffViewer/index.js +11 -0
- package/dist/DiffViewer/parseUnifiedDiff.d.ts +31 -0
- package/dist/DiffViewer/parseUnifiedDiff.d.ts.map +1 -0
- package/dist/DiffViewer/parseUnifiedDiff.js +379 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/package.json +4 -4
- package/src/DiffViewer/diffTypes.ts +73 -0
- package/src/DiffViewer/index.ts +20 -0
- package/src/DiffViewer/parseUnifiedDiff.test.ts +397 -0
- package/src/DiffViewer/parseUnifiedDiff.ts +436 -0
- package/src/Schedule/Schedule.test.tsx +97 -0
- package/src/Schedule/__tests__/ScheduleTimeGridSkippedMidnight.a11y.chromium.spec.ts +113 -0
- package/src/index.ts +14 -3
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file diffTypes.ts
|
|
3
|
+
* @input None (type-only module)
|
|
4
|
+
* @output Exports the structured diff model DiffViewer renders: DiffViewerFile,
|
|
5
|
+
* DiffViewerHunk, DiffViewerLine, DiffViewerLineKind, DiffViewerFileStatus,
|
|
6
|
+
* DiffViewerSide, DiffViewerLineRef
|
|
7
|
+
* @position Lab data model; produced by parseUnifiedDiff (or built by hand) and
|
|
8
|
+
* consumed by DiffViewer
|
|
9
|
+
*
|
|
10
|
+
* SYNC: When modified, update:
|
|
11
|
+
* - /packages/lab/src/DiffViewer/index.ts (type exports)
|
|
12
|
+
*/
|
|
13
|
+
/** What one line of a hunk does: adds, removes, or keeps a line. */
|
|
14
|
+
export type DiffViewerLineKind = 'added' | 'removed' | 'context';
|
|
15
|
+
/** How the file changed as a whole. */
|
|
16
|
+
export type DiffViewerFileStatus = 'added' | 'deleted' | 'modified' | 'renamed';
|
|
17
|
+
/**
|
|
18
|
+
* Which version of the file a line number belongs to: `old` is the original
|
|
19
|
+
* (left in split view), `new` the changed version (right in split view).
|
|
20
|
+
*/
|
|
21
|
+
export type DiffViewerSide = 'old' | 'new';
|
|
22
|
+
/** One line of a hunk, without its leading `+`/`-`/space glyph. */
|
|
23
|
+
export interface DiffViewerLine {
|
|
24
|
+
kind: DiffViewerLineKind;
|
|
25
|
+
/** The line's text with the diff glyph removed. */
|
|
26
|
+
content: string;
|
|
27
|
+
/** 1-based line number in the old file; `null` for an added line. */
|
|
28
|
+
oldLineNumber: number | null;
|
|
29
|
+
/** 1-based line number in the new file; `null` for a removed line. */
|
|
30
|
+
newLineNumber: number | null;
|
|
31
|
+
}
|
|
32
|
+
/** One `@@` hunk: a run of changed lines with their surrounding context. */
|
|
33
|
+
export interface DiffViewerHunk {
|
|
34
|
+
/** The hunk header as written, e.g. `@@ -12,7 +12,9 @@ function save()`. */
|
|
35
|
+
header: string;
|
|
36
|
+
oldStart: number;
|
|
37
|
+
oldLines: number;
|
|
38
|
+
newStart: number;
|
|
39
|
+
newLines: number;
|
|
40
|
+
lines: DiffViewerLine[];
|
|
41
|
+
}
|
|
42
|
+
/** One file's changes. */
|
|
43
|
+
export interface DiffViewerFile {
|
|
44
|
+
/** Path before the change; `null` when the file was added. */
|
|
45
|
+
oldPath: string | null;
|
|
46
|
+
/** Path after the change; `null` when the file was deleted. */
|
|
47
|
+
newPath: string | null;
|
|
48
|
+
status: DiffViewerFileStatus;
|
|
49
|
+
/** True when the patch reports a binary change with no line hunks. */
|
|
50
|
+
isBinary: boolean;
|
|
51
|
+
hunks: DiffViewerHunk[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Identifies one line of a rendered diff for annotations and line-number
|
|
55
|
+
* clicks. Every line has exactly one ref, the same in unified and split view,
|
|
56
|
+
* so `side` + `lineNumber` is a stable anchor (e.g. for a review comment): an
|
|
57
|
+
* added line is `new`, a removed line is `old`, and a context line is `new`.
|
|
58
|
+
*/
|
|
59
|
+
export interface DiffViewerLineRef {
|
|
60
|
+
side: DiffViewerSide;
|
|
61
|
+
lineNumber: number;
|
|
62
|
+
line: DiffViewerLine;
|
|
63
|
+
hunkIndex: number;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=diffTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diffTypes.d.ts","sourceRoot":"","sources":["../../src/DiffViewer/diffTypes.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,oEAAoE;AACpE,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjE,uCAAuC;AACvC,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAEhF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,CAAC;AAE3C,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sEAAsE;IACtE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,0BAA0B;AAC1B,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file index.ts
|
|
3
|
+
* @input Imports from parseUnifiedDiff.ts and diffTypes.ts
|
|
4
|
+
* @output Exports the structured diff model and the unified-diff parser
|
|
5
|
+
* @position Entry point for the DiffViewer folder; re-exported by
|
|
6
|
+
* /packages/lab/src/index.ts
|
|
7
|
+
*/
|
|
8
|
+
export { parseUnifiedDiff } from './parseUnifiedDiff';
|
|
9
|
+
export type { DiffViewerFile, DiffViewerFileStatus, DiffViewerHunk, DiffViewerLine, DiffViewerLineKind, DiffViewerLineRef, DiffViewerSide, } from './diffTypes';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/DiffViewer/index.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACpD,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,GACf,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file index.ts
|
|
5
|
+
* @input Imports from parseUnifiedDiff.ts and diffTypes.ts
|
|
6
|
+
* @output Exports the structured diff model and the unified-diff parser
|
|
7
|
+
* @position Entry point for the DiffViewer folder; re-exported by
|
|
8
|
+
* /packages/lab/src/index.ts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { parseUnifiedDiff } from "./parseUnifiedDiff.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file parseUnifiedDiff.ts
|
|
3
|
+
* @input A unified diff / patch string (`git diff`, `diff -u`, or a bare hunk)
|
|
4
|
+
* @output Exports parseUnifiedDiff(patch) → DiffViewerFile[]
|
|
5
|
+
* @position Lab utility; turns patch text into the structured model DiffViewer
|
|
6
|
+
* renders
|
|
7
|
+
*
|
|
8
|
+
* Tolerant by design: unknown header lines are skipped, a hunk whose counts
|
|
9
|
+
* run short ends where its lines end, and input with no recognizable file or
|
|
10
|
+
* hunk returns an empty array. It never throws.
|
|
11
|
+
*
|
|
12
|
+
* SYNC: When modified, update:
|
|
13
|
+
* - /packages/lab/src/DiffViewer/parseUnifiedDiff.test.ts
|
|
14
|
+
*/
|
|
15
|
+
import type { DiffViewerFile } from './diffTypes';
|
|
16
|
+
/**
|
|
17
|
+
* Parse a unified diff into one {@link DiffViewerFile} per file.
|
|
18
|
+
*
|
|
19
|
+
* Accepts `git diff` output (with `diff --git`, mode, rename, copy, and
|
|
20
|
+
* binary lines), classic `diff -u` output (`---`/`+++` pairs), several files in one
|
|
21
|
+
* patch, and a bare `@@` hunk with no file header (returned as one file with
|
|
22
|
+
* null paths). Input it cannot read yields `[]`; it never throws.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```
|
|
26
|
+
* const files = parseUnifiedDiff(patch);
|
|
27
|
+
* files.map((file) => <DiffViewer key={file.newPath ?? file.oldPath} file={file} />);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseUnifiedDiff(patch: string): DiffViewerFile[];
|
|
31
|
+
//# sourceMappingURL=parseUnifiedDiff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseUnifiedDiff.d.ts","sourceRoot":"","sources":["../../src/DiffViewer/parseUnifiedDiff.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,aAAa,CAAC;AAkOrB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,EAAE,CA8KhE"}
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file parseUnifiedDiff.ts
|
|
5
|
+
* @input A unified diff / patch string (`git diff`, `diff -u`, or a bare hunk)
|
|
6
|
+
* @output Exports parseUnifiedDiff(patch) → DiffViewerFile[]
|
|
7
|
+
* @position Lab utility; turns patch text into the structured model DiffViewer
|
|
8
|
+
* renders
|
|
9
|
+
*
|
|
10
|
+
* Tolerant by design: unknown header lines are skipped, a hunk whose counts
|
|
11
|
+
* run short ends where its lines end, and input with no recognizable file or
|
|
12
|
+
* hunk returns an empty array. It never throws.
|
|
13
|
+
*
|
|
14
|
+
* SYNC: When modified, update:
|
|
15
|
+
* - /packages/lab/src/DiffViewer/parseUnifiedDiff.test.ts
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
19
|
+
const GIT_HEADER_PREFIX = 'diff --git ';
|
|
20
|
+
const BINARY_PREFIX = 'Binary files ';
|
|
21
|
+
const BINARY_SUFFIX = ' differ';
|
|
22
|
+
const BINARY_SEPARATOR = ' and ';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The two paths of a `Binary files X and Y differ` line, or null when the
|
|
26
|
+
* line is not one. Plain string matching, not a regex, so any line (however
|
|
27
|
+
* long, whatever characters it holds) is read in one pass. Like the greedy
|
|
28
|
+
* pattern it replaces, the separator is the last ` and `.
|
|
29
|
+
*/
|
|
30
|
+
function parseBinaryLine(line) {
|
|
31
|
+
if (!line.startsWith(BINARY_PREFIX) || !line.endsWith(BINARY_SUFFIX)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const middle = line.slice(BINARY_PREFIX.length, line.length - BINARY_SUFFIX.length);
|
|
35
|
+
const split = middle.lastIndexOf(BINARY_SEPARATOR);
|
|
36
|
+
if (split <= 0 || split + BINARY_SEPARATOR.length >= middle.length) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
oldPath: middle.slice(0, split),
|
|
41
|
+
newPath: middle.slice(split + BINARY_SEPARATOR.length)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const C_ESCAPES = {
|
|
45
|
+
a: 0x07,
|
|
46
|
+
b: 0x08,
|
|
47
|
+
t: 0x09,
|
|
48
|
+
n: 0x0a,
|
|
49
|
+
v: 0x0b,
|
|
50
|
+
f: 0x0c,
|
|
51
|
+
r: 0x0d,
|
|
52
|
+
'"': 0x22,
|
|
53
|
+
'\\': 0x5c
|
|
54
|
+
};
|
|
55
|
+
const utf8 = new TextDecoder();
|
|
56
|
+
const utf8Encoder = new TextEncoder();
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Read a git C-style quoted path starting at `start` (the opening quote).
|
|
60
|
+
* Git quotes a path that holds non-ASCII bytes or special characters and
|
|
61
|
+
* writes those bytes as octal escapes (`"caf\303\251.md"`), so the escapes
|
|
62
|
+
* are collected as bytes and decoded as UTF-8. Returns the path and the index
|
|
63
|
+
* just past the closing quote, or null when the quote never closes.
|
|
64
|
+
*/
|
|
65
|
+
function readQuoted(text, start) {
|
|
66
|
+
const bytes = [];
|
|
67
|
+
let i = start + 1;
|
|
68
|
+
while (i < text.length) {
|
|
69
|
+
const ch = text[i];
|
|
70
|
+
if (ch === '"') {
|
|
71
|
+
return {
|
|
72
|
+
value: utf8.decode(new Uint8Array(bytes)),
|
|
73
|
+
end: i + 1
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (ch === '\\' && i + 1 < text.length) {
|
|
77
|
+
const next = text[i + 1];
|
|
78
|
+
const octal = /^[0-7]{3}/.exec(text.slice(i + 1, i + 4));
|
|
79
|
+
if (octal != null) {
|
|
80
|
+
bytes.push(parseInt(octal[0], 8));
|
|
81
|
+
i += 4;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (next in C_ESCAPES) {
|
|
85
|
+
bytes.push(C_ESCAPES[next]);
|
|
86
|
+
i += 2;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Any other character stands for itself (as UTF-8 bytes).
|
|
91
|
+
const codePoint = text.codePointAt(i) ?? 0;
|
|
92
|
+
const char = String.fromCodePoint(codePoint);
|
|
93
|
+
bytes.push(...utf8Encoder.encode(char));
|
|
94
|
+
i += char.length;
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The path written in `raw`, unquoted and decoded when git quoted it. */
|
|
100
|
+
function unquotePath(raw) {
|
|
101
|
+
if (raw.startsWith('"')) {
|
|
102
|
+
const quoted = readQuoted(raw, 0);
|
|
103
|
+
if (quoted != null) {
|
|
104
|
+
return quoted.value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return raw;
|
|
108
|
+
}
|
|
109
|
+
function stripPrefix(path, prefix) {
|
|
110
|
+
return path.startsWith(prefix) ? path.slice(prefix.length) : path;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The two paths of a `diff --git` line. Git quotes a path that holds special
|
|
115
|
+
* or non-ASCII characters; quoted paths are read whole and decoded. An
|
|
116
|
+
* unquoted path may hold spaces, so a space can look like the separator: when
|
|
117
|
+
* both sides name the same path (every change except a rename) the separator
|
|
118
|
+
* is the middle space. A rename writes `rename from` / `rename to` lines,
|
|
119
|
+
* which replace these paths, so the first-space split is only a fallback.
|
|
120
|
+
*/
|
|
121
|
+
function parseGitHeader(line) {
|
|
122
|
+
if (!line.startsWith(GIT_HEADER_PREFIX)) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const rest = line.slice(GIT_HEADER_PREFIX.length);
|
|
126
|
+
const paths = (left, right) => ({
|
|
127
|
+
oldPath: stripPrefix(left, 'a/'),
|
|
128
|
+
newPath: stripPrefix(right, 'b/')
|
|
129
|
+
});
|
|
130
|
+
if (rest.startsWith('"')) {
|
|
131
|
+
const left = readQuoted(rest, 0);
|
|
132
|
+
if (left != null && rest[left.end] === ' ') {
|
|
133
|
+
return paths(left.value, unquotePath(rest.slice(left.end + 1)));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (rest.endsWith('"')) {
|
|
137
|
+
// Only the new side is quoted: it starts at the last ` "` that reads to
|
|
138
|
+
// the end of the line as one quoted path.
|
|
139
|
+
for (let split = rest.lastIndexOf(' "'); split > 0; split = rest.lastIndexOf(' "', split - 1)) {
|
|
140
|
+
const right = readQuoted(rest, split + 1);
|
|
141
|
+
if (right != null && right.end === rest.length) {
|
|
142
|
+
return paths(rest.slice(0, split), right.value);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (rest.length % 2 === 1) {
|
|
147
|
+
const middle = (rest.length - 1) / 2;
|
|
148
|
+
const left = rest.slice(0, middle);
|
|
149
|
+
const right = rest.slice(middle + 1);
|
|
150
|
+
if (rest[middle] === ' ' && stripPrefix(left, 'a/') === stripPrefix(right, 'b/')) {
|
|
151
|
+
return paths(left, right);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const space = rest.indexOf(' ');
|
|
155
|
+
return space <= 0 ? null : paths(rest.slice(0, space), rest.slice(space + 1));
|
|
156
|
+
}
|
|
157
|
+
function emptyFile() {
|
|
158
|
+
return {
|
|
159
|
+
oldPath: null,
|
|
160
|
+
newPath: null,
|
|
161
|
+
status: null,
|
|
162
|
+
isBinary: false,
|
|
163
|
+
hunks: []
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* `a/src/x.ts` → `src/x.ts`; `/dev/null` → null; drops a trailing
|
|
169
|
+
* tab+timestamp and decodes a quoted path.
|
|
170
|
+
*/
|
|
171
|
+
function cleanPath(raw, prefix) {
|
|
172
|
+
let path = unquotePath(raw.split('\t')[0].trim());
|
|
173
|
+
if (path === '/dev/null') {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
if (path.startsWith(prefix)) {
|
|
177
|
+
path = path.slice(prefix.length);
|
|
178
|
+
}
|
|
179
|
+
return path;
|
|
180
|
+
}
|
|
181
|
+
function finalize(file) {
|
|
182
|
+
let status = file.status;
|
|
183
|
+
if (status == null) {
|
|
184
|
+
if (file.oldPath == null && file.newPath != null) {
|
|
185
|
+
status = 'added';
|
|
186
|
+
} else if (file.newPath == null && file.oldPath != null) {
|
|
187
|
+
status = 'deleted';
|
|
188
|
+
} else {
|
|
189
|
+
// Only git's rename lines say a file moved. Two different paths
|
|
190
|
+
// without them (`diff -u a.orig a`, `diff -ruN old new`, a copy) are an
|
|
191
|
+
// edit between two files, so both paths are kept.
|
|
192
|
+
status = 'modified';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
oldPath: status === 'added' ? null : file.oldPath,
|
|
197
|
+
newPath: status === 'deleted' ? null : file.newPath,
|
|
198
|
+
status,
|
|
199
|
+
isBinary: file.isBinary,
|
|
200
|
+
hunks: file.hunks
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function hasContent(file) {
|
|
204
|
+
return file.hunks.length > 0 || file.isBinary || file.oldPath != null || file.newPath != null || file.status != null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Parse a unified diff into one {@link DiffViewerFile} per file.
|
|
209
|
+
*
|
|
210
|
+
* Accepts `git diff` output (with `diff --git`, mode, rename, copy, and
|
|
211
|
+
* binary lines), classic `diff -u` output (`---`/`+++` pairs), several files in one
|
|
212
|
+
* patch, and a bare `@@` hunk with no file header (returned as one file with
|
|
213
|
+
* null paths). Input it cannot read yields `[]`; it never throws.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```
|
|
217
|
+
* const files = parseUnifiedDiff(patch);
|
|
218
|
+
* files.map((file) => <DiffViewer key={file.newPath ?? file.oldPath} file={file} />);
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export function parseUnifiedDiff(patch) {
|
|
222
|
+
const lines = patch.split('\n').map(line => line.replace(/\r$/, ''));
|
|
223
|
+
const files = [];
|
|
224
|
+
let file = null;
|
|
225
|
+
let hunk = null;
|
|
226
|
+
let oldRemaining = 0;
|
|
227
|
+
let newRemaining = 0;
|
|
228
|
+
let oldLine = 0;
|
|
229
|
+
let newLine = 0;
|
|
230
|
+
const flush = () => {
|
|
231
|
+
if (file != null && hasContent(file)) {
|
|
232
|
+
files.push(finalize(file));
|
|
233
|
+
}
|
|
234
|
+
file = null;
|
|
235
|
+
hunk = null;
|
|
236
|
+
};
|
|
237
|
+
for (let i = 0; i < lines.length; i++) {
|
|
238
|
+
const line = lines[i];
|
|
239
|
+
|
|
240
|
+
// Inside a hunk: consume body lines until both counts are spent.
|
|
241
|
+
if (hunk != null && (oldRemaining > 0 || newRemaining > 0)) {
|
|
242
|
+
const glyph = line[0];
|
|
243
|
+
if (glyph === '\\') {
|
|
244
|
+
// "" — annotates the previous line.
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (glyph === '+') {
|
|
248
|
+
hunk.lines.push({
|
|
249
|
+
kind: 'added',
|
|
250
|
+
content: line.slice(1),
|
|
251
|
+
oldLineNumber: null,
|
|
252
|
+
newLineNumber: newLine++
|
|
253
|
+
});
|
|
254
|
+
newRemaining--;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (glyph === '-') {
|
|
258
|
+
hunk.lines.push({
|
|
259
|
+
kind: 'removed',
|
|
260
|
+
content: line.slice(1),
|
|
261
|
+
oldLineNumber: oldLine++,
|
|
262
|
+
newLineNumber: null
|
|
263
|
+
});
|
|
264
|
+
oldRemaining--;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (glyph === ' ' || line === '') {
|
|
268
|
+
// Some tools strip the trailing space of an empty context line.
|
|
269
|
+
if (line === '' && i === lines.length - 1) {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
hunk.lines.push({
|
|
273
|
+
kind: 'context',
|
|
274
|
+
content: line.slice(1),
|
|
275
|
+
oldLineNumber: oldLine++,
|
|
276
|
+
newLineNumber: newLine++
|
|
277
|
+
});
|
|
278
|
+
oldRemaining--;
|
|
279
|
+
newRemaining--;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
// Anything else ends a short hunk; fall through and read it as a header.
|
|
283
|
+
hunk = null;
|
|
284
|
+
}
|
|
285
|
+
if (hunk != null && line.startsWith('\\')) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
const gitPaths = parseGitHeader(line);
|
|
289
|
+
if (gitPaths != null) {
|
|
290
|
+
flush();
|
|
291
|
+
file = emptyFile();
|
|
292
|
+
file.oldPath = gitPaths.oldPath;
|
|
293
|
+
file.newPath = gitPaths.newPath;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (line.startsWith('--- ') && (lines[i + 1]?.startsWith('+++ ') ?? false)) {
|
|
297
|
+
// A `---`/`+++` pair opens a new file unless it belongs to a
|
|
298
|
+
// `diff --git` header whose hunks have not started yet. A binary entry
|
|
299
|
+
// never takes a pair: in `diff -r` output it was a file of its own.
|
|
300
|
+
if (file == null || file.hunks.length > 0 || file.isBinary) {
|
|
301
|
+
flush();
|
|
302
|
+
file = emptyFile();
|
|
303
|
+
}
|
|
304
|
+
const current = file;
|
|
305
|
+
current.oldPath = cleanPath(line.slice(4), 'a/');
|
|
306
|
+
current.newPath = cleanPath(lines[i + 1].slice(4), 'b/');
|
|
307
|
+
if (current.oldPath == null && current.status == null) {
|
|
308
|
+
current.status = 'added';
|
|
309
|
+
} else if (current.newPath == null && current.status == null) {
|
|
310
|
+
current.status = 'deleted';
|
|
311
|
+
}
|
|
312
|
+
i++;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const header = HUNK_HEADER.exec(line);
|
|
316
|
+
if (header) {
|
|
317
|
+
file ??= emptyFile();
|
|
318
|
+
const oldStart = Number(header[1]);
|
|
319
|
+
const oldLines = header[2] == null ? 1 : Number(header[2]);
|
|
320
|
+
const newStart = Number(header[3]);
|
|
321
|
+
const newLines = header[4] == null ? 1 : Number(header[4]);
|
|
322
|
+
const next = {
|
|
323
|
+
header: line,
|
|
324
|
+
oldStart,
|
|
325
|
+
oldLines,
|
|
326
|
+
newStart,
|
|
327
|
+
newLines,
|
|
328
|
+
lines: []
|
|
329
|
+
};
|
|
330
|
+
file.hunks.push(next);
|
|
331
|
+
hunk = next;
|
|
332
|
+
oldRemaining = oldLines;
|
|
333
|
+
newRemaining = newLines;
|
|
334
|
+
// A zero-length side's start names the line *before* the hunk.
|
|
335
|
+
oldLine = oldLines === 0 ? oldStart + 1 : oldStart;
|
|
336
|
+
newLine = newLines === 0 ? newStart + 1 : newStart;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// GNU `diff -r` reports a binary file with this one line and no header,
|
|
341
|
+
// so unless it belongs to a `diff --git` header still being read (no
|
|
342
|
+
// hunks yet, not already binary), it is a file of its own.
|
|
343
|
+
const binary = parseBinaryLine(line);
|
|
344
|
+
if (binary != null && (file == null || file.hunks.length > 0 || file.isBinary)) {
|
|
345
|
+
flush();
|
|
346
|
+
const own = emptyFile();
|
|
347
|
+
own.oldPath = cleanPath(binary.oldPath, 'a/');
|
|
348
|
+
own.newPath = cleanPath(binary.newPath, 'b/');
|
|
349
|
+
own.isBinary = true;
|
|
350
|
+
file = own;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (file == null) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
const current = file;
|
|
357
|
+
if (line.startsWith('new file mode')) {
|
|
358
|
+
current.status = 'added';
|
|
359
|
+
} else if (line.startsWith('deleted file mode')) {
|
|
360
|
+
current.status = 'deleted';
|
|
361
|
+
} else if (line.startsWith('rename from ')) {
|
|
362
|
+
current.oldPath = unquotePath(line.slice('rename from '.length));
|
|
363
|
+
current.status = 'renamed';
|
|
364
|
+
} else if (line.startsWith('rename to ')) {
|
|
365
|
+
current.newPath = unquotePath(line.slice('rename to '.length));
|
|
366
|
+
current.status = 'renamed';
|
|
367
|
+
} else if (line.startsWith('copy from ')) {
|
|
368
|
+
// A copy keeps its source, so it reads as an edit from the source path
|
|
369
|
+
// to the new one; these lines also fix paths the header split wrongly.
|
|
370
|
+
current.oldPath = unquotePath(line.slice('copy from '.length));
|
|
371
|
+
} else if (line.startsWith('copy to ')) {
|
|
372
|
+
current.newPath = unquotePath(line.slice('copy to '.length));
|
|
373
|
+
} else if (line.startsWith('Binary files ') || line === 'GIT binary patch') {
|
|
374
|
+
current.isBinary = true;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
flush();
|
|
378
|
+
return files;
|
|
379
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -28,5 +28,6 @@ export { SankeyChart, type SankeyChartProps, SankeyLink, type SankeyLinkProps, S
|
|
|
28
28
|
export * from './CircularProgress';
|
|
29
29
|
export * from './ListInput';
|
|
30
30
|
export { LogStream, type LogStreamProps, type LogEntry, type LogStreamLevel, } from './LogStream';
|
|
31
|
+
export { parseUnifiedDiff, type DiffViewerFile, type DiffViewerFileStatus, type DiffViewerHunk, type DiffViewerLine, type DiffViewerLineKind, type DiffViewerLineRef, type DiffViewerSide, } from './DiffViewer';
|
|
31
32
|
export { MobileTokenizer, type MobileTokenizerProps, type MobileTokenizerChange, } from './MobileTokenizer';
|
|
32
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -66,12 +66,14 @@ export * from "./ListInput/index.js";
|
|
|
66
66
|
// LogStream — experimental streaming log viewer
|
|
67
67
|
export { LogStream } from "./LogStream/index.js";
|
|
68
68
|
|
|
69
|
+
// DiffViewer — the structured diff model and the unified-diff parser
|
|
70
|
+
export { parseUnifiedDiff } from "./DiffViewer/index.js";
|
|
71
|
+
|
|
69
72
|
// MobileTokenizer — Lab prototype (stack layer 1) of the touch Tokenizer
|
|
70
73
|
// flow: summary trigger + stacked manage/add BottomSheets. Graduates to
|
|
71
74
|
// Core Tokenizer presentation="bottom-sheet" (stack layer 2).
|
|
72
75
|
export { MobileTokenizer } from "./MobileTokenizer/index.js";
|
|
73
76
|
|
|
74
|
-
// RichTextEditor (RFC facebook/astryx#3899)
|
|
75
|
-
//
|
|
76
|
-
// independently by an adopting application. Import it from there:
|
|
77
|
+
// RichTextEditor (RFC facebook/astryx#3899) moved out of @astryxdesign/lab into
|
|
78
|
+
// its own package, @astryxdesign/richtext. Import it from there:
|
|
77
79
|
// import {RichTextEditor, RichTextView} from '@astryxdesign/richtext';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.7.1-canary.
|
|
3
|
+
"version": "0.7.1-canary.fc89798",
|
|
4
4
|
"description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@stylexjs/stylex": ">=0.10.0",
|
|
50
|
-
"@astryxdesign/core": "0.7.1-canary.
|
|
50
|
+
"@astryxdesign/core": "0.7.1-canary.fc89798",
|
|
51
51
|
"react": ">=19.0.0",
|
|
52
52
|
"react-dom": ">=19.0.0"
|
|
53
53
|
},
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"d3-shape": "^3.2.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@astryxdesign/a11y-spec": "0.7.1-canary.
|
|
61
|
-
"@astryxdesign/cli": "0.7.1-canary.
|
|
60
|
+
"@astryxdesign/a11y-spec": "0.7.1-canary.fc89798",
|
|
61
|
+
"@astryxdesign/cli": "0.7.1-canary.fc89798",
|
|
62
62
|
"@babel/cli": "^7.29.7",
|
|
63
63
|
"@babel/core": "^7.29.7",
|
|
64
64
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file diffTypes.ts
|
|
5
|
+
* @input None (type-only module)
|
|
6
|
+
* @output Exports the structured diff model DiffViewer renders: DiffViewerFile,
|
|
7
|
+
* DiffViewerHunk, DiffViewerLine, DiffViewerLineKind, DiffViewerFileStatus,
|
|
8
|
+
* DiffViewerSide, DiffViewerLineRef
|
|
9
|
+
* @position Lab data model; produced by parseUnifiedDiff (or built by hand) and
|
|
10
|
+
* consumed by DiffViewer
|
|
11
|
+
*
|
|
12
|
+
* SYNC: When modified, update:
|
|
13
|
+
* - /packages/lab/src/DiffViewer/index.ts (type exports)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** What one line of a hunk does: adds, removes, or keeps a line. */
|
|
17
|
+
export type DiffViewerLineKind = 'added' | 'removed' | 'context';
|
|
18
|
+
|
|
19
|
+
/** How the file changed as a whole. */
|
|
20
|
+
export type DiffViewerFileStatus = 'added' | 'deleted' | 'modified' | 'renamed';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Which version of the file a line number belongs to: `old` is the original
|
|
24
|
+
* (left in split view), `new` the changed version (right in split view).
|
|
25
|
+
*/
|
|
26
|
+
export type DiffViewerSide = 'old' | 'new';
|
|
27
|
+
|
|
28
|
+
/** One line of a hunk, without its leading `+`/`-`/space glyph. */
|
|
29
|
+
export interface DiffViewerLine {
|
|
30
|
+
kind: DiffViewerLineKind;
|
|
31
|
+
/** The line's text with the diff glyph removed. */
|
|
32
|
+
content: string;
|
|
33
|
+
/** 1-based line number in the old file; `null` for an added line. */
|
|
34
|
+
oldLineNumber: number | null;
|
|
35
|
+
/** 1-based line number in the new file; `null` for a removed line. */
|
|
36
|
+
newLineNumber: number | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** One `@@` hunk: a run of changed lines with their surrounding context. */
|
|
40
|
+
export interface DiffViewerHunk {
|
|
41
|
+
/** The hunk header as written, e.g. `@@ -12,7 +12,9 @@ function save()`. */
|
|
42
|
+
header: string;
|
|
43
|
+
oldStart: number;
|
|
44
|
+
oldLines: number;
|
|
45
|
+
newStart: number;
|
|
46
|
+
newLines: number;
|
|
47
|
+
lines: DiffViewerLine[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** One file's changes. */
|
|
51
|
+
export interface DiffViewerFile {
|
|
52
|
+
/** Path before the change; `null` when the file was added. */
|
|
53
|
+
oldPath: string | null;
|
|
54
|
+
/** Path after the change; `null` when the file was deleted. */
|
|
55
|
+
newPath: string | null;
|
|
56
|
+
status: DiffViewerFileStatus;
|
|
57
|
+
/** True when the patch reports a binary change with no line hunks. */
|
|
58
|
+
isBinary: boolean;
|
|
59
|
+
hunks: DiffViewerHunk[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Identifies one line of a rendered diff for annotations and line-number
|
|
64
|
+
* clicks. Every line has exactly one ref, the same in unified and split view,
|
|
65
|
+
* so `side` + `lineNumber` is a stable anchor (e.g. for a review comment): an
|
|
66
|
+
* added line is `new`, a removed line is `old`, and a context line is `new`.
|
|
67
|
+
*/
|
|
68
|
+
export interface DiffViewerLineRef {
|
|
69
|
+
side: DiffViewerSide;
|
|
70
|
+
lineNumber: number;
|
|
71
|
+
line: DiffViewerLine;
|
|
72
|
+
hunkIndex: number;
|
|
73
|
+
}
|