]*\/>)[^>]*>?/;
+ // regex for matching an attribute string that was left open at the endof a line
+ // so we can ensure we have the proper indent
+ //
+ const closeAttrDoubleRegex = /^\s*([^><]|\\")*"/;
+ const closeAttrSingleRegex = /^\s*([^><]|\\')*'/;
+
// regex for matching a self closing html element that has no />
//
const selfClosingRegex = new RegExp(`^\\s*<(${selfClosingList}).+\\/?>`);
@@ -620,6 +633,8 @@ export function formatTemplate(tmpl: string, templateType: string): string {
let i18nDepth = 0;
let inMigratedBlock = false;
let inI18nBlock = false;
+ let inAttribute = false;
+ let isDoubleQuotes = false;
for (let [index, line] of lines.entries()) {
depth +=
[...line.matchAll(startMarkerRegex)].length - [...line.matchAll(endMarkerRegex)].length;
@@ -633,7 +648,7 @@ export function formatTemplate(tmpl: string, templateType: string): string {
lineWasMigrated = true;
}
if ((line.trim() === '' && index !== 0 && index !== lines.length - 1) &&
- (inMigratedBlock || lineWasMigrated) && !inI18nBlock) {
+ (inMigratedBlock || lineWasMigrated) && !inI18nBlock && !inAttribute) {
// skip blank lines except if it's the first line or last line
// this preserves leading and trailing spaces if they are already present
continue;
@@ -655,10 +670,25 @@ export function formatTemplate(tmpl: string, templateType: string): string {
indent = indent.slice(2);
}
- const newLine =
- inI18nBlock ? line : mindent + (line.trim() !== '' ? indent : '') + line.trim();
+ // if a line ends in an unclosed attribute, we need to note that and close it later
+ if (!inAttribute && openAttrDoubleRegex.test(line)) {
+ inAttribute = true;
+ isDoubleQuotes = true;
+ } else if (!inAttribute && openAttrSingleRegex.test(line)) {
+ inAttribute = true;
+ isDoubleQuotes = false;
+ }
+
+ const newLine = (inI18nBlock || inAttribute) ?
+ line :
+ mindent + (line.trim() !== '' ? indent : '') + line.trim();
formatted.push(newLine);
+ if ((inAttribute && isDoubleQuotes && closeAttrDoubleRegex.test(line)) ||
+ (inAttribute && !isDoubleQuotes && closeAttrSingleRegex.test(line))) {
+ inAttribute = false;
+ }
+
// this matches any self closing element that actually has a />
if (closeMultiLineElRegex.test(line)) {
// multi line self closing tag
diff --git a/packages/core/schematics/test/control_flow_migration_spec.ts b/packages/core/schematics/test/control_flow_migration_spec.ts
index e55a691d9bb9f..04c95d46ffe01 100644
--- a/packages/core/schematics/test/control_flow_migration_spec.ts
+++ b/packages/core/schematics/test/control_flow_migration_spec.ts
@@ -4755,6 +4755,83 @@ describe('control flow migration', () => {
expect(actual).toBe(expected);
});
+
+ it('should indent multi-line attribute strings to the right place', async () => {
+ writeFile('/comp.ts', `
+ import {Component} from '@angular/core';
+ import {NgIf} from '@angular/common';
+
+ @Component({
+ templateUrl: './comp.html'
+ })
+ class Comp {
+ show = false;
+ }
+ `);
+
+ writeFile('/comp.html', [
+ `