1- import { parse } from '../src/parser.js'
1+ import { jest } from '@jest/globals'
2+
3+ const loadParser = async parseSyncMock => {
4+ jest . resetModules ( )
5+ if ( parseSyncMock ) {
6+ jest . unstable_mockModule ( 'oxc-parser' , ( ) => ( { parseSync : parseSyncMock } ) )
7+ }
8+ return import ( '../src/parser.js' )
9+ }
210
311describe ( 'parse' , ( ) => {
4- it ( 'parses 2023 ecmascript and jsx while tracking block comments' , ( ) => {
12+ it ( 'parses 2023 ecmascript and jsx while tracking block comments' , async ( ) => {
513 const src = `
614 // inline comment
715 const Component = () => {
@@ -23,8 +31,231 @@ describe('parse', () => {
2331 )
2432 }
2533 `
34+ const { parse } = await loadParser ( )
2635 const { astComments } = parse ( src )
2736
2837 expect ( astComments ) . toEqual ( [ { start : 175 , end : 188 , text : ' comment ' } ] )
2938 } )
39+
40+ it ( 'throws on parser errors' , async ( ) => {
41+ const parseSync = jest . fn ( ) . mockReturnValue ( {
42+ program : { type : 'Program' , body : [ ] } ,
43+ comments : [ ] ,
44+ errors : [ { message : 'boom' } ]
45+ } )
46+ const { parse } = await loadParser ( parseSync )
47+
48+ expect ( ( ) => parse ( 'bad' ) ) . toThrow ( '[oxc-parser] boom' )
49+ } )
50+
51+ it ( 'uses a generic message when error text is missing' , async ( ) => {
52+ const parseSync = jest . fn ( ) . mockReturnValue ( {
53+ program : { type : 'Program' , body : [ ] } ,
54+ comments : [ ] ,
55+ errors : [ { message : 123 } ]
56+ } )
57+ const { parse } = await loadParser ( parseSync )
58+
59+ expect ( ( ) => parse ( 'bad' ) ) . toThrow ( '[oxc-parser] Parse error' )
60+ } )
61+
62+ it ( 'handles non-node programs' , async ( ) => {
63+ const parseSync = jest . fn ( ) . mockReturnValue ( {
64+ program : null ,
65+ comments : [ ] ,
66+ errors : [ ]
67+ } )
68+ const { parse } = await loadParser ( parseSync )
69+ const result = parse ( '' )
70+
71+ expect ( result . importExpressionNodes ) . toEqual ( [ ] )
72+ } )
73+
74+ it ( 'normalizes span-based import expressions' , async ( ) => {
75+ const parseSync = jest . fn ( ) . mockReturnValue ( {
76+ program : {
77+ type : 'Program' ,
78+ body : [
79+ {
80+ type : 'ImportExpression' ,
81+ span : { start : 1 , end : 9 } ,
82+ source : {
83+ type : 'StringLiteral' ,
84+ span : { start : 4 , end : 8 }
85+ }
86+ }
87+ ]
88+ } ,
89+ comments : [ ] ,
90+ errors : [ ]
91+ } )
92+ const { parse } = await loadParser ( parseSync )
93+ const result = parse ( 'import("./x")' )
94+
95+ expect ( result . importExpressionNodes ) . toEqual ( [
96+ expect . objectContaining ( {
97+ start : 1 ,
98+ end : 9 ,
99+ source : expect . objectContaining ( { start : 4 , end : 8 } )
100+ } )
101+ ] )
102+ } )
103+
104+ it ( 'handles non-object sources and missing spans' , async ( ) => {
105+ const parseSync = jest . fn ( ) . mockReturnValue ( {
106+ program : {
107+ type : 'Program' ,
108+ body : [
109+ {
110+ type : 'ImportExpression' ,
111+ span : { start : 1 , end : 9 } ,
112+ source : 123
113+ }
114+ ]
115+ } ,
116+ comments : [ ] ,
117+ errors : [ ]
118+ } )
119+ const { parse } = await loadParser ( parseSync )
120+ const result = parse ( 'import("./x")' )
121+
122+ expect ( result . importExpressionNodes ) . toEqual ( [ ] )
123+ } )
124+
125+ it ( 'adds start/end from spans when missing' , async ( ) => {
126+ const parseSync = jest . fn ( ) . mockReturnValue ( {
127+ program : {
128+ type : 'Program' ,
129+ body : [
130+ {
131+ type : 'ImportExpression' ,
132+ span : { start : 10 , end : 30 } ,
133+ source : {
134+ type : 'StringLiteral' ,
135+ span : { start : 18 , end : 28 }
136+ }
137+ }
138+ ]
139+ } ,
140+ comments : [ ] ,
141+ errors : [ ]
142+ } )
143+ const { parse } = await loadParser ( parseSync )
144+ const result = parse ( 'import("./x")' )
145+
146+ expect ( result . importExpressionNodes [ 0 ] ) . toEqual (
147+ expect . objectContaining ( {
148+ start : 10 ,
149+ end : 30 ,
150+ source : expect . objectContaining ( { start : 18 , end : 28 } )
151+ } )
152+ )
153+ } )
154+
155+ it ( 'skips import expressions without source spans' , async ( ) => {
156+ const parseSync = jest . fn ( ) . mockReturnValue ( {
157+ program : {
158+ type : 'Program' ,
159+ body : [
160+ {
161+ type : 'ImportExpression' ,
162+ span : { start : 1 , end : 9 } ,
163+ source : null
164+ }
165+ ]
166+ } ,
167+ comments : [ ] ,
168+ errors : [ ]
169+ } )
170+ const { parse } = await loadParser ( parseSync )
171+ const result = parse ( 'import("./x")' )
172+
173+ expect ( result . importExpressionNodes ) . toEqual ( [ ] )
174+ } )
175+
176+ it ( 'filters non-block comments' , async ( ) => {
177+ const parseSync = jest . fn ( ) . mockReturnValue ( {
178+ program : { type : 'Program' , body : [ ] } ,
179+ comments : [ { type : 'Line' , start : 1 , end : 3 , value : 'line' } ] ,
180+ errors : [ ]
181+ } )
182+ const { parse } = await loadParser ( parseSync )
183+ const result = parse ( '// comment' )
184+
185+ expect ( result . astComments ) . toEqual ( [ ] )
186+ } )
187+
188+ it ( 'reads block comment fields from kind/span/text' , async ( ) => {
189+ const parseSync = jest . fn ( ) . mockReturnValue ( {
190+ program : { type : 'Program' , body : [ ] } ,
191+ comments : [
192+ {
193+ kind : 'Block' ,
194+ span : { start : 5 , end : 9 } ,
195+ text : ' block '
196+ }
197+ ] ,
198+ errors : [ ]
199+ } )
200+ const { parse } = await loadParser ( parseSync )
201+ const result = parse ( '/* block */' )
202+
203+ expect ( result . astComments ) . toEqual ( [ { start : 5 , end : 9 , text : ' block ' } ] )
204+ } )
205+
206+ it ( 'falls back to comment content when text is missing' , async ( ) => {
207+ const parseSync = jest . fn ( ) . mockReturnValue ( {
208+ program : { type : 'Program' , body : [ ] } ,
209+ comments : [
210+ {
211+ type : 'Block' ,
212+ start : 2 ,
213+ end : 6 ,
214+ content : ' content '
215+ }
216+ ] ,
217+ errors : [ ]
218+ } )
219+ const { parse } = await loadParser ( parseSync )
220+ const result = parse ( '/* content */' )
221+
222+ expect ( result . astComments ) . toEqual ( [ { start : 2 , end : 6 , text : ' content ' } ] )
223+ } )
224+
225+ it ( 'uses comment value when present' , async ( ) => {
226+ const parseSync = jest . fn ( ) . mockReturnValue ( {
227+ program : { type : 'Program' , body : [ ] } ,
228+ comments : [
229+ {
230+ type : 'Block' ,
231+ start : 3 ,
232+ end : 7 ,
233+ value : ' value '
234+ }
235+ ] ,
236+ errors : [ ]
237+ } )
238+ const { parse } = await loadParser ( parseSync )
239+ const result = parse ( '/* value */' )
240+
241+ expect ( result . astComments ) . toEqual ( [ { start : 3 , end : 7 , text : ' value ' } ] )
242+ } )
243+
244+ it ( 'defaults to empty comment text when fields are missing' , async ( ) => {
245+ const parseSync = jest . fn ( ) . mockReturnValue ( {
246+ program : { type : 'Program' , body : [ ] } ,
247+ comments : [
248+ {
249+ type : 'Block' ,
250+ start : 1 ,
251+ end : 2
252+ }
253+ ] ,
254+ errors : [ ]
255+ } )
256+ const { parse } = await loadParser ( parseSync )
257+ const result = parse ( '/* */' )
258+
259+ expect ( result . astComments ) . toEqual ( [ { start : 1 , end : 2 , text : '' } ] )
260+ } )
30261} )
0 commit comments