diff --git a/packages/core/schematics/migrations/template-var-assignment/README.md b/packages/core/schematics/migrations/template-var-assignment/README.md new file mode 100644 index 0000000000..2cf411fec7 --- /dev/null +++ b/packages/core/schematics/migrations/template-var-assignment/README.md @@ -0,0 +1,27 @@ +## Assignments to template variables + +With Ivy, assignments to template variables are no longer supported +as template variables are effectively constants. + +This means that assignments to template variables will break your +application once Ivy is enabled by default. For example: + +```html + +``` + +In the example from above, a value is assigned to the `option` +template variable on `click`. This will ultimately break your +application and therefore the logic needs to be adjusted to not +update the `option` variable, but rather the given element in +the `options` array: + +```html + +``` \ No newline at end of file diff --git a/packages/core/schematics/migrations/template-var-assignment/index.ts b/packages/core/schematics/migrations/template-var-assignment/index.ts index 2adc588d11..d8c520a30a 100644 --- a/packages/core/schematics/migrations/template-var-assignment/index.ts +++ b/packages/core/schematics/migrations/template-var-assignment/index.ts @@ -19,6 +19,10 @@ import {NgComponentTemplateVisitor} from './angular/ng_component_template'; type Logger = logging.LoggerApi; +const README_URL = + 'https://github.com/angular/angular/tree/master/packages/core/schematics/migrations/template-var-assignment/README.md'; +const FAILURE_MESSAGE = `Found assignment to template variable.`; + /** Entry point for the V8 template variable assignment schematic. */ export default function(): Rule { return (tree: Tree, context: SchematicContext) => { @@ -62,6 +66,7 @@ function runTemplateVariableAssignmentCheck( rootSourceFiles.forEach(sourceFile => templateVisitor.visitNode(sourceFile)); const {resolvedTemplates} = templateVisitor; + const collectedFailures: string[] = []; // Analyze each resolved template and print a warning for property writes to // template variables. @@ -76,9 +81,18 @@ function runTemplateVariableAssignmentCheck( nodes.forEach(n => { const {line, character} = template.getCharacterAndLineOfPosition(n.start); - logger.warn( - `${displayFilePath}@${line + 1}:${character + 1}: Found assignment to template ` + - `variable. This does not work with Ivy and needs to be updated.`); + collectedFailures.push(`${displayFilePath}@${line + 1}:${character + 1}: ${FAILURE_MESSAGE}`); }); }); + + if (collectedFailures.length) { + logger.info('---- Template Variable Assignment schematic ----'); + logger.info('Assignments to template variables will no longer work with Ivy as'); + logger.info('template variables are effectively constants in Ivy. Read more about'); + logger.info(`this change here: ${README_URL}`); + logger.info(''); + logger.info('The following template assignments were found:'); + collectedFailures.forEach(failure => logger.warn(`⮑ ${failure}`)); + logger.info('------------------------------------------------'); + } } diff --git a/packages/core/schematics/test/template_var_assignment_migration_spec.ts b/packages/core/schematics/test/template_var_assignment_migration_spec.ts index 918459a2da..2b56dd5c41 100644 --- a/packages/core/schematics/test/template_var_assignment_migration_spec.ts +++ b/packages/core/schematics/test/template_var_assignment_migration_spec.ts @@ -18,7 +18,7 @@ describe('template variable assignment migration', () => { let tree: UnitTestTree; let tmpDirPath: string; let previousWorkingDir: string; - let consoleOutput: string[]; + let warnOutput: string[]; beforeEach(() => { runner = new SchematicTestRunner('test', require.resolve('../migrations.json')); @@ -31,8 +31,12 @@ describe('template variable assignment migration', () => { } })); - consoleOutput = []; - runner.logger.subscribe(logEntry => consoleOutput.push(logEntry.message)); + warnOutput = []; + runner.logger.subscribe(logEntry => { + if (logEntry.level === 'warn') { + warnOutput.push(logEntry.message); + } + }); previousWorkingDir = shx.pwd(); tmpDirPath = getSystemPath(host.root); @@ -67,8 +71,8 @@ describe('template variable assignment migration', () => { runMigration(); - expect(consoleOutput.length).toBe(1); - expect(consoleOutput[0]).toMatch(/^index.ts@5:69: Found assignment/); + expect(warnOutput.length).toBe(1); + expect(warnOutput[0]).toMatch(/^⮑ {3}index.ts@5:69: Found assignment/); }); it('should warn for two-way data binding assigning to "as" variable', () => { @@ -89,8 +93,8 @@ describe('template variable assignment migration', () => { runMigration(); - expect(consoleOutput.length).toBe(1); - expect(consoleOutput).toMatch(/^tmpl.html@3:31: Found assignment/); + expect(warnOutput.length).toBe(1); + expect(warnOutput).toMatch(/^⮑ {3}tmpl.html@3:31: Found assignment/); }); it('should warn for bound event assignments to "as" variable', () => { @@ -112,9 +116,9 @@ describe('template variable assignment migration', () => { runMigration(); - expect(consoleOutput.length).toBe(2); - expect(consoleOutput[0]).toMatch(/^sub_dir\/tmpl.html@3:25: Found assignment/); - expect(consoleOutput[1]).toMatch(/^sub_dir\/tmpl.html@4:25: Found assignment/); + expect(warnOutput.length).toBe(2); + expect(warnOutput[0]).toMatch(/^⮑ {3}sub_dir\/tmpl.html@3:25: Found assignment/); + expect(warnOutput[1]).toMatch(/^⮑ {3}sub_dir\/tmpl.html@4:25: Found assignment/); }); it('should warn for bound event assignments to template "let" variables', () => { @@ -136,9 +140,9 @@ describe('template variable assignment migration', () => { runMigration(); - expect(consoleOutput.length).toBe(2); - expect(consoleOutput[0]).toMatch(/^sub_dir\/tmpl.html@3:25: Found assignment/); - expect(consoleOutput[1]).toMatch(/^sub_dir\/tmpl.html@4:25: Found assignment/); + expect(warnOutput.length).toBe(2); + expect(warnOutput[0]).toMatch(/^⮑ {3}sub_dir\/tmpl.html@3:25: Found assignment/); + expect(warnOutput[1]).toMatch(/^⮑ {3}sub_dir\/tmpl.html@4:25: Found assignment/); }); it('should not warn for bound event assignments to component property', () => { @@ -155,7 +159,8 @@ describe('template variable assignment migration', () => { runMigration(); - expect(consoleOutput.length).toBe(0); + expect(warnOutput.length).toBe(0); + }); }); it('should not throw an error if a detected template fails parsing', () => { @@ -172,6 +177,6 @@ describe('template variable assignment migration', () => { runMigration(); - expect(consoleOutput.length).toBe(0); + expect(warnOutput.length).toBe(0); }); });