@@ -25,6 +25,14 @@ const logger = createLogger('VariableResolver')
2525
2626type ShellQuoteContext = 'single' | 'double' | null
2727type CodeStringQuoteContext = ShellQuoteContext | 'template'
28+ type CodeScanMode =
29+ | { type : 'normal' }
30+ | { type : 'single' }
31+ | { type : 'double' }
32+ | { type : 'template' }
33+ | { type : 'template-expression' ; depth : number }
34+ | { type : 'line-comment' }
35+ | { type : 'block-comment' }
2836
2937export class VariableResolver {
3038 private resolvers : Resolver [ ]
@@ -353,7 +361,7 @@ export class VariableResolver {
353361 ) : string {
354362 if ( language === 'python' ) {
355363 const expression = `globals()[${ JSON . stringify ( varName ) } ]`
356- const quoteContext = this . getCodeStringQuoteContext ( template , matchIndex )
364+ const quoteContext = this . getCodeStringQuoteContext ( template , matchIndex , language )
357365 if ( quoteContext === 'single' || quoteContext === 'double' ) {
358366 const quote = quoteContext === 'single' ? "'" : '"'
359367 return `${ quote } + json.dumps(${ expression } ) + ${ quote } `
@@ -366,7 +374,7 @@ export class VariableResolver {
366374 }
367375
368376 const expression = `globalThis[${ JSON . stringify ( varName ) } ]`
369- const quoteContext = this . getCodeStringQuoteContext ( template , matchIndex )
377+ const quoteContext = this . getCodeStringQuoteContext ( template , matchIndex , language )
370378 if ( quoteContext === 'template' ) {
371379 return `\${JSON.stringify(${ expression } )}`
372380 }
@@ -413,25 +421,126 @@ export class VariableResolver {
413421 return JSON . stringify ( value )
414422 }
415423
416- private getCodeStringQuoteContext ( template : string , index : number ) : CodeStringQuoteContext {
417- let quoteContext : CodeStringQuoteContext = null
424+ private getCodeStringQuoteContext (
425+ template : string ,
426+ index : number ,
427+ language : string | undefined
428+ ) : CodeStringQuoteContext {
429+ const isPython = language === 'python'
430+ const modes : CodeScanMode [ ] = [ { type : 'normal' } ]
418431
419432 for ( let i = 0 ; i < index ; i ++ ) {
420433 const char = template [ i ]
421- if ( quoteContext !== null && char === '\\' ) {
434+ const next = template [ i + 1 ]
435+ const mode = modes [ modes . length - 1 ]
436+
437+ if ( mode . type === 'line-comment' ) {
438+ if ( char === '\n' ) {
439+ modes . pop ( )
440+ }
441+ continue
442+ }
443+
444+ if ( mode . type === 'block-comment' ) {
445+ if ( char === '*' && next === '/' ) {
446+ modes . pop ( )
447+ i ++
448+ }
449+ continue
450+ }
451+
452+ if ( mode . type === 'single' || mode . type === 'double' ) {
453+ const quote = mode . type === 'single' ? "'" : '"'
454+ if ( char === '\\' ) {
455+ i ++
456+ continue
457+ }
458+ if ( char === quote || char === '\n' ) {
459+ modes . pop ( )
460+ }
461+ continue
462+ }
463+
464+ if ( mode . type === 'template' ) {
465+ if ( char === '\\' ) {
466+ i ++
467+ continue
468+ }
469+ if ( char === '`' ) {
470+ modes . pop ( )
471+ continue
472+ }
473+ if ( char === '$' && next === '{' ) {
474+ modes . push ( { type : 'template-expression' , depth : 1 } )
475+ i ++
476+ }
477+ continue
478+ }
479+
480+ if ( mode . type === 'template-expression' ) {
481+ if ( ! isPython && char === '/' && next === '/' ) {
482+ modes . push ( { type : 'line-comment' } )
483+ i ++
484+ continue
485+ }
486+ if ( ! isPython && char === '/' && next === '*' ) {
487+ modes . push ( { type : 'block-comment' } )
488+ i ++
489+ continue
490+ }
491+ if ( char === "'" ) {
492+ modes . push ( { type : 'single' } )
493+ continue
494+ }
495+ if ( char === '"' ) {
496+ modes . push ( { type : 'double' } )
497+ continue
498+ }
499+ if ( ! isPython && char === '`' ) {
500+ modes . push ( { type : 'template' } )
501+ continue
502+ }
503+ if ( char === '{' ) {
504+ mode . depth += 1
505+ continue
506+ }
507+ if ( char === '}' ) {
508+ mode . depth -= 1
509+ if ( mode . depth === 0 ) {
510+ modes . pop ( )
511+ }
512+ }
513+ continue
514+ }
515+
516+ if ( isPython && char === '#' ) {
517+ modes . push ( { type : 'line-comment' } )
518+ continue
519+ }
520+ if ( ! isPython && char === '/' && next === '/' ) {
521+ modes . push ( { type : 'line-comment' } )
422522 i ++
423523 continue
424524 }
425- if ( char === "'" && quoteContext !== 'double' && quoteContext !== 'template' ) {
426- quoteContext = quoteContext === 'single' ? null : 'single'
427- } else if ( char === '"' && quoteContext !== 'single' && quoteContext !== 'template' ) {
428- quoteContext = quoteContext === 'double' ? null : 'double'
429- } else if ( char === '`' && quoteContext !== 'single' && quoteContext !== 'double' ) {
430- quoteContext = quoteContext === 'template' ? null : 'template'
525+ if ( ! isPython && char === '/' && next === '*' ) {
526+ modes . push ( { type : 'block-comment' } )
527+ i ++
528+ continue
529+ }
530+ if ( char === "'" ) {
531+ modes . push ( { type : 'single' } )
532+ } else if ( char === '"' ) {
533+ modes . push ( { type : 'double' } )
534+ } else if ( ! isPython && char === '`' ) {
535+ modes . push ( { type : 'template' } )
431536 }
432537 }
433538
434- return quoteContext
539+ const mode = modes [ modes . length - 1 ]
540+ if ( mode . type === 'single' || mode . type === 'double' || mode . type === 'template' ) {
541+ return mode . type
542+ }
543+ return null
435544 }
436545
437546 private formatShellContextVariableReference (
0 commit comments