@git-diff-view/react 0.0.11 → 0.0.12

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.
@@ -72,334 +72,79 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
72
72
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
73
73
  };
74
74
 
75
- /******************************************************************************
76
- Copyright (c) Microsoft Corporation.
77
-
78
- Permission to use, copy, modify, and/or distribute this software for any
79
- purpose with or without fee is hereby granted.
80
-
81
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
82
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
83
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
84
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
85
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
86
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
87
- PERFORMANCE OF THIS SOFTWARE.
88
- ***************************************************************************** */
89
- /* global Reflect, Promise, SuppressedError, Symbol */
90
-
91
-
92
- function __classPrivateFieldGet(receiver, state, kind, f) {
93
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
94
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
95
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
96
- }
97
-
98
- function __classPrivateFieldSet(receiver, state, value, kind, f) {
99
- if (kind === "m") throw new TypeError("Private method is not writable");
100
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
101
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
102
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
103
- }
104
-
105
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
106
- var e = new Error(message);
107
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
108
- };
109
-
110
- const processAST = (ast) => {
111
- let lineNumber = 1;
112
- const syntaxObj = {};
113
- const loopAST = (nodes, wrapper) => {
114
- nodes.forEach((node) => {
115
- if (node.type === "text") {
116
- if (node.value.indexOf("\n") === -1) {
117
- const valueLength = node.value.length;
118
- if (!syntaxObj[lineNumber]) {
119
- node.startIndex = 0;
120
- node.endIndex = valueLength - 1;
121
- const item = {
122
- value: node.value,
123
- lineNumber,
124
- valueLength,
125
- nodeList: [{ node, wrapper }],
126
- };
127
- syntaxObj[lineNumber] = item;
128
- }
129
- else {
130
- node.startIndex = syntaxObj[lineNumber].valueLength;
131
- node.endIndex = node.startIndex + valueLength - 1;
132
- syntaxObj[lineNumber].value += node.value;
133
- syntaxObj[lineNumber].valueLength += valueLength;
134
- syntaxObj[lineNumber].nodeList.push({ node, wrapper });
135
- }
136
- node.lineNumber = lineNumber;
137
- return;
138
- }
139
- const lines = node.value.split("\n");
140
- node.children = node.children || [];
141
- for (let i = 0; i < lines.length; i++) {
142
- const _value = i === lines.length - 1 ? lines[i] : lines[i] + "\n";
143
- const _lineNumber = i === 0 ? lineNumber : ++lineNumber;
144
- const _valueLength = _value.length;
145
- const _node = {
146
- type: "text",
147
- value: _value,
148
- startIndex: Infinity,
149
- endIndex: Infinity,
150
- lineNumber: _lineNumber,
151
- };
152
- if (!syntaxObj[_lineNumber]) {
153
- _node.startIndex = 0;
154
- _node.endIndex = _valueLength - 1;
155
- const item = {
156
- value: _value,
157
- lineNumber: _lineNumber,
158
- valueLength: _valueLength,
159
- nodeList: [{ node: _node, wrapper }],
160
- };
161
- syntaxObj[_lineNumber] = item;
162
- }
163
- else {
164
- _node.startIndex = syntaxObj[_lineNumber].valueLength;
165
- _node.endIndex = _node.startIndex + _valueLength - 1;
166
- syntaxObj[_lineNumber].value += _value;
167
- syntaxObj[_lineNumber].valueLength += _valueLength;
168
- syntaxObj[_lineNumber].nodeList.push({ node: _node, wrapper });
169
- }
170
- node.children.push(_node);
171
- }
172
- node.lineNumber = lineNumber;
173
- return;
174
- }
175
- if (node.children) {
176
- loopAST(node.children, node);
177
- node.lineNumber = lineNumber;
178
- }
179
- });
180
- };
181
- loopAST(ast.children);
182
- return { syntaxFileObject: syntaxObj, syntaxFileLineNumber: lineNumber };
183
- };
184
-
185
- const lowlight = lowlight$1.createLowlight(lowlight$1.all);
186
- // !SEE https://github.com/highlightjs/highlightjs-vue
187
- lowlight.register("vue", function hljsDefineVue(hljs) {
188
- return {
189
- subLanguage: "xml",
190
- contains: [
191
- hljs.COMMENT("<!--", "-->", {
192
- relevance: 10,
193
- }),
194
- {
195
- begin: /^(\s*)(<script>)/gm,
196
- end: /^(\s*)(<\/script>)/gm,
197
- subLanguage: "javascript",
198
- excludeBegin: true,
199
- excludeEnd: true,
200
- },
201
- {
202
- begin: /^(?:\s*)(?:<script\s+lang=(["'])ts\1>)/gm,
203
- end: /^(\s*)(<\/script>)/gm,
204
- subLanguage: "typescript",
205
- excludeBegin: true,
206
- excludeEnd: true,
207
- },
208
- {
209
- begin: /^(\s*)(<style(\s+scoped)?>)/gm,
210
- end: /^(\s*)(<\/style>)/gm,
211
- subLanguage: "css",
212
- excludeBegin: true,
213
- excludeEnd: true,
214
- },
215
- {
216
- begin: /^(?:\s*)(?:<style(?:\s+scoped)?\s+lang=(["'])(?:s[ca]ss)\1(?:\s+scoped)?>)/gm,
217
- end: /^(\s*)(<\/style>)/gm,
218
- subLanguage: "scss",
219
- excludeBegin: true,
220
- excludeEnd: true,
221
- },
222
- {
223
- begin: /^(?:\s*)(?:<style(?:\s+scoped)?\s+lang=(["'])stylus\1(?:\s+scoped)?>)/gm,
224
- end: /^(\s*)(<\/style>)/gm,
225
- subLanguage: "stylus",
226
- excludeBegin: true,
227
- excludeEnd: true,
228
- },
229
- ],
230
- };
231
- });
232
- const instance = { name: "lowlight" };
233
- let _maxLineToIgnoreSyntax = 2000;
234
- const _ignoreSyntaxHighlightList = [];
235
- Object.defineProperty(instance, "maxLineToIgnoreSyntax", {
236
- get: () => _maxLineToIgnoreSyntax,
237
- });
238
- Object.defineProperty(instance, "setMaxLineToIgnoreSyntax", {
239
- value: (v) => {
240
- _maxLineToIgnoreSyntax = v;
241
- },
242
- });
243
- Object.defineProperty(instance, "ignoreSyntaxHighlightList", {
244
- get: () => _ignoreSyntaxHighlightList,
245
- });
246
- Object.defineProperty(instance, "setIgnoreSyntaxHighlightList", {
247
- value: (v) => {
248
- _ignoreSyntaxHighlightList.length = 0;
249
- _ignoreSyntaxHighlightList.push(...v);
250
- },
251
- });
252
- Object.defineProperty(instance, "getAST", {
253
- value: (raw, fileName, lang) => {
254
- let hasRegisteredLang = true;
255
- if (!lowlight.registered(lang)) {
256
- console.warn(`not support current lang: ${lang} yet`);
257
- hasRegisteredLang = false;
258
- }
259
- if (fileName &&
260
- highlighter.ignoreSyntaxHighlightList.some((item) => item instanceof RegExp ? item.test(fileName) : fileName === item)) {
261
- console.warn(`ignore syntax for current file, because the fileName is in the ignoreSyntaxHighlightList: ${fileName}`);
262
- return;
263
- }
264
- if (hasRegisteredLang) {
265
- return lowlight.highlight(lang, raw);
266
- }
267
- else {
268
- return lowlight.highlightAuto(raw);
269
- }
270
- },
271
- });
272
- Object.defineProperty(instance, "processAST", {
273
- value: (ast) => {
274
- return processAST(ast);
275
- },
276
- });
277
- const highlighter = instance;
278
-
279
- var _Cache_keyArray, _Cache_maxLength;
280
- class Cache extends Map {
281
- constructor() {
282
- super(...arguments);
283
- _Cache_keyArray.set(this, []);
284
- _Cache_maxLength.set(this, 30);
285
- }
286
- setMaxLength(length) {
287
- __classPrivateFieldSet(this, _Cache_maxLength, length, "f");
288
- this._checkLength();
289
- }
290
- set(key, value) {
291
- if (this.has(key))
292
- return this;
293
- __classPrivateFieldGet(this, _Cache_keyArray, "f").push(key);
294
- this._checkLength();
295
- return super.set(key, value);
296
- }
297
- _checkLength() {
298
- while (__classPrivateFieldGet(this, _Cache_keyArray, "f").length > __classPrivateFieldGet(this, _Cache_maxLength, "f")) {
299
- const key = __classPrivateFieldGet(this, _Cache_keyArray, "f").shift();
300
- this.delete(key);
301
- }
302
- }
303
- }
304
- _Cache_keyArray = new WeakMap(), _Cache_maxLength = new WeakMap();
305
-
306
- var _File_instances, _File_doCheck;
307
- const map = new Cache();
308
- const devKey = "@git-diff-cache";
309
- map.setMaxLength(50);
310
- map.name = "@git-diff-view/core";
311
- if (typeof globalThis !== "undefined") {
312
- if (Array.isArray(globalThis[devKey])) {
313
- globalThis[devKey] = globalThis[devKey].filter((i) => i !== map);
314
- if (globalThis[devKey].length > 0) {
315
- console.warn("there are multiple instance of @git-diff-view/core in the one environment!");
316
- }
317
- globalThis[devKey].push(map);
318
- }
319
- else {
320
- globalThis[devKey] = [map];
321
- }
322
- }
323
- class File {
324
- constructor(raw, lang, fileName) {
325
- _File_instances.add(this);
326
- this.raw = raw;
327
- this.lang = lang;
328
- this.fileName = fileName;
329
- this.rawFile = {};
330
- this.hasDoRaw = false;
331
- this.syntaxFile = {};
332
- this.hasDoSyntax = false;
333
- this.maxLineNumber = 0;
334
- Object.defineProperty(this, "__v_skip", { value: true });
335
- }
336
- doSyntax({ registerHighlighter }) {
337
- if (!this.raw || this.hasDoSyntax)
338
- return;
339
- const _highlighter = registerHighlighter || highlighter;
340
- if (this.syntaxLength) {
341
- console.error("current file already doSyntax before!");
342
- return;
343
- }
344
- if (this.rawLength > _highlighter.maxLineToIgnoreSyntax) {
345
- console.warn(`ignore syntax for current file, because the rawLength is too long: ${this.rawLength}`);
346
- return;
347
- }
348
- this.ast = _highlighter.getAST(this.raw, this.fileName, this.lang);
349
- if (!this.ast)
350
- return;
351
- const { syntaxFileObject, syntaxFileLineNumber } = _highlighter.processAST(this.ast);
352
- this.syntaxFile = syntaxFileObject;
353
- this.syntaxLength = syntaxFileLineNumber;
354
- this.highlighterName = _highlighter.name;
355
- {
356
- __classPrivateFieldGet(this, _File_instances, "m", _File_doCheck).call(this);
357
- }
358
- this.hasDoSyntax = true;
75
+ exports.DiffHunkExpansionType = void 0;
76
+ (function (DiffHunkExpansionType) {
77
+ /** The hunk header cannot be expanded at all. */
78
+ DiffHunkExpansionType["None"] = "None";
79
+ /**
80
+ * The hunk header can be expanded up exclusively. Only the first hunk can be
81
+ * expanded up exclusively.
82
+ */
83
+ DiffHunkExpansionType["Up"] = "Up";
84
+ /**
85
+ * The hunk header can be expanded down exclusively. Only the last hunk (if
86
+ * it's the dummy hunk with only one line) can be expanded down exclusively.
87
+ */
88
+ DiffHunkExpansionType["Down"] = "Down";
89
+ /** The hunk header can be expanded both up and down. */
90
+ DiffHunkExpansionType["Both"] = "Both";
91
+ /**
92
+ * The hunk header represents a short gap that, when expanded, will
93
+ * result in merging this hunk and the hunk above.
94
+ */
95
+ DiffHunkExpansionType["Short"] = "Short";
96
+ })(exports.DiffHunkExpansionType || (exports.DiffHunkExpansionType = {}));
97
+ /** each diff is made up of a number of hunks */
98
+ class DiffHunk {
99
+ /**
100
+ * @param header The details from the diff hunk header about the line start and patch length.
101
+ * @param lines The contents - context and changes - of the diff section.
102
+ * @param unifiedDiffStart The diff hunk's start position in the overall file diff.
103
+ * @param unifiedDiffEnd The diff hunk's end position in the overall file diff.
104
+ */
105
+ constructor(header, lines, unifiedDiffStart, unifiedDiffEnd, expansionType) {
106
+ this.header = header;
107
+ this.lines = lines;
108
+ this.unifiedDiffStart = unifiedDiffStart;
109
+ this.unifiedDiffEnd = unifiedDiffEnd;
110
+ this.expansionType = expansionType;
359
111
  }
360
- doRaw() {
361
- if (!this.raw || this.hasDoRaw)
362
- return;
363
- const rawString = this.raw;
364
- const rawArray = rawString.split("\n");
365
- this.rawLength = rawArray.length;
366
- this.maxLineNumber = rawArray.length;
367
- this.rawFile = {};
368
- for (let i = 0; i < rawArray.length; i++) {
369
- this.rawFile[i + 1] = i < rawArray.length - 1 ? rawArray[i] + "\n" : rawArray[i];
112
+ equals(other) {
113
+ if (this === other) {
114
+ return true;
370
115
  }
371
- // reduce 对于大数组性能很差
372
- // this.rawFile = rawArray.reduce(
373
- // (p, item, index) => ({
374
- // ...p,
375
- // [index + 1]: index < rawArray.length - 1 ? item + "\n" : item,
376
- // }),
377
- // {}
378
- // );
379
- this.hasDoRaw = true;
116
+ return (this.header.equals(other.header) &&
117
+ this.unifiedDiffStart === other.unifiedDiffStart &&
118
+ this.unifiedDiffEnd === other.unifiedDiffEnd &&
119
+ this.expansionType === other.expansionType &&
120
+ this.lines.length === other.lines.length &&
121
+ this.lines.every((xLine, ix) => xLine.equals(other.lines[ix])));
380
122
  }
381
123
  }
382
- _File_instances = new WeakSet(), _File_doCheck = function _File_doCheck() {
383
- if (this.rawLength && this.syntaxLength) {
384
- if (this.rawLength !== this.syntaxLength) {
385
- console.warn("the rawLength not match for the syntaxLength");
386
- }
387
- Object.values(this.syntaxFile).forEach(({ value, lineNumber }) => {
388
- if (value !== this.rawFile[lineNumber]) {
389
- console.log("some line not match:" + value + " __ " + this.rawFile[lineNumber] + " __ at: " + lineNumber + " lineNumber");
390
- }
391
- });
124
+ /** details about the start and end of a diff hunk */
125
+ class DiffHunkHeader {
126
+ /**
127
+ * @param oldStartLine The line in the old (or original) file where this diff hunk starts.
128
+ * @param oldLineCount The number of lines in the old (or original) file that this diff hunk covers
129
+ * @param newStartLine The line in the new file where this diff hunk starts.
130
+ * @param newLineCount The number of lines in the new file that this diff hunk covers.
131
+ */
132
+ constructor(oldStartLine, oldLineCount, newStartLine, newLineCount) {
133
+ this.oldStartLine = oldStartLine;
134
+ this.oldLineCount = oldLineCount;
135
+ this.newStartLine = newStartLine;
136
+ this.newLineCount = newLineCount;
392
137
  }
393
- };
394
- const getFile = (raw, lang, fileName) => {
395
- const key = raw + "--" + "0.0.11" + "--" + lang;
396
- if (map.has(key))
397
- return map.get(key);
398
- const file = new File(raw, lang, fileName);
399
- map.set(key, file);
400
- return file;
401
- };
402
- const _cacheMap = map;
138
+ toDiffLineRepresentation() {
139
+ return `@@ -${this.oldStartLine},${this.oldLineCount} +${this.newStartLine},${this.newLineCount} @@`;
140
+ }
141
+ equals(other) {
142
+ return (this.oldStartLine === other.oldStartLine &&
143
+ this.oldLineCount === other.oldLineCount &&
144
+ this.newStartLine === other.newStartLine &&
145
+ this.oldStartLine === other.oldStartLine);
146
+ }
147
+ }
403
148
 
404
149
  exports.NewLineSymbol = void 0;
405
150
  (function (NewLineSymbol) {
@@ -443,29 +188,19 @@ function relativeChanges(addition, deletion) {
443
188
  const aEndStr = stringA.slice(-2);
444
189
  const bEndStr = stringB.slice(-2);
445
190
  const hasNewLineChanged = addition.noTrailingNewLine !== deletion.noTrailingNewLine;
446
- if (_stringA === _stringB && (hasNewLineChanged || aEndStr !== bEndStr)) {
191
+ const aSymbol = aEndStr === "\r\n" ? exports.NewLineSymbol.CRLF : aEndStr.endsWith("\r") ? exports.NewLineSymbol.CR : exports.NewLineSymbol.LF;
192
+ const bSymbol = bEndStr === "\r\n" ? exports.NewLineSymbol.CRLF : bEndStr.endsWith("\r") ? exports.NewLineSymbol.CR : exports.NewLineSymbol.LF;
193
+ if (_stringA === _stringB && (hasNewLineChanged || aSymbol !== bSymbol)) {
447
194
  return {
448
195
  stringARange: {
449
196
  location: _stringA.length,
450
197
  length: stringA.length - _stringA.length,
451
- newLineSymbol: hasNewLineChanged
452
- ? exports.NewLineSymbol.NEWLINE
453
- : aEndStr === "\r\n"
454
- ? exports.NewLineSymbol.CRLF
455
- : aEndStr.endsWith("\r")
456
- ? exports.NewLineSymbol.CR
457
- : exports.NewLineSymbol.LF,
198
+ newLineSymbol: hasNewLineChanged ? exports.NewLineSymbol.NEWLINE : aSymbol,
458
199
  },
459
200
  stringBRange: {
460
201
  location: _stringB.length,
461
202
  length: stringB.length - _stringB.length,
462
- newLineSymbol: hasNewLineChanged
463
- ? exports.NewLineSymbol.NEWLINE
464
- : bEndStr === "\r\n"
465
- ? exports.NewLineSymbol.CRLF
466
- : bEndStr.endsWith("\r")
467
- ? exports.NewLineSymbol.CR
468
- : exports.NewLineSymbol.LF,
203
+ newLineSymbol: hasNewLineChanged ? exports.NewLineSymbol.NEWLINE : bSymbol,
469
204
  },
470
205
  };
471
206
  }
@@ -527,530 +262,801 @@ class DiffLine {
527
262
  withNoTrailingNewLine(noTrailingNewLine) {
528
263
  return new DiffLine(this.text, this.type, this.originalLineNumber, this.oldLineNumber, this.newLineNumber, noTrailingNewLine);
529
264
  }
530
- isIncludeableLine() {
531
- return this.type === exports.DiffLineType.Add || this.type === exports.DiffLineType.Delete;
265
+ isIncludeableLine() {
266
+ return this.type === exports.DiffLineType.Add || this.type === exports.DiffLineType.Delete;
267
+ }
268
+ /** The content of the line, i.e., without the line type marker. */
269
+ get content() {
270
+ return this.text.substring(1);
271
+ }
272
+ equals(other) {
273
+ return (this.text === other.text &&
274
+ this.type === other.type &&
275
+ this.originalLineNumber === other.originalLineNumber &&
276
+ this.oldLineNumber === other.oldLineNumber &&
277
+ this.newLineNumber === other.newLineNumber &&
278
+ this.noTrailingNewLine === other.noTrailingNewLine);
279
+ }
280
+ clone(text) {
281
+ return new DiffLine(text, this.type, this.originalLineNumber, this.oldLineNumber, this.newLineNumber);
282
+ }
283
+ }
284
+ const checkDiffLineIncludeChange = (diffLine) => {
285
+ if (!diffLine)
286
+ return false;
287
+ return diffLine.type === exports.DiffLineType.Add || diffLine.type === exports.DiffLineType.Delete;
288
+ };
289
+
290
+ /** How many new lines will be added to a diff hunk by default. */
291
+ const DefaultDiffExpansionStep = 40;
292
+ function assertNever(_, message) {
293
+ throw new Error(message);
294
+ }
295
+ /** Utility function for getting the digit count of the largest line number in an array of diff hunks */
296
+ function getLargestLineNumber(hunks) {
297
+ var _a, _b;
298
+ if (hunks.length === 0) {
299
+ return 0;
300
+ }
301
+ for (let i = hunks.length - 1; i >= 0; i--) {
302
+ const hunk = hunks[i];
303
+ for (let j = hunk.lines.length - 1; j >= 0; j--) {
304
+ const line = hunk.lines[j];
305
+ if (line.type === exports.DiffLineType.Hunk) {
306
+ continue;
307
+ }
308
+ const newLineNumber = (_a = line.newLineNumber) !== null && _a !== void 0 ? _a : 0;
309
+ const oldLineNumber = (_b = line.oldLineNumber) !== null && _b !== void 0 ? _b : 0;
310
+ return newLineNumber > oldLineNumber ? newLineNumber : oldLineNumber;
311
+ }
312
+ }
313
+ return 0;
314
+ }
315
+ /**
316
+ * Calculates whether or not a hunk header can be expanded up, down, both, or if
317
+ * the space represented by the hunk header is short and expansion there would
318
+ * mean merging with the hunk above.
319
+ *
320
+ * @param hunkIndex Index of the hunk to evaluate within the whole diff.
321
+ * @param hunkHeader Header of the hunk to evaluate.
322
+ * @param previousHunk Hunk previous to the one to evaluate. Null if the
323
+ * evaluated hunk is the first one.
324
+ */
325
+ function getHunkHeaderExpansionType(hunkIndex, hunkHeader, previousHunk) {
326
+ const distanceToPrevious = previousHunk === null
327
+ ? Infinity
328
+ : hunkHeader.oldStartLine - previousHunk.header.oldStartLine - previousHunk.header.oldLineCount;
329
+ // In order to simplify the whole logic around expansion, only the hunk at the
330
+ // top can be expanded up exclusively, and only the hunk at the bottom (the
331
+ // dummy one, see getTextDiffWithBottomDummyHunk) can be expanded down
332
+ // exclusively.
333
+ // The rest of the hunks can be expanded both ways, except those which are too
334
+ // short and therefore the direction of expansion doesn't matter.
335
+ if (hunkIndex === 0) {
336
+ // The top hunk can only be expanded if there is content above it
337
+ if (hunkHeader.oldStartLine > 1 && hunkHeader.newStartLine > 1) {
338
+ return exports.DiffHunkExpansionType.Up;
339
+ }
340
+ else {
341
+ return exports.DiffHunkExpansionType.None;
342
+ }
343
+ }
344
+ else if (distanceToPrevious <= DefaultDiffExpansionStep) {
345
+ return exports.DiffHunkExpansionType.Short;
346
+ }
347
+ else {
348
+ return exports.DiffHunkExpansionType.Both;
349
+ }
350
+ }
351
+ const numIterator = (num, cb) => {
352
+ const re = [];
353
+ for (let i = 0; i < num; i++) {
354
+ re.push(cb(i));
355
+ }
356
+ return re;
357
+ };
358
+ const getLang = (fileName) => {
359
+ const dotIndex = fileName.lastIndexOf(".");
360
+ const extension = fileName.slice(dotIndex + 1);
361
+ return extension;
362
+ };
363
+ const getDiffRange = (additions, deletions) => {
364
+ if (additions.length === deletions.length) {
365
+ const len = additions.length;
366
+ for (let i = 0; i < len; i++) {
367
+ const addition = additions[i];
368
+ const deletion = deletions[i];
369
+ const hasDiffRange = hasRelativeChange(addition, deletion);
370
+ if (hasDiffRange) {
371
+ const { stringARange, stringBRange } = relativeChanges(addition, deletion);
372
+ addition.needRematch = true;
373
+ addition.range = stringARange;
374
+ deletion.needRematch = true;
375
+ deletion.range = stringBRange;
376
+ }
377
+ }
378
+ }
379
+ };
380
+
381
+ /* eslint-disable max-lines */
382
+ // !NOTE: ALL of the diff parse logic copy from desktop, SEE https://github.com/desktop/desktop
383
+ // https://en.wikipedia.org/wiki/Diff_utility
384
+ //
385
+ // @@ -l,s +l,s @@ optional section heading
386
+ //
387
+ // The hunk range information contains two hunk ranges. The range for the hunk of the original
388
+ // file is preceded by a minus symbol, and the range for the new file is preceded by a plus
389
+ // symbol. Each hunk range is of the format l,s where l is the starting line number and s is
390
+ // the number of lines the change hunk applies to for each respective file.
391
+ //
392
+ // In many versions of GNU diff, each range can omit the comma and trailing value s,
393
+ // in which case s defaults to 1
394
+ const diffHeaderRe = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
395
+ /**
396
+ * Regular expression matching invisible bidirectional Unicode characters that
397
+ * may be interpreted or compiled differently than what it appears. More info:
398
+ * https://github.co/hiddenchars
399
+ */
400
+ const HiddenBidiCharsRegex = /[\u202A-\u202E]|[\u2066-\u2069]/;
401
+ const DiffPrefixAdd = "+";
402
+ const DiffPrefixDelete = "-";
403
+ const DiffPrefixContext = " ";
404
+ const DiffPrefixNoNewline = "\\";
405
+ const DiffLinePrefixChars = new Set([
406
+ DiffPrefixAdd,
407
+ DiffPrefixDelete,
408
+ DiffPrefixContext,
409
+ DiffPrefixNoNewline,
410
+ ]);
411
+ /**
412
+ * A parser for the GNU unified diff format
413
+ *
414
+ * See https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
415
+ */
416
+ class DiffParser {
417
+ constructor() {
418
+ Object.defineProperty(this, "__v_skip", { value: true });
419
+ this.reset();
420
+ }
421
+ /**
422
+ * Resets the internal parser state so that it can be reused.
423
+ *
424
+ * This is done automatically at the end of each parse run.
425
+ */
426
+ reset() {
427
+ this.ls = 0;
428
+ this.le = -1;
429
+ this.text = "";
430
+ }
431
+ /**
432
+ * Aligns the internal character pointers at the boundaries of
433
+ * the next line.
434
+ *
435
+ * Returns true if successful or false if the end of the diff
436
+ * has been reached.
437
+ */
438
+ nextLine() {
439
+ this.ls = this.le + 1;
440
+ // We've reached the end of the diff
441
+ if (this.ls >= this.text.length) {
442
+ return false;
443
+ }
444
+ this.le = this.text.indexOf("\n", this.ls);
445
+ // If we can't find the next newline character we'll put our
446
+ // end pointer at the end of the diff string
447
+ if (this.le === -1) {
448
+ this.le = this.text.length;
449
+ }
450
+ // We've succeeded if there's anything to read in between the
451
+ // start and the end
452
+ return this.ls !== this.le;
453
+ }
454
+ /**
455
+ * Advances to the next line and returns it as a substring
456
+ * of the raw diff text. Returns null if end of diff was
457
+ * reached.
458
+ */
459
+ readLine(header) {
460
+ if (header) {
461
+ return this.nextLine() ? this.text.substring(this.ls, this.le) : null;
462
+ }
463
+ else {
464
+ return this.nextLine() ? this.text.substring(this.ls + 1, this.le + 1) : null;
465
+ }
466
+ }
467
+ /** Tests if the current line starts with the given search text */
468
+ lineStartsWith(searchString) {
469
+ return this.text.startsWith(searchString, this.ls);
532
470
  }
533
- /** The content of the line, i.e., without the line type marker. */
534
- get content() {
535
- return this.text.substring(1);
471
+ /** Tests if the current line ends with the given search text */
472
+ lineEndsWith(searchString) {
473
+ return this.text.endsWith(searchString, this.le);
536
474
  }
537
- equals(other) {
538
- return (this.text === other.text &&
539
- this.type === other.type &&
540
- this.originalLineNumber === other.originalLineNumber &&
541
- this.oldLineNumber === other.oldLineNumber &&
542
- this.newLineNumber === other.newLineNumber &&
543
- this.noTrailingNewLine === other.noTrailingNewLine);
475
+ /**
476
+ * Returns the starting character of the next line without
477
+ * advancing the internal state. Returns null if advancing
478
+ * would mean reaching the end of the diff.
479
+ */
480
+ peek() {
481
+ const p = this.le + 1;
482
+ return p < this.text.length ? this.text[p] : null;
544
483
  }
545
- clone(text) {
546
- return new DiffLine(text, this.type, this.originalLineNumber, this.oldLineNumber, this.newLineNumber);
484
+ /**
485
+ * Parse the diff header, meaning everything from the
486
+ * start of the diff output to the end of the line beginning
487
+ * with +++
488
+ *
489
+ * Example diff header:
490
+ *
491
+ * diff --git a/app/src/lib/diff-parser.ts b/app/src/lib/diff-parser.ts
492
+ * index e1d4871..3bd3ee0 100644
493
+ * --- a/app/src/lib/diff-parser.ts
494
+ * +++ b/app/src/lib/diff-parser.ts
495
+ *
496
+ * Returns an object with information extracted from the diff
497
+ * header (currently whether it's a binary patch) or null if
498
+ * the end of the diff was reached before the +++ line could be
499
+ * found (which is a valid state).
500
+ */
501
+ parseDiffHeader() {
502
+ // TODO: There's information in here that we might want to
503
+ // capture, such as mode changes
504
+ while (this.nextLine()) {
505
+ if (this.lineStartsWith("Binary files ") && this.lineEndsWith("differ")) {
506
+ return { isBinary: true };
507
+ }
508
+ if (this.lineStartsWith("+++")) {
509
+ return { isBinary: false };
510
+ }
511
+ }
512
+ // It's not an error to not find the +++ line, see the
513
+ // 'parses diff of empty file' test in diff-parser-tests.ts
514
+ return null;
547
515
  }
548
- }
549
- const checkDiffLineIncludeChange = (diffLine) => {
550
- if (!diffLine)
551
- return false;
552
- return diffLine.type === exports.DiffLineType.Add || diffLine.type === exports.DiffLineType.Delete;
553
- };
554
-
555
- var DiffHunkExpansionType;
556
- (function (DiffHunkExpansionType) {
557
- /** The hunk header cannot be expanded at all. */
558
- DiffHunkExpansionType["None"] = "None";
559
516
  /**
560
- * The hunk header can be expanded up exclusively. Only the first hunk can be
561
- * expanded up exclusively.
517
+ * Attempts to convert a RegExp capture group into a number.
518
+ * If the group doesn't exist or wasn't captured the function
519
+ * will return the value of the defaultValue parameter or throw
520
+ * an error if no default value was provided. If the captured
521
+ * string can't be converted to a number an error will be thrown.
562
522
  */
563
- DiffHunkExpansionType["Up"] = "Up";
523
+ numberFromGroup(m, group, defaultValue = null) {
524
+ const str = m[group];
525
+ if (!str) {
526
+ if (!defaultValue) {
527
+ throw new Error(`Group ${group} missing from regexp match and no defaultValue was provided`);
528
+ }
529
+ return defaultValue;
530
+ }
531
+ const num = parseInt(str, 10);
532
+ if (isNaN(num)) {
533
+ throw new Error(`Could not parse capture group ${group} into number: ${str}`);
534
+ }
535
+ return num;
536
+ }
564
537
  /**
565
- * The hunk header can be expanded down exclusively. Only the last hunk (if
566
- * it's the dummy hunk with only one line) can be expanded down exclusively.
538
+ * Parses a hunk header or throws an error if the given line isn't
539
+ * a well-formed hunk header.
540
+ *
541
+ * We currently only extract the line number information and
542
+ * ignore any hunk headings.
543
+ *
544
+ * Example hunk header (text within ``):
545
+ *
546
+ * `@@ -84,10 +82,8 @@ export function parseRawDiff(lines: ReadonlyArray<string>): Diff {`
547
+ *
548
+ * Where everything after the last @@ is what's known as the hunk, or section, heading
567
549
  */
568
- DiffHunkExpansionType["Down"] = "Down";
569
- /** The hunk header can be expanded both up and down. */
570
- DiffHunkExpansionType["Both"] = "Both";
550
+ parseHunkHeader(line) {
551
+ const m = diffHeaderRe.exec(line);
552
+ if (!m) {
553
+ throw new Error(`Invalid hunk header format`);
554
+ }
555
+ // If endLines are missing default to 1, see diffHeaderRe docs
556
+ const oldStartLine = this.numberFromGroup(m, 1);
557
+ const oldLineCount = this.numberFromGroup(m, 2, 1);
558
+ const newStartLine = this.numberFromGroup(m, 3);
559
+ const newLineCount = this.numberFromGroup(m, 4, 1);
560
+ return new DiffHunkHeader(oldStartLine, oldLineCount, newStartLine, newLineCount);
561
+ }
571
562
  /**
572
- * The hunk header represents a short gap that, when expanded, will
573
- * result in merging this hunk and the hunk above.
563
+ * Convenience function which lets us leverage the type system to
564
+ * prove exhaustive checks in parseHunk.
565
+ *
566
+ * Takes an arbitrary string and checks to see if the first character
567
+ * of that string is one of the allowed prefix characters for diff
568
+ * lines (ie lines in between hunk headers).
574
569
  */
575
- DiffHunkExpansionType["Short"] = "Short";
576
- })(DiffHunkExpansionType || (DiffHunkExpansionType = {}));
577
- /** each diff is made up of a number of hunks */
578
- class DiffHunk {
570
+ parseLinePrefix(c) {
571
+ // Since we know that DiffLinePrefixChars and the DiffLinePrefix type
572
+ // include the same characters we can tell the type system that we
573
+ // now know that c[0] is one of the characters in the DifflinePrefix set
574
+ if (c && c.length && DiffLinePrefixChars.has(c[0])) {
575
+ return c[0];
576
+ }
577
+ return null;
578
+ }
579
579
  /**
580
- * @param header The details from the diff hunk header about the line start and patch length.
581
- * @param lines The contents - context and changes - of the diff section.
582
- * @param unifiedDiffStart The diff hunk's start position in the overall file diff.
583
- * @param unifiedDiffEnd The diff hunk's end position in the overall file diff.
580
+ * Parses a hunk, including its header or throws an error if the diff doesn't
581
+ * contain a well-formed diff hunk at the current position.
582
+ *
583
+ * Expects that the position has been advanced to the beginning of a presumed
584
+ * diff hunk header.
585
+ *
586
+ * @param linesConsumed The number of unified diff lines consumed up until
587
+ * this point by the diff parser. Used to give the
588
+ * position and length (in lines) of the parsed hunk
589
+ * relative to the overall parsed diff. These numbers
590
+ * have no real meaning in the context of a diff and
591
+ * are only used to aid the app in line-selections.
584
592
  */
585
- constructor(header, lines, unifiedDiffStart, unifiedDiffEnd, expansionType) {
586
- this.header = header;
587
- this.lines = lines;
588
- this.unifiedDiffStart = unifiedDiffStart;
589
- this.unifiedDiffEnd = unifiedDiffEnd;
590
- this.expansionType = expansionType;
593
+ parseHunk(linesConsumed, hunkIndex, previousHunk) {
594
+ const headerLine = this.readLine(true);
595
+ if (!headerLine) {
596
+ throw new Error("Expected hunk header but reached end of diff");
597
+ }
598
+ const header = this.parseHunkHeader(headerLine);
599
+ const lines = new Array();
600
+ lines.push(new DiffLine(headerLine, exports.DiffLineType.Hunk, 1, null, null));
601
+ let c;
602
+ let rollingDiffBeforeCounter = header.oldStartLine;
603
+ let rollingDiffAfterCounter = header.newStartLine;
604
+ let diffLineNumber = linesConsumed;
605
+ while ((c = this.parseLinePrefix(this.peek()))) {
606
+ const line = this.readLine(false);
607
+ diffLineNumber++;
608
+ if (!line) {
609
+ throw new Error("Expected unified diff line but reached end of diff");
610
+ }
611
+ // A marker indicating that the last line in the original or the new file
612
+ // is missing a trailing newline. In other words, the presence of this marker
613
+ // means that the new and/or original file lacks a trailing newline.
614
+ //
615
+ // When we find it we have to look up the previous line and set the
616
+ // noTrailingNewLine flag
617
+ if (c === DiffPrefixNoNewline) {
618
+ // See https://github.com/git/git/blob/21f862b498925194f8f1ebe8203b7a7df756555b/apply.c#L1725-L1732
619
+ if (line.length < 12) {
620
+ throw new Error(`Expected "no newline at end of file" marker to be at least 12 bytes long`);
621
+ }
622
+ const previousLineIndex = lines.length - 1;
623
+ const previousLine = lines[previousLineIndex];
624
+ lines[previousLineIndex] = previousLine.withNoTrailingNewLine(true);
625
+ continue;
626
+ }
627
+ let diffLine;
628
+ if (c === DiffPrefixAdd) {
629
+ diffLine = new DiffLine(line, exports.DiffLineType.Add, diffLineNumber, null, rollingDiffAfterCounter++);
630
+ }
631
+ else if (c === DiffPrefixDelete) {
632
+ diffLine = new DiffLine(line, exports.DiffLineType.Delete, diffLineNumber, rollingDiffBeforeCounter++, null);
633
+ }
634
+ else if (c === DiffPrefixContext) {
635
+ diffLine = new DiffLine(line, exports.DiffLineType.Context, diffLineNumber, rollingDiffBeforeCounter++, rollingDiffAfterCounter++);
636
+ }
637
+ else {
638
+ return assertNever(c, `Unknown DiffLinePrefix: ${c}`);
639
+ }
640
+ lines.push(diffLine);
641
+ }
642
+ if (lines.length === 1) {
643
+ throw new Error("Malformed diff, empty hunk");
644
+ }
645
+ return new DiffHunk(header, lines, linesConsumed, linesConsumed + lines.length - 1, getHunkHeaderExpansionType(hunkIndex, header, previousHunk));
591
646
  }
592
- equals(other) {
593
- if (this === other) {
594
- return true;
647
+ /**
648
+ * Parse a well-formed unified diff into hunks and lines.
649
+ *
650
+ * @param text A unified diff produced by git diff, git log --patch
651
+ * or any other git plumbing command that produces unified
652
+ * diffs.
653
+ */
654
+ parse(text) {
655
+ this.text = text;
656
+ try {
657
+ const headerInfo = this.parseDiffHeader();
658
+ const headerEnd = this.le;
659
+ const header = this.text.substring(0, headerEnd);
660
+ // empty diff
661
+ if (!headerInfo) {
662
+ return {
663
+ header,
664
+ contents: "",
665
+ hunks: [],
666
+ isBinary: false,
667
+ maxLineNumber: 0,
668
+ hasHiddenBidiChars: false,
669
+ };
670
+ }
671
+ if (headerInfo.isBinary) {
672
+ return {
673
+ header,
674
+ contents: "",
675
+ hunks: [],
676
+ isBinary: true,
677
+ maxLineNumber: 0,
678
+ hasHiddenBidiChars: false,
679
+ };
680
+ }
681
+ const hunks = new Array();
682
+ let linesConsumed = 0;
683
+ let previousHunk = null;
684
+ do {
685
+ const hunk = this.parseHunk(linesConsumed, hunks.length, previousHunk);
686
+ hunks.push(hunk);
687
+ previousHunk = hunk;
688
+ linesConsumed += hunk.lines.length;
689
+ } while (this.peek());
690
+ const contents = this.text
691
+ .substring(headerEnd + 1, this.le)
692
+ // Note that this simply returns a reference to the
693
+ // substring if no match is found, it does not create
694
+ // a new string instance.
695
+ .replace(/\n\/g, "");
696
+ return {
697
+ header,
698
+ contents,
699
+ hunks,
700
+ isBinary: headerInfo.isBinary,
701
+ maxLineNumber: getLargestLineNumber(hunks),
702
+ hasHiddenBidiChars: HiddenBidiCharsRegex.test(text),
703
+ };
704
+ }
705
+ finally {
706
+ this.reset();
595
707
  }
596
- return (this.header.equals(other.header) &&
597
- this.unifiedDiffStart === other.unifiedDiffStart &&
598
- this.unifiedDiffEnd === other.unifiedDiffEnd &&
599
- this.expansionType === other.expansionType &&
600
- this.lines.length === other.lines.length &&
601
- this.lines.every((xLine, ix) => xLine.equals(other.lines[ix])));
602
- }
603
- }
604
- /** details about the start and end of a diff hunk */
605
- class DiffHunkHeader {
606
- /**
607
- * @param oldStartLine The line in the old (or original) file where this diff hunk starts.
608
- * @param oldLineCount The number of lines in the old (or original) file that this diff hunk covers
609
- * @param newStartLine The line in the new file where this diff hunk starts.
610
- * @param newLineCount The number of lines in the new file that this diff hunk covers.
611
- */
612
- constructor(oldStartLine, oldLineCount, newStartLine, newLineCount) {
613
- this.oldStartLine = oldStartLine;
614
- this.oldLineCount = oldLineCount;
615
- this.newStartLine = newStartLine;
616
- this.newLineCount = newLineCount;
617
- }
618
- toDiffLineRepresentation() {
619
- return `@@ -${this.oldStartLine},${this.oldLineCount} +${this.newStartLine},${this.newLineCount} @@`;
620
- }
621
- equals(other) {
622
- return (this.oldStartLine === other.oldStartLine &&
623
- this.oldLineCount === other.oldLineCount &&
624
- this.newStartLine === other.newStartLine &&
625
- this.oldStartLine === other.oldStartLine);
626
708
  }
627
709
  }
710
+ const parseInstance = new DiffParser();
628
711
 
629
- /** How many new lines will be added to a diff hunk by default. */
630
- const DefaultDiffExpansionStep = 20;
631
- function assertNever(_, message) {
632
- throw new Error(message);
633
- }
634
- /** Utility function for getting the digit count of the largest line number in an array of diff hunks */
635
- function getLargestLineNumber(hunks) {
636
- var _a, _b;
637
- if (hunks.length === 0) {
638
- return 0;
639
- }
640
- for (let i = hunks.length - 1; i >= 0; i--) {
641
- const hunk = hunks[i];
642
- for (let j = hunk.lines.length - 1; j >= 0; j--) {
643
- const line = hunk.lines[j];
644
- if (line.type === exports.DiffLineType.Hunk) {
645
- continue;
712
+ /******************************************************************************
713
+ Copyright (c) Microsoft Corporation.
714
+
715
+ Permission to use, copy, modify, and/or distribute this software for any
716
+ purpose with or without fee is hereby granted.
717
+
718
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
719
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
720
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
721
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
722
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
723
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
724
+ PERFORMANCE OF THIS SOFTWARE.
725
+ ***************************************************************************** */
726
+ /* global Reflect, Promise, SuppressedError, Symbol */
727
+
728
+
729
+ function __classPrivateFieldGet(receiver, state, kind, f) {
730
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
731
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
732
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
733
+ }
734
+
735
+ function __classPrivateFieldSet(receiver, state, value, kind, f) {
736
+ if (kind === "m") throw new TypeError("Private method is not writable");
737
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
738
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
739
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
740
+ }
741
+
742
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
743
+ var e = new Error(message);
744
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
745
+ };
746
+
747
+ const processAST = (ast) => {
748
+ let lineNumber = 1;
749
+ const syntaxObj = {};
750
+ const loopAST = (nodes, wrapper) => {
751
+ nodes.forEach((node) => {
752
+ if (node.type === "text") {
753
+ if (node.value.indexOf("\n") === -1) {
754
+ const valueLength = node.value.length;
755
+ if (!syntaxObj[lineNumber]) {
756
+ node.startIndex = 0;
757
+ node.endIndex = valueLength - 1;
758
+ const item = {
759
+ value: node.value,
760
+ lineNumber,
761
+ valueLength,
762
+ nodeList: [{ node, wrapper }],
763
+ };
764
+ syntaxObj[lineNumber] = item;
765
+ }
766
+ else {
767
+ node.startIndex = syntaxObj[lineNumber].valueLength;
768
+ node.endIndex = node.startIndex + valueLength - 1;
769
+ syntaxObj[lineNumber].value += node.value;
770
+ syntaxObj[lineNumber].valueLength += valueLength;
771
+ syntaxObj[lineNumber].nodeList.push({ node, wrapper });
772
+ }
773
+ node.lineNumber = lineNumber;
774
+ return;
775
+ }
776
+ const lines = node.value.split("\n");
777
+ node.children = node.children || [];
778
+ for (let i = 0; i < lines.length; i++) {
779
+ const _value = i === lines.length - 1 ? lines[i] : lines[i] + "\n";
780
+ const _lineNumber = i === 0 ? lineNumber : ++lineNumber;
781
+ const _valueLength = _value.length;
782
+ const _node = {
783
+ type: "text",
784
+ value: _value,
785
+ startIndex: Infinity,
786
+ endIndex: Infinity,
787
+ lineNumber: _lineNumber,
788
+ };
789
+ if (!syntaxObj[_lineNumber]) {
790
+ _node.startIndex = 0;
791
+ _node.endIndex = _valueLength - 1;
792
+ const item = {
793
+ value: _value,
794
+ lineNumber: _lineNumber,
795
+ valueLength: _valueLength,
796
+ nodeList: [{ node: _node, wrapper }],
797
+ };
798
+ syntaxObj[_lineNumber] = item;
799
+ }
800
+ else {
801
+ _node.startIndex = syntaxObj[_lineNumber].valueLength;
802
+ _node.endIndex = _node.startIndex + _valueLength - 1;
803
+ syntaxObj[_lineNumber].value += _value;
804
+ syntaxObj[_lineNumber].valueLength += _valueLength;
805
+ syntaxObj[_lineNumber].nodeList.push({ node: _node, wrapper });
806
+ }
807
+ node.children.push(_node);
808
+ }
809
+ node.lineNumber = lineNumber;
810
+ return;
646
811
  }
647
- const newLineNumber = (_a = line.newLineNumber) !== null && _a !== void 0 ? _a : 0;
648
- const oldLineNumber = (_b = line.oldLineNumber) !== null && _b !== void 0 ? _b : 0;
649
- return newLineNumber > oldLineNumber ? newLineNumber : oldLineNumber;
812
+ if (node.children) {
813
+ loopAST(node.children, node);
814
+ node.lineNumber = lineNumber;
815
+ }
816
+ });
817
+ };
818
+ loopAST(ast.children);
819
+ return { syntaxFileObject: syntaxObj, syntaxFileLineNumber: lineNumber };
820
+ };
821
+
822
+ const lowlight = lowlight$1.createLowlight(lowlight$1.all);
823
+ // !SEE https://github.com/highlightjs/highlightjs-vue
824
+ lowlight.register("vue", function hljsDefineVue(hljs) {
825
+ return {
826
+ subLanguage: "xml",
827
+ contains: [
828
+ hljs.COMMENT("<!--", "-->", {
829
+ relevance: 10,
830
+ }),
831
+ {
832
+ begin: /^(\s*)(<script>)/gm,
833
+ end: /^(\s*)(<\/script>)/gm,
834
+ subLanguage: "javascript",
835
+ excludeBegin: true,
836
+ excludeEnd: true,
837
+ },
838
+ {
839
+ begin: /^(?:\s*)(?:<script\s+lang=(["'])ts\1>)/gm,
840
+ end: /^(\s*)(<\/script>)/gm,
841
+ subLanguage: "typescript",
842
+ excludeBegin: true,
843
+ excludeEnd: true,
844
+ },
845
+ {
846
+ begin: /^(\s*)(<style(\s+scoped)?>)/gm,
847
+ end: /^(\s*)(<\/style>)/gm,
848
+ subLanguage: "css",
849
+ excludeBegin: true,
850
+ excludeEnd: true,
851
+ },
852
+ {
853
+ begin: /^(?:\s*)(?:<style(?:\s+scoped)?\s+lang=(["'])(?:s[ca]ss)\1(?:\s+scoped)?>)/gm,
854
+ end: /^(\s*)(<\/style>)/gm,
855
+ subLanguage: "scss",
856
+ excludeBegin: true,
857
+ excludeEnd: true,
858
+ },
859
+ {
860
+ begin: /^(?:\s*)(?:<style(?:\s+scoped)?\s+lang=(["'])stylus\1(?:\s+scoped)?>)/gm,
861
+ end: /^(\s*)(<\/style>)/gm,
862
+ subLanguage: "stylus",
863
+ excludeBegin: true,
864
+ excludeEnd: true,
865
+ },
866
+ ],
867
+ };
868
+ });
869
+ const instance = { name: "lowlight" };
870
+ let _maxLineToIgnoreSyntax = 2000;
871
+ const _ignoreSyntaxHighlightList = [];
872
+ Object.defineProperty(instance, "maxLineToIgnoreSyntax", {
873
+ get: () => _maxLineToIgnoreSyntax,
874
+ });
875
+ Object.defineProperty(instance, "setMaxLineToIgnoreSyntax", {
876
+ value: (v) => {
877
+ _maxLineToIgnoreSyntax = v;
878
+ },
879
+ });
880
+ Object.defineProperty(instance, "ignoreSyntaxHighlightList", {
881
+ get: () => _ignoreSyntaxHighlightList,
882
+ });
883
+ Object.defineProperty(instance, "setIgnoreSyntaxHighlightList", {
884
+ value: (v) => {
885
+ _ignoreSyntaxHighlightList.length = 0;
886
+ _ignoreSyntaxHighlightList.push(...v);
887
+ },
888
+ });
889
+ Object.defineProperty(instance, "getAST", {
890
+ value: (raw, fileName, lang) => {
891
+ let hasRegisteredLang = true;
892
+ if (!lowlight.registered(lang)) {
893
+ console.warn(`not support current lang: ${lang} yet`);
894
+ hasRegisteredLang = false;
895
+ }
896
+ if (fileName &&
897
+ highlighter.ignoreSyntaxHighlightList.some((item) => item instanceof RegExp ? item.test(fileName) : fileName === item)) {
898
+ console.warn(`ignore syntax for current file, because the fileName is in the ignoreSyntaxHighlightList: ${fileName}`);
899
+ return;
650
900
  }
651
- }
652
- return 0;
653
- }
654
- /**
655
- * Calculates whether or not a hunk header can be expanded up, down, both, or if
656
- * the space represented by the hunk header is short and expansion there would
657
- * mean merging with the hunk above.
658
- *
659
- * @param hunkIndex Index of the hunk to evaluate within the whole diff.
660
- * @param hunkHeader Header of the hunk to evaluate.
661
- * @param previousHunk Hunk previous to the one to evaluate. Null if the
662
- * evaluated hunk is the first one.
663
- */
664
- function getHunkHeaderExpansionType(hunkIndex, hunkHeader, previousHunk) {
665
- const distanceToPrevious = previousHunk === null
666
- ? Infinity
667
- : hunkHeader.oldStartLine - previousHunk.header.oldStartLine - previousHunk.header.oldLineCount;
668
- // In order to simplify the whole logic around expansion, only the hunk at the
669
- // top can be expanded up exclusively, and only the hunk at the bottom (the
670
- // dummy one, see getTextDiffWithBottomDummyHunk) can be expanded down
671
- // exclusively.
672
- // The rest of the hunks can be expanded both ways, except those which are too
673
- // short and therefore the direction of expansion doesn't matter.
674
- if (hunkIndex === 0) {
675
- // The top hunk can only be expanded if there is content above it
676
- if (hunkHeader.oldStartLine > 1 && hunkHeader.newStartLine > 1) {
677
- return DiffHunkExpansionType.Up;
901
+ if (hasRegisteredLang) {
902
+ return lowlight.highlight(lang, raw);
678
903
  }
679
904
  else {
680
- return DiffHunkExpansionType.None;
681
- }
682
- }
683
- else if (distanceToPrevious <= DefaultDiffExpansionStep) {
684
- return DiffHunkExpansionType.Short;
685
- }
686
- else {
687
- return DiffHunkExpansionType.Both;
688
- }
689
- }
690
- const numIterator = (num, cb) => {
691
- const re = [];
692
- for (let i = 0; i < num; i++) {
693
- re.push(cb(i));
694
- }
695
- return re;
696
- };
697
- const getLang = (fileName) => {
698
- const dotIndex = fileName.lastIndexOf(".");
699
- const extension = fileName.slice(dotIndex + 1);
700
- return extension;
701
- };
702
- const getDiffRange = (additions, deletions) => {
703
- if (additions.length === deletions.length) {
704
- const len = additions.length;
705
- for (let i = 0; i < len; i++) {
706
- const addition = additions[i];
707
- const deletion = deletions[i];
708
- const hasDiffRange = hasRelativeChange(addition, deletion);
709
- if (hasDiffRange) {
710
- const { stringARange, stringBRange } = relativeChanges(addition, deletion);
711
- addition.needRematch = true;
712
- addition.range = stringARange;
713
- deletion.needRematch = true;
714
- deletion.range = stringBRange;
715
- }
905
+ return lowlight.highlightAuto(raw);
716
906
  }
717
- }
718
- };
907
+ },
908
+ });
909
+ Object.defineProperty(instance, "processAST", {
910
+ value: (ast) => {
911
+ return processAST(ast);
912
+ },
913
+ });
914
+ Object.defineProperty(instance, "hasRegisteredCurrentLang", {
915
+ value: (lang) => {
916
+ return lowlight.registered(lang);
917
+ },
918
+ });
919
+ const highlighter = instance;
719
920
 
720
- /* eslint-disable max-lines */
721
- // !NOTE: ALL of the diff parse logic copy from desktop, SEE https://github.com/desktop/desktop
722
- // https://en.wikipedia.org/wiki/Diff_utility
723
- //
724
- // @@ -l,s +l,s @@ optional section heading
725
- //
726
- // The hunk range information contains two hunk ranges. The range for the hunk of the original
727
- // file is preceded by a minus symbol, and the range for the new file is preceded by a plus
728
- // symbol. Each hunk range is of the format l,s where l is the starting line number and s is
729
- // the number of lines the change hunk applies to for each respective file.
730
- //
731
- // In many versions of GNU diff, each range can omit the comma and trailing value s,
732
- // in which case s defaults to 1
733
- const diffHeaderRe = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
734
- /**
735
- * Regular expression matching invisible bidirectional Unicode characters that
736
- * may be interpreted or compiled differently than what it appears. More info:
737
- * https://github.co/hiddenchars
738
- */
739
- const HiddenBidiCharsRegex = /[\u202A-\u202E]|[\u2066-\u2069]/;
740
- const DiffPrefixAdd = "+";
741
- const DiffPrefixDelete = "-";
742
- const DiffPrefixContext = " ";
743
- const DiffPrefixNoNewline = "\\";
744
- const DiffLinePrefixChars = new Set([
745
- DiffPrefixAdd,
746
- DiffPrefixDelete,
747
- DiffPrefixContext,
748
- DiffPrefixNoNewline,
749
- ]);
750
- /**
751
- * A parser for the GNU unified diff format
752
- *
753
- * See https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
754
- */
755
- class DiffParser {
921
+ var _Cache_keyArray, _Cache_maxLength;
922
+ class Cache extends Map {
756
923
  constructor() {
757
- Object.defineProperty(this, "__v_skip", { value: true });
758
- this.reset();
759
- }
760
- /**
761
- * Resets the internal parser state so that it can be reused.
762
- *
763
- * This is done automatically at the end of each parse run.
764
- */
765
- reset() {
766
- this.ls = 0;
767
- this.le = -1;
768
- this.text = "";
769
- }
770
- /**
771
- * Aligns the internal character pointers at the boundaries of
772
- * the next line.
773
- *
774
- * Returns true if successful or false if the end of the diff
775
- * has been reached.
776
- */
777
- nextLine() {
778
- this.ls = this.le + 1;
779
- // We've reached the end of the diff
780
- if (this.ls >= this.text.length) {
781
- return false;
782
- }
783
- this.le = this.text.indexOf("\n", this.ls);
784
- // If we can't find the next newline character we'll put our
785
- // end pointer at the end of the diff string
786
- if (this.le === -1) {
787
- this.le = this.text.length;
788
- }
789
- // We've succeeded if there's anything to read in between the
790
- // start and the end
791
- return this.ls !== this.le;
792
- }
793
- /**
794
- * Advances to the next line and returns it as a substring
795
- * of the raw diff text. Returns null if end of diff was
796
- * reached.
797
- */
798
- readLine(header) {
799
- if (header) {
800
- return this.nextLine() ? this.text.substring(this.ls, this.le) : null;
801
- }
802
- else {
803
- return this.nextLine() ? this.text.substring(this.ls + 1, this.le + 1) : null;
804
- }
805
- }
806
- /** Tests if the current line starts with the given search text */
807
- lineStartsWith(searchString) {
808
- return this.text.startsWith(searchString, this.ls);
809
- }
810
- /** Tests if the current line ends with the given search text */
811
- lineEndsWith(searchString) {
812
- return this.text.endsWith(searchString, this.le);
813
- }
814
- /**
815
- * Returns the starting character of the next line without
816
- * advancing the internal state. Returns null if advancing
817
- * would mean reaching the end of the diff.
818
- */
819
- peek() {
820
- const p = this.le + 1;
821
- return p < this.text.length ? this.text[p] : null;
822
- }
823
- /**
824
- * Parse the diff header, meaning everything from the
825
- * start of the diff output to the end of the line beginning
826
- * with +++
827
- *
828
- * Example diff header:
829
- *
830
- * diff --git a/app/src/lib/diff-parser.ts b/app/src/lib/diff-parser.ts
831
- * index e1d4871..3bd3ee0 100644
832
- * --- a/app/src/lib/diff-parser.ts
833
- * +++ b/app/src/lib/diff-parser.ts
834
- *
835
- * Returns an object with information extracted from the diff
836
- * header (currently whether it's a binary patch) or null if
837
- * the end of the diff was reached before the +++ line could be
838
- * found (which is a valid state).
839
- */
840
- parseDiffHeader() {
841
- // TODO: There's information in here that we might want to
842
- // capture, such as mode changes
843
- while (this.nextLine()) {
844
- if (this.lineStartsWith("Binary files ") && this.lineEndsWith("differ")) {
845
- return { isBinary: true };
846
- }
847
- if (this.lineStartsWith("+++")) {
848
- return { isBinary: false };
849
- }
850
- }
851
- // It's not an error to not find the +++ line, see the
852
- // 'parses diff of empty file' test in diff-parser-tests.ts
853
- return null;
924
+ super(...arguments);
925
+ _Cache_keyArray.set(this, []);
926
+ _Cache_maxLength.set(this, 30);
854
927
  }
855
- /**
856
- * Attempts to convert a RegExp capture group into a number.
857
- * If the group doesn't exist or wasn't captured the function
858
- * will return the value of the defaultValue parameter or throw
859
- * an error if no default value was provided. If the captured
860
- * string can't be converted to a number an error will be thrown.
861
- */
862
- numberFromGroup(m, group, defaultValue = null) {
863
- const str = m[group];
864
- if (!str) {
865
- if (!defaultValue) {
866
- throw new Error(`Group ${group} missing from regexp match and no defaultValue was provided`);
867
- }
868
- return defaultValue;
869
- }
870
- const num = parseInt(str, 10);
871
- if (isNaN(num)) {
872
- throw new Error(`Could not parse capture group ${group} into number: ${str}`);
873
- }
874
- return num;
928
+ setMaxLength(length) {
929
+ __classPrivateFieldSet(this, _Cache_maxLength, length, "f");
930
+ this._checkLength();
875
931
  }
876
- /**
877
- * Parses a hunk header or throws an error if the given line isn't
878
- * a well-formed hunk header.
879
- *
880
- * We currently only extract the line number information and
881
- * ignore any hunk headings.
882
- *
883
- * Example hunk header (text within ``):
884
- *
885
- * `@@ -84,10 +82,8 @@ export function parseRawDiff(lines: ReadonlyArray<string>): Diff {`
886
- *
887
- * Where everything after the last @@ is what's known as the hunk, or section, heading
888
- */
889
- parseHunkHeader(line) {
890
- const m = diffHeaderRe.exec(line);
891
- if (!m) {
892
- throw new Error(`Invalid hunk header format`);
932
+ set(key, value) {
933
+ if (this.has(key))
934
+ return this;
935
+ __classPrivateFieldGet(this, _Cache_keyArray, "f").push(key);
936
+ this._checkLength();
937
+ return super.set(key, value);
938
+ }
939
+ _checkLength() {
940
+ while (__classPrivateFieldGet(this, _Cache_keyArray, "f").length > __classPrivateFieldGet(this, _Cache_maxLength, "f")) {
941
+ const key = __classPrivateFieldGet(this, _Cache_keyArray, "f").shift();
942
+ this.delete(key);
893
943
  }
894
- // If endLines are missing default to 1, see diffHeaderRe docs
895
- const oldStartLine = this.numberFromGroup(m, 1);
896
- const oldLineCount = this.numberFromGroup(m, 2, 1);
897
- const newStartLine = this.numberFromGroup(m, 3);
898
- const newLineCount = this.numberFromGroup(m, 4, 1);
899
- return new DiffHunkHeader(oldStartLine, oldLineCount, newStartLine, newLineCount);
900
944
  }
901
- /**
902
- * Convenience function which lets us leverage the type system to
903
- * prove exhaustive checks in parseHunk.
904
- *
905
- * Takes an arbitrary string and checks to see if the first character
906
- * of that string is one of the allowed prefix characters for diff
907
- * lines (ie lines in between hunk headers).
908
- */
909
- parseLinePrefix(c) {
910
- // Since we know that DiffLinePrefixChars and the DiffLinePrefix type
911
- // include the same characters we can tell the type system that we
912
- // now know that c[0] is one of the characters in the DifflinePrefix set
913
- if (c && c.length && DiffLinePrefixChars.has(c[0])) {
914
- return c[0];
945
+ }
946
+ _Cache_keyArray = new WeakMap(), _Cache_maxLength = new WeakMap();
947
+
948
+ var _File_instances, _File_doCheck;
949
+ const map = new Cache();
950
+ const devKey = "@git-diff-cache";
951
+ map.setMaxLength(50);
952
+ map.name = "@git-diff-view/core";
953
+ if (typeof globalThis !== "undefined") {
954
+ if (Array.isArray(globalThis[devKey])) {
955
+ globalThis[devKey] = globalThis[devKey].filter((i) => i !== map);
956
+ if (globalThis[devKey].length > 0) {
957
+ console.warn("there are multiple instance of @git-diff-view/core in the one environment!");
915
958
  }
916
- return null;
959
+ globalThis[devKey].push(map);
917
960
  }
918
- /**
919
- * Parses a hunk, including its header or throws an error if the diff doesn't
920
- * contain a well-formed diff hunk at the current position.
921
- *
922
- * Expects that the position has been advanced to the beginning of a presumed
923
- * diff hunk header.
924
- *
925
- * @param linesConsumed The number of unified diff lines consumed up until
926
- * this point by the diff parser. Used to give the
927
- * position and length (in lines) of the parsed hunk
928
- * relative to the overall parsed diff. These numbers
929
- * have no real meaning in the context of a diff and
930
- * are only used to aid the app in line-selections.
931
- */
932
- parseHunk(linesConsumed, hunkIndex, previousHunk) {
933
- const headerLine = this.readLine(true);
934
- if (!headerLine) {
935
- throw new Error("Expected hunk header but reached end of diff");
961
+ else {
962
+ globalThis[devKey] = [map];
963
+ }
964
+ }
965
+ class File {
966
+ static createInstance(data) {
967
+ const file = new File(data === null || data === void 0 ? void 0 : data.raw, data === null || data === void 0 ? void 0 : data.lang, data === null || data === void 0 ? void 0 : data.fileName);
968
+ file.ast = data === null || data === void 0 ? void 0 : data.ast;
969
+ file.rawFile = data === null || data === void 0 ? void 0 : data.rawFile;
970
+ file.hasDoRaw = data === null || data === void 0 ? void 0 : data.hasDoRaw;
971
+ file.rawLength = data === null || data === void 0 ? void 0 : data.rawLength;
972
+ file.syntaxFile = data === null || data === void 0 ? void 0 : data.syntaxFile;
973
+ file.hasDoSyntax = data === null || data === void 0 ? void 0 : data.hasDoSyntax;
974
+ file.syntaxLength = data === null || data === void 0 ? void 0 : data.syntaxLength;
975
+ file.highlighterName = data === null || data === void 0 ? void 0 : data.highlighterName;
976
+ file.maxLineNumber = data === null || data === void 0 ? void 0 : data.maxLineNumber;
977
+ return file;
978
+ }
979
+ constructor(raw, lang, fileName) {
980
+ _File_instances.add(this);
981
+ this.raw = raw;
982
+ this.lang = lang;
983
+ this.fileName = fileName;
984
+ this.rawFile = {};
985
+ this.hasDoRaw = false;
986
+ this.syntaxFile = {};
987
+ this.hasDoSyntax = false;
988
+ this.maxLineNumber = 0;
989
+ Object.defineProperty(this, "__v_skip", { value: true });
990
+ }
991
+ doSyntax({ registerHighlighter }) {
992
+ if (!this.raw || this.hasDoSyntax)
993
+ return;
994
+ const _highlighter = registerHighlighter || highlighter;
995
+ if (this.syntaxLength) {
996
+ console.error("current file already doSyntax before!");
997
+ return;
936
998
  }
937
- const header = this.parseHunkHeader(headerLine);
938
- const lines = new Array();
939
- lines.push(new DiffLine(headerLine, exports.DiffLineType.Hunk, 1, null, null));
940
- let c;
941
- let rollingDiffBeforeCounter = header.oldStartLine;
942
- let rollingDiffAfterCounter = header.newStartLine;
943
- let diffLineNumber = linesConsumed;
944
- while ((c = this.parseLinePrefix(this.peek()))) {
945
- const line = this.readLine(false);
946
- diffLineNumber++;
947
- if (!line) {
948
- throw new Error("Expected unified diff line but reached end of diff");
949
- }
950
- // A marker indicating that the last line in the original or the new file
951
- // is missing a trailing newline. In other words, the presence of this marker
952
- // means that the new and/or original file lacks a trailing newline.
953
- //
954
- // When we find it we have to look up the previous line and set the
955
- // noTrailingNewLine flag
956
- if (c === DiffPrefixNoNewline) {
957
- // See https://github.com/git/git/blob/21f862b498925194f8f1ebe8203b7a7df756555b/apply.c#L1725-L1732
958
- if (line.length < 12) {
959
- throw new Error(`Expected "no newline at end of file" marker to be at least 12 bytes long`);
960
- }
961
- const previousLineIndex = lines.length - 1;
962
- const previousLine = lines[previousLineIndex];
963
- lines[previousLineIndex] = previousLine.withNoTrailingNewLine(true);
964
- continue;
965
- }
966
- let diffLine;
967
- if (c === DiffPrefixAdd) {
968
- diffLine = new DiffLine(line, exports.DiffLineType.Add, diffLineNumber, null, rollingDiffAfterCounter++);
969
- }
970
- else if (c === DiffPrefixDelete) {
971
- diffLine = new DiffLine(line, exports.DiffLineType.Delete, diffLineNumber, rollingDiffBeforeCounter++, null);
972
- }
973
- else if (c === DiffPrefixContext) {
974
- diffLine = new DiffLine(line, exports.DiffLineType.Context, diffLineNumber, rollingDiffBeforeCounter++, rollingDiffAfterCounter++);
975
- }
976
- else {
977
- return assertNever(c, `Unknown DiffLinePrefix: ${c}`);
978
- }
979
- lines.push(diffLine);
999
+ if (this.rawLength > _highlighter.maxLineToIgnoreSyntax) {
1000
+ console.warn(`ignore syntax for current file, because the rawLength is too long: ${this.rawLength}`);
1001
+ return;
980
1002
  }
981
- if (lines.length === 1) {
982
- throw new Error("Malformed diff, empty hunk");
1003
+ this.ast = _highlighter.getAST(this.raw, this.fileName, this.lang);
1004
+ if (!this.ast)
1005
+ return;
1006
+ const { syntaxFileObject, syntaxFileLineNumber } = _highlighter.processAST(this.ast);
1007
+ this.syntaxFile = syntaxFileObject;
1008
+ this.syntaxLength = syntaxFileLineNumber;
1009
+ this.highlighterName = _highlighter.name;
1010
+ {
1011
+ __classPrivateFieldGet(this, _File_instances, "m", _File_doCheck).call(this);
983
1012
  }
984
- return new DiffHunk(header, lines, linesConsumed, linesConsumed + lines.length - 1, getHunkHeaderExpansionType(hunkIndex, header, previousHunk));
1013
+ this.hasDoSyntax = true;
985
1014
  }
986
- /**
987
- * Parse a well-formed unified diff into hunks and lines.
988
- *
989
- * @param text A unified diff produced by git diff, git log --patch
990
- * or any other git plumbing command that produces unified
991
- * diffs.
992
- */
993
- parse(text) {
994
- this.text = text;
995
- try {
996
- const headerInfo = this.parseDiffHeader();
997
- const headerEnd = this.le;
998
- const header = this.text.substring(0, headerEnd);
999
- // empty diff
1000
- if (!headerInfo) {
1001
- return {
1002
- header,
1003
- contents: "",
1004
- hunks: [],
1005
- isBinary: false,
1006
- maxLineNumber: 0,
1007
- hasHiddenBidiChars: false,
1008
- };
1009
- }
1010
- if (headerInfo.isBinary) {
1011
- return {
1012
- header,
1013
- contents: "",
1014
- hunks: [],
1015
- isBinary: true,
1016
- maxLineNumber: 0,
1017
- hasHiddenBidiChars: false,
1018
- };
1019
- }
1020
- const hunks = new Array();
1021
- let linesConsumed = 0;
1022
- let previousHunk = null;
1023
- do {
1024
- const hunk = this.parseHunk(linesConsumed, hunks.length, previousHunk);
1025
- hunks.push(hunk);
1026
- previousHunk = hunk;
1027
- linesConsumed += hunk.lines.length;
1028
- } while (this.peek());
1029
- const contents = this.text
1030
- .substring(headerEnd + 1, this.le)
1031
- // Note that this simply returns a reference to the
1032
- // substring if no match is found, it does not create
1033
- // a new string instance.
1034
- .replace(/\n\/g, "");
1035
- return {
1036
- header,
1037
- contents,
1038
- hunks,
1039
- isBinary: headerInfo.isBinary,
1040
- maxLineNumber: getLargestLineNumber(hunks),
1041
- hasHiddenBidiChars: HiddenBidiCharsRegex.test(text),
1042
- };
1043
- }
1044
- finally {
1045
- this.reset();
1015
+ doRaw() {
1016
+ if (!this.raw || this.hasDoRaw)
1017
+ return;
1018
+ const rawString = this.raw;
1019
+ const rawArray = rawString.split("\n");
1020
+ this.rawLength = rawArray.length;
1021
+ this.maxLineNumber = rawArray.length;
1022
+ this.rawFile = {};
1023
+ for (let i = 0; i < rawArray.length; i++) {
1024
+ this.rawFile[i + 1] = i < rawArray.length - 1 ? rawArray[i] + "\n" : rawArray[i];
1046
1025
  }
1026
+ // reduce 对于大数组性能很差
1027
+ // this.rawFile = rawArray.reduce(
1028
+ // (p, item, index) => ({
1029
+ // ...p,
1030
+ // [index + 1]: index < rawArray.length - 1 ? item + "\n" : item,
1031
+ // }),
1032
+ // {}
1033
+ // );
1034
+ this.hasDoRaw = true;
1047
1035
  }
1048
1036
  }
1049
- const parseInstance = new DiffParser();
1037
+ _File_instances = new WeakSet(), _File_doCheck = function _File_doCheck() {
1038
+ if (this.rawLength && this.syntaxLength) {
1039
+ if (this.rawLength !== this.syntaxLength) {
1040
+ console.warn("the rawLength not match for the syntaxLength");
1041
+ }
1042
+ Object.values(this.syntaxFile).forEach(({ value, lineNumber }) => {
1043
+ if (value !== this.rawFile[lineNumber]) {
1044
+ console.log("some line not match:" + value + " __ " + this.rawFile[lineNumber] + " __ at: " + lineNumber + " lineNumber");
1045
+ }
1046
+ });
1047
+ }
1048
+ };
1049
+ const getFile = (raw, lang, fileName) => {
1050
+ const key = raw + "--" + "0.0.12" + "--" + lang;
1051
+ if (map.has(key))
1052
+ return map.get(key);
1053
+ const file = new File(raw, lang, fileName);
1054
+ map.set(key, file);
1055
+ return file;
1056
+ };
1057
+ const _cacheMap = map;
1050
1058
 
1051
- /* eslint-disable @typescript-eslint/ban-ts-comment */
1052
- /* eslint-disable max-lines */
1053
- var _DiffFile_instances, _DiffFile_oldFileResult, _DiffFile_newFileResult, _DiffFile_diffListResults, _DiffFile_diffLines, _DiffFile_oldFileDiffLines, _DiffFile_newFileDiffLines, _DiffFile_oldFileLines, _DiffFile_newFileLines, _DiffFile_oldFileSyntaxLines, _DiffFile_newFileSyntaxLines, _DiffFile_oldFilePlaceholderLines, _DiffFile_newFilePlaceholderLines, _DiffFile_splitLeftLines, _DiffFile_splitRightLines, _DiffFile_splitHunksLines, _DiffFile_unifiedLines, _DiffFile_unifiedHunksLines, _DiffFile_listeners, _DiffFile_hasInitRaw, _DiffFile_hasInitSyntax, _DiffFile_hasBuildSplit, _DiffFile_hasBuildUnified, _DiffFile_updateCount, _DiffFile_composeByDiff, _DiffFile_highlighterName, _DiffFile_id, _DiffFile_clonedInstance, _DiffFile_doDiff, _DiffFile_doFile, _DiffFile_composeRaw, _DiffFile_composeFile, _DiffFile_composeDiff, _DiffFile_composeSyntax, _DiffFile_getOldDiffLine, _DiffFile_getNewDiffLine, _DiffFile_getOldRawLine, _DiffFile_getNewRawLine;
1059
+ var _DiffFile_instances, _DiffFile_oldFileResult, _DiffFile_newFileResult, _DiffFile_diffListResults, _DiffFile_diffLines, _DiffFile_oldFileDiffLines, _DiffFile_newFileDiffLines, _DiffFile_oldFileLines, _DiffFile_newFileLines, _DiffFile_oldFileSyntaxLines, _DiffFile_newFileSyntaxLines, _DiffFile_oldFilePlaceholderLines, _DiffFile_newFilePlaceholderLines, _DiffFile_splitLeftLines, _DiffFile_splitRightLines, _DiffFile_splitHunksLines, _DiffFile_unifiedLines, _DiffFile_unifiedHunksLines, _DiffFile_listeners, _DiffFile_hasInitRaw, _DiffFile_hasInitSyntax, _DiffFile_hasBuildSplit, _DiffFile_hasBuildUnified, _DiffFile_updateCount, _DiffFile_composeByDiff, _DiffFile_composeByMerge, _DiffFile_composeByFullMerge, _DiffFile_highlighterName, _DiffFile_id, _DiffFile_clonedInstance, _DiffFile_doDiff, _DiffFile_doFile, _DiffFile_composeRaw, _DiffFile_composeFile, _DiffFile_composeDiff, _DiffFile_composeSyntax, _DiffFile_getOldDiffLine, _DiffFile_getNewDiffLine, _DiffFile_getOldRawLine, _DiffFile_getNewRawLine;
1054
1060
  const composeLen = 40;
1055
1061
  const idSet = new Set();
1056
1062
  class DiffFile {
@@ -1058,7 +1064,12 @@ class DiffFile {
1058
1064
  var _a, _b, _c, _d, _e, _f;
1059
1065
  const instance = new DiffFile(((_a = data === null || data === void 0 ? void 0 : data.oldFile) === null || _a === void 0 ? void 0 : _a.fileName) || "", ((_b = data === null || data === void 0 ? void 0 : data.oldFile) === null || _b === void 0 ? void 0 : _b.content) || "", ((_c = data === null || data === void 0 ? void 0 : data.newFile) === null || _c === void 0 ? void 0 : _c.fileName) || "", ((_d = data === null || data === void 0 ? void 0 : data.newFile) === null || _d === void 0 ? void 0 : _d.content) || "", (data === null || data === void 0 ? void 0 : data.hunks) || [], ((_e = data === null || data === void 0 ? void 0 : data.oldFile) === null || _e === void 0 ? void 0 : _e.fileLang) || "", ((_f = data === null || data === void 0 ? void 0 : data.newFile) === null || _f === void 0 ? void 0 : _f.fileLang) || "");
1060
1066
  if (bundle) {
1061
- instance.mergeBundle(bundle);
1067
+ if (bundle.isFullMerge) {
1068
+ instance._mergeFullBundle(bundle);
1069
+ }
1070
+ else {
1071
+ instance.mergeBundle(bundle);
1072
+ }
1062
1073
  }
1063
1074
  return instance;
1064
1075
  }
@@ -1091,8 +1102,10 @@ class DiffFile {
1091
1102
  _DiffFile_hasBuildUnified.set(this, false);
1092
1103
  _DiffFile_updateCount.set(this, 0);
1093
1104
  _DiffFile_composeByDiff.set(this, false);
1105
+ _DiffFile_composeByMerge.set(this, false);
1106
+ _DiffFile_composeByFullMerge.set(this, false);
1094
1107
  _DiffFile_highlighterName.set(this, void 0);
1095
- this._version_ = "0.0.11";
1108
+ this._version_ = "0.0.12";
1096
1109
  this._oldFileContent = "";
1097
1110
  this._oldFileLang = "";
1098
1111
  this._newFileContent = "";
@@ -1100,9 +1113,9 @@ class DiffFile {
1100
1113
  this.diffLineLength = 0;
1101
1114
  this.splitLineLength = 0;
1102
1115
  this.unifiedLineLength = 0;
1103
- this.expandSplitAll = false;
1104
- this.expandUnifiedAll = false;
1105
- this.hasCollapsed = false;
1116
+ this.hasExpandSplitAll = false;
1117
+ this.hasExpandUnifiedAll = false;
1118
+ this.hasSomeLineCollapsed = false;
1106
1119
  _DiffFile_id.set(this, "");
1107
1120
  _DiffFile_clonedInstance.set(this, new Map());
1108
1121
  this.getSplitLeftLine = (index) => {
@@ -1241,13 +1254,13 @@ class DiffFile {
1241
1254
  Object.keys(__classPrivateFieldGet(this, _DiffFile_splitHunksLines, "f") || {}).forEach((key) => {
1242
1255
  this.onSplitHunkExpand("all", +key, false);
1243
1256
  });
1244
- this.expandSplitAll = true;
1257
+ this.hasExpandSplitAll = true;
1245
1258
  }
1246
1259
  else {
1247
1260
  Object.keys(__classPrivateFieldGet(this, _DiffFile_unifiedHunksLines, "f") || {}).forEach((key) => {
1248
1261
  this.onUnifiedHunkExpand("all", +key, false);
1249
1262
  });
1250
- this.expandUnifiedAll = true;
1263
+ this.hasExpandUnifiedAll = true;
1251
1264
  }
1252
1265
  this.notifyAll();
1253
1266
  };
@@ -1279,7 +1292,7 @@ class DiffFile {
1279
1292
  __classPrivateFieldGet(this, _DiffFile_splitHunksLines, "f")[item.splitInfo.endHiddenIndex] = item;
1280
1293
  }
1281
1294
  });
1282
- this.expandSplitAll = false;
1295
+ this.hasExpandSplitAll = false;
1283
1296
  }
1284
1297
  else {
1285
1298
  Object.values(__classPrivateFieldGet(this, _DiffFile_unifiedLines, "f") || {}).forEach((item) => {
@@ -1301,7 +1314,7 @@ class DiffFile {
1301
1314
  __classPrivateFieldGet(this, _DiffFile_unifiedHunksLines, "f")[item.unifiedInfo.endHiddenIndex] = item;
1302
1315
  }
1303
1316
  });
1304
- this.expandUnifiedAll = false;
1317
+ this.hasExpandUnifiedAll = false;
1305
1318
  }
1306
1319
  this.notifyAll();
1307
1320
  };
@@ -1353,7 +1366,7 @@ class DiffFile {
1353
1366
  const unifiedLineLength = this.unifiedLineLength;
1354
1367
  const composeByDiff = __classPrivateFieldGet(this, _DiffFile_composeByDiff, "f");
1355
1368
  const highlighterName = __classPrivateFieldGet(this, _DiffFile_highlighterName, "f");
1356
- const hasCollapsed = this.hasCollapsed;
1369
+ const hasSomeLineCollapsed = this.hasSomeLineCollapsed;
1357
1370
  // split
1358
1371
  const splitLeftLines = __classPrivateFieldGet(this, _DiffFile_splitLeftLines, "f");
1359
1372
  const splitRightLines = __classPrivateFieldGet(this, _DiffFile_splitRightLines, "f");
@@ -1384,8 +1397,9 @@ class DiffFile {
1384
1397
  unifiedHunkLines,
1385
1398
  highlighterName,
1386
1399
  composeByDiff,
1387
- hasCollapsed,
1400
+ hasSomeLineCollapsed,
1388
1401
  version,
1402
+ isFullMerge: false,
1389
1403
  };
1390
1404
  };
1391
1405
  this.mergeBundle = (data) => {
@@ -1405,12 +1419,14 @@ class DiffFile {
1405
1419
  __classPrivateFieldSet(this, _DiffFile_newFilePlaceholderLines, data.newFilePlaceholderLines, "f");
1406
1420
  this.splitLineLength = data.splitLineLength;
1407
1421
  this.unifiedLineLength = data.unifiedLineLength;
1408
- this.hasCollapsed = data.hasCollapsed;
1422
+ this.hasSomeLineCollapsed = data.hasSomeLineCollapsed;
1409
1423
  __classPrivateFieldSet(this, _DiffFile_splitLeftLines, data.splitLeftLines, "f");
1410
1424
  __classPrivateFieldSet(this, _DiffFile_splitRightLines, data.splitRightLines, "f");
1411
1425
  __classPrivateFieldSet(this, _DiffFile_splitHunksLines, data.splitHunkLines, "f");
1412
1426
  __classPrivateFieldSet(this, _DiffFile_unifiedLines, data.unifiedLines, "f");
1413
1427
  __classPrivateFieldSet(this, _DiffFile_unifiedHunksLines, data.unifiedHunkLines, "f");
1428
+ // mark this instance as a merged instance
1429
+ __classPrivateFieldSet(this, _DiffFile_composeByMerge, true, "f");
1414
1430
  if (this._version_ !== data.version) {
1415
1431
  console.error("the version of the `diffInstance` is not match, some error may happen!");
1416
1432
  }
@@ -1447,14 +1463,21 @@ class DiffFile {
1447
1463
  return Object.assign(Object.assign({}, bundle), { oldFileResult,
1448
1464
  newFileResult,
1449
1465
  diffLines,
1450
- diffListResults });
1466
+ diffListResults,
1467
+ // get current instance is a fullMerge instance or not
1468
+ isFullMerge: __classPrivateFieldGet(this, _DiffFile_composeByMerge, "f") ? __classPrivateFieldGet(this, _DiffFile_composeByFullMerge, "f") : true });
1451
1469
  };
1452
1470
  this._mergeFullBundle = (data) => {
1453
1471
  this.mergeBundle(data);
1454
- __classPrivateFieldSet(this, _DiffFile_oldFileResult, data.oldFileResult, "f");
1455
- __classPrivateFieldSet(this, _DiffFile_newFileResult, data.newFileResult, "f");
1456
- __classPrivateFieldSet(this, _DiffFile_diffLines, data.diffLines, "f");
1457
- __classPrivateFieldSet(this, _DiffFile_diffListResults, data.diffListResults, "f");
1472
+ try {
1473
+ __classPrivateFieldSet(this, _DiffFile_oldFileResult, File.createInstance(data.oldFileResult), "f");
1474
+ __classPrivateFieldSet(this, _DiffFile_newFileResult, File.createInstance(data.newFileResult), "f");
1475
+ __classPrivateFieldSet(this, _DiffFile_diffLines, data.diffLines, "f");
1476
+ __classPrivateFieldSet(this, _DiffFile_diffListResults, data.diffListResults, "f");
1477
+ __classPrivateFieldSet(this, _DiffFile_composeByFullMerge, data.isFullMerge, "f");
1478
+ }
1479
+ catch (_a) {
1480
+ }
1458
1481
  };
1459
1482
  this._destroy = () => {
1460
1483
  this.clearId();
@@ -1529,6 +1552,10 @@ class DiffFile {
1529
1552
  var _a, _b;
1530
1553
  if (__classPrivateFieldGet(this, _DiffFile_hasInitSyntax, "f"))
1531
1554
  return;
1555
+ if (__classPrivateFieldGet(this, _DiffFile_composeByMerge, "f") && !__classPrivateFieldGet(this, _DiffFile_composeByFullMerge, "f")) {
1556
+ console.error(`this instance can not do syntax because of the data missing, try to use '_getFullBundle' & '_mergeFullBundle' instead of 'getBundle' & 'mergeBundle'`);
1557
+ return;
1558
+ }
1532
1559
  __classPrivateFieldGet(this, _DiffFile_instances, "m", _DiffFile_composeSyntax).call(this, { registerHighlighter });
1533
1560
  __classPrivateFieldSet(this, _DiffFile_highlighterName, ((_a = __classPrivateFieldGet(this, _DiffFile_oldFileResult, "f")) === null || _a === void 0 ? void 0 : _a.highlighterName) || ((_b = __classPrivateFieldGet(this, _DiffFile_newFileResult, "f")) === null || _b === void 0 ? void 0 : _b.highlighterName) || __classPrivateFieldGet(this, _DiffFile_highlighterName, "f"), "f");
1534
1561
  __classPrivateFieldSet(this, _DiffFile_hasInitSyntax, true, "f");
@@ -1631,7 +1658,7 @@ class DiffFile {
1631
1658
  hideStart = len;
1632
1659
  }
1633
1660
  if (isHidden) {
1634
- this.hasCollapsed = true;
1661
+ this.hasSomeLineCollapsed = true;
1635
1662
  }
1636
1663
  prevIsHidden = isHidden;
1637
1664
  if (oldDiffLine && newDiffLine && !oldLineHasChange && !newLineHasChange) {
@@ -1762,7 +1789,7 @@ class DiffFile {
1762
1789
  hideStart = len;
1763
1790
  }
1764
1791
  if (isHidden) {
1765
- this.hasCollapsed = true;
1792
+ this.hasSomeLineCollapsed = true;
1766
1793
  }
1767
1794
  prevIsHidden = isHidden;
1768
1795
  if (oldDiffLine && newDiffLine && !oldLineHasChange && !newLineHasChange) {
@@ -1808,7 +1835,7 @@ class DiffFile {
1808
1835
  this.notifyAll();
1809
1836
  }
1810
1837
  }
1811
- _DiffFile_oldFileResult = new WeakMap(), _DiffFile_newFileResult = new WeakMap(), _DiffFile_diffListResults = new WeakMap(), _DiffFile_diffLines = new WeakMap(), _DiffFile_oldFileDiffLines = new WeakMap(), _DiffFile_newFileDiffLines = new WeakMap(), _DiffFile_oldFileLines = new WeakMap(), _DiffFile_newFileLines = new WeakMap(), _DiffFile_oldFileSyntaxLines = new WeakMap(), _DiffFile_newFileSyntaxLines = new WeakMap(), _DiffFile_oldFilePlaceholderLines = new WeakMap(), _DiffFile_newFilePlaceholderLines = new WeakMap(), _DiffFile_splitLeftLines = new WeakMap(), _DiffFile_splitRightLines = new WeakMap(), _DiffFile_splitHunksLines = new WeakMap(), _DiffFile_unifiedLines = new WeakMap(), _DiffFile_unifiedHunksLines = new WeakMap(), _DiffFile_listeners = new WeakMap(), _DiffFile_hasInitRaw = new WeakMap(), _DiffFile_hasInitSyntax = new WeakMap(), _DiffFile_hasBuildSplit = new WeakMap(), _DiffFile_hasBuildUnified = new WeakMap(), _DiffFile_updateCount = new WeakMap(), _DiffFile_composeByDiff = new WeakMap(), _DiffFile_highlighterName = new WeakMap(), _DiffFile_id = new WeakMap(), _DiffFile_clonedInstance = new WeakMap(), _DiffFile_instances = new WeakSet(), _DiffFile_doDiff = function _DiffFile_doDiff() {
1838
+ _DiffFile_oldFileResult = new WeakMap(), _DiffFile_newFileResult = new WeakMap(), _DiffFile_diffListResults = new WeakMap(), _DiffFile_diffLines = new WeakMap(), _DiffFile_oldFileDiffLines = new WeakMap(), _DiffFile_newFileDiffLines = new WeakMap(), _DiffFile_oldFileLines = new WeakMap(), _DiffFile_newFileLines = new WeakMap(), _DiffFile_oldFileSyntaxLines = new WeakMap(), _DiffFile_newFileSyntaxLines = new WeakMap(), _DiffFile_oldFilePlaceholderLines = new WeakMap(), _DiffFile_newFilePlaceholderLines = new WeakMap(), _DiffFile_splitLeftLines = new WeakMap(), _DiffFile_splitRightLines = new WeakMap(), _DiffFile_splitHunksLines = new WeakMap(), _DiffFile_unifiedLines = new WeakMap(), _DiffFile_unifiedHunksLines = new WeakMap(), _DiffFile_listeners = new WeakMap(), _DiffFile_hasInitRaw = new WeakMap(), _DiffFile_hasInitSyntax = new WeakMap(), _DiffFile_hasBuildSplit = new WeakMap(), _DiffFile_hasBuildUnified = new WeakMap(), _DiffFile_updateCount = new WeakMap(), _DiffFile_composeByDiff = new WeakMap(), _DiffFile_composeByMerge = new WeakMap(), _DiffFile_composeByFullMerge = new WeakMap(), _DiffFile_highlighterName = new WeakMap(), _DiffFile_id = new WeakMap(), _DiffFile_clonedInstance = new WeakMap(), _DiffFile_instances = new WeakSet(), _DiffFile_doDiff = function _DiffFile_doDiff() {
1812
1839
  if (!this._diffList)
1813
1840
  return;
1814
1841
  __classPrivateFieldSet(this, _DiffFile_diffListResults, this._diffList.map((s) => parseInstance.parse(s)), "f");
@@ -2122,7 +2149,7 @@ const getUnifiedContentLine = (diffFile) => {
2122
2149
  return lines.filter((line) => line.type === exports.DiffFileLineType.content);
2123
2150
  };
2124
2151
 
2125
- const versions = "0.0.11";
2152
+ const versions = "0.0.12";
2126
2153
 
2127
2154
  const useUnmount = (cb, deps) => {
2128
2155
  const ref = React.useRef(cb);
@@ -3565,7 +3592,7 @@ const _InternalDiffView = (props) => {
3565
3592
  ]);
3566
3593
  const value = React.useMemo(() => ({ useDiffContext }), [useDiffContext]);
3567
3594
  return (React__namespace.createElement(DiffViewContext.Provider, { value: value },
3568
- React__namespace.createElement("div", { className: "diff-tailwindcss-wrapper", "data-component": "git-diff-view", "data-version": `${"0.0.11"}`, "data-highlighter": diffFile._getHighlighterName() },
3595
+ React__namespace.createElement("div", { className: "diff-tailwindcss-wrapper", "data-component": "git-diff-view", "data-version": `${"0.0.12"}`, "data-highlighter": diffFile._getHighlighterName() },
3569
3596
  React__namespace.createElement("div", { className: "diff-style-root", style: {
3570
3597
  // @ts-ignore
3571
3598
  [diffFontSizeName]: diffViewFontSize + "px",
@@ -3618,14 +3645,18 @@ const DiffViewWithRef = (props, ref) => {
3618
3645
  };
3619
3646
  const DiffView = React.forwardRef(DiffViewWithRef);
3620
3647
  DiffView.displayName = "DiffView";
3621
- const version = "0.0.11";
3648
+ const version = "0.0.12";
3622
3649
 
3623
3650
  exports.DefaultDiffExpansionStep = DefaultDiffExpansionStep;
3624
3651
  exports.DiffFile = DiffFile;
3652
+ exports.DiffHunk = DiffHunk;
3653
+ exports.DiffHunkHeader = DiffHunkHeader;
3625
3654
  exports.DiffLine = DiffLine;
3655
+ exports.DiffParser = DiffParser;
3626
3656
  exports.DiffView = DiffView;
3627
3657
  exports.DiffViewContext = DiffViewContext;
3628
3658
  exports.File = File;
3659
+ exports.HiddenBidiCharsRegex = HiddenBidiCharsRegex;
3629
3660
  exports._cacheMap = _cacheMap;
3630
3661
  exports.assertNever = assertNever;
3631
3662
  exports.checkDiffLineIncludeChange = checkDiffLineIncludeChange;
@@ -3643,6 +3674,7 @@ exports.getUnifiedLines = getUnifiedLines;
3643
3674
  exports.hasRelativeChange = hasRelativeChange;
3644
3675
  exports.highlighter = highlighter;
3645
3676
  exports.numIterator = numIterator;
3677
+ exports.parseInstance = parseInstance;
3646
3678
  exports.processAST = processAST;
3647
3679
  exports.relativeChanges = relativeChanges;
3648
3680
  exports.useDiffViewContext = useDiffViewContext;