build(docs-infra): enable more TypeScript strictness flags (#32980)

PR Close #32980
This commit is contained in:
George Kalpakas 2019-10-03 12:46:38 +03:00 committed by Miško Hevery
parent 9abc1f9156
commit b2666a2857
16 changed files with 64 additions and 57 deletions

View File

@ -11,7 +11,7 @@ import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { combineLatest, Observable, ReplaySubject } from 'rxjs';
import { LocationService } from 'app/shared/location.service';
import { ApiSection, ApiService } from './api.service';
import { ApiItem, ApiSection, ApiService } from './api.service';
import { Option } from 'app/shared/select/select.component';
import { map } from 'rxjs/operators';
@ -112,28 +112,20 @@ export class ApiListComponent implements OnInit {
//////// Private //////////
private filterSection(section: ApiSection, { query, status, type }: SearchCriteria) {
const items = section.items!.filter(item => {
return matchesType() && matchesStatus() && matchesQuery();
const sectionNameMatches = !query || section.name.indexOf(query) !== -1;
function matchesQuery() {
return !query ||
section.name.indexOf(query) !== -1 ||
item.name.indexOf(query) !== -1;
}
const matchesQuery = (item: ApiItem) =>
sectionNameMatches || item.name.indexOf(query!) !== -1;
const matchesStatus = (item: ApiItem) =>
status === 'all' || status === item.stability || (status === 'security-risk' && item.securityRisk);
const matchesType = (item: ApiItem) =>
type === 'all' || type === item.docType;
function matchesStatus() {
return status === 'all' ||
status === item.stability ||
(status === 'security-risk' && item.securityRisk);
}
function matchesType() {
return type === 'all' || type === item.docType;
}
});
const items = section.items!.filter(item =>
matchesType(item) && matchesStatus(item) && matchesQuery(item));
// If there are no items we still return an empty array if the section name matches and the type is 'package'
return items.length ? items : (type === 'package' && (!query || section.name.indexOf(query) !== -1)) ? [] : null;
return items.length ? items : (sectionNameMatches && type === 'package') ? [] : null;
}
// Get initial search criteria from URL search params

View File

@ -45,7 +45,7 @@ export class ApiService implements OnDestroy {
this.fetchSections(); // TODO: get URL for fetchSections by configuration?
// makes sectionsSubject hot; subscribe ensures stays alive (always refCount > 0);
this._sections.subscribe(sections => this.logger.log('ApiService got API sections') );
this._sections.subscribe(sections => this.logger.log(`ApiService got API ${sections.length} section(s)`));
}
return this._sections.pipe(tap(sections => {

View File

@ -251,7 +251,7 @@ describe('CodeComponent', () => {
actualCode = spy.calls.mostRecent().args[0];
expect(actualCode).toBe(expectedCode, `when linenums=${linenums}`);
expect(actualCode.match(/\r?\n/g).length).toBe(5);
expect(actualCode.match(/\r?\n/g)!.length).toBe(5);
spy.calls.reset();
});

View File

@ -113,9 +113,9 @@ export class CodeComponent implements OnChanges {
this.codeText = this.getCodeText(); // store the unformatted code as text (for copying)
this.pretty
.formatCode(leftAlignedCode, this.language, this.getLinenums(leftAlignedCode))
.formatCode(leftAlignedCode, this.language, this.getLinenums())
.pipe(tap(() => this.codeFormatted.emit()))
.subscribe(c => this.setCodeHtml(c), err => { /* ignore failure to format */ }
.subscribe(c => this.setCodeHtml(c), () => { /* ignore failure to format */ }
);
}
@ -156,7 +156,7 @@ export class CodeComponent implements OnChanges {
}
/** Gets the calculated value of linenums (boolean/number). */
getLinenums(code: string) {
getLinenums() {
const linenums =
typeof this.linenums === 'boolean' ? this.linenums :
this.linenums === 'true' ? true :

View File

@ -85,7 +85,7 @@ describe('ContributorListComponent', () => {
searchResult: SearchResult = {};
search = jasmine.createSpy('search').and.callFake(() => this.searchResult);
setSearch = jasmine.createSpy('setSearch')
.and.callFake((label: string, result: SearchResult) => {
.and.callFake((_label: string, result: SearchResult) => {
this.searchResult = result;
});
}

View File

@ -260,10 +260,10 @@ class FakeComponentFactory extends ComponentFactory<any> {
constructor(private identifyingInput: string) { super(); }
create(injector: Injector,
projectableNodes?: any[][],
rootSelectorOrNode?: string | any,
ngModule?: NgModuleRef<any>): ComponentRef<any> {
create(_injector: Injector,
_projectableNodes?: any[][],
_rootSelectorOrNode?: string | any,
_ngModule?: NgModuleRef<any>): ComponentRef<any> {
return jasmine.createSpy('ComponentRef') as any;
}
}
@ -271,7 +271,7 @@ class FakeComponentFactory extends ComponentFactory<any> {
class FakeComponentFactoryResolver extends ComponentFactoryResolver {
constructor(private modulePath: string) { super(); }
resolveComponentFactory(component: Type<any>): ComponentFactory<any> {
resolveComponentFactory(_component: Type<any>): ComponentFactory<any> {
return new FakeComponentFactory(this.modulePath);
}
}
@ -288,7 +288,7 @@ class FakeModuleRef extends NgModuleRef<WithCustomElementComponent> {
}
destroy() {}
onDestroy(callback: () => void) {}
onDestroy(_callback: () => void) {}
}
class FakeModuleFactory extends NgModuleFactory<any> {
@ -297,7 +297,7 @@ class FakeModuleFactory extends NgModuleFactory<any> {
constructor(private modulePath: string) { super(); }
create(parentInjector: Injector | null): NgModuleRef<any> {
create(_parentInjector: Injector | null): NgModuleRef<any> {
return this.moduleRefToCreate;
}
}

View File

@ -47,7 +47,7 @@ describe('DocViewerComponent', () => {
parentFixture.detectChanges();
};
beforeEach(() => renderSpy = spyOn(docViewer, 'render').and.returnValue([null]));
beforeEach(() => renderSpy = spyOn(docViewer, 'render').and.returnValue(of(undefined)));
it('should render the new document', () => {
setCurrentDoc('foo', 'bar');
@ -87,7 +87,7 @@ describe('DocViewerComponent', () => {
describe('#ngOnDestroy()', () => {
it('should stop responding to document changes', () => {
const renderSpy = spyOn(docViewer, 'render').and.returnValue([undefined]);
const renderSpy = spyOn(docViewer, 'render').and.returnValue(of(undefined));
expect(renderSpy).not.toHaveBeenCalled();

View File

@ -39,7 +39,7 @@ describe('ScrollSpiedElement', () => {
describe('ScrollSpiedElementGroup', () => {
describe('#calibrate()', () => {
it('should calculate `top` for all spied elements', () => {
const spy = spyOn(ScrollSpiedElement.prototype, 'calculateTop').and.returnValue(0);
const spy = spyOn(ScrollSpiedElement.prototype, 'calculateTop');
const elems = [{}, {}, {}] as Element[];
const group = new ScrollSpiedElementGroup(elems);
@ -68,7 +68,7 @@ describe('ScrollSpiedElementGroup', () => {
const tops = [50, 150, 100];
spyOn(ScrollSpiedElement.prototype, 'calculateTop').and.callFake(
function(this: ScrollSpiedElement, scrollTop: number, topOffset: number) {
function(this: ScrollSpiedElement) {
this.top = tops[this.index];
});

View File

@ -31,7 +31,7 @@ describe('SearchResultsComponent', () => {
/** Pass the given search results to the component and trigger change detection. */
function setSearchResults(query: string, results: SearchResult[]) {
component.searchResults = {query, results};
component.ngOnChanges({});
component.ngOnChanges();
fixture.detectChanges();
}

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { SearchResult, SearchResults, SearchArea } from 'app/search/interfaces';
/**
@ -27,7 +27,7 @@ export class SearchResultsComponent implements OnChanges {
readonly topLevelFolders = ['guide', 'tutorial'];
searchAreas: SearchArea[] = [];
ngOnChanges(changes: SimpleChanges) {
ngOnChanges() {
this.searchAreas = this.processSearchResults(this.searchResults);
}

View File

@ -365,7 +365,7 @@ class MockScrollSpyService {
return this.$$lastInfo;
}
spyOn(headings: HTMLHeadingElement[]): ScrollSpyInfo {
spyOn(_headings: HTMLHeadingElement[]): ScrollSpyInfo {
return this.$$lastInfo = {
active: new Subject<ScrollItem | null>(),
unspy: jasmine.createSpy('unspy'),

View File

@ -20,9 +20,14 @@ export class TestDocViewerComponent extends DocViewerComponent {
currViewContainer: HTMLElement;
nextViewContainer: HTMLElement;
prepareTitleAndToc(targetElem: HTMLElement, docId: string): () => void { return null as any; }
render(doc: DocumentContents): Observable<void> { return null as any; }
swapViews(onInsertedCb?: () => void): Observable<void> { return null as any; }
// Only used for type-casting; the actual implementation is irrelevant.
prepareTitleAndToc(_targetElem: HTMLElement, _docId: string): () => void { return null as any; }
// Only used for type-casting; the actual implementation is irrelevant.
render(_doc: DocumentContents): Observable<void> { return null as any; }
// Only used for type-casting; the actual implementation is irrelevant.
swapViews(_onInsertedCb?: () => void): Observable<void> { return null as any; }
}
@ -82,7 +87,7 @@ export class TestModule { }
export class ObservableWithSubscriptionSpies<T = void> extends Observable<T> {
unsubscribeSpies: jasmine.Spy[] = [];
subscribeSpy = spyOn(this, 'subscribe').and.callFake((...args: any[]) => {
subscribeSpy = spyOn(this as Observable<T>, 'subscribe').and.callFake((...args: any[]) => {
const subscription = super.subscribe(...args);
const unsubscribeSpy = spyOn(subscription, 'unsubscribe').and.callThrough();
this.unsubscribeSpies.push(unsubscribeSpy);

View File

@ -47,18 +47,21 @@ export class FirebaseGlob {
}
}
test(url: string) {
test(url: string): boolean {
return XRegExp.test(url, this.regex);
}
match(url: string) {
match(url: string): { [key: string]: string } | undefined {
const match = XRegExp.exec(url, this.regex) as ReturnType<typeof XRegExp.exec> & { [captured: string]: string };
if (match) {
const result: { [key: string]: string } = {};
const names = this.regex.xregexp.captureNames || [];
names.forEach(name => result[name] = (match[name]));
return result;
if (!match) {
return undefined;
}
const result: { [key: string]: string } = {};
const names = this.regex.xregexp.captureNames || [];
names.forEach(name => result[name] = (match[name]));
return result;
}
}

View File

@ -5,12 +5,15 @@ export class FirebaseRedirect {
glob = new FirebaseGlob(this.source);
constructor(public source: string, public destination: string) {}
replace(url: string) {
replace(url: string): string | undefined {
const match = this.glob.match(url);
if (match) {
const paramReplacers = Object.keys(this.glob.namedParams).map(name => [ XRegExp(`:${name}`, 'g'), match[name] ]);
const restReplacers = Object.keys(this.glob.restParams).map(name => [ XRegExp(`:${name}\\*`, 'g'), match[name] ]);
return XRegExp.replaceEach(this.destination, [...paramReplacers, ...restReplacers]);
if (!match) {
return undefined;
}
const paramReplacers = Object.keys(this.glob.namedParams).map(name => [ XRegExp(`:${name}`, 'g'), match[name] ]);
const restReplacers = Object.keys(this.glob.restParams).map(name => [ XRegExp(`:${name}\\*`, 'g'), match[name] ]);
return XRegExp.replaceEach(this.destination, [...paramReplacers, ...restReplacers]);
}
}

View File

@ -11,7 +11,7 @@ export class FirebaseRedirector {
this.redirects = redirects.map(redirect => new FirebaseRedirect(redirect.source, redirect.destination));
}
redirect(url: string) {
redirect(url: string): string {
let ttl = 50;
while (ttl > 0) {
const newUrl = this.doRedirect(url);
@ -24,6 +24,7 @@ export class FirebaseRedirector {
}
throw new Error('infinite redirect loop');
}
private doRedirect(url: string) {
for (const redirect of this.redirects) {
const newUrl = redirect.replace(url);

View File

@ -19,7 +19,10 @@
],
"skipLibCheck": true,
"strict": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
// disabled because this is on by default in tsc 2.7 breaking our codebase - we need to refactor
"strictPropertyInitialization": false
},