| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {logging, normalize} from '@angular-devkit/core'; | 
					
						
							|  |  |  | import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; | 
					
						
							| 
									
										
										
										
											2020-04-02 11:01:43 +02:00
										 |  |  | import {relative} from 'path'; | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-08 16:16:56 +02:00
										 |  |  | import {NgComponentTemplateVisitor} from '../../utils/ng_component_template'; | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; | 
					
						
							| 
									
										
										
										
											2020-11-20 20:25:30 +01:00
										 |  |  | import {canMigrateFile, createMigrationProgram} from '../../utils/typescript/compiler_host'; | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import {analyzeResolvedTemplate} from './analyze_template'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Logger = logging.LoggerApi; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-28 20:30:33 +02:00
										 |  |  | const README_URL = 'https://v8.angular.io/guide/deprecations#cannot-assign-to-template-variables'; | 
					
						
							| 
									
										
										
										
											2019-04-04 12:52:29 +02:00
										 |  |  | const FAILURE_MESSAGE = `Found assignment to template variable.`; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | /** Entry point for the V8 template variable assignment schematic. */ | 
					
						
							|  |  |  | export default function(): Rule { | 
					
						
							|  |  |  |   return (tree: Tree, context: SchematicContext) => { | 
					
						
							| 
									
										
										
										
											2019-04-22 21:11:29 +02:00
										 |  |  |     const {buildPaths, testPaths} = getProjectTsConfigPaths(tree); | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  |     const basePath = process.cwd(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 21:11:29 +02:00
										 |  |  |     if (!buildPaths.length && !testPaths.length) { | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  |       throw new SchematicsException( | 
					
						
							|  |  |  |           'Could not find any tsconfig file. Cannot check templates for template variable ' + | 
					
						
							|  |  |  |           'assignments.'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 21:11:29 +02:00
										 |  |  |     for (const tsconfigPath of [...buildPaths, ...testPaths]) { | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  |       runTemplateVariableAssignmentCheck(tree, tsconfigPath, basePath, context.logger); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Runs the template variable assignment check. Warns developers | 
					
						
							|  |  |  |  * if values are assigned to template variables within output bindings. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function runTemplateVariableAssignmentCheck( | 
					
						
							|  |  |  |     tree: Tree, tsconfigPath: string, basePath: string, logger: Logger) { | 
					
						
							| 
									
										
										
										
											2020-04-02 11:01:43 +02:00
										 |  |  |   const {program} = createMigrationProgram(tree, tsconfigPath, basePath); | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  |   const typeChecker = program.getTypeChecker(); | 
					
						
							|  |  |  |   const templateVisitor = new NgComponentTemplateVisitor(typeChecker); | 
					
						
							| 
									
										
										
										
											2020-11-20 20:25:30 +01:00
										 |  |  |   const sourceFiles = | 
					
						
							|  |  |  |       program.getSourceFiles().filter(sourceFile => canMigrateFile(basePath, sourceFile, program)); | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Analyze source files by detecting HTML templates.
 | 
					
						
							| 
									
										
										
										
											2019-05-05 12:02:35 +02:00
										 |  |  |   sourceFiles.forEach(sourceFile => templateVisitor.visitNode(sourceFile)); | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const {resolvedTemplates} = templateVisitor; | 
					
						
							| 
									
										
										
										
											2019-04-04 12:52:29 +02:00
										 |  |  |   const collectedFailures: string[] = []; | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Analyze each resolved template and print a warning for property writes to
 | 
					
						
							|  |  |  |   // template variables.
 | 
					
						
							| 
									
										
										
										
											2019-04-11 18:59:12 +02:00
										 |  |  |   resolvedTemplates.forEach(template => { | 
					
						
							|  |  |  |     const filePath = template.filePath; | 
					
						
							|  |  |  |     const nodes = analyzeResolvedTemplate(template); | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!nodes) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const displayFilePath = normalize(relative(basePath, filePath)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     nodes.forEach(n => { | 
					
						
							|  |  |  |       const {line, character} = template.getCharacterAndLineOfPosition(n.start); | 
					
						
							| 
									
										
										
										
											2019-04-04 12:52:29 +02:00
										 |  |  |       collectedFailures.push(`${displayFilePath}@${line + 1}:${character + 1}: ${FAILURE_MESSAGE}`); | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-04-04 12:52:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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}`)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-03-30 12:48:21 +01:00
										 |  |  | } |