@@ -12,6 +12,7 @@ const styleRulesPath = path.join(scriptDir, 'style-rules.yml');
1212/**
1313 * Enhanced GitHub Documentation Validator with inline comments and friendly reporting
1414 * Implements Strapi's 12 Rules of Technical Writing with human-like feedback
15+ * Uses diff content directly - no file fetching needed!
1516 */
1617class EnhancedGitHubDocumentationValidator {
1718 constructor ( options = { } ) {
@@ -88,9 +89,9 @@ class EnhancedGitHubDocumentationValidator {
8889 return ;
8990 }
9091
91- // Process each file
92+ // Process each file using diff content directly
9293 for ( const [ filePath , diffInfo ] of Object . entries ( parsedDiff . files ) ) {
93- await this . validateFileWithDiff ( filePath , diffInfo ) ;
94+ await this . validateFileWithDiffContent ( filePath , diffInfo , diffContent ) ;
9495 }
9596
9697 // Generate results
@@ -105,9 +106,9 @@ class EnhancedGitHubDocumentationValidator {
105106 }
106107
107108 /**
108- * Validate a single file against the diff info
109+ * Validate a single file using content extracted directly from diff
109110 */
110- async validateFileWithDiff ( filePath , diffInfo ) {
111+ async validateFileWithDiffContent ( filePath , diffInfo , fullDiffContent ) {
111112 try {
112113 this . log ( `🔍 Analyzing: ${ filePath } ` , 'debug' ) ;
113114
@@ -116,55 +117,88 @@ class EnhancedGitHubDocumentationValidator {
116117 return ;
117118 }
118119
119- // Fetch file content from GitHub
120- const fileContent = await this . fetchFileContent ( filePath ) ;
120+ // Extract added/modified lines content from the diff
121+ const addedContent = this . extractAddedLinesFromDiff ( filePath , fullDiffContent , diffInfo ) ;
121122
122- // Generate filtered content for analysis
123- const { content : filteredContent , lineMapping, changedLines } =
124- this . diffParser . generateFilteredContent ( fileContent , diffInfo ) ;
125-
126- if ( ! filteredContent . trim ( ) ) {
127- this . log ( `📄 No changed content to analyze in: ${ filePath } ` , 'debug' ) ;
123+ if ( ! addedContent . trim ( ) ) {
124+ this . log ( `📄 No added content to analyze in: ${ filePath } ` , 'debug' ) ;
128125 return ;
129126 }
130127
131- // Apply all rules
132- const allIssues = this . applyAllRules ( filteredContent , filePath , { lineMapping, changedLines, diffInfo } ) ;
128+ this . log ( `📝 Extracted ${ addedContent . split ( '\n' ) . length } lines of added content` , 'debug' ) ;
129+
130+ // Apply all rules to the added content
131+ const allIssues = this . applyAllRules ( addedContent , filePath , { diffInfo } ) ;
133132
134- // Filter for changed lines only
135- const relevantIssues = this . filterIssuesForChangedLines ( allIssues , changedLines , lineMapping , diffInfo ) ;
133+ // Map line numbers back to original file line numbers
134+ const mappedIssues = this . mapLinesToOriginal ( allIssues , diffInfo , addedContent ) ;
136135
137136 // Categorize and store issues
138- this . categorizeIssues ( relevantIssues ) ;
137+ this . categorizeIssues ( mappedIssues ) ;
139138 this . results . summary . filesProcessed ++ ;
140139
141- this . log ( `📊 ${ filePath } : ${ relevantIssues . length } issues found` , 'debug' ) ;
140+ this . log ( `📊 ${ filePath } : ${ mappedIssues . length } issues found` , 'debug' ) ;
142141
143142 } catch ( error ) {
144143 this . log ( `⚠️ Error analyzing ${ filePath } : ${ error . message } ` , 'warn' ) ;
145144 }
146145 }
147146
148147 /**
149- * Fetch file content from GitHub
148+ * Extract added lines content from the diff for a specific file
150149 */
151- async fetchFileContent ( filePath ) {
152- const url = `https://raw.githubusercontent.com/${ this . options . repoOwner } /${ this . options . repoName } /main/${ filePath } ` ;
150+ extractAddedLinesFromDiff ( filePath , fullDiffContent , diffInfo ) {
151+ const lines = fullDiffContent . split ( '\n' ) ;
152+ const addedLines = [ ] ;
153+ let inFileSection = false ;
154+ let inChunk = false ;
155+
156+ for ( const line of lines ) {
157+ // Check if we're entering the section for our file
158+ if ( line . startsWith ( 'diff --git' ) && line . includes ( filePath ) ) {
159+ inFileSection = true ;
160+ continue ;
161+ }
162+
163+ // Check if we're entering another file's section
164+ if ( line . startsWith ( 'diff --git' ) && ! line . includes ( filePath ) ) {
165+ inFileSection = false ;
166+ continue ;
167+ }
168+
169+ if ( ! inFileSection ) continue ;
170+
171+ // Check if we're in a diff chunk
172+ if ( line . startsWith ( '@@' ) ) {
173+ inChunk = true ;
174+ continue ;
175+ }
176+
177+ if ( inChunk && line . startsWith ( '+' ) && ! line . startsWith ( '+++' ) ) {
178+ // This is an added line - remove the '+' prefix
179+ addedLines . push ( line . substring ( 1 ) ) ;
180+ }
181+ }
153182
154- return new Promise ( ( resolve , reject ) => {
155- https . get ( url , ( response ) => {
156- let data = '' ;
157- response . on ( 'data' , ( chunk ) => { data += chunk ; } ) ;
158- response . on ( 'end' , ( ) => {
159- if ( response . statusCode === 200 ) {
160- resolve ( data ) ;
161- } else {
162- reject ( new Error ( `Failed to fetch ${ filePath } : HTTP ${ response . statusCode } ` ) ) ;
163- }
164- } ) ;
165- } ) . on ( 'error' , ( error ) => {
166- reject ( error ) ;
167- } ) ;
183+ return addedLines . join ( '\n' ) ;
184+ }
185+
186+ /**
187+ * Map line numbers from the extracted content back to original file line numbers
188+ */
189+ mapLinesToOriginal ( issues , diffInfo , addedContent ) {
190+ const addedContentLines = addedContent . split ( '\n' ) ;
191+ const addedLineNumbers = Array . from ( diffInfo . addedLines ) . sort ( ( a , b ) => a - b ) ;
192+
193+ return issues . map ( issue => {
194+ // Map the line number from the extracted content to the original file
195+ const extractedLineIndex = issue . line - 1 ; // Convert to 0-based index
196+
197+ if ( extractedLineIndex >= 0 && extractedLineIndex < addedLineNumbers . length ) {
198+ issue . line = addedLineNumbers [ extractedLineIndex ] ;
199+ }
200+
201+ return issue ;
168202 } ) ;
169203 }
170204
@@ -182,14 +216,6 @@ class EnhancedGitHubDocumentationValidator {
182216 issue . ruleId = rule . id ;
183217 issue . category = rule . category ;
184218 issue . ruleDescription = rule . description ;
185-
186- // Map line numbers if we have diff context
187- if ( diffContext && diffContext . lineMapping ) {
188- const originalLine = diffContext . lineMapping [ issue . line ] ;
189- if ( originalLine ) {
190- issue . line = originalLine ;
191- }
192- }
193219 } ) ;
194220 allIssues . push ( ...issues ) ;
195221 } catch ( error ) {
@@ -200,36 +226,6 @@ class EnhancedGitHubDocumentationValidator {
200226 return allIssues ;
201227 }
202228
203- /**
204- * Filter issues to only those on changed lines
205- */
206- filterIssuesForChangedLines ( issues , changedLines , lineMapping , diffInfo ) {
207- if ( ! changedLines || diffInfo . isNewFile || diffInfo . analyzeEntireFile ) {
208- return issues ;
209- }
210-
211- const actuallyChangedLines = new Set ( [
212- ...changedLines . added ,
213- ...changedLines . modified
214- ] ) ;
215-
216- return issues . filter ( issue => {
217- // Direct hit on changed line
218- if ( actuallyChangedLines . has ( issue . line ) ) {
219- return true ;
220- }
221-
222- // Proximity check for contextual rules (within 2 lines)
223- for ( const changedLine of actuallyChangedLines ) {
224- if ( Math . abs ( issue . line - changedLine ) <= 2 ) {
225- return true ;
226- }
227- }
228-
229- return false ;
230- } ) ;
231- }
232-
233229 /**
234230 * Categorize issues by severity
235231 */
0 commit comments