| 
									
										
										
										
											2016-10-23 22:37:15 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 14:55:58 -08:00
										 |  |  | import {RuleFailure} from 'tslint/lib'; | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  | import {RuleWalker} from 'tslint/lib/language/walker'; | 
					
						
							| 
									
										
										
										
											2015-10-28 15:04:55 -07:00
										 |  |  | import {AbstractRule} from 'tslint/lib/rules'; | 
					
						
							| 
									
										
										
										
											2015-12-21 14:50:56 -08:00
										 |  |  | import * as ts from 'typescript'; | 
					
						
							| 
									
										
										
										
											2015-10-28 15:04:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class Rule extends AbstractRule { | 
					
						
							|  |  |  |   public apply(sourceFile: ts.SourceFile): RuleFailure[] { | 
					
						
							|  |  |  |     const typedefWalker = new TypedefWalker(sourceFile, this.getOptions()); | 
					
						
							|  |  |  |     return this.applyWithWalker(typedefWalker); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TypedefWalker extends RuleWalker { | 
					
						
							|  |  |  |   protected visitPropertyDeclaration(node: ts.PropertyDeclaration): void { | 
					
						
							|  |  |  |     this.assertInternalAnnotationPresent(node); | 
					
						
							|  |  |  |     super.visitPropertyDeclaration(node); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public visitMethodDeclaration(node: ts.MethodDeclaration): void { | 
					
						
							|  |  |  |     this.assertInternalAnnotationPresent(node); | 
					
						
							|  |  |  |     super.visitMethodDeclaration(node); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private hasInternalAnnotation(range: ts.CommentRange): boolean { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |     const text = this.getSourceFile().text; | 
					
						
							|  |  |  |     const comment = text.substring(range.pos, range.end); | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  |     return comment.indexOf('@internal') >= 0; | 
					
						
							| 
									
										
										
										
											2015-10-28 15:04:55 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private assertInternalAnnotationPresent(node: ts.Declaration) { | 
					
						
							|  |  |  |     if (node.name.getText().charAt(0) !== '_') return; | 
					
						
							| 
									
										
										
										
											2017-01-24 09:05:34 -08:00
										 |  |  |     if (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Private) return; | 
					
						
							| 
									
										
										
										
											2015-10-28 15:04:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const ranges = ts.getLeadingCommentRanges(this.getSourceFile().text, node.pos); | 
					
						
							|  |  |  |     if (ranges) { | 
					
						
							|  |  |  |       for (let i = 0; i < ranges.length; i++) { | 
					
						
							|  |  |  |         if (this.hasInternalAnnotation(ranges[i])) return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.addFailure(this.createFailure( | 
					
						
							|  |  |  |         node.getStart(), node.getWidth(), | 
					
						
							|  |  |  |         `module-private member ${node.name.getText()} must be annotated @internal`)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |