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:
Paul Gschwendtner 2021-06-04 16:57:07 +02:00 committed by Jessica Janiuk
parent 71e14a71f5
commit 2d0ff0a5d3
35 changed files with 36 additions and 34 deletions

View File

@ -96,4 +96,4 @@ export class HttpContext {
keys(): IterableIterator<HttpContextToken<unknown>> { keys(): IterableIterator<HttpContextToken<unknown>> {
return this.map.keys(); return this.map.keys();
} }
} }

View File

@ -7,4 +7,4 @@
*/ */
export * from './src/compiler'; export * from './src/compiler';
export {NgCompilerHost} from './src/host'; export {NgCompilerHost} from './src/host';

View File

@ -38,4 +38,4 @@ runInEachFileSystem(() => {
expect(secondCompilation.safeToSkipEmit(fooSf)).toBeFalse(); expect(secondCompilation.safeToSkipEmit(fooSf)).toBeFalse();
}); });
}); });
}); });

View File

@ -10,4 +10,4 @@ export {ExportScope, ScopeData} from './src/api';
export {ComponentScopeReader, CompoundComponentScopeReader} from './src/component_scope'; export {ComponentScopeReader, CompoundComponentScopeReader} from './src/component_scope';
export {DtsModuleScopeResolver, MetadataDtsModuleScopeResolver} from './src/dependency'; export {DtsModuleScopeResolver, MetadataDtsModuleScopeResolver} from './src/dependency';
export {DeclarationData, LocalModuleScope, LocalModuleScopeRegistry, LocalNgModuleData} from './src/local'; export {DeclarationData, LocalModuleScope, LocalModuleScopeRegistry, LocalNgModuleData} from './src/local';
export {TypeCheckScope, TypeCheckScopeRegistry} from './src/typecheck'; export {TypeCheckScope, TypeCheckScopeRegistry} from './src/typecheck';

View File

@ -62,4 +62,4 @@ export interface RemoteScope {
* Those pipes used by the component that requires this scope to be set remotely. * Those pipes used by the component that requires this scope to be set remotely.
*/ */
pipes: Reference[]; pipes: Reference[];
} }

View File

@ -1127,4 +1127,4 @@ function isIvyNgModule(clazz: ts.ClassDeclaration): boolean {
// No Ivy 'ɵmod' property found. // No Ivy 'ɵmod' property found.
return false; return false;
} }

View File

@ -59,4 +59,4 @@ function hasProperty(node: ts.ObjectLiteralExpression, propertyName: string): bo
} }
} }
return false; return false;
} }

View File

@ -16,4 +16,4 @@ import * as ts from 'typescript';
export interface UpdateRecorder { export interface UpdateRecorder {
updateNode(node: ts.Node, newText: string): void; updateNode(node: ts.Node, newText: string): void;
commitUpdate(): void; commitUpdate(): void;
} }

View File

@ -129,4 +129,4 @@ function getNamedImports(importDeclaration: ts.ImportDeclaration|undefined): ts.
} }
return undefined; return undefined;
} }

View File

@ -21,4 +21,4 @@ export const enum InjectorMarkers {
* Marks that the current type is `Injector` * Marks that the current type is `Injector`
*/ */
Injector = -1 Injector = -1
} }

View File

@ -95,4 +95,4 @@ export class ElementRef<T = any> {
*/ */
export function unwrapElementRef<T, R>(value: T|ElementRef<R>): T|R { export function unwrapElementRef<T, R>(value: T|ElementRef<R>): T|R {
return value instanceof ElementRef ? value.nativeElement : value; return value instanceof ElementRef ? value.nativeElement : value;
} }

View File

@ -202,4 +202,4 @@ interface QueryListInternal<T> extends QueryList<T> {
length: number; length: number;
last: T; last: T;
first: T; first: T;
} }

View File

@ -31,4 +31,4 @@ export function assertPureTNodeType(type: TNodeType) {
throwError(`Expected TNodeType to have only a single type selected, but got ${ throwError(`Expected TNodeType to have only a single type selected, but got ${
toTNodeTypeAsString(type)}.`); toTNodeTypeAsString(type)}.`);
} }
} }

View File

@ -129,4 +129,4 @@ export function assertOneOf(value: any, ...validValues: any[]) {
if (validValues.indexOf(value) !== -1) return true; if (validValues.indexOf(value) !== -1) return true;
throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${ throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${
JSON.stringify(value)}.`); JSON.stringify(value)}.`);
} }

View File

@ -48,4 +48,4 @@ const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
export function escapeCommentText(value: string): string { export function escapeCommentText(value: string): string {
return value.replace( return value.replace(
COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED)); COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED));
} }

View File

@ -40,4 +40,4 @@ describe('comment node text escaping', () => {
expect(script).toBeFalsy(); expect(script).toBeFalsy();
}); });
}); });
}); });

View File

@ -16,4 +16,4 @@ describe('InjectFlags', () => {
expect(InjectFlags.SkipSelf).toEqual(InternalInjectFlags.SkipSelf as number); expect(InjectFlags.SkipSelf).toEqual(InternalInjectFlags.SkipSelf as number);
expect(InjectFlags.Optional).toEqual(InternalInjectFlags.Optional as number); expect(InjectFlags.Optional).toEqual(InternalInjectFlags.Optional as number);
}); });
}); });

View File

@ -25,4 +25,4 @@ describe('node interfaces', () => {
.toEqual('Element|Container|ElementContainer|Projection|IcuContainer'); .toEqual('Element|Container|ElementContainer|Projection|IcuContainer');
}); });
}); });
}); });

View File

@ -199,4 +199,4 @@ export function isDOMElement(obj: any): obj is Element {
*/ */
export function isDOMText(obj: any): obj is Text { export function isDOMText(obj: any): obj is Text {
return obj instanceof Text; return obj instanceof Text;
} }

View File

@ -34,4 +34,4 @@ describe('isShapeOf', () => {
expect(isShapeOf({required: true, extra: 'is ok'}, {required: true, missing: true})) expect(isShapeOf({required: true, extra: 'is ok'}, {required: true, missing: true}))
.toBeFalse(); .toBeFalse();
}); });
}); });

View File

@ -116,4 +116,4 @@ function expectNgModuleDef(
function unwrap(values: Type<any>[]|(() => Type<any>[])): Type<any>[] { function unwrap(values: Type<any>[]|(() => Type<any>[])): Type<any>[] {
return typeof values === 'function' ? values() : values; return typeof values === 'function' ? values() : values;
} }

View File

@ -252,4 +252,4 @@ export function matchI18nMutableOpCodes(expectedMutableOpCodes: string[]):
}; };
return matcher; return matcher;
} }

View File

@ -93,4 +93,4 @@ describe('render3 matchers', () => {
expect(matcher.jasmineToString!()).toEqual(`[#TEXT: "myText" != #TEXT: "other text"]`); expect(matcher.jasmineToString!()).toEqual(`[#TEXT: "myText" != #TEXT: "other text"]`);
}); });
}); });
}); });

View File

@ -81,4 +81,4 @@ export class ViewFixture {
this.leaveView(); this.leaveView();
} }
} }
} }

View File

@ -210,4 +210,4 @@ export class BuiltInControlValueAccessor extends BaseControlValueAccessor {
* @publicApi * @publicApi
*/ */
export const NG_VALUE_ACCESSOR = export const NG_VALUE_ACCESSOR =
new InjectionToken<ReadonlyArray<ControlValueAccessor>>('NgValueAccessor'); new InjectionToken<ReadonlyArray<ControlValueAccessor>>('NgValueAccessor');

View File

@ -575,4 +575,4 @@ function getUniqueLocations<T extends ts.DocumentSpan>(locations: readonly T[]):
uniqueLocations.set(createLocationKey(location), location); uniqueLocations.set(createLocationKey(location), location);
} }
return Array.from(uniqueLocations.values()); return Array.from(uniqueLocations.values());
} }

View File

@ -413,4 +413,4 @@ function getRenameRequestPosition(renameRequest: RenameRequest): FilePosition {
renameRequest.requestNode.getStart() : renameRequest.requestNode.getStart() :
renameRequest.renamePosition.position; renameRequest.renamePosition.position;
return {fileName, position}; return {fileName, position};
} }

View File

@ -294,4 +294,4 @@ export function getParentClassMeta(requestNode: ts.Node, compiler: NgCompiler):
return null; return null;
} }
return compiler.getMeta(parentClass); return compiler.getMeta(parentClass);
} }

View File

@ -101,4 +101,4 @@ function last<T>(array: T[]): T {
throw new Error(`last() called on empty array`); throw new Error(`last() called on empty array`);
} }
return array[array.length - 1]; return array[array.length - 1];
} }

View File

@ -374,4 +374,4 @@ export function getTemplateLocationFromShimLocation(
return null; return null;
} }
return {templateUrl, span}; return {templateUrl, span};
} }

View File

@ -103,4 +103,4 @@ const _ESCAPED_CHARS: [RegExp, string][] = [
function escapeXml(text: string): string { function escapeXml(text: string): string {
return _ESCAPED_CHARS.reduce( return _ESCAPED_CHARS.reduce(
(text: string, entry: [RegExp, string]) => text.replace(entry[0], entry[1]), text); (text: string, entry: [RegExp, string]) => text.replace(entry[0], entry[1]), text);
} }

View File

@ -73,4 +73,4 @@ describe('extractIcuPlaceholders()', () => {
'}\n }}\n}', '}\n }}\n}',
]); ]);
}); });
}); });

View File

@ -181,4 +181,4 @@ export class RouterLinkActive implements OnChanges, OnDestroy, AfterContentInit
this.linkWithHref && isActiveCheckFn(this.linkWithHref) || this.linkWithHref && isActiveCheckFn(this.linkWithHref) ||
this.links.some(isActiveCheckFn) || this.linksWithHrefs.some(isActiveCheckFn); this.links.some(isActiveCheckFn) || this.linksWithHrefs.some(isActiveCheckFn);
} }
} }

View File

@ -136,4 +136,4 @@ export function sortByMatchingOutlets(routes: Routes, outletName: string): Route
const sortedConfig = routes.filter(r => getOutlet(r) === outletName); const sortedConfig = routes.filter(r => getOutlet(r) === outletName);
sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName)); sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName));
return sortedConfig; return sortedConfig;
} }

View File

@ -6,6 +6,7 @@
"node_modules/tslint-no-toplevel-property-access/rules" "node_modules/tslint-no-toplevel-property-access/rules"
], ],
"rules": { "rules": {
"eofline": true,
"file-header": [ "file-header": [
true, true,
{ {
@ -56,6 +57,7 @@
] ]
}, },
"jsRules": { "jsRules": {
"eofline": true,
"file-header": [ "file-header": [
true, true,
{ {