difit 2.0.2 → 2.0.4
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/cli/index.js +1 -1
- package/dist/cli/index.test.js +17 -17
- package/dist/cli/utils.js +40 -2
- package/dist/cli/utils.test.js +33 -0
- package/dist/client/assets/{index-8bOJqzQC.js → index-BAqzWO4G.js} +51 -41
- package/dist/client/assets/index-Bo95t_L8.css +1 -0
- package/dist/client/assets/{prism-java-XP5rs1ZV.js → prism-java-qbeIxN8m.js} +1 -1
- package/dist/client/assets/{prism-php-CYxq20-J.js → prism-php-CkKTjm8O.js} +1 -1
- package/dist/client/assets/{prism-ruby-BoO_oIbk.js → prism-ruby-DoYrLzd_.js} +1 -1
- package/dist/client/assets/{prism-solidity-CHQMoOrF.js → prism-solidity-yzLt942n.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/git-diff.js +0 -6
- package/dist/server/git-diff.test.js +26 -1
- package/dist/server/server.js +1 -1
- package/dist/server/server.test.js +3 -3
- package/dist/tui/App.js +4 -4
- package/dist/tui/components/DiffViewer.d.ts +1 -1
- package/dist/tui/components/DiffViewer.js +1 -1
- package/dist/tui/components/FileList.d.ts +1 -1
- package/dist/tui/components/FileList.js +1 -1
- package/dist/tui/components/SideBySideDiffViewer.d.ts +1 -1
- package/dist/tui/components/SideBySideDiffViewer.js +42 -39
- package/dist/tui/components/StatusBar.js +1 -1
- package/dist/tui/utils/parseDiff.d.ts +1 -1
- package/dist/tui/utils/parseDiff.js +1 -2
- package/dist/utils/gitUtils.d.ts +4 -0
- package/dist/utils/gitUtils.js +29 -0
- package/dist/utils/gitUtils.test.d.ts +1 -0
- package/dist/utils/gitUtils.test.js +63 -0
- package/package.json +3 -1
- package/dist/client/assets/index-sXbQL2XR.css +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -16,7 +16,7 @@ program
|
|
|
16
16
|
.argument('[commit-ish]', 'Git commit, tag, branch, HEAD~n reference, or "working"/"staged"/"."', 'HEAD')
|
|
17
17
|
.argument('[compare-with]', 'Optional: Compare with this commit/branch (shows diff between commit-ish and compare-with)')
|
|
18
18
|
.option('--port <port>', 'preferred port (auto-assigned if occupied)', parseInt)
|
|
19
|
-
.option('--host <host>', 'host address to bind', '
|
|
19
|
+
.option('--host <host>', 'host address to bind', '')
|
|
20
20
|
.option('--no-open', 'do not automatically open browser')
|
|
21
21
|
.option('--mode <mode>', 'diff mode (side-by-side or inline)', 'side-by-side')
|
|
22
22
|
.option('--tui', 'use terminal UI instead of web interface')
|
package/dist/cli/index.test.js
CHANGED
|
@@ -107,7 +107,7 @@ describe('CLI index.ts', () => {
|
|
|
107
107
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
108
108
|
.argument('[compare-with]', 'compare-with')
|
|
109
109
|
.option('--port <port>', 'port', parseInt)
|
|
110
|
-
.option('--host <host>', 'host', '
|
|
110
|
+
.option('--host <host>', 'host', '')
|
|
111
111
|
.option('--no-open', 'no-open')
|
|
112
112
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
113
113
|
.option('--tui', 'tui')
|
|
@@ -149,7 +149,7 @@ describe('CLI index.ts', () => {
|
|
|
149
149
|
targetCommitish: expectedTarget,
|
|
150
150
|
baseCommitish: expectedBase,
|
|
151
151
|
preferredPort: undefined,
|
|
152
|
-
host: '
|
|
152
|
+
host: '',
|
|
153
153
|
openBrowser: true,
|
|
154
154
|
mode: 'side-by-side',
|
|
155
155
|
});
|
|
@@ -184,7 +184,7 @@ describe('CLI index.ts', () => {
|
|
|
184
184
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
185
185
|
.argument('[compare-with]', 'compare-with')
|
|
186
186
|
.option('--port <port>', 'port', parseInt)
|
|
187
|
-
.option('--host <host>', 'host', '
|
|
187
|
+
.option('--host <host>', 'host', '')
|
|
188
188
|
.option('--no-open', 'no-open')
|
|
189
189
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
190
190
|
.option('--tui', 'tui')
|
|
@@ -206,7 +206,7 @@ describe('CLI index.ts', () => {
|
|
|
206
206
|
targetCommitish: 'HEAD',
|
|
207
207
|
baseCommitish: 'HEAD^',
|
|
208
208
|
preferredPort: expectedOptions.port,
|
|
209
|
-
host: expectedOptions.host || '
|
|
209
|
+
host: expectedOptions.host || '',
|
|
210
210
|
openBrowser: expectedOptions.open !== false,
|
|
211
211
|
mode: expectedOptions.mode || 'side-by-side',
|
|
212
212
|
};
|
|
@@ -224,7 +224,7 @@ describe('CLI index.ts', () => {
|
|
|
224
224
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
225
225
|
.argument('[compare-with]', 'compare-with')
|
|
226
226
|
.option('--port <port>', 'port', parseInt)
|
|
227
|
-
.option('--host <host>', 'host', '
|
|
227
|
+
.option('--host <host>', 'host', '')
|
|
228
228
|
.option('--no-open', 'no-open')
|
|
229
229
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
230
230
|
.option('--tui', 'tui')
|
|
@@ -255,7 +255,7 @@ describe('CLI index.ts', () => {
|
|
|
255
255
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
256
256
|
.argument('[compare-with]', 'compare-with')
|
|
257
257
|
.option('--port <port>', 'port', parseInt)
|
|
258
|
-
.option('--host <host>', 'host', '
|
|
258
|
+
.option('--host <host>', 'host', '')
|
|
259
259
|
.option('--no-open', 'no-open')
|
|
260
260
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
261
261
|
.option('--tui', 'tui')
|
|
@@ -291,7 +291,7 @@ describe('CLI index.ts', () => {
|
|
|
291
291
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
292
292
|
.argument('[compare-with]', 'compare-with')
|
|
293
293
|
.option('--port <port>', 'port', parseInt)
|
|
294
|
-
.option('--host <host>', 'host', '
|
|
294
|
+
.option('--host <host>', 'host', '')
|
|
295
295
|
.option('--no-open', 'no-open')
|
|
296
296
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
297
297
|
.option('--tui', 'tui')
|
|
@@ -326,7 +326,7 @@ describe('CLI index.ts', () => {
|
|
|
326
326
|
targetCommitish: 'abc123',
|
|
327
327
|
baseCommitish: 'def456',
|
|
328
328
|
preferredPort: undefined,
|
|
329
|
-
host: '
|
|
329
|
+
host: '',
|
|
330
330
|
openBrowser: true,
|
|
331
331
|
mode: 'side-by-side',
|
|
332
332
|
});
|
|
@@ -337,7 +337,7 @@ describe('CLI index.ts', () => {
|
|
|
337
337
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
338
338
|
.argument('[compare-with]', 'compare-with')
|
|
339
339
|
.option('--port <port>', 'port', parseInt)
|
|
340
|
-
.option('--host <host>', 'host', '
|
|
340
|
+
.option('--host <host>', 'host', '')
|
|
341
341
|
.option('--no-open', 'no-open')
|
|
342
342
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
343
343
|
.option('--tui', 'tui')
|
|
@@ -370,7 +370,7 @@ describe('CLI index.ts', () => {
|
|
|
370
370
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
371
371
|
.argument('[compare-with]', 'compare-with')
|
|
372
372
|
.option('--port <port>', 'port', parseInt)
|
|
373
|
-
.option('--host <host>', 'host', '
|
|
373
|
+
.option('--host <host>', 'host', '')
|
|
374
374
|
.option('--no-open', 'no-open')
|
|
375
375
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
376
376
|
.option('--tui', 'tui')
|
|
@@ -413,7 +413,7 @@ describe('CLI index.ts', () => {
|
|
|
413
413
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
414
414
|
.argument('[compare-with]', 'compare-with')
|
|
415
415
|
.option('--port <port>', 'port', parseInt)
|
|
416
|
-
.option('--host <host>', 'host', '
|
|
416
|
+
.option('--host <host>', 'host', '')
|
|
417
417
|
.option('--no-open', 'no-open')
|
|
418
418
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
419
419
|
.option('--tui', 'tui')
|
|
@@ -447,7 +447,7 @@ describe('CLI index.ts', () => {
|
|
|
447
447
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
448
448
|
.argument('[compare-with]', 'compare-with')
|
|
449
449
|
.option('--port <port>', 'port', parseInt)
|
|
450
|
-
.option('--host <host>', 'host', '
|
|
450
|
+
.option('--host <host>', 'host', '')
|
|
451
451
|
.option('--no-open', 'no-open')
|
|
452
452
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
453
453
|
.option('--tui', 'tui')
|
|
@@ -474,7 +474,7 @@ describe('CLI index.ts', () => {
|
|
|
474
474
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
475
475
|
.argument('[compare-with]', 'compare-with')
|
|
476
476
|
.option('--port <port>', 'port', parseInt)
|
|
477
|
-
.option('--host <host>', 'host', '
|
|
477
|
+
.option('--host <host>', 'host', '')
|
|
478
478
|
.option('--no-open', 'no-open')
|
|
479
479
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
480
480
|
.option('--tui', 'tui')
|
|
@@ -528,7 +528,7 @@ describe('CLI index.ts', () => {
|
|
|
528
528
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
529
529
|
.argument('[compare-with]', 'compare-with')
|
|
530
530
|
.option('--port <port>', 'port', parseInt)
|
|
531
|
-
.option('--host <host>', 'host', '
|
|
531
|
+
.option('--host <host>', 'host', '')
|
|
532
532
|
.option('--no-open', 'no-open')
|
|
533
533
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
534
534
|
.option('--tui', 'tui')
|
|
@@ -566,7 +566,7 @@ describe('CLI index.ts', () => {
|
|
|
566
566
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
567
567
|
.argument('[compare-with]', 'compare-with')
|
|
568
568
|
.option('--port <port>', 'port', parseInt)
|
|
569
|
-
.option('--host <host>', 'host', '
|
|
569
|
+
.option('--host <host>', 'host', '')
|
|
570
570
|
.option('--no-open', 'no-open')
|
|
571
571
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
572
572
|
.option('--tui', 'tui')
|
|
@@ -604,7 +604,7 @@ describe('CLI index.ts', () => {
|
|
|
604
604
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
605
605
|
.argument('[compare-with]', 'compare-with')
|
|
606
606
|
.option('--port <port>', 'port', parseInt)
|
|
607
|
-
.option('--host <host>', 'host', '
|
|
607
|
+
.option('--host <host>', 'host', '')
|
|
608
608
|
.option('--no-open', 'no-open')
|
|
609
609
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
610
610
|
.option('--tui', 'tui')
|
|
@@ -653,7 +653,7 @@ describe('CLI index.ts', () => {
|
|
|
653
653
|
.argument('[commit-ish]', 'commit-ish', 'HEAD')
|
|
654
654
|
.argument('[compare-with]', 'compare-with')
|
|
655
655
|
.option('--port <port>', 'port', parseInt)
|
|
656
|
-
.option('--host <host>', 'host', '
|
|
656
|
+
.option('--host <host>', 'host', '')
|
|
657
657
|
.option('--no-open', 'no-open')
|
|
658
658
|
.option('--mode <mode>', 'mode', 'side-by-side')
|
|
659
659
|
.option('--tui', 'tui')
|
package/dist/cli/utils.js
CHANGED
|
@@ -21,9 +21,47 @@ export function validateCommitish(commitish) {
|
|
|
21
21
|
/^[a-f0-9]{4,40}\^+$/i, // SHA hashes with ^ suffix (parent references)
|
|
22
22
|
/^[a-f0-9]{4,40}~\d+$/i, // SHA hashes with ~N suffix (ancestor references)
|
|
23
23
|
/^HEAD(~\d+|\^\d*)*$/, // HEAD, HEAD~1, HEAD^, HEAD^2, etc.
|
|
24
|
-
/^[a-zA-Z][a-zA-Z0-9_\-/.@]*$/, // branch names, tags (must start with letter, no ^ or ~ in middle)
|
|
25
24
|
];
|
|
26
|
-
|
|
25
|
+
// Check if it matches any specific patterns first
|
|
26
|
+
if (validPatterns.some((pattern) => pattern.test(trimmed))) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
// For branch names, use git's rules
|
|
30
|
+
return isValidBranchName(trimmed);
|
|
31
|
+
}
|
|
32
|
+
function isValidBranchName(name) {
|
|
33
|
+
// Git branch name rules
|
|
34
|
+
if (name.startsWith('-'))
|
|
35
|
+
return false; // Cannot start with dash
|
|
36
|
+
if (name.endsWith('.'))
|
|
37
|
+
return false; // Cannot end with dot
|
|
38
|
+
if (name === '@')
|
|
39
|
+
return false; // Cannot be just @
|
|
40
|
+
if (name.includes('..'))
|
|
41
|
+
return false; // No consecutive dots
|
|
42
|
+
if (name.includes('@{'))
|
|
43
|
+
return false; // No @{ sequence
|
|
44
|
+
if (name.includes('//'))
|
|
45
|
+
return false; // No consecutive slashes
|
|
46
|
+
if (name.startsWith('/') || name.endsWith('/'))
|
|
47
|
+
return false; // No leading/trailing slashes
|
|
48
|
+
if (name.endsWith('.lock'))
|
|
49
|
+
return false; // Cannot end with .lock
|
|
50
|
+
// Check for forbidden characters
|
|
51
|
+
const forbiddenChars = /[~^:?*[\\\x00-\x20\x7F]/;
|
|
52
|
+
if (forbiddenChars.test(name))
|
|
53
|
+
return false;
|
|
54
|
+
// Check path components
|
|
55
|
+
const components = name.split('/');
|
|
56
|
+
for (const component of components) {
|
|
57
|
+
if (component === '')
|
|
58
|
+
return false; // Empty component
|
|
59
|
+
if (component.startsWith('.'))
|
|
60
|
+
return false; // Component cannot start with dot
|
|
61
|
+
if (component.endsWith('.lock'))
|
|
62
|
+
return false; // Component cannot end with .lock
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
27
65
|
}
|
|
28
66
|
export function shortHash(hash) {
|
|
29
67
|
return hash.substring(0, 7);
|
package/dist/cli/utils.test.js
CHANGED
|
@@ -28,9 +28,22 @@ describe('CLI Utils', () => {
|
|
|
28
28
|
expect(validateCommitish('HEAD~2^1')).toBe(true);
|
|
29
29
|
});
|
|
30
30
|
it('should validate branch names', () => {
|
|
31
|
+
// Valid branch names according to git rules
|
|
31
32
|
expect(validateCommitish('main')).toBe(true);
|
|
32
33
|
expect(validateCommitish('feature/new-feature')).toBe(true);
|
|
33
34
|
expect(validateCommitish('develop')).toBe(true);
|
|
35
|
+
expect(validateCommitish('feature-123')).toBe(true); // dash and numbers (not at start)
|
|
36
|
+
expect(validateCommitish('feature_branch')).toBe(true); // underscore
|
|
37
|
+
expect(validateCommitish('hotfix@bug')).toBe(true); // @ character (not followed by {)
|
|
38
|
+
expect(validateCommitish('feature+new')).toBe(true); // plus character
|
|
39
|
+
expect(validateCommitish('feature=test')).toBe(true); // equals character
|
|
40
|
+
expect(validateCommitish('feature!important')).toBe(true); // exclamation
|
|
41
|
+
expect(validateCommitish('feature,list')).toBe(true); // comma
|
|
42
|
+
expect(validateCommitish('feature;test')).toBe(true); // semicolon
|
|
43
|
+
expect(validateCommitish('feature"quoted"')).toBe(true); // quotes
|
|
44
|
+
expect(validateCommitish("feature'quoted'")).toBe(true); // single quotes
|
|
45
|
+
expect(validateCommitish('release/v2.3.1')).toBe(true); // version numbers
|
|
46
|
+
expect(validateCommitish('bugfix/login-timeout')).toBe(true); // path with dash
|
|
34
47
|
});
|
|
35
48
|
it('should validate special cases', () => {
|
|
36
49
|
expect(validateCommitish('.')).toBe(true); // working directory diff
|
|
@@ -40,6 +53,26 @@ describe('CLI Utils', () => {
|
|
|
40
53
|
expect(validateCommitish(' ')).toBe(false);
|
|
41
54
|
expect(validateCommitish('HEAD~')).toBe(false);
|
|
42
55
|
expect(validateCommitish('abc')).toBe(true); // short hashes are valid
|
|
56
|
+
// Invalid branch names according to git rules
|
|
57
|
+
expect(validateCommitish('-feature')).toBe(false); // cannot start with dash
|
|
58
|
+
expect(validateCommitish('feature.')).toBe(false); // cannot end with dot
|
|
59
|
+
expect(validateCommitish('@')).toBe(false); // cannot be just @
|
|
60
|
+
expect(validateCommitish('feature..test')).toBe(false); // no consecutive dots
|
|
61
|
+
expect(validateCommitish('feature@{upstream}')).toBe(false); // no @{ sequence
|
|
62
|
+
expect(validateCommitish('feature//test')).toBe(false); // no consecutive slashes
|
|
63
|
+
expect(validateCommitish('/feature')).toBe(false); // cannot start with slash
|
|
64
|
+
expect(validateCommitish('feature/')).toBe(false); // cannot end with slash
|
|
65
|
+
expect(validateCommitish('feature.lock')).toBe(false); // cannot end with .lock
|
|
66
|
+
expect(validateCommitish('feature^invalid')).toBe(false); // ^ not allowed
|
|
67
|
+
expect(validateCommitish('feature~invalid')).toBe(false); // ~ not allowed
|
|
68
|
+
expect(validateCommitish('feature:invalid')).toBe(false); // : not allowed
|
|
69
|
+
expect(validateCommitish('feature?invalid')).toBe(false); // ? not allowed
|
|
70
|
+
expect(validateCommitish('feature*invalid')).toBe(false); // * not allowed
|
|
71
|
+
expect(validateCommitish('feature[invalid')).toBe(false); // [ not allowed
|
|
72
|
+
expect(validateCommitish('feature\\invalid')).toBe(false); // \ not allowed
|
|
73
|
+
expect(validateCommitish('feature invalid')).toBe(false); // space not allowed
|
|
74
|
+
expect(validateCommitish('feature/.hidden')).toBe(false); // component cannot start with dot
|
|
75
|
+
expect(validateCommitish('feature/test.lock')).toBe(false); // component cannot end with .lock
|
|
43
76
|
});
|
|
44
77
|
it('should reject non-string input', () => {
|
|
45
78
|
expect(validateCommitish(null)).toBe(false);
|