@@ -229,4 +229,201 @@ access(all) fun main(): Address {
229229 expect ( ix . message . cadence ) . toEqual ( expected )
230230 } )
231231 } )
232+
233+ describe ( "mixed import syntax" , ( ) => {
234+ test ( "supports both string imports and traditional imports" , async ( ) => {
235+ const CADENCE = `import "FungibleToken"
236+ import MyContract from 0x12345678
237+
238+ access(all) fun main(): Address {
239+ return 0x12345678
240+ }`
241+
242+ const expected = `import FungibleToken from 0xf233dcee88fe0abe
243+ import MyContract from 0x12345678
244+
245+ access(all) fun main(): Address {
246+ return 0x12345678
247+ }`
248+
249+ await config ( ) . put ( "system.contracts.FungibleToken" , "0xf233dcee88fe0abe" )
250+ await idle ( )
251+
252+ const ix = await pipe ( [
253+ makeScript ,
254+ put ( "ix.cadence" , CADENCE ) ,
255+ async ix => resolveCadence ( ix , await getGlobalContext ( ) ) ,
256+ ] ) ( initInteraction ( ) )
257+
258+ expect ( ix . message . cadence ) . toEqual ( expected )
259+ } )
260+
261+ test ( "supports multiple string imports with traditional imports" , async ( ) => {
262+ const CADENCE = `import "FungibleToken"
263+ import "NonFungibleToken"
264+ import MyContract from 0xABCDEF
265+ import FlowToken from 0x0ae53cb6e3f42a79
266+
267+ access(all) fun main(): String {
268+ return "mixed imports work"
269+ }`
270+
271+ const expected = `import FungibleToken from 0xf233dcee88fe0abe
272+ import NonFungibleToken from 0x1d7e57aa55817448
273+ import MyContract from 0xABCDEF
274+ import FlowToken from 0x0ae53cb6e3f42a79
275+
276+ access(all) fun main(): String {
277+ return "mixed imports work"
278+ }`
279+
280+ await config ( ) . put ( "system.contracts.FungibleToken" , "0xf233dcee88fe0abe" )
281+ await config ( ) . put (
282+ "system.contracts.NonFungibleToken" ,
283+ "0x1d7e57aa55817448"
284+ )
285+ await idle ( )
286+
287+ const ix = await pipe ( [
288+ makeScript ,
289+ put ( "ix.cadence" , CADENCE ) ,
290+ async ix => resolveCadence ( ix , await getGlobalContext ( ) ) ,
291+ ] ) ( initInteraction ( ) )
292+
293+ expect ( ix . message . cadence ) . toEqual ( expected )
294+ } )
295+
296+ test ( "traditional imports with explicit addresses should not be modified" , async ( ) => {
297+ const CADENCE = `import FlowToken from 0x7e60df042a9c0868
298+ import MyContract from 0x1234567890abcdef
299+
300+ access(all) fun main(): UFix64 {
301+ return 42.0
302+ }`
303+
304+ const expected = `import FlowToken from 0x7e60df042a9c0868
305+ import MyContract from 0x1234567890abcdef
306+
307+ access(all) fun main(): UFix64 {
308+ return 42.0
309+ }`
310+
311+ // No config needed - explicit addresses should work as-is
312+ const ix = await pipe ( [
313+ makeScript ,
314+ put ( "ix.cadence" , CADENCE ) ,
315+ async ix => resolveCadence ( ix , await getGlobalContext ( ) ) ,
316+ ] ) ( initInteraction ( ) )
317+
318+ expect ( ix . message . cadence ) . toEqual ( expected )
319+ } )
320+
321+ test ( "string import without config should log warning and leave import unchanged" , async ( ) => {
322+ const CADENCE = `import "UnconfiguredContract"
323+ import FlowToken from 0x7e60df042a9c0868
324+
325+ access(all) fun main(): Bool {
326+ return true
327+ }`
328+
329+ const expected = `import "UnconfiguredContract"
330+ import FlowToken from 0x7e60df042a9c0868
331+
332+ access(all) fun main(): Bool {
333+ return true
334+ }`
335+
336+ // Spy on console.warn to verify warning is logged
337+ const warnSpy = jest . spyOn ( console , "warn" ) . mockImplementation ( )
338+
339+ const ix = await pipe ( [
340+ makeScript ,
341+ put ( "ix.cadence" , CADENCE ) ,
342+ async ix => resolveCadence ( ix , await getGlobalContext ( ) ) ,
343+ ] ) ( initInteraction ( ) )
344+
345+ expect ( ix . message . cadence ) . toEqual ( expected )
346+
347+ // Verify warning was logged
348+ expect ( warnSpy ) . toHaveBeenCalled ( )
349+ const warnCall = warnSpy . mock . calls . find ( call =>
350+ call . join ( " " ) . includes ( "Contract Placeholder not found" )
351+ )
352+ expect ( warnCall ) . toBeDefined ( )
353+ expect ( warnCall ?. join ( " " ) ) . toContain ( "UnconfiguredContract" )
354+
355+ warnSpy . mockRestore ( )
356+ } )
357+
358+ test ( "legacy placeholders and string imports together should throw invariant error" , async ( ) => {
359+ const CADENCE = `import "FungibleToken"
360+ import FlowToken from 0xFLOWTOKEN
361+
362+ access(all) fun main(): Bool {
363+ return true
364+ }`
365+
366+ config ( ) . put ( "system.contracts.FungibleToken" , "0xf233dcee88fe0abe" )
367+ config ( ) . put ( "0xFLOWTOKEN" , "0x7e60df042a9c0868" )
368+ await idle ( )
369+
370+ await expect ( async ( ) => {
371+ await pipe ( [
372+ makeScript ,
373+ put ( "ix.cadence" , CADENCE ) ,
374+ async ix => resolveCadence ( ix , await getGlobalContext ( ) ) ,
375+ ] ) ( initInteraction ( ) )
376+ } ) . rejects . toThrow (
377+ "Both account identifier and contract identifier syntax not simultaneously supported."
378+ )
379+ } )
380+
381+ test ( "legacy placeholders alone should work without string imports" , async ( ) => {
382+ const CADENCE = `import FlowToken from 0xFLOWTOKEN
383+ import MyContract from 0xMYCONTRACT
384+
385+ access(all) fun main(): Address {
386+ return 0xFLOWTOKEN
387+ }`
388+
389+ const expected = `import FlowToken from 0x7e60df042a9c0868
390+ import MyContract from 0x1234567890abcdef
391+
392+ access(all) fun main(): Address {
393+ return 0x7e60df042a9c0868
394+ }`
395+
396+ config ( ) . put ( "0xFLOWTOKEN" , "0x7e60df042a9c0868" )
397+ config ( ) . put ( "0xMYCONTRACT" , "0x1234567890abcdef" )
398+ await idle ( )
399+
400+ const ix = await pipe ( [
401+ makeScript ,
402+ put ( "ix.cadence" , CADENCE ) ,
403+ async ix => resolveCadence ( ix , await getGlobalContext ( ) ) ,
404+ ] ) ( initInteraction ( ) )
405+
406+ expect ( ix . message . cadence ) . toEqual ( expected )
407+ } )
408+ } )
409+
410+ describe ( "no imports" , ( ) => {
411+ test ( "cadence with no imports should remain unchanged" , async ( ) => {
412+ const CADENCE = `access(all) fun main(): String {
413+ return "Hello, Flow!"
414+ }`
415+
416+ const expected = `access(all) fun main(): String {
417+ return "Hello, Flow!"
418+ }`
419+
420+ const ix = await pipe ( [
421+ makeScript ,
422+ put ( "ix.cadence" , CADENCE ) ,
423+ async ix => resolveCadence ( ix , await getGlobalContext ( ) ) ,
424+ ] ) ( initInteraction ( ) )
425+
426+ expect ( ix . message . cadence ) . toEqual ( expected )
427+ } )
428+ } )
232429} )
0 commit comments