@@ -30,6 +30,34 @@ import type { NormalizedAbsolutePath } from '../../../jsts/src/rules/helpers/fil
3030 */
3131const PARSING_ERROR_RULE_KEY = 'S2260' ;
3232
33+ function isValidOneBasedLine ( line : number ) : line is number {
34+ return line >= 1 ;
35+ }
36+
37+ function toTextRange (
38+ line : number ,
39+ column : number ,
40+ endLine : number | undefined ,
41+ endColumn : number | undefined ,
42+ ) : analyzer . ITextRange | undefined {
43+ if ( ! isValidOneBasedLine ( line ) ) {
44+ return undefined ;
45+ }
46+
47+ const resolvedEndLine = endLine ?? line ;
48+ if ( ! isValidOneBasedLine ( resolvedEndLine ) ) {
49+ return undefined ;
50+ }
51+
52+ const startLineOffset = column ?? 0 ;
53+ return {
54+ startLine : line ,
55+ startLineOffset,
56+ endLine : resolvedEndLine ,
57+ endLineOffset : endColumn ?? startLineOffset ,
58+ } ;
59+ }
60+
3361/**
3462 * Transform a single Issue from the internal format to the gRPC Issue format.
3563 *
@@ -52,32 +80,31 @@ const PARSING_ERROR_RULE_KEY = 'S2260';
5280 * @returns gRPC Issue object ready for protobuf serialization
5381 */
5482function transformIssue ( issue : JsTsIssue ) : analyzer . IIssue {
55- const textRange : analyzer . ITextRange = {
56- startLine : issue . line ,
57- startLineOffset : issue . column ,
58- endLine : issue . endLine ?? issue . line ,
59- endLineOffset : issue . endColumn ?? issue . column ,
60- } ;
83+ const textRange = toTextRange ( issue . line , issue . column , issue . endLine , issue . endColumn ) ;
6184
6285 // Transform secondary locations into flows
6386 const flows : analyzer . IFlow [ ] = [ ] ;
6487 if ( issue . secondaryLocations && issue . secondaryLocations . length > 0 ) {
65- const locations : analyzer . IFlowLocation [ ] = issue . secondaryLocations . map ( loc => ( {
66- textRange : {
67- startLine : loc . line ,
68- startLineOffset : loc . column ,
69- endLine : loc . endLine ,
70- endLineOffset : loc . endColumn ,
71- } ,
72- message : loc . message ?? '' ,
73- file : issue . filePath ,
74- } ) ) ;
75-
76- flows . push ( {
77- type : analyzer . FlowType . FLOW_TYPE_DATA ,
78- description : '' ,
79- locations,
80- } ) ;
88+ const locations : analyzer . IFlowLocation [ ] = [ ] ;
89+
90+ for ( const loc of issue . secondaryLocations ) {
91+ const range = toTextRange ( loc . line , loc . column , loc . endLine , loc . endColumn ) ;
92+ if ( range !== undefined ) {
93+ locations . push ( {
94+ textRange : range ,
95+ message : loc . message ?? '' ,
96+ filePath : issue . filePath ,
97+ } ) ;
98+ }
99+ }
100+
101+ if ( locations . length > 0 ) {
102+ flows . push ( {
103+ type : analyzer . FlowType . FLOW_TYPE_DATA ,
104+ description : '' ,
105+ locations,
106+ } ) ;
107+ }
81108 }
82109
83110 const repo = issue . language === 'js' ? 'javascript' : 'typescript' ;
@@ -112,12 +139,27 @@ function transformCssIssue(issue: CssIssue, filePath: string): analyzer.IIssue {
112139 filePath,
113140 message : issue . message ,
114141 rule : { repo : 'css' , rule : sqKey } ,
115- textRange : {
116- startLine : issue . line ,
117- startLineOffset : issue . column ,
118- endLine : issue . endLine ?? issue . line ,
119- endLineOffset : issue . endColumn ?? issue . column ,
120- } ,
142+ textRange : toTextRange ( issue . line , issue . column , issue . endLine , issue . endColumn ) ,
143+ flows : [ ] ,
144+ } ;
145+ }
146+
147+ /**
148+ * Transform a parsing error into a gRPC issue.
149+ *
150+ * Mirrors Java-side behavior: when line is missing, the issue is file-level
151+ * and does not carry a text range.
152+ */
153+ function transformParsingErrorIssue (
154+ message : string ,
155+ filePath : NormalizedAbsolutePath ,
156+ line : number | undefined ,
157+ ) : analyzer . IIssue {
158+ return {
159+ filePath,
160+ message,
161+ rule : { repo : 'javascript' , rule : PARSING_ERROR_RULE_KEY } ,
162+ textRange : line !== undefined ? toTextRange ( line , 0 , undefined , undefined ) : undefined ,
121163 flows : [ ] ,
122164 } ;
123165}
@@ -158,6 +200,7 @@ function restorePath(filePath: NormalizedAbsolutePath, pathMap: Map<string, stri
158200 * ```
159201 *
160202 * @param output - The ProjectAnalysisOutput from analyzeProject()
203+ * @param pathMap - Optional mapping from normalized absolute paths to original request paths
161204 * @returns gRPC IAnalyzeResponse ready for protobuf serialization
162205 */
163206export function transformProjectOutputToResponse (
@@ -198,16 +241,7 @@ export function transformProjectOutputToResponse(
198241 } ) ;
199242
200243 issues . push (
201- transformIssue ( {
202- ruleId : PARSING_ERROR_RULE_KEY ,
203- message,
204- line : line ?? 1 ,
205- column : 0 ,
206- language : 'js' ,
207- secondaryLocations : [ ] ,
208- ruleESLintKeys : [ ] ,
209- filePath : originalPath as NormalizedAbsolutePath ,
210- } ) ,
244+ transformParsingErrorIssue ( message , originalPath as NormalizedAbsolutePath , line ) ,
211245 ) ;
212246 continue ;
213247 }
0 commit comments