@@ -320,4 +320,98 @@ describe('ResourceStateImporter', () => {
320320 expect ( result . warning ) . toBeUndefined ( ) ;
321321 } ) ;
322322 } ) ;
323+
324+ describe ( 'Logical ID uniqueness' , ( ) => {
325+ it ( 'should generate unique logical IDs with numeric suffixes' , async ( ) => {
326+ const uri = 'test://test-unique-ids.template' ;
327+ const initialContent = `{
328+ "AWSTemplateFormatVersion": "2010-09-09",
329+ "Resources": {
330+ "IAMRole": {
331+ "Type": "AWS::IAM::Role",
332+ "Properties": {
333+ "RoleName": "ExistingRole"
334+ }
335+ },
336+ "IAMRole1": {
337+ "Type": "AWS::IAM::Role",
338+ "Properties": {
339+ "RoleName": "ExistingRole1"
340+ }
341+ }
342+ }
343+ }` ;
344+
345+ createAndRegisterDocument ( uri , initialContent , DocumentType . JSON ) ;
346+
347+ const mockResource = createMockResourceState ( 'AWS::IAM::Role' ) ;
348+ const resourceSelections : ResourceSelection [ ] = [
349+ {
350+ resourceType : 'AWS::IAM::Role' ,
351+ resourceIdentifiers : [ mockResource . identifier ] ,
352+ } ,
353+ ] ;
354+
355+ mockResourceStateManager . getResource . mockResolvedValue ( mockResource ) ;
356+
357+ const params : ResourceStateParams = {
358+ resourceSelections,
359+ textDocument : { uri } as any ,
360+ range : { start : { line : 0 , character : 0 } , end : { line : 0 , character : 0 } } ,
361+ context : { diagnostics : [ ] , only : [ ] , triggerKind : 1 } ,
362+ purpose : ResourceStatePurpose . IMPORT ,
363+ } ;
364+
365+ const result = await importer . importResourceState ( params ) ;
366+
367+ expect ( result . edit ) . toBeDefined ( ) ;
368+ expect ( result . edit ! . changes ! [ uri ] ) . toBeDefined ( ) ;
369+
370+ const textEdit = result . edit ! . changes ! [ uri ] [ 0 ] ;
371+ expect ( textEdit . newText ) . toContain ( '"IAMRole2"' ) ;
372+ expect ( textEdit . newText ) . not . toContain ( '"IAMRole"' ) ;
373+ expect ( textEdit . newText ) . not . toContain ( '"IAMRole1"' ) ;
374+ } ) ;
375+
376+ it ( 'should generate multiple unique logical IDs in same import' , async ( ) => {
377+ const uri = 'test://test-multiple-unique-ids.template' ;
378+ const initialContent = `{
379+ "AWSTemplateFormatVersion": "2010-09-09",
380+ "Resources": {}
381+ }` ;
382+
383+ createAndRegisterDocument ( uri , initialContent , DocumentType . JSON ) ;
384+
385+ const mockResource1 = createMockResourceState ( 'AWS::IAM::Role' ) ;
386+ const mockResource2 = createMockResourceState ( 'AWS::IAM::Role' ) ;
387+ const mockResource3 = createMockResourceState ( 'AWS::IAM::Role' ) ;
388+
389+ const resourceSelections : ResourceSelection [ ] = [
390+ {
391+ resourceType : 'AWS::IAM::Role' ,
392+ resourceIdentifiers : [ mockResource1 . identifier , mockResource2 . identifier , mockResource3 . identifier ] ,
393+ } ,
394+ ] ;
395+
396+ mockResourceStateManager . getResource . mockResolvedValue ( mockResource1 ) ;
397+
398+ const params : ResourceStateParams = {
399+ resourceSelections,
400+ textDocument : { uri } as any ,
401+ range : { start : { line : 0 , character : 0 } , end : { line : 0 , character : 0 } } ,
402+ context : { diagnostics : [ ] , only : [ ] , triggerKind : 1 } ,
403+ purpose : ResourceStatePurpose . IMPORT ,
404+ } ;
405+
406+ const result = await importer . importResourceState ( params ) ;
407+
408+ expect ( result . edit ) . toBeDefined ( ) ;
409+ expect ( result . edit ! . changes ! [ uri ] ) . toBeDefined ( ) ;
410+
411+ const textEdit = result . edit ! . changes ! [ uri ] [ 0 ] ;
412+ expect ( textEdit . newText ) . toContain ( '"IAMRole"' ) ;
413+ expect ( textEdit . newText ) . toContain ( '"IAMRole1"' ) ;
414+ expect ( textEdit . newText ) . toContain ( '"IAMRole2"' ) ;
415+ } ) ;
416+ } ) ;
323417} ) ;
0 commit comments