@@ -204,3 +204,124 @@ describe('extractJSDocComments - @ignore tag', () => {
204204 expect ( dataTypes ?. deprecated ) . toBe ( true ) ;
205205 } ) ;
206206} ) ;
207+
208+ describe ( 'extractJSDocComments - @operationId tag' , ( ) => {
209+ it ( 'should extract @operationId from JSDoc comment' , ( ) => {
210+ const code = `
211+ /**
212+ * Get user by ID
213+ * @operationId getUserById
214+ * @response UserResponse
215+ */
216+ export async function GET() {}
217+ ` ;
218+
219+ const ast = parseTypeScriptFile ( code ) ;
220+ let dataTypes ;
221+
222+ traverse ( ast , {
223+ ExportNamedDeclaration : ( path ) => {
224+ dataTypes = extractJSDocComments ( path ) ;
225+ } ,
226+ } ) ;
227+
228+ expect ( dataTypes ) . toBeDefined ( ) ;
229+ expect ( dataTypes ?. operationId ) . toBe ( 'getUserById' ) ;
230+ expect ( dataTypes ?. responseType ) . toBe ( 'UserResponse' ) ;
231+ } ) ;
232+
233+ it ( 'should return empty operationId when not specified' , ( ) => {
234+ const code = `
235+ /**
236+ * Get user by ID
237+ * @response UserResponse
238+ */
239+ export async function GET() {}
240+ ` ;
241+
242+ const ast = parseTypeScriptFile ( code ) ;
243+ let dataTypes ;
244+
245+ traverse ( ast , {
246+ ExportNamedDeclaration : ( path ) => {
247+ dataTypes = extractJSDocComments ( path ) ;
248+ } ,
249+ } ) ;
250+
251+ expect ( dataTypes ) . toBeDefined ( ) ;
252+ expect ( dataTypes ?. operationId ) . toBe ( '' ) ;
253+ expect ( dataTypes ?. responseType ) . toBe ( 'UserResponse' ) ;
254+ } ) ;
255+
256+ it ( 'should handle @operationId with underscores and numbers' , ( ) => {
257+ const code = `
258+ /**
259+ * @operationId create_user_v2
260+ */
261+ export async function POST() {}
262+ ` ;
263+
264+ const ast = parseTypeScriptFile ( code ) ;
265+ let dataTypes ;
266+
267+ traverse ( ast , {
268+ ExportNamedDeclaration : ( path ) => {
269+ dataTypes = extractJSDocComments ( path ) ;
270+ } ,
271+ } ) ;
272+
273+ expect ( dataTypes ?. operationId ) . toBe ( 'create_user_v2' ) ;
274+ } ) ;
275+
276+ it ( 'should extract @operationId alongside other tags' , ( ) => {
277+ const code = `
278+ /**
279+ * Create new user
280+ * @description Creates a new user in the system
281+ * @operationId createNewUser
282+ * @body CreateUserBody
283+ * @response 201:UserResponse
284+ * @auth bearer
285+ * @tag Users
286+ */
287+ export async function POST() {}
288+ ` ;
289+
290+ const ast = parseTypeScriptFile ( code ) ;
291+ let dataTypes ;
292+
293+ traverse ( ast , {
294+ ExportNamedDeclaration : ( path ) => {
295+ dataTypes = extractJSDocComments ( path ) ;
296+ } ,
297+ } ) ;
298+
299+ expect ( dataTypes ?. operationId ) . toBe ( 'createNewUser' ) ;
300+ expect ( dataTypes ?. description ) . toBe ( 'Creates a new user in the system' ) ;
301+ expect ( dataTypes ?. bodyType ) . toBe ( 'CreateUserBody' ) ;
302+ expect ( dataTypes ?. successCode ) . toBe ( '201' ) ;
303+ expect ( dataTypes ?. responseType ) . toBe ( 'UserResponse' ) ;
304+ expect ( dataTypes ?. auth ) . toBe ( 'BearerAuth' ) ;
305+ expect ( dataTypes ?. tag ) . toBe ( 'Users' ) ;
306+ } ) ;
307+
308+ it ( 'should handle camelCase operationId' , ( ) => {
309+ const code = `
310+ /**
311+ * @operationId listAllUsersWithFilters
312+ */
313+ export async function GET() {}
314+ ` ;
315+
316+ const ast = parseTypeScriptFile ( code ) ;
317+ let dataTypes ;
318+
319+ traverse ( ast , {
320+ ExportNamedDeclaration : ( path ) => {
321+ dataTypes = extractJSDocComments ( path ) ;
322+ } ,
323+ } ) ;
324+
325+ expect ( dataTypes ?. operationId ) . toBe ( 'listAllUsersWithFilters' ) ;
326+ } ) ;
327+ } ) ;
0 commit comments