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 { combineLatest, Observable, ReplaySubject } from 'rxjs';
import { LocationService } from 'app/shared/location.service'; 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 { Option } from 'app/shared/select/select.component';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
@ -112,28 +112,20 @@ export class ApiListComponent implements OnInit {
//////// Private ////////// //////// Private //////////
private filterSection(section: ApiSection, { query, status, type }: SearchCriteria) { private filterSection(section: ApiSection, { query, status, type }: SearchCriteria) {
const items = section.items!.filter(item => { const sectionNameMatches = !query || section.name.indexOf(query) !== -1;
return matchesType() && matchesStatus() && matchesQuery();
function matchesQuery() { const matchesQuery = (item: ApiItem) =>
return !query || sectionNameMatches || item.name.indexOf(query!) !== -1;
section.name.indexOf(query) !== -1 || const matchesStatus = (item: ApiItem) =>
item.name.indexOf(query) !== -1; status === 'all' || status === item.stability || (status === 'security-risk' && item.securityRisk);
} const matchesType = (item: ApiItem) =>
type === 'all' || type === item.docType;
function matchesStatus() { const items = section.items!.filter(item =>
return status === 'all' || matchesType(item) && matchesStatus(item) && matchesQuery(item));
status === item.stability ||
(status === 'security-risk' && item.securityRisk);
}
function matchesType() {
return type === 'all' || type === item.docType;
}
});
// If there are no items we still return an empty array if the section name matches and the type is 'package' // 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 // 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? this.fetchSections(); // TODO: get URL for fetchSections by configuration?
// makes sectionsSubject hot; subscribe ensures stays alive (always refCount > 0); // 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 => { return this._sections.pipe(tap(sections => {

View File

@ -251,7 +251,7 @@ describe('CodeComponent', () => {
actualCode = spy.calls.mostRecent().args[0]; actualCode = spy.calls.mostRecent().args[0];
expect(actualCode).toBe(expectedCode, `when linenums=${linenums}`); 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(); 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.codeText = this.getCodeText(); // store the unformatted code as text (for copying)
this.pretty this.pretty
.formatCode(leftAlignedCode, this.language, this.getLinenums(leftAlignedCode)) .formatCode(leftAlignedCode, this.language, this.getLinenums())
.pipe(tap(() => this.codeFormatted.emit())) .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). */ /** Gets the calculated value of linenums (boolean/number). */
getLinenums(code: string) { getLinenums() {
const linenums = const linenums =
typeof this.linenums === 'boolean' ? this.linenums : typeof this.linenums === 'boolean' ? this.linenums :
this.linenums === 'true' ? true : this.linenums === 'true' ? true :

View File

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

View File

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

View File

@ -47,7 +47,7 @@ describe('DocViewerComponent', () => {
parentFixture.detectChanges(); 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', () => { it('should render the new document', () => {
setCurrentDoc('foo', 'bar'); setCurrentDoc('foo', 'bar');
@ -87,7 +87,7 @@ describe('DocViewerComponent', () => {
describe('#ngOnDestroy()', () => { describe('#ngOnDestroy()', () => {
it('should stop responding to document changes', () => { 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(); expect(renderSpy).not.toHaveBeenCalled();

View File

@ -39,7 +39,7 @@ describe('ScrollSpiedElement', () => {
describe('ScrollSpiedElementGroup', () => { describe('ScrollSpiedElementGroup', () => {
describe('#calibrate()', () => { describe('#calibrate()', () => {
it('should calculate `top` for all spied elements', () => { 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 elems = [{}, {}, {}] as Element[];
const group = new ScrollSpiedElementGroup(elems); const group = new ScrollSpiedElementGroup(elems);
@ -68,7 +68,7 @@ describe('ScrollSpiedElementGroup', () => {
const tops = [50, 150, 100]; const tops = [50, 150, 100];
spyOn(ScrollSpiedElement.prototype, 'calculateTop').and.callFake( spyOn(ScrollSpiedElement.prototype, 'calculateTop').and.callFake(
function(this: ScrollSpiedElement, scrollTop: number, topOffset: number) { function(this: ScrollSpiedElement) {
this.top = tops[this.index]; 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. */ /** Pass the given search results to the component and trigger change detection. */
function setSearchResults(query: string, results: SearchResult[]) { function setSearchResults(query: string, results: SearchResult[]) {
component.searchResults = {query, results}; component.searchResults = {query, results};
component.ngOnChanges({}); component.ngOnChanges();
fixture.detectChanges(); 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'; import { SearchResult, SearchResults, SearchArea } from 'app/search/interfaces';
/** /**
@ -27,7 +27,7 @@ export class SearchResultsComponent implements OnChanges {
readonly topLevelFolders = ['guide', 'tutorial']; readonly topLevelFolders = ['guide', 'tutorial'];
searchAreas: SearchArea[] = []; searchAreas: SearchArea[] = [];
ngOnChanges(changes: SimpleChanges) { ngOnChanges() {
this.searchAreas = this.processSearchResults(this.searchResults); this.searchAreas = this.processSearchResults(this.searchResults);
} }

View File

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

View File

@ -20,9 +20,14 @@ export class TestDocViewerComponent extends DocViewerComponent {
currViewContainer: HTMLElement; currViewContainer: HTMLElement;
nextViewContainer: HTMLElement; nextViewContainer: HTMLElement;
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; } prepareTitleAndToc(_targetElem: HTMLElement, _docId: string): () => void { return null as any; }
swapViews(onInsertedCb?: () => void): Observable<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> { export class ObservableWithSubscriptionSpies<T = void> extends Observable<T> {
unsubscribeSpies: jasmine.Spy[] = []; 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 subscription = super.subscribe(...args);
const unsubscribeSpy = spyOn(subscription, 'unsubscribe').and.callThrough(); const unsubscribeSpy = spyOn(subscription, 'unsubscribe').and.callThrough();
this.unsubscribeSpies.push(unsubscribeSpy); this.unsubscribeSpies.push(unsubscribeSpy);

View File

@ -47,19 +47,22 @@ export class FirebaseGlob {
} }
} }
test(url: string) { test(url: string): boolean {
return XRegExp.test(url, this.regex); 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 }; const match = XRegExp.exec(url, this.regex) as ReturnType<typeof XRegExp.exec> & { [captured: string]: string };
if (match) {
if (!match) {
return undefined;
}
const result: { [key: string]: string } = {}; const result: { [key: string]: string } = {};
const names = this.regex.xregexp.captureNames || []; const names = this.regex.xregexp.captureNames || [];
names.forEach(name => result[name] = (match[name])); names.forEach(name => result[name] = (match[name]));
return result; return result;
} }
}
} }
function replaceModifiedPattern(_: string, modifier: string, pattern: string) { function replaceModifiedPattern(_: string, modifier: string, pattern: string) {

View File

@ -5,12 +5,15 @@ export class FirebaseRedirect {
glob = new FirebaseGlob(this.source); glob = new FirebaseGlob(this.source);
constructor(public source: string, public destination: string) {} constructor(public source: string, public destination: string) {}
replace(url: string) { replace(url: string): string | undefined {
const match = this.glob.match(url); const match = this.glob.match(url);
if (match) {
if (!match) {
return undefined;
}
const paramReplacers = Object.keys(this.glob.namedParams).map(name => [ XRegExp(`:${name}`, 'g'), match[name] ]); 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] ]); const restReplacers = Object.keys(this.glob.restParams).map(name => [ XRegExp(`:${name}\\*`, 'g'), match[name] ]);
return XRegExp.replaceEach(this.destination, [...paramReplacers, ...restReplacers]); 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)); this.redirects = redirects.map(redirect => new FirebaseRedirect(redirect.source, redirect.destination));
} }
redirect(url: string) { redirect(url: string): string {
let ttl = 50; let ttl = 50;
while (ttl > 0) { while (ttl > 0) {
const newUrl = this.doRedirect(url); const newUrl = this.doRedirect(url);
@ -24,6 +24,7 @@ export class FirebaseRedirector {
} }
throw new Error('infinite redirect loop'); throw new Error('infinite redirect loop');
} }
private doRedirect(url: string) { private doRedirect(url: string) {
for (const redirect of this.redirects) { for (const redirect of this.redirects) {
const newUrl = redirect.replace(url); const newUrl = redirect.replace(url);

View File

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