ci: add lint error for files with missing trailing new-line (#42478)
For quite a while it is an unspoken convention to add a trailing new-line files within the Angular repository. This was never enforced automatically, but has been frequently raised in pull requests through manual review. This commit sets up a lint rule so that this is "officially" enforced and doesn't require manual review. PR Close #42478
This commit is contained in:
		
							parent
							
								
									71e14a71f5
								
							
						
					
					
						commit
						2d0ff0a5d3
					
				| @ -96,4 +96,4 @@ export class HttpContext { | ||||
|   keys(): IterableIterator<HttpContextToken<unknown>> { | ||||
|     return this.map.keys(); | ||||
|   } | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -7,4 +7,4 @@ | ||||
|  */ | ||||
| 
 | ||||
| export * from './src/compiler'; | ||||
| export {NgCompilerHost} from './src/host'; | ||||
| export {NgCompilerHost} from './src/host'; | ||||
|  | ||||
| @ -38,4 +38,4 @@ runInEachFileSystem(() => { | ||||
|       expect(secondCompilation.safeToSkipEmit(fooSf)).toBeFalse(); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| }); | ||||
|  | ||||
| @ -10,4 +10,4 @@ export {ExportScope, ScopeData} from './src/api'; | ||||
| export {ComponentScopeReader, CompoundComponentScopeReader} from './src/component_scope'; | ||||
| export {DtsModuleScopeResolver, MetadataDtsModuleScopeResolver} from './src/dependency'; | ||||
| export {DeclarationData, LocalModuleScope, LocalModuleScopeRegistry, LocalNgModuleData} from './src/local'; | ||||
| export {TypeCheckScope, TypeCheckScopeRegistry} from './src/typecheck'; | ||||
| export {TypeCheckScope, TypeCheckScopeRegistry} from './src/typecheck'; | ||||
|  | ||||
| @ -62,4 +62,4 @@ export interface RemoteScope { | ||||
|    * Those pipes used by the component that requires this scope to be set remotely. | ||||
|    */ | ||||
|   pipes: Reference[]; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -1127,4 +1127,4 @@ function isIvyNgModule(clazz: ts.ClassDeclaration): boolean { | ||||
| 
 | ||||
|   // No Ivy 'ɵmod' property found.
 | ||||
|   return false; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -59,4 +59,4 @@ function hasProperty(node: ts.ObjectLiteralExpression, propertyName: string): bo | ||||
|     } | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -16,4 +16,4 @@ import * as ts from 'typescript'; | ||||
| export interface UpdateRecorder { | ||||
|   updateNode(node: ts.Node, newText: string): void; | ||||
|   commitUpdate(): void; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -129,4 +129,4 @@ function getNamedImports(importDeclaration: ts.ImportDeclaration|undefined): ts. | ||||
|   } | ||||
| 
 | ||||
|   return undefined; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -21,4 +21,4 @@ export const enum InjectorMarkers { | ||||
|    * Marks that the current type is `Injector` | ||||
|    */ | ||||
|   Injector = -1 | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -95,4 +95,4 @@ export class ElementRef<T = any> { | ||||
|  */ | ||||
| export function unwrapElementRef<T, R>(value: T|ElementRef<R>): T|R { | ||||
|   return value instanceof ElementRef ? value.nativeElement : value; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -202,4 +202,4 @@ interface QueryListInternal<T> extends QueryList<T> { | ||||
|   length: number; | ||||
|   last: T; | ||||
|   first: T; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -31,4 +31,4 @@ export function assertPureTNodeType(type: TNodeType) { | ||||
|     throwError(`Expected TNodeType to have only a single type selected, but got ${ | ||||
|         toTNodeTypeAsString(type)}.`);
 | ||||
|   } | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -129,4 +129,4 @@ export function assertOneOf(value: any, ...validValues: any[]) { | ||||
|   if (validValues.indexOf(value) !== -1) return true; | ||||
|   throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${ | ||||
|       JSON.stringify(value)}.`);
 | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -48,4 +48,4 @@ const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B'; | ||||
| export function escapeCommentText(value: string): string { | ||||
|   return value.replace( | ||||
|       COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED)); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -40,4 +40,4 @@ describe('comment node text escaping', () => { | ||||
|          expect(script).toBeFalsy(); | ||||
|        }); | ||||
|   }); | ||||
| }); | ||||
| }); | ||||
|  | ||||
| @ -16,4 +16,4 @@ describe('InjectFlags', () => { | ||||
|     expect(InjectFlags.SkipSelf).toEqual(InternalInjectFlags.SkipSelf as number); | ||||
|     expect(InjectFlags.Optional).toEqual(InternalInjectFlags.Optional as number); | ||||
|   }); | ||||
| }); | ||||
| }); | ||||
|  | ||||
| @ -25,4 +25,4 @@ describe('node interfaces', () => { | ||||
|           .toEqual('Element|Container|ElementContainer|Projection|IcuContainer'); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| }); | ||||
|  | ||||
| @ -199,4 +199,4 @@ export function isDOMElement(obj: any): obj is Element { | ||||
|  */ | ||||
| export function isDOMText(obj: any): obj is Text { | ||||
|   return obj instanceof Text; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -34,4 +34,4 @@ describe('isShapeOf', () => { | ||||
|     expect(isShapeOf({required: true, extra: 'is ok'}, {required: true, missing: true})) | ||||
|         .toBeFalse(); | ||||
|   }); | ||||
| }); | ||||
| }); | ||||
|  | ||||
| @ -116,4 +116,4 @@ function expectNgModuleDef( | ||||
| 
 | ||||
| function unwrap(values: Type<any>[]|(() => Type<any>[])): Type<any>[] { | ||||
|   return typeof values === 'function' ? values() : values; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -252,4 +252,4 @@ export function matchI18nMutableOpCodes(expectedMutableOpCodes: string[]): | ||||
|   }; | ||||
| 
 | ||||
|   return matcher; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -93,4 +93,4 @@ describe('render3 matchers', () => { | ||||
|       expect(matcher.jasmineToString!()).toEqual(`[#TEXT: "myText" != #TEXT: "other text"]`); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| }); | ||||
|  | ||||
| @ -81,4 +81,4 @@ export class ViewFixture { | ||||
|       this.leaveView(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -210,4 +210,4 @@ export class BuiltInControlValueAccessor extends BaseControlValueAccessor { | ||||
|  * @publicApi | ||||
|  */ | ||||
| export const NG_VALUE_ACCESSOR = | ||||
|     new InjectionToken<ReadonlyArray<ControlValueAccessor>>('NgValueAccessor'); | ||||
|     new InjectionToken<ReadonlyArray<ControlValueAccessor>>('NgValueAccessor'); | ||||
|  | ||||
| @ -575,4 +575,4 @@ function getUniqueLocations<T extends ts.DocumentSpan>(locations: readonly T[]): | ||||
|     uniqueLocations.set(createLocationKey(location), location); | ||||
|   } | ||||
|   return Array.from(uniqueLocations.values()); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -413,4 +413,4 @@ function getRenameRequestPosition(renameRequest: RenameRequest): FilePosition { | ||||
|       renameRequest.requestNode.getStart() : | ||||
|       renameRequest.renamePosition.position; | ||||
|   return {fileName, position}; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -294,4 +294,4 @@ export function getParentClassMeta(requestNode: ts.Node, compiler: NgCompiler): | ||||
|     return null; | ||||
|   } | ||||
|   return compiler.getMeta(parentClass); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -101,4 +101,4 @@ function last<T>(array: T[]): T { | ||||
|     throw new Error(`last() called on empty array`); | ||||
|   } | ||||
|   return array[array.length - 1]; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -374,4 +374,4 @@ export function getTemplateLocationFromShimLocation( | ||||
|     return null; | ||||
|   } | ||||
|   return {templateUrl, span}; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -103,4 +103,4 @@ const _ESCAPED_CHARS: [RegExp, string][] = [ | ||||
| function escapeXml(text: string): string { | ||||
|   return _ESCAPED_CHARS.reduce( | ||||
|       (text: string, entry: [RegExp, string]) => text.replace(entry[0], entry[1]), text); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -73,4 +73,4 @@ describe('extractIcuPlaceholders()', () => { | ||||
|           '}\n  }}\n}', | ||||
|         ]); | ||||
|   }); | ||||
| }); | ||||
| }); | ||||
|  | ||||
| @ -181,4 +181,4 @@ export class RouterLinkActive implements OnChanges, OnDestroy, AfterContentInit | ||||
|         this.linkWithHref && isActiveCheckFn(this.linkWithHref) || | ||||
|         this.links.some(isActiveCheckFn) || this.linksWithHrefs.some(isActiveCheckFn); | ||||
|   } | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -136,4 +136,4 @@ export function sortByMatchingOutlets(routes: Routes, outletName: string): Route | ||||
|   const sortedConfig = routes.filter(r => getOutlet(r) === outletName); | ||||
|   sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName)); | ||||
|   return sortedConfig; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
|     "node_modules/tslint-no-toplevel-property-access/rules" | ||||
|   ], | ||||
|   "rules": { | ||||
|     "eofline": true, | ||||
|     "file-header": [ | ||||
|       true, | ||||
|       { | ||||
| @ -56,6 +57,7 @@ | ||||
|     ] | ||||
|   }, | ||||
|   "jsRules": { | ||||
|     "eofline": true, | ||||
|     "file-header": [ | ||||
|       true, | ||||
|       { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user