11import path from 'path'
2+ // @ts -expect-error: hush
23import gitDiffTree from 'git-diff-tree'
34import { findUpOne } from 'vfile-find-up'
45
56const own = { } . hasOwnProperty
67
8+ /** @type {string } */
79let previousRange
810
11+ /** @type {import('unified').Plugin<[]> } */
912export default function diff ( ) {
13+ /** @type {Record<string, string> } */
1014 let cache = { }
1115
12- return transform
13-
14- function transform ( tree , file , next ) {
16+ return function ( _ , file , next ) {
1517 const base = file . dirname
18+ /** @type {string|undefined } */
1619 let commitRange
20+ /** @type {string[]|undefined } */
1721 let range
1822
1923 // Looks like Travis.
@@ -23,6 +27,7 @@ export default function diff() {
2327 }
2428 // Looks like GH Actions.
2529 else if ( process . env . GITHUB_SHA ) {
30+ // @ts -expect-error: fine.
2631 range =
2732 // This is a PR: check the whole PR.
2833 // Refs take the form `refs/heads/main`.
@@ -32,10 +37,17 @@ export default function diff() {
3237 process . env . GITHUB_HEAD_REF . split ( '/' ) . pop ( )
3338 ]
3439 : [ process . env . GITHUB_SHA + '^1' , process . env . GITHUB_SHA ]
40+ // @ts -expect-error: We definitely just defined this
3541 commitRange = range . join ( '...' )
3642 }
3743
38- if ( ! base || ! commitRange || range . length !== 2 ) {
44+ if (
45+ ! base ||
46+ ! commitRange ||
47+ ! range ||
48+ ! file . dirname ||
49+ range . length !== 2
50+ ) {
3951 return next ( )
4052 }
4153
@@ -48,71 +60,84 @@ export default function diff() {
4860 if ( own . call ( cache , base ) ) {
4961 tick ( cache [ base ] )
5062 } else {
51- findUpOne ( '.git' , file . dirname , ongit )
52- }
63+ findUpOne ( '.git' , file . dirname , ( error , git ) => {
64+ // Never happens.
65+ /* c8 ignore next */
66+ if ( error ) return next ( error )
5367
54- function ongit ( error , git ) {
55- // Never happens.
56- /* c8 ignore next */
57- if ( error ) return next ( error )
68+ // Not testable in a Git repo…
69+ /* c8 ignore next */
70+ if ( ! git ) return next ( new Error ( 'Not in a git repository' ) )
5871
59- // Not testable in a Git repo…
60- /* c8 ignore next */
61- if ( ! git ) return next ( new Error ( 'Not in a git repository' ) )
62-
63- cache [ base ] = git . dirname
64- tick ( git . dirname )
72+ cache [ base ] = git . dirname
73+ tick ( git . dirname )
74+ } )
6575 }
6676
77+ /**
78+ * @param {string } root
79+ */
6780 function tick ( root ) {
81+ /** @type {Record<string, [number, number][]> } */
6882 const diffs = { }
6983
7084 gitDiffTree ( path . join ( root , '.git' ) , {
85+ // @ts -expect-error: fine.
7186 originalRev : range [ 0 ] ,
87+ // @ts -expect-error: fine.
7288 rev : range [ 1 ]
7389 } )
7490 . on ( 'error' , next )
75- . on ( 'data' , ( type , data ) => {
76- if ( type !== 'patch' ) return
77-
78- const lines = data . lines
79- const re = / ^ @ @ - ( \d + ) , ? ( \d + ) ? \+ ( \d + ) , ? ( \d + ) ? @ @ /
80- const match = lines [ 0 ] . match ( re )
81-
82- // Should not happen, maybe if Git returns weird diffs?
83- /* c8 ignore next */
84- if ( ! match ) return
85-
86- const ranges = [ ]
87- const start = Number . parseInt ( match [ 3 ] , 10 ) - 1
88- let index = 0
89- let position
90-
91- while ( ++ index < lines . length ) {
92- const line = lines [ index ]
93-
94- if ( line . charAt ( 0 ) === '+' ) {
95- const no = start + index
96-
97- if ( position === undefined ) {
98- position = ranges . length
99- ranges . push ( [ no , no ] )
91+ . on (
92+ 'data' ,
93+ /**
94+ * @param {string } type
95+ * @param {{lines: string, aPath: string, bPath: string} } data
96+ */
97+ ( type , data ) => {
98+ if ( type !== 'patch' ) return
99+
100+ const lines = data . lines
101+ const re = / ^ @ @ - ( \d + ) , ? ( \d + ) ? \+ ( \d + ) , ? ( \d + ) ? @ @ /
102+ const match = lines [ 0 ] . match ( re )
103+
104+ // Should not happen, maybe if Git returns weird diffs?
105+ /* c8 ignore next */
106+ if ( ! match ) return
107+
108+ /** @type {[number, number][] } */
109+ const ranges = [ ]
110+ const start = Number . parseInt ( match [ 3 ] , 10 ) - 1
111+ let index = 0
112+ /** @type {number|undefined } */
113+ let position
114+
115+ while ( ++ index < lines . length ) {
116+ const line = lines [ index ]
117+
118+ if ( line . charAt ( 0 ) === '+' ) {
119+ const no = start + index
120+
121+ if ( position === undefined ) {
122+ position = ranges . length
123+ ranges . push ( [ no , no ] )
124+ } else {
125+ ranges [ position ] [ 1 ] = no
126+ }
100127 } else {
101- ranges [ position ] [ 1 ] = no
128+ position = undefined
102129 }
103- } else {
104- position = undefined
105130 }
106- }
107131
108- const fp = path . resolve ( root , data . bPath )
132+ const fp = path . resolve ( root , data . bPath )
109133
110- // Long diffs.
111- /* c8 ignore next */
112- if ( ! ( fp in diffs ) ) diffs [ fp ] = [ ]
134+ // Long diffs.
135+ /* c8 ignore next */
136+ if ( ! ( fp in diffs ) ) diffs [ fp ] = [ ]
113137
114- diffs [ fp ] . push ( ...ranges )
115- } )
138+ diffs [ fp ] . push ( ...ranges )
139+ }
140+ )
116141 . on ( 'end' , ( ) => {
117142 const fp = path . resolve ( file . cwd , file . path )
118143 const ranges = diffs [ fp ]
@@ -125,7 +150,10 @@ export default function diff() {
125150
126151 file . messages = file . messages . filter ( ( message ) =>
127152 ranges . some (
128- ( range ) => message . line >= range [ 0 ] && message . line <= range [ 1 ]
153+ ( range ) =>
154+ message . line &&
155+ message . line >= range [ 0 ] &&
156+ message . line <= range [ 1 ]
129157 )
130158 )
131159
0 commit comments