@@ -160,7 +160,7 @@ function analyzeDecorators(
160160 // Leave the end as undefined which means that the range is until the end of the file.
161161 if ( ts . isStringLiteralLike ( prop . initializer ) ) {
162162 const path = join ( dirname ( sourceFile . fileName ) , prop . initializer . text ) ;
163- AnalyzedFile . addRange ( path , analyzedFiles , { start : 0 , node : prop , type : 'template ' } ) ;
163+ AnalyzedFile . addRange ( path , analyzedFiles , { start : 0 , node : prop , type : 'templateUrl ' } ) ;
164164 }
165165 break ;
166166 }
@@ -429,11 +429,16 @@ export function getMainBlock(etm: ElementToMigrate, tmpl: string, offset: number
429429 return { start, middle, end} ;
430430}
431431
432+ const selfClosingList = 'input|br|img|base|wbr|area|col|embed|hr|link|meta|param|source|track' ;
433+
432434/**
433435 * re-indents all the lines in the template properly post migration
434436 */
435- export function formatTemplate ( tmpl : string ) : string {
437+ export function formatTemplate ( tmpl : string , templateType : string ) : string {
436438 if ( tmpl . indexOf ( '\n' ) > - 1 ) {
439+ // tracks if a self closing element opened without closing yet
440+ let openSelfClosingEl = false ;
441+
437442 // match any type of control flow block as start of string ignoring whitespace
438443 // @if | @switch | @case | @default | @for | } @else
439444 const openBlockRegex = / ^ \s * \@ ( i f | s w i t c h | c a s e | d e f a u l t | f o r ) | ^ \s * \} \s \@ e l s e / ;
@@ -442,45 +447,93 @@ export function formatTemplate(tmpl: string): string {
442447 // <div thing="stuff" [binding]="true"> || <div thing="stuff" [binding]="true"
443448 const openElRegex = / ^ \s * < ( [ a - z 0 - 9 ] + ) (? ! [ ^ > ] * \/ > ) [ ^ > ] * > ? / ;
444449
450+ // regex for matching a self closing html element that has no />
451+ // <div thing="stuff" [binding]="true"> || <div thing="stuff" [binding]="true"
452+ const selfClosingRegex = new RegExp ( `^\\s*<(${ selfClosingList } ).+\\/?>` ) ;
453+
454+ // regex for matching a self closing html element that is on multi lines
455+ // <div thing="stuff" [binding]="true"> || <div thing="stuff" [binding]="true"
456+ const openSelfClosingRegex = new RegExp ( `^\\s*<(${ selfClosingList } )(?![^>]*\\/>)[^>]*$` ) ;
457+
445458 // match closing block or else block
446459 // } | } @else
447460 const closeBlockRegex = / ^ \s * \} \s * $ | ^ \s * \} \s \@ e l s e / ;
448461
449462 // matches closing of an html element
450463 // </element>
451- const closeElRegex = / \s * < \/ ( [ a - z 0 - 9 \- ] + ) * > / ;
464+ const closeElRegex = / \s * < \/ ( [ a - z A - Z 0 - 9 \- ] + ) * > / ;
452465
453466 // matches closing of a self closing html element when the element is on multiple lines
454467 // [binding]="value" />
455- const closeMultiLineElRegex = / ^ \s * ( [ a - z 0 - 9 \- \[ \] ] + ) ? = ? " ? ( [ ^ ” < ] + ) ? " ? \s ? \/ > $ / ;
468+ const closeMultiLineElRegex = / ^ \s * ( [ a - z A - Z 0 - 9 \- \[ \] ] + ) ? = ? " ? ( [ ^ ” < ] + ) ? " ? \s ? \/ > $ / ;
469+
470+ // matches closing of a self closing html element when the element is on multiple lines
471+ // with no / in the closing: [binding]="value">
472+ const closeSelfClosingMultiLineRegex = / ^ \s * ( [ a - z A - Z 0 - 9 \- \[ \] ] + ) ? = ? " ? ( [ ^ ” \/ < ] + ) ? " ? \s ? > $ / ;
456473
457474 // matches an open and close of an html element on a single line with no breaks
458475 // <div>blah</div>
459- const singleLineElRegex = / ^ \s * < ( [ a - z 0 - 9 ] + ) (? ! [ ^ > ] * \/ > ) [ ^ > ] * > .* < \/ ( [ a - z 0 - 9 \- ] + ) * > / ;
476+ const singleLineElRegex = / \s * < ( [ a - z A - Z 0 - 9 ] + ) (? ! [ ^ > ] * \/ > ) [ ^ > ] * > .* < \/ ( [ a - z A - Z 0 - 9 \- ] + ) * > / ;
460477 const lines = tmpl . split ( '\n' ) ;
461478 const formatted = [ ] ;
479+ // the indent applied during formatting
462480 let indent = '' ;
481+ // the pre-existing indent in an inline template that we'd like to preserve
482+ let mindent = '' ;
463483 for ( let [ index , line ] of lines . entries ( ) ) {
464484 if ( line . trim ( ) === '' && index !== 0 && index !== lines . length - 1 ) {
465485 // skip blank lines except if it's the first line or last line
486+ // this preserves leading and trailing spaces if they are already present
466487 continue ;
467488 }
489+ // preserves the indentation of an inline template
490+ if ( templateType === 'template' && index <= 1 ) {
491+ // first real line of an inline template
492+ const ind = line . search ( / \S / ) ;
493+ mindent = ( ind > - 1 ) ? line . slice ( 0 , ind ) : '' ;
494+ }
495+
496+ // if a block closes, an element closes, and it's not an element on a single line or the end
497+ // of a self closing tag
468498 if ( ( closeBlockRegex . test ( line ) ||
469499 ( closeElRegex . test ( line ) &&
470500 ( ! singleLineElRegex . test ( line ) && ! closeMultiLineElRegex . test ( line ) ) ) ) &&
471501 indent !== '' ) {
472502 // close block, reduce indent
473503 indent = indent . slice ( 2 ) ;
474504 }
475- formatted . push ( indent + line . trim ( ) ) ;
505+
506+ formatted . push ( mindent + indent + line . trim ( ) ) ;
507+
508+ // this matches any self closing element that actually has a />
476509 if ( closeMultiLineElRegex . test ( line ) ) {
477510 // multi line self closing tag
478511 indent = indent . slice ( 2 ) ;
512+ if ( openSelfClosingEl ) {
513+ openSelfClosingEl = false ;
514+ }
515+ }
516+
517+ // this matches a self closing element that doesn't have a / in the >
518+ if ( closeSelfClosingMultiLineRegex . test ( line ) && openSelfClosingEl ) {
519+ openSelfClosingEl = false ;
520+ indent = indent . slice ( 2 ) ;
479521 }
480- if ( ( openBlockRegex . test ( line ) || openElRegex . test ( line ) ) && ! singleLineElRegex . test ( line ) ) {
522+
523+ // this matches an open control flow block, an open HTML element, but excludes single line
524+ // self closing tags
525+ if ( ( openBlockRegex . test ( line ) || openElRegex . test ( line ) ) && ! singleLineElRegex . test ( line ) &&
526+ ! selfClosingRegex . test ( line ) && ! openSelfClosingRegex . test ( line ) ) {
481527 // open block, increase indent
482528 indent += ' ' ;
483529 }
530+
531+ // This is a self closing element that is definitely not fully closed and is on multiple lines
532+ if ( openSelfClosingRegex . test ( line ) ) {
533+ openSelfClosingEl = true ;
534+ // add to the indent for the properties on it to look nice
535+ indent += ' ' ;
536+ }
484537 }
485538 tmpl = formatted . join ( '\n' ) ;
486539 }
0 commit comments