style(aio): enforce strict TypeScript checks (#21342)
Closes #20646 PR Close #21342
This commit is contained in:
parent
246de65140
commit
c5c6d84fe6
|
@ -18,7 +18,6 @@
|
|||
"@angular/core": "^5.0.0",
|
||||
"@angular/forms": "^5.0.0",
|
||||
"@angular/http": "^5.0.0",
|
||||
"@angular/service-worker": "^5.0.0",
|
||||
"@angular/platform-browser": "^5.0.0",
|
||||
"@angular/platform-browser-dynamic": "^5.0.0",
|
||||
"@angular/router": "^5.0.0",
|
||||
|
|
|
@ -25,7 +25,7 @@ export class ApiPage extends SitePage {
|
|||
// and we want to be able to pull out the code elements from only the first level
|
||||
// if `onlyDirect` is set to `true`.
|
||||
const selector = `.descendants.${docType} ${onlyDirect ? '>' : ''} li > :not(ul) code`;
|
||||
return element.all(by.css(selector)).map<string>(item => item.getText());
|
||||
return element.all(by.css(selector)).map<string>(item => item && item.getText());
|
||||
}
|
||||
|
||||
getOverview(docType) {
|
||||
|
|
|
@ -62,6 +62,6 @@ export class SitePage {
|
|||
getSearchResults() {
|
||||
const results = element.all(by.css('.search-results li'));
|
||||
browser.wait(ExpectedConditions.presenceOf(results.first()), 8000);
|
||||
return results.map(link => link.getText());
|
||||
return results.map(link => link && link.getText());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -314,7 +314,7 @@ describe('AppComponent', () => {
|
|||
it('should not navigate when change to a version without a url', () => {
|
||||
setupSelectorForTesting();
|
||||
const versionWithoutUrlIndex = component.docVersions.length;
|
||||
const versionWithoutUrl = component.docVersions[versionWithoutUrlIndex] = { title: 'foo', url: null };
|
||||
const versionWithoutUrl = component.docVersions[versionWithoutUrlIndex] = { title: 'foo' };
|
||||
selectElement.triggerEventHandler('change', { option: versionWithoutUrl, index: versionWithoutUrlIndex });
|
||||
expect(locationService.go).not.toHaveBeenCalled();
|
||||
});
|
||||
|
@ -520,9 +520,9 @@ describe('AppComponent', () => {
|
|||
|
||||
describe('aio-toc', () => {
|
||||
let tocDebugElement: DebugElement;
|
||||
let tocContainer: DebugElement;
|
||||
let tocContainer: DebugElement|null;
|
||||
|
||||
const setHasFloatingToc = hasFloatingToc => {
|
||||
const setHasFloatingToc = (hasFloatingToc: boolean) => {
|
||||
component.hasFloatingToc = hasFloatingToc;
|
||||
fixture.detectChanges();
|
||||
|
||||
|
@ -551,12 +551,12 @@ describe('AppComponent', () => {
|
|||
});
|
||||
|
||||
it('should update the TOC container\'s `maxHeight` based on `tocMaxHeight`', () => {
|
||||
expect(tocContainer.styles['max-height']).toBeNull();
|
||||
expect(tocContainer!.styles['max-height']).toBeNull();
|
||||
|
||||
component.tocMaxHeight = '100';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(tocContainer.styles['max-height']).toBe('100px');
|
||||
expect(tocContainer!.styles['max-height']).toBe('100px');
|
||||
});
|
||||
|
||||
it('should restrain scrolling inside the ToC container', () => {
|
||||
|
@ -565,7 +565,7 @@ describe('AppComponent', () => {
|
|||
|
||||
expect(restrainScrolling).not.toHaveBeenCalled();
|
||||
|
||||
tocContainer.triggerEventHandler('mousewheel', evt);
|
||||
tocContainer!.triggerEventHandler('mousewheel', evt);
|
||||
expect(restrainScrolling).toHaveBeenCalledWith(evt);
|
||||
});
|
||||
});
|
||||
|
@ -591,7 +591,7 @@ describe('AppComponent', () => {
|
|||
initializeTest();
|
||||
fixture.detectChanges();
|
||||
const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement;
|
||||
expect(banner.textContent.trim()).toEqual('');
|
||||
expect(banner.textContent!.trim()).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -985,9 +985,9 @@ describe('AppComponent', () => {
|
|||
checkHostClass('mode', 'archive');
|
||||
});
|
||||
|
||||
function checkHostClass(type, value) {
|
||||
function checkHostClass(type: string, value: string) {
|
||||
const host = fixture.debugElement;
|
||||
const classes = host.properties['className'];
|
||||
const classes: string = host.properties['className'];
|
||||
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
|
||||
expect(classArray.length).toBeLessThanOrEqual(1, `"${classes}" should have only one class matching ${type}-*`);
|
||||
expect(classArray).toEqual([`${type}-${value}`], `"${classes}" should contain ${type}-${value}`);
|
||||
|
@ -1212,10 +1212,10 @@ class TestHttpClient {
|
|||
if (/navigation\.json/.test(url)) {
|
||||
data = this.navJson;
|
||||
} else {
|
||||
const match = /generated\/docs\/(.+)\.json/.exec(url);
|
||||
const id = match[1];
|
||||
const match = /generated\/docs\/(.+)\.json/.exec(url)!;
|
||||
const id = match[1]!;
|
||||
// Make up a title for test purposes
|
||||
const title = id.split('/').pop().replace(/^([a-z])/, (_, letter) => letter.toUpperCase());
|
||||
const title = id.split('/').pop()!.replace(/^([a-z])/, (_, letter) => letter.toUpperCase());
|
||||
const h1 = (id === 'no-title') ? '' : `<h1>${title}</h1>`;
|
||||
const contents = `${h1}<h2 id="#somewhere">Some heading</h2>`;
|
||||
data = { id, contents };
|
||||
|
|
|
@ -152,19 +152,19 @@ export class AppComponent implements OnInit {
|
|||
this.navigationService.navigationViews.map(views => views['docVersions']))
|
||||
.subscribe(([versionInfo, versions]) => {
|
||||
// TODO(pbd): consider whether we can lookup the stable and next versions from the internet
|
||||
const computedVersions = [
|
||||
const computedVersions: NavigationNode[] = [
|
||||
{ title: 'next', url: 'https://next.angular.io' },
|
||||
{ title: 'stable', url: 'https://angular.io' },
|
||||
];
|
||||
if (this.deployment.mode === 'archive') {
|
||||
computedVersions.push({ title: `v${versionInfo.major}`, url: null });
|
||||
computedVersions.push({ title: `v${versionInfo.major}` });
|
||||
}
|
||||
this.docVersions = [...computedVersions, ...versions];
|
||||
|
||||
// Find the current version - eithers title matches the current deployment mode
|
||||
// or its title matches the major version of the current version info
|
||||
this.currentDocVersion = this.docVersions.find(version =>
|
||||
version.title === this.deployment.mode || version.title === `v${versionInfo.major}`);
|
||||
version.title === this.deployment.mode || version.title === `v${versionInfo.major}`)!;
|
||||
this.currentDocVersion.title += ` (v${versionInfo.raw})`;
|
||||
});
|
||||
|
||||
|
@ -232,7 +232,7 @@ export class AppComponent implements OnInit {
|
|||
}
|
||||
|
||||
@HostListener('window:resize', ['$event.target.innerWidth'])
|
||||
onResize(width) {
|
||||
onResize(width: number) {
|
||||
this.isSideBySide = width > this.sideBySideWidth;
|
||||
this.showFloatingToc.next(width > this.showFloatingTocWidth);
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ export class AppComponent implements OnInit {
|
|||
}
|
||||
|
||||
// Deal with anchor clicks; climb DOM tree until anchor found (or null)
|
||||
let target = eventTarget;
|
||||
let target: HTMLElement|null = eventTarget;
|
||||
while (target && !(target instanceof HTMLAnchorElement)) {
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
@ -335,8 +335,8 @@ export class AppComponent implements OnInit {
|
|||
// Must wait until now for mat-toolbar to be measurable.
|
||||
const el = this.hostElement.nativeElement as Element;
|
||||
this.tocMaxHeightOffset =
|
||||
el.querySelector('footer').clientHeight +
|
||||
el.querySelector('.app-toolbar').clientHeight +
|
||||
el.querySelector('footer')!.clientHeight +
|
||||
el.querySelector('.app-toolbar')!.clientHeight +
|
||||
24; // fudge margin
|
||||
}
|
||||
|
||||
|
@ -375,7 +375,7 @@ export class AppComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
|
||||
doSearch(query) {
|
||||
doSearch(query: string) {
|
||||
this.searchResults = this.searchService.search(query);
|
||||
this.showSearchResults = !!query;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('AppModule', () => {
|
|||
});
|
||||
|
||||
it('should provide a list of eagerly-loaded embedded components', () => {
|
||||
const eagerSelector = Object.keys(componentsMap).find(selector => Array.isArray(componentsMap[selector]));
|
||||
const eagerSelector = Object.keys(componentsMap).find(selector => Array.isArray(componentsMap[selector]))!;
|
||||
const selectorCount = eagerSelector.split(',').length;
|
||||
|
||||
expect(eagerSelector).not.toBeNull();
|
||||
|
@ -34,7 +34,7 @@ describe('AppModule', () => {
|
|||
});
|
||||
|
||||
it('should provide a list of lazy-loaded embedded components', () => {
|
||||
const lazySelector = Object.keys(componentsMap).find(selector => selector.includes('code-example'));
|
||||
const lazySelector = Object.keys(componentsMap).find(selector => selector.includes('code-example'))!;
|
||||
const selectorCount = lazySelector.split(',').length;
|
||||
|
||||
expect(lazySelector).not.toBeNull();
|
||||
|
|
|
@ -2,5 +2,5 @@ export interface DocumentContents {
|
|||
/** The unique identifier for this document */
|
||||
id: string;
|
||||
/** The HTML to display in the doc viewer */
|
||||
contents: string;
|
||||
contents: string|null;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ describe('DocumentService', () => {
|
|||
});
|
||||
|
||||
it('should emit a document each time the location changes', () => {
|
||||
let latestDocument: DocumentContents;
|
||||
let latestDocument: DocumentContents|undefined;
|
||||
const doc0 = { contents: 'doc 0', id: 'initial/doc' };
|
||||
const doc1 = { contents: 'doc 1', id: 'new/doc' };
|
||||
const { docService, locationService } = getServices('initial/doc');
|
||||
|
@ -67,7 +67,7 @@ describe('DocumentService', () => {
|
|||
});
|
||||
|
||||
it('should emit the not-found document if the document is not found on the server', () => {
|
||||
let currentDocument: DocumentContents;
|
||||
let currentDocument: DocumentContents|undefined;
|
||||
const notFoundDoc = { id: FILE_NOT_FOUND_ID, contents: '<h1>Page Not Found</h1>' };
|
||||
const { docService } = getServices('missing/doc');
|
||||
docService.currentDocument.subscribe(doc => currentDocument = doc);
|
||||
|
@ -82,7 +82,7 @@ describe('DocumentService', () => {
|
|||
});
|
||||
|
||||
it('should emit a hard-coded not-found document if the not-found document is not found on the server', () => {
|
||||
let currentDocument: DocumentContents;
|
||||
let currentDocument: DocumentContents|undefined;
|
||||
const hardCodedNotFoundDoc = { contents: 'Document not found', id: FILE_NOT_FOUND_ID };
|
||||
const nextDoc = { contents: 'Next Doc', id: 'new/doc' };
|
||||
const { docService, locationService } = getServices(FILE_NOT_FOUND_ID);
|
||||
|
@ -99,7 +99,7 @@ describe('DocumentService', () => {
|
|||
});
|
||||
|
||||
it('should use a hard-coded error doc if the request fails (but not cache it)', () => {
|
||||
let latestDocument: DocumentContents;
|
||||
let latestDocument: DocumentContents|undefined;
|
||||
const doc1 = { contents: 'doc 1' };
|
||||
const doc2 = { contents: 'doc 2' };
|
||||
const { docService, locationService } = getServices('initial/doc');
|
||||
|
@ -107,7 +107,7 @@ describe('DocumentService', () => {
|
|||
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||
|
||||
httpMock.expectOne({}).flush(null, {status: 500, statusText: 'Server Error'});
|
||||
expect(latestDocument.id).toEqual(FETCHING_ERROR_ID);
|
||||
expect(latestDocument!.id).toEqual(FETCHING_ERROR_ID);
|
||||
|
||||
locationService.go('new/doc');
|
||||
httpMock.expectOne({}).flush(doc1);
|
||||
|
@ -119,14 +119,14 @@ describe('DocumentService', () => {
|
|||
});
|
||||
|
||||
it('should not crash the app if the response is invalid JSON', () => {
|
||||
let latestDocument: DocumentContents;
|
||||
let latestDocument: DocumentContents|undefined;
|
||||
const doc1 = { contents: 'doc 1' };
|
||||
const { docService, locationService } = getServices('initial/doc');
|
||||
|
||||
docService.currentDocument.subscribe(doc => latestDocument = doc);
|
||||
|
||||
httpMock.expectOne({}).flush('this is invalid JSON');
|
||||
expect(latestDocument.id).toEqual(FETCHING_ERROR_ID);
|
||||
expect(latestDocument!.id).toEqual(FETCHING_ERROR_ID);
|
||||
|
||||
locationService.go('new/doc');
|
||||
httpMock.expectOne({}).flush(doc1);
|
||||
|
@ -134,7 +134,7 @@ describe('DocumentService', () => {
|
|||
});
|
||||
|
||||
it('should not make a request to the server if the doc is in the cache already', () => {
|
||||
let latestDocument: DocumentContents;
|
||||
let latestDocument: DocumentContents|undefined;
|
||||
let subscription: Subscription;
|
||||
|
||||
const doc0 = { contents: 'doc 0' };
|
||||
|
|
|
@ -52,7 +52,7 @@ export class DocumentService {
|
|||
if ( !this.cache.has(id)) {
|
||||
this.cache.set(id, this.fetchDocument(id));
|
||||
}
|
||||
return this.cache.get(id);
|
||||
return this.cache.get(id)!;
|
||||
}
|
||||
|
||||
private fetchDocument(id: string): Observable<DocumentContents> {
|
||||
|
|
|
@ -127,9 +127,9 @@ describe('EmbedComponentsService', () => {
|
|||
const componentRefs = service.createComponents(host);
|
||||
componentRefs[0].changeDetectorRef.detectChanges();
|
||||
|
||||
const barEl = host.querySelector('aio-eager-bar');
|
||||
const barEl = host.querySelector('aio-eager-bar')!;
|
||||
|
||||
expect(barEl['aioEagerBarContent']).toBe(projectedContent);
|
||||
expect((barEl as any)['aioEagerBarContent']).toBe(projectedContent);
|
||||
expect(barEl.innerHTML).toContain(projectedContent);
|
||||
});
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ export class EmbedComponentsService {
|
|||
// Hack: Preserve the current element content, because the factory will empty it out.
|
||||
// Security: The source of this `innerHTML` should always be authored by the documentation
|
||||
// team and is considered to be safe.
|
||||
host[contentPropertyName] = host.innerHTML;
|
||||
(host as any)[contentPropertyName] = host.innerHTML;
|
||||
componentRefs.push(factory.create(this.injector, [], host));
|
||||
}
|
||||
});
|
||||
|
@ -141,7 +141,7 @@ export class EmbedComponentsService {
|
|||
this.componentFactoriesReady.set(compsOrPath, readyPromise);
|
||||
}
|
||||
|
||||
return this.componentFactoriesReady.get(compsOrPath);
|
||||
return this.componentFactoriesReady.get(compsOrPath)!;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('ApiListComponent', () => {
|
|||
*/
|
||||
function expectFilteredResult(label: string, itemTest: (item: ApiItem) => boolean) {
|
||||
component.filteredSections.subscribe(filtered => {
|
||||
let badItem: ApiItem;
|
||||
let badItem: ApiItem|undefined;
|
||||
expect(filtered.length).toBeGreaterThan(0, 'expected something');
|
||||
expect(filtered.every(section => section.items.every(
|
||||
item => {
|
||||
|
@ -53,7 +53,7 @@ describe('ApiListComponent', () => {
|
|||
});
|
||||
|
||||
it('should return all complete sections when no criteria', () => {
|
||||
let filtered: ApiSection[];
|
||||
let filtered: ApiSection[]|undefined;
|
||||
component.filteredSections.subscribe(f => filtered = f);
|
||||
expect(filtered).toEqual(sections);
|
||||
});
|
||||
|
@ -68,7 +68,7 @@ describe('ApiListComponent', () => {
|
|||
component.filteredSections.subscribe(filtered => {
|
||||
expect(filtered.length).toBe(1, 'only one section');
|
||||
expect(filtered[0].name).toBe('core');
|
||||
expect(filtered[0].items.every(item => item.show)).toBe(true, 'all core items shown');
|
||||
expect(filtered[0].items.every(item => !!item.show)).toBe(true, 'all core items shown');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ describe('ApiService', () => {
|
|||
let completed = false;
|
||||
|
||||
service.sections.subscribe(
|
||||
null,
|
||||
null,
|
||||
undefined,
|
||||
undefined,
|
||||
() => completed = true
|
||||
);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ export class CodeExampleComponent implements OnInit {
|
|||
const element: HTMLElement = this.elementRef.nativeElement;
|
||||
|
||||
this.language = element.getAttribute('language') || '';
|
||||
this.linenums = element.getAttribute('linenums');
|
||||
this.linenums = element.getAttribute('linenums') || '';
|
||||
this.path = element.getAttribute('path') || '';
|
||||
this.region = element.getAttribute('region') || '';
|
||||
this.title = element.getAttribute('title') || '';
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
import { Component, ElementRef, OnInit } from '@angular/core';
|
||||
|
||||
export interface TabInfo {
|
||||
class: string;
|
||||
class: string|null;
|
||||
code: string;
|
||||
language: string;
|
||||
language: string|null;
|
||||
linenums: any;
|
||||
path: string;
|
||||
region: string;
|
||||
title: string;
|
||||
title: string|null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,8 +36,8 @@ describe('CodeComponent', () => {
|
|||
// we take strict measures to wipe it out in the `afterAll`
|
||||
// and make sure THAT runs after the tests by making component creation async
|
||||
afterAll(() => {
|
||||
delete window['prettyPrint'];
|
||||
delete window['prettyPrintOne'];
|
||||
delete (window as any)['prettyPrint'];
|
||||
delete (window as any)['prettyPrintOne'];
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -170,7 +170,7 @@ export class CodeComponent implements OnChanges {
|
|||
}
|
||||
}
|
||||
|
||||
function leftAlign(text) {
|
||||
function leftAlign(text: string) {
|
||||
let indent = Number.MAX_VALUE;
|
||||
const lines = text.split('\n');
|
||||
lines.forEach(line => {
|
||||
|
|
|
@ -7,7 +7,9 @@ import 'rxjs/add/operator/first';
|
|||
|
||||
import { Logger } from 'app/shared/logger.service';
|
||||
|
||||
declare const System;
|
||||
declare const System: {
|
||||
import(name: string): Promise<any>;
|
||||
};
|
||||
|
||||
type PrettyPrintOne = (code: string, language?: string, linenums?: number | boolean) => string;
|
||||
|
||||
|
@ -24,12 +26,12 @@ export class PrettyPrinter {
|
|||
}
|
||||
|
||||
private getPrettyPrintOne(): Promise<PrettyPrintOne> {
|
||||
const ppo = window['prettyPrintOne'];
|
||||
const ppo = (window as any)['prettyPrintOne'];
|
||||
return ppo ? Promise.resolve(ppo) :
|
||||
// prettify.js is not in window global; load it with webpack loader
|
||||
System.import('assets/js/prettify.js')
|
||||
.then(
|
||||
() => window['prettyPrintOne'],
|
||||
() => (window as any)['prettyPrintOne'],
|
||||
err => {
|
||||
const msg = 'Cannot get prettify.js from server';
|
||||
this.logger.error(msg, err);
|
||||
|
|
|
@ -38,7 +38,7 @@ export class ContributorListComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
selectGroup(name) {
|
||||
selectGroup(name: string) {
|
||||
name = name.toLowerCase();
|
||||
this.selectedGroup = this.groups.find(g => g.name.toLowerCase() === name) || this.groups[0];
|
||||
this.locationService.setSearch('', {group: this.selectedGroup.name});
|
||||
|
|
|
@ -40,7 +40,7 @@ export class ContributorComponent {
|
|||
noPicture = '_no-one.png';
|
||||
pictureBase = CONTENT_URL_PREFIX + 'images/bios/';
|
||||
|
||||
flipCard(person) {
|
||||
flipCard(person: Contributor) {
|
||||
person.isFlipped = !person.isFlipped;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ describe('ContributorService', () => {
|
|||
|
||||
it('contributors observable should complete', () => {
|
||||
let completed = false;
|
||||
contribService.contributors.subscribe(null, null, () => completed = true);
|
||||
contribService.contributors.subscribe(undefined, undefined, () => completed = true);
|
||||
expect(true).toBe(true, 'observable completed');
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ export class ContributorService {
|
|||
const contributors = this.http.get<{[key: string]: Contributor}>(contributorsPath)
|
||||
// Create group map
|
||||
.map(contribs => {
|
||||
const contribMap = new Map<string, Contributor[]>();
|
||||
const contribMap: { [name: string]: Contributor[]} = {};
|
||||
Object.keys(contribs).forEach(key => {
|
||||
const contributor = contribs[key];
|
||||
const group = contributor.group;
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('LiveExampleComponent', () => {
|
|||
let liveExampleComponent: LiveExampleComponent;
|
||||
let fixture: ComponentFixture<HostComponent>;
|
||||
let testPath: string;
|
||||
let liveExampleContent: string;
|
||||
let liveExampleContent: string|null;
|
||||
|
||||
//////// test helpers ////////
|
||||
|
||||
|
@ -66,7 +66,7 @@ describe('LiveExampleComponent', () => {
|
|||
.overrideComponent(EmbeddedPlunkerComponent, {set: {template: 'NO IFRAME'}});
|
||||
|
||||
testPath = defaultTestPath;
|
||||
liveExampleContent = undefined;
|
||||
liveExampleContent = null;
|
||||
});
|
||||
|
||||
describe('when not embedded', () => {
|
||||
|
|
|
@ -94,7 +94,7 @@ export class LiveExampleComponent implements OnInit {
|
|||
let exampleDir = attrs.name;
|
||||
if (!exampleDir) {
|
||||
// take last segment, excluding hash fragment and query params
|
||||
exampleDir = location.path(false).match(/[^\/?\#]+(?=\/?(?:$|\#|\?))/)[0];
|
||||
exampleDir = (location.path(false).match(/[^\/?\#]+(?=\/?(?:$|\#|\?))/) || [])[0];
|
||||
}
|
||||
this.exampleDir = exampleDir.trim();
|
||||
this.zipName = exampleDir.indexOf('/') === -1 ? this.exampleDir : exampleDir.split('/')[0];
|
||||
|
@ -150,7 +150,7 @@ export class LiveExampleComponent implements OnInit {
|
|||
}
|
||||
|
||||
@HostListener('window:resize', ['$event.target.innerWidth'])
|
||||
onResize(width) {
|
||||
onResize(width: number) {
|
||||
if (this.mode !== 'downloadOnly') {
|
||||
this.calcPlnkrLink(width);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ describe('ResourceService', () => {
|
|||
|
||||
it('categories observable should complete', () => {
|
||||
let completed = false;
|
||||
resourceService.categories.subscribe(null, null, () => completed = true);
|
||||
resourceService.categories.subscribe(undefined, undefined, () => completed = true);
|
||||
expect(true).toBe(true, 'observable completed');
|
||||
});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ describe('DocViewerComponent', () => {
|
|||
describe('#doc', () => {
|
||||
let renderSpy: jasmine.Spy;
|
||||
|
||||
const setCurrentDoc = (contents, id = 'fizz/buzz') => {
|
||||
const setCurrentDoc = (contents: string|null, id = 'fizz/buzz') => {
|
||||
parentComponent.currentDoc = {contents, id};
|
||||
parentFixture.detectChanges();
|
||||
};
|
||||
|
@ -432,7 +432,7 @@ describe('DocViewerComponent', () => {
|
|||
});
|
||||
|
||||
it('should store the embedded components', async () => {
|
||||
const embeddedComponents = [];
|
||||
const embeddedComponents: ComponentRef<any>[] = [];
|
||||
embedIntoSpy.and.returnValue(of(embeddedComponents));
|
||||
|
||||
await doRender('Some content');
|
||||
|
@ -678,7 +678,7 @@ describe('DocViewerComponent', () => {
|
|||
describe(`(.${NO_ANIMATIONS}: ${noAnimations})`, () => {
|
||||
beforeEach(() => docViewerEl.classList[noAnimations ? 'add' : 'remove'](NO_ANIMATIONS));
|
||||
|
||||
it('should return an observable', done => {
|
||||
it('should return an observable', (done: DoneFn) => {
|
||||
docViewer.swapViews().subscribe(done, done.fail);
|
||||
});
|
||||
|
||||
|
|
|
@ -114,12 +114,12 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
|
|||
const hasToc = !!titleEl && !/no-?toc/i.test(titleEl.className);
|
||||
|
||||
if (hasToc) {
|
||||
titleEl.insertAdjacentHTML('afterend', '<aio-toc class="embedded"></aio-toc>');
|
||||
titleEl!.insertAdjacentHTML('afterend', '<aio-toc class="embedded"></aio-toc>');
|
||||
}
|
||||
|
||||
return () => {
|
||||
this.tocService.reset();
|
||||
let title = '';
|
||||
let title: string|null = '';
|
||||
|
||||
// Only create ToC for docs with an `<h1>` heading.
|
||||
// If you don't want a ToC, add "no-toc" class to `<h1>`.
|
||||
|
@ -169,7 +169,7 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
|
|||
* entering animation has been completed. This is useful for work that needs to be done as soon as
|
||||
* the element has been attached to the DOM.
|
||||
*/
|
||||
protected swapViews(onInsertedCb = () => undefined): Observable<void> {
|
||||
protected swapViews(onInsertedCb = () => {}): Observable<void> {
|
||||
const raf$ = new Observable<void>(subscriber => {
|
||||
const rafId = requestAnimationFrame(() => {
|
||||
subscriber.next();
|
||||
|
@ -182,15 +182,18 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
|
|||
// According to the [CSSOM spec](https://drafts.csswg.org/cssom/#serializing-css-values),
|
||||
// `time` values should be returned in seconds.
|
||||
const getActualDuration = (elem: HTMLElement) => {
|
||||
const cssValue = getComputedStyle(elem).transitionDuration;
|
||||
const cssValue = getComputedStyle(elem).transitionDuration || '';
|
||||
const seconds = Number(cssValue.replace(/s$/, ''));
|
||||
return 1000 * seconds;
|
||||
};
|
||||
const animateProp =
|
||||
(elem: HTMLElement, prop: string, from: string, to: string, duration = 200) => {
|
||||
(elem: HTMLElement, prop: keyof CSSStyleDeclaration, from: string, to: string, duration = 200) => {
|
||||
const animationsDisabled = !DocViewerComponent.animationsEnabled
|
||||
|| this.hostElement.classList.contains(NO_ANIMATIONS);
|
||||
|
||||
if (prop === 'length' || prop === 'parentRule') {
|
||||
// We cannot animate length or parentRule properties because they are readonly
|
||||
return this.void$;
|
||||
}
|
||||
elem.style.transition = '';
|
||||
return animationsDisabled
|
||||
? this.void$.do(() => elem.style[prop] = to)
|
||||
|
@ -201,7 +204,7 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
|
|||
// setting each style.
|
||||
.switchMap(() => raf$).do(() => elem.style[prop] = from)
|
||||
.switchMap(() => raf$).do(() => elem.style.transition = `all ${duration}ms ease-in-out`)
|
||||
.switchMap(() => raf$).do(() => elem.style[prop] = to)
|
||||
.switchMap(() => raf$).do(() => (elem.style as any)[prop] = to)
|
||||
.switchMap(() => timer(getActualDuration(elem))).switchMap(() => this.void$);
|
||||
};
|
||||
|
||||
|
@ -214,7 +217,7 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
|
|||
done$ = done$
|
||||
// Remove the current view from the viewer.
|
||||
.switchMap(() => animateLeave(this.currViewContainer))
|
||||
.do(() => this.currViewContainer.parentElement.removeChild(this.currViewContainer))
|
||||
.do(() => this.currViewContainer.parentElement!.removeChild(this.currViewContainer))
|
||||
.do(() => this.docRemoved.emit());
|
||||
}
|
||||
|
||||
|
|
|
@ -73,18 +73,18 @@ describe('TocComponent', () => {
|
|||
it('should update when the TocItems are updated', () => {
|
||||
tocService.tocList.next([tocItem('Heading A')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAllNodes(By.css('li')).length).toBe(1);
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
|
||||
tocService.tocList.next([tocItem('Heading A'), tocItem('Heading B'), tocItem('Heading C')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAllNodes(By.css('li')).length).toBe(3);
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(3);
|
||||
});
|
||||
|
||||
it('should only display H2 and H3 TocItems', () => {
|
||||
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C', 'h3')]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const tocItems = tocComponentDe.queryAllNodes(By.css('li'));
|
||||
const tocItems = tocComponentDe.queryAll(By.css('li'));
|
||||
const textContents = tocItems.map(item => item.nativeNode.textContent.trim());
|
||||
|
||||
expect(tocItems.length).toBe(2);
|
||||
|
@ -97,12 +97,12 @@ describe('TocComponent', () => {
|
|||
it('should stop listening for TocItems once destroyed', () => {
|
||||
tocService.tocList.next([tocItem('Heading A')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAllNodes(By.css('li')).length).toBe(1);
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
|
||||
tocComponent.ngOnDestroy();
|
||||
tocService.tocList.next([tocItem('Heading A', 'h1'), tocItem('Heading B'), tocItem('Heading C')]);
|
||||
fixture.detectChanges();
|
||||
expect(tocComponentDe.queryAllNodes(By.css('li')).length).toBe(1);
|
||||
expect(tocComponentDe.queryAll(By.css('li')).length).toBe(1);
|
||||
});
|
||||
|
||||
describe('when fewer than `maxPrimary` TocItems', () => {
|
||||
|
@ -339,7 +339,7 @@ describe('TocComponent', () => {
|
|||
|
||||
it('should re-apply the `active` class when the list elements change', () => {
|
||||
const getActiveTextContent = () =>
|
||||
page.listItems.find(By.css('.active')).nativeElement.textContent.trim();
|
||||
page.listItems.find(By.css('.active'))!.nativeElement.textContent.trim();
|
||||
|
||||
tocComponent.activeIndex = 1;
|
||||
fixture.detectChanges();
|
||||
|
@ -462,7 +462,7 @@ class TestScrollService {
|
|||
class TestTocService {
|
||||
tocList = new BehaviorSubject<TocItem[]>(getTestTocList());
|
||||
activeItemIndex = new BehaviorSubject<number | null>(null);
|
||||
setActiveIndex(index) {
|
||||
setActiveIndex(index: number|null) {
|
||||
this.activeItemIndex.next(index);
|
||||
if (asap.scheduled) {
|
||||
asap.flush();
|
||||
|
|
|
@ -93,6 +93,6 @@ export class TocComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
function count<T>(array: T[], fn: (T) => boolean) {
|
||||
function count<T>(array: T[], fn: (item: T) => boolean) {
|
||||
return array.reduce((count, item) => fn(item) ? count + 1 : count, 0);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('NavigationService', () => {
|
|||
|
||||
it('navigationViews observable should complete', () => {
|
||||
let completed = false;
|
||||
navService.navigationViews.subscribe(null, null, () => completed = true);
|
||||
navService.navigationViews.subscribe(undefined, undefined, () => completed = true);
|
||||
expect(true).toBe(true, 'observable completed');
|
||||
|
||||
// Stop `$httpMock.verify()` from complaining.
|
||||
|
@ -53,15 +53,15 @@ describe('NavigationService', () => {
|
|||
});
|
||||
|
||||
it('should return the same object to all subscribers', () => {
|
||||
let views1: NavigationViews;
|
||||
let views1: NavigationViews|undefined;
|
||||
navService.navigationViews.subscribe(views => views1 = views);
|
||||
|
||||
let views2: NavigationViews;
|
||||
let views2: NavigationViews|undefined;
|
||||
navService.navigationViews.subscribe(views => views2 = views);
|
||||
|
||||
httpMock.expectOne({}).flush({ TopBar: [{ url: 'a' }] });
|
||||
|
||||
let views3: NavigationViews;
|
||||
let views3: NavigationViews|undefined;
|
||||
navService.navigationViews.subscribe(views => views3 = views);
|
||||
|
||||
expect(views2).toBe(views1);
|
||||
|
@ -143,7 +143,7 @@ describe('NavigationService', () => {
|
|||
url: 'b',
|
||||
view: 'SideNav',
|
||||
nodes: [
|
||||
sideNavNodes[0].children[0],
|
||||
sideNavNodes[0].children![0],
|
||||
sideNavNodes[0]
|
||||
]
|
||||
}
|
||||
|
@ -155,8 +155,8 @@ describe('NavigationService', () => {
|
|||
url: 'd',
|
||||
view: 'SideNav',
|
||||
nodes: [
|
||||
sideNavNodes[0].children[0].children[1],
|
||||
sideNavNodes[0].children[0],
|
||||
sideNavNodes[0].children![0].children![1],
|
||||
sideNavNodes[0].children![0],
|
||||
sideNavNodes[0]
|
||||
]
|
||||
}
|
||||
|
@ -200,8 +200,8 @@ describe('NavigationService', () => {
|
|||
url: 'c',
|
||||
view: 'SideNav',
|
||||
nodes: [
|
||||
sideNavNodes[0].children[0].children[0],
|
||||
sideNavNodes[0].children[0],
|
||||
sideNavNodes[0].children![0].children![0],
|
||||
sideNavNodes[0].children![0],
|
||||
sideNavNodes[0]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ export class NavigationService {
|
|||
|
||||
(navMap, url) => {
|
||||
const urlKey = url.startsWith('api/') ? 'api' : url;
|
||||
return navMap[urlKey] || { '' : { view: '', url: urlKey, nodes: [] }};
|
||||
return navMap.get(urlKey) || { '' : { view: '', url: urlKey, nodes: [] }};
|
||||
})
|
||||
.publishReplay(1);
|
||||
currentNodes.connect();
|
||||
|
@ -145,7 +145,10 @@ export class NavigationService {
|
|||
if (url) {
|
||||
// Strip off trailing slashes from nodes in the navMap - they are not relevant to matching
|
||||
const cleanedUrl = url.replace(/\/$/, '');
|
||||
const navMapItem = navMap[cleanedUrl] = navMap[cleanedUrl] || {};
|
||||
if (!navMap.has(cleanedUrl)) {
|
||||
navMap.set(cleanedUrl, {});
|
||||
}
|
||||
const navMapItem = navMap.get(cleanedUrl)!;
|
||||
navMapItem[view] = { url, view, nodes };
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ describe('SearchService', () => {
|
|||
|
||||
it('should push the response to the returned observable', () => {
|
||||
const mockSearchResults = { results: ['a', 'b'] };
|
||||
let actualSearchResults;
|
||||
let actualSearchResults: any;
|
||||
(mockWorker.sendMessage as jasmine.Spy).and.returnValue(Observable.of(mockSearchResults));
|
||||
service.search('some query').subscribe(results => actualSearchResults = results);
|
||||
expect(actualSearchResults).toEqual(mockSearchResults);
|
||||
|
|
|
@ -8,29 +8,26 @@ describe('Attribute Utilities', () => {
|
|||
beforeEach(() => {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = `<div a b="true" c="false" D="foo" d-E></div>`;
|
||||
testEl = div.querySelector('div');
|
||||
testEl = div.querySelector('div')!;
|
||||
});
|
||||
|
||||
describe('getAttrs', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
this.expectedMap = {
|
||||
const expectedMap = {
|
||||
a: '',
|
||||
b: 'true',
|
||||
c: 'false',
|
||||
d: 'foo',
|
||||
'd-e': ''
|
||||
};
|
||||
});
|
||||
|
||||
it('should get attr map from getAttrs(element)', () => {
|
||||
const actual = getAttrs(testEl);
|
||||
expect(actual).toEqual(this.expectedMap);
|
||||
expect(actual).toEqual(expectedMap);
|
||||
});
|
||||
|
||||
it('should get attr map from getAttrs(elementRef)', () => {
|
||||
const actual = getAttrs(new ElementRef(testEl));
|
||||
expect(actual).toEqual(this.expectedMap);
|
||||
expect(actual).toEqual(expectedMap);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ interface StringMap { [index: string]: string; }
|
|||
*/
|
||||
export function getAttrs(el: HTMLElement | ElementRef): StringMap {
|
||||
const attrs: NamedNodeMap = el instanceof ElementRef ? el.nativeElement.attributes : el.attributes;
|
||||
const attrMap = {};
|
||||
const attrMap: StringMap = {};
|
||||
for (const attr of attrs as any /* cast due to https://github.com/Microsoft/TypeScript/issues/2695 */) {
|
||||
attrMap[attr.name.toLowerCase()] = attr.value;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ export function getAttrs(el: HTMLElement | ElementRef): StringMap {
|
|||
export function getAttrValue(attrs: StringMap, attr: string | string[] = ''): string {
|
||||
return attrs[typeof attr === 'string' ?
|
||||
attr.toLowerCase() :
|
||||
attr.find(a => attrs[a.toLowerCase()] !== undefined)
|
||||
attr.find(a => attrs[a.toLowerCase()] !== undefined) || ''
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ export function getAttrValue(attrs: StringMap, attr: string | string[] = ''): st
|
|||
* @param attrValue The string value of some attribute (or undefined if attribute not present)
|
||||
* @param def Default boolean value when attribute is undefined.
|
||||
*/
|
||||
export function boolFromValue(attrValue: string, def: boolean = false) {
|
||||
export function boolFromValue(attrValue: string|undefined, def: boolean = false) {
|
||||
// tslint:disable-next-line:triple-equals
|
||||
return attrValue == undefined ? def : attrValue.trim() !== 'false';
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
|
||||
export class CopierService {
|
||||
private fakeElem: HTMLTextAreaElement;
|
||||
private fakeElem: HTMLTextAreaElement|null;
|
||||
|
||||
/**
|
||||
* Creates a fake textarea element, sets its value from `text` property,
|
||||
|
|
|
@ -11,7 +11,7 @@ describe('CustomIconRegistry', () => {
|
|||
{ name: 'test_icon', svgSource: svgSrc }
|
||||
];
|
||||
const registry = new CustomIconRegistry(mockHttp, mockSanitizer, svgIcons);
|
||||
let svgElement: SVGElement;
|
||||
let svgElement: SVGElement|undefined;
|
||||
registry.getNamedSvgIcon('test_icon').subscribe(el => svgElement = el);
|
||||
expect(svgElement).toEqual(createSvg(svgSrc));
|
||||
});
|
||||
|
@ -36,8 +36,8 @@ describe('CustomIconRegistry', () => {
|
|||
});
|
||||
});
|
||||
|
||||
function createSvg(svgSrc) {
|
||||
function createSvg(svgSrc: string): SVGElement {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = svgSrc;
|
||||
return div.querySelector('svg');
|
||||
return div.querySelector('svg')!;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ export class CustomIconRegistry extends MatIconRegistry {
|
|||
svgIcons.forEach(icon => {
|
||||
// SECURITY: the source for the SVG icons is provided in code by trusted developers
|
||||
div.innerHTML = icon.svgSource;
|
||||
this.preloadedSvgElements[icon.name] = div.querySelector('svg');
|
||||
this.preloadedSvgElements[icon.name] = div.querySelector('svg')!;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ export class GaService {
|
|||
this.ga('send', 'pageview');
|
||||
}
|
||||
|
||||
ga(...args) {
|
||||
this.window['ga'](...args);
|
||||
ga(...args: any[]) {
|
||||
(this.window as any)['ga'](...args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ describe('LocationService', () => {
|
|||
location.simulatePopState('/next-url2');
|
||||
location.simulatePopState('/next-url3');
|
||||
|
||||
let initialUrl;
|
||||
let initialUrl: string|undefined;
|
||||
service.currentUrl.subscribe(url => initialUrl = url);
|
||||
expect(initialUrl).toEqual('next-url3');
|
||||
});
|
||||
|
@ -49,7 +49,7 @@ describe('LocationService', () => {
|
|||
location.simulatePopState('/initial-url2');
|
||||
location.simulatePopState('/initial-url3');
|
||||
|
||||
const urls = [];
|
||||
const urls: string[] = [];
|
||||
service.currentUrl.subscribe(url => urls.push(url));
|
||||
|
||||
location.simulatePopState('/next-url1');
|
||||
|
@ -69,13 +69,13 @@ describe('LocationService', () => {
|
|||
location.simulatePopState('/initial-url2');
|
||||
location.simulatePopState('/initial-url3');
|
||||
|
||||
const urls1 = [];
|
||||
const urls1: string[] = [];
|
||||
service.currentUrl.subscribe(url => urls1.push(url));
|
||||
|
||||
location.simulatePopState('/next-url1');
|
||||
location.simulatePopState('/next-url2');
|
||||
|
||||
const urls2 = [];
|
||||
const urls2: string[] = [];
|
||||
service.currentUrl.subscribe(url => urls2.push(url));
|
||||
|
||||
location.simulatePopState('/next-url3');
|
||||
|
@ -150,7 +150,7 @@ describe('LocationService', () => {
|
|||
});
|
||||
|
||||
it('should strip the query off the url', () => {
|
||||
let path: string;
|
||||
let path: string|undefined;
|
||||
|
||||
service.currentPath.subscribe(p => path = p);
|
||||
|
||||
|
@ -182,7 +182,7 @@ describe('LocationService', () => {
|
|||
location.simulatePopState('/next/url2');
|
||||
location.simulatePopState('/next/url3');
|
||||
|
||||
let initialPath: string;
|
||||
let initialPath: string|undefined;
|
||||
service.currentPath.subscribe(path => initialPath = path);
|
||||
|
||||
expect(initialPath).toEqual('next/url3');
|
||||
|
@ -247,7 +247,7 @@ describe('LocationService', () => {
|
|||
});
|
||||
|
||||
it('should emit the new url', () => {
|
||||
const urls = [];
|
||||
const urls: string[] = [];
|
||||
service.go('some-initial-url');
|
||||
|
||||
service.currentUrl.subscribe(url => urls.push(url));
|
||||
|
@ -259,7 +259,7 @@ describe('LocationService', () => {
|
|||
});
|
||||
|
||||
it('should strip leading and trailing slashes', () => {
|
||||
let url: string;
|
||||
let url: string|undefined;
|
||||
|
||||
service.currentUrl.subscribe(u => url = u);
|
||||
service.go('/some/url/');
|
||||
|
@ -269,23 +269,18 @@ describe('LocationService', () => {
|
|||
expect(url).toBe('some/url');
|
||||
});
|
||||
|
||||
it('should ignore undefined URL string', noUrlTest(undefined));
|
||||
it('should ignore null URL string', noUrlTest(null));
|
||||
it('should ignore empty URL string', noUrlTest(''));
|
||||
function noUrlTest(testUrl: string) {
|
||||
return function() {
|
||||
it('should ignore empty URL string', () => {
|
||||
const initialUrl = 'some/url';
|
||||
const goExternalSpy = spyOn(service, 'goExternal');
|
||||
let url: string;
|
||||
let url: string|undefined;
|
||||
|
||||
service.go(initialUrl);
|
||||
service.currentUrl.subscribe(u => url = u);
|
||||
|
||||
service.go(testUrl);
|
||||
service.go('');
|
||||
expect(url).toEqual(initialUrl, 'should not have re-navigated locally');
|
||||
expect(goExternalSpy).not.toHaveBeenCalled();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
it('should leave the site for external url that starts with "http"', () => {
|
||||
const goExternalSpy = spyOn(service, 'goExternal');
|
||||
|
@ -310,7 +305,7 @@ describe('LocationService', () => {
|
|||
});
|
||||
|
||||
it('should not update currentUrl for external url that starts with "http"', () => {
|
||||
let localUrl: string;
|
||||
let localUrl: string|undefined;
|
||||
spyOn(service, 'goExternal');
|
||||
service.currentUrl.subscribe(url => localUrl = url);
|
||||
service.go('https://some/far/away/land');
|
||||
|
|
|
@ -18,7 +18,7 @@ export class LocationService {
|
|||
.map(url => this.stripSlashes(url));
|
||||
|
||||
currentPath = this.currentUrl
|
||||
.map(url => url.match(/[^?#]*/)[0]) // strip query and hash
|
||||
.map(url => (url.match(/[^?#]*/) || [])[0]) // strip query and hash
|
||||
.do(path => this.gaService.locationChanged(path));
|
||||
|
||||
constructor(
|
||||
|
@ -30,14 +30,14 @@ export class LocationService {
|
|||
this.urlSubject.next(location.path(true));
|
||||
|
||||
this.location.subscribe(state => {
|
||||
return this.urlSubject.next(state.url);
|
||||
return this.urlSubject.next(state.url || '');
|
||||
});
|
||||
|
||||
swUpdates.updateActivated.subscribe(() => this.swUpdateActivated = true);
|
||||
}
|
||||
|
||||
// TODO?: ignore if url-without-hash-or-search matches current location?
|
||||
go(url: string) {
|
||||
go(url: string|null|undefined) {
|
||||
if (!url) { return; }
|
||||
url = this.stripSlashes(url);
|
||||
if (/^http/.test(url) || this.swUpdateActivated) {
|
||||
|
@ -62,8 +62,8 @@ export class LocationService {
|
|||
return url.replace(/^\/+/, '').replace(/\/+(\?|#|$)/, '$1');
|
||||
}
|
||||
|
||||
search(): { [index: string]: string; } {
|
||||
const search = {};
|
||||
search() {
|
||||
const search: { [index: string]: string|undefined; } = {};
|
||||
const path = this.location.path();
|
||||
const q = path.indexOf('?');
|
||||
if (q > -1) {
|
||||
|
@ -80,11 +80,10 @@ export class LocationService {
|
|||
return search;
|
||||
}
|
||||
|
||||
setSearch(label: string, params: {}) {
|
||||
setSearch(label: string, params: { [key: string]: string|undefined}) {
|
||||
const search = Object.keys(params).reduce((acc, key) => {
|
||||
const value = params[key];
|
||||
// tslint:disable-next-line:triple-equals
|
||||
return value == undefined ? acc :
|
||||
return (value === undefined) ? acc :
|
||||
acc += (acc ? '&' : '?') + `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
||||
}, '');
|
||||
|
||||
|
|
|
@ -5,17 +5,17 @@ import { environment } from '../../environments/environment';
|
|||
@Injectable()
|
||||
export class Logger {
|
||||
|
||||
log(value: any, ...rest) {
|
||||
log(value: any, ...rest: any[]) {
|
||||
if (!environment.production) {
|
||||
console.log(value, ...rest);
|
||||
}
|
||||
}
|
||||
|
||||
error(value: any, ...rest) {
|
||||
error(value: any, ...rest: any[]) {
|
||||
console.error(value, ...rest);
|
||||
}
|
||||
|
||||
warn(value: any, ...rest) {
|
||||
warn(value: any, ...rest: any[]) {
|
||||
console.warn(value, ...rest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,14 +60,15 @@ describe('ScrollSpiedElementGroup', () => {
|
|||
|
||||
describe('#onScroll()', () => {
|
||||
let group: ScrollSpiedElementGroup;
|
||||
let activeItems: ScrollItem[];
|
||||
let activeItems: (ScrollItem|null)[];
|
||||
|
||||
const activeIndices = () => activeItems.map(x => x && x.index);
|
||||
|
||||
beforeEach(() => {
|
||||
const tops = [50, 150, 100];
|
||||
|
||||
spyOn(ScrollSpiedElement.prototype, 'calculateTop').and.callFake(function(scrollTop, topOffset) {
|
||||
spyOn(ScrollSpiedElement.prototype, 'calculateTop').and.callFake(
|
||||
function(this: ScrollSpiedElement, scrollTop: number, topOffset: number) {
|
||||
this.top = tops[this.index];
|
||||
});
|
||||
|
||||
|
@ -234,7 +235,7 @@ describe('ScrollSpyService', () => {
|
|||
|
||||
it('should remember and emit the last active item to new subscribers', () => {
|
||||
const items = [{index: 1}, {index: 2}, {index: 3}] as ScrollItem[];
|
||||
let lastActiveItem: ScrollItem | null;
|
||||
let lastActiveItem: ScrollItem|null;
|
||||
|
||||
const info = scrollSpyService.spyOn([]);
|
||||
const spiedElemGroup = getSpiedElemGroups()[0];
|
||||
|
@ -246,12 +247,12 @@ describe('ScrollSpyService', () => {
|
|||
spiedElemGroup.activeScrollItem.next(items[1]);
|
||||
info.active.subscribe(item => lastActiveItem = item);
|
||||
|
||||
expect(lastActiveItem).toBe(items[1]);
|
||||
expect(lastActiveItem!).toBe(items[1]);
|
||||
|
||||
spiedElemGroup.activeScrollItem.next(null);
|
||||
info.active.subscribe(item => lastActiveItem = item);
|
||||
|
||||
expect(lastActiveItem).toBeNull();
|
||||
expect(lastActiveItem!).toBeNull();
|
||||
});
|
||||
|
||||
it('should only emit distinct values on `active`', () => {
|
||||
|
|
|
@ -102,7 +102,7 @@ export class ScrollSpiedElementGroup {
|
|||
* @param {number} maxScrollTop - The maximum possible `scrollTop` (based on the viewport size).
|
||||
*/
|
||||
onScroll(scrollTop: number, maxScrollTop: number) {
|
||||
let activeItem: ScrollItem;
|
||||
let activeItem: ScrollItem|undefined;
|
||||
|
||||
if (scrollTop + 1 >= maxScrollTop) {
|
||||
activeItem = this.spiedElements[0];
|
||||
|
@ -112,6 +112,7 @@ export class ScrollSpiedElementGroup {
|
|||
activeItem = spiedElem;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ describe('ScrollService', () => {
|
|||
|
||||
const topOfPage = new MockElement();
|
||||
document.getElementById.and
|
||||
.callFake(id => id === 'top-of-page' ? topOfPage : null);
|
||||
.callFake((id: string) => id === 'top-of-page' ? topOfPage : null);
|
||||
|
||||
scrollService.scroll();
|
||||
expect(topOfPage.scrollIntoView).toHaveBeenCalled();
|
||||
|
@ -201,7 +201,7 @@ describe('ScrollService', () => {
|
|||
it('should scroll to top', () => {
|
||||
const topOfPageElement = <Element><any> new MockElement();
|
||||
document.getElementById.and.callFake(
|
||||
id => id === 'top-of-page' ? topOfPageElement : null
|
||||
(id: string) => id === 'top-of-page' ? topOfPageElement : null
|
||||
);
|
||||
|
||||
scrollService.scrollToTop();
|
||||
|
|
|
@ -20,7 +20,7 @@ export class ScrollService {
|
|||
const toolbar = this.document.querySelector('.app-toolbar');
|
||||
this._topOffset = (toolbar && toolbar.clientHeight || 0) + topMargin;
|
||||
}
|
||||
return this._topOffset;
|
||||
return this._topOffset!;
|
||||
}
|
||||
|
||||
get topOfPageElement() {
|
||||
|
@ -54,7 +54,7 @@ export class ScrollService {
|
|||
* Scroll to the element.
|
||||
* Don't scroll if no element.
|
||||
*/
|
||||
scrollToElement(element: Element) {
|
||||
scrollToElement(element: Element|null) {
|
||||
if (element) {
|
||||
element.scrollIntoView();
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ describe('SearchResultsComponent', () => {
|
|||
return take === undefined ? results : results.slice(0, take);
|
||||
}
|
||||
|
||||
function compareTitle(l: {title: string}, r: {title: string}) {
|
||||
return l.title.toUpperCase() > r.title.toUpperCase() ? 1 : -1;
|
||||
function compareTitle(l: SearchResult, r: SearchResult) {
|
||||
return l.title!.toUpperCase() > r.title!.toUpperCase() ? 1 : -1;
|
||||
}
|
||||
|
||||
function setSearchResults(query: string, results: SearchResult[]) {
|
||||
|
@ -117,7 +117,7 @@ describe('SearchResultsComponent', () => {
|
|||
|
||||
it('should omit search results with no title', () => {
|
||||
const results = [
|
||||
{ path: 'news', title: undefined, type: 'marketing', keywords: '', titleWords: '' }
|
||||
{ path: 'news', title: '', type: 'marketing', keywords: '', titleWords: '' }
|
||||
];
|
||||
|
||||
setSearchResults('something', results);
|
||||
|
@ -131,11 +131,11 @@ describe('SearchResultsComponent', () => {
|
|||
|
||||
describe('when a search result anchor is clicked', () => {
|
||||
let searchResult: SearchResult;
|
||||
let selected: SearchResult;
|
||||
let selected: SearchResult|null;
|
||||
let anchor: DebugElement;
|
||||
|
||||
beforeEach(() => {
|
||||
component.resultSelected.subscribe(result => selected = result);
|
||||
component.resultSelected.subscribe((result: SearchResult) => selected = result);
|
||||
|
||||
selected = null;
|
||||
searchResult = { path: 'news', title: 'News', type: 'marketing', keywords: '', titleWords: '' };
|
||||
|
|
|
@ -44,7 +44,7 @@ export class SearchResultsComponent implements OnChanges {
|
|||
return [];
|
||||
}
|
||||
this.notFoundMessage = 'No results found.';
|
||||
const searchAreaMap = {};
|
||||
const searchAreaMap: { [key: string]: SearchResult[] } = {};
|
||||
search.results.forEach(result => {
|
||||
if (!result.title) { return; } // bad data; should fix
|
||||
const areaName = this.computeAreaName(result) || this.defaultArea;
|
||||
|
|
|
@ -37,10 +37,10 @@ describe('SelectComponent', () => {
|
|||
|
||||
describe('button', () => {
|
||||
it('should display the label if provided', () => {
|
||||
expect(getButton().textContent.trim()).toEqual('');
|
||||
expect(getButton().textContent!.trim()).toEqual('');
|
||||
host.label = 'Label:';
|
||||
fixture.detectChanges();
|
||||
expect(getButton().textContent.trim()).toEqual('Label:');
|
||||
expect(getButton().textContent!.trim()).toEqual('Label:');
|
||||
});
|
||||
|
||||
it('should contain a symbol `<span>` if hasSymbol is true', () => {
|
||||
|
@ -49,7 +49,7 @@ describe('SelectComponent', () => {
|
|||
fixture.detectChanges();
|
||||
const span = getButton().querySelector('span');
|
||||
expect(span).not.toEqual(null);
|
||||
expect(span.className).toContain('symbol');
|
||||
expect(span!.className).toContain('symbol');
|
||||
});
|
||||
|
||||
it('should display the selected option, if there is one', () => {
|
||||
|
@ -57,7 +57,7 @@ describe('SelectComponent', () => {
|
|||
host.selected = options[0];
|
||||
fixture.detectChanges();
|
||||
expect(getButton().textContent).toContain(options[0].title);
|
||||
expect(getButton().querySelector('span').className).toContain(options[0].value);
|
||||
expect(getButton().querySelector('span')!.className).toContain(options[0].value);
|
||||
});
|
||||
|
||||
it('should toggle the visibility of the options list when clicked', () => {
|
||||
|
@ -90,7 +90,7 @@ describe('SelectComponent', () => {
|
|||
fixture.detectChanges();
|
||||
expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 });
|
||||
expect(getButton().textContent).toContain(options[0].title);
|
||||
expect(getButton().querySelector('span').className).toContain(options[0].value);
|
||||
expect(getButton().querySelector('span')!.className).toContain(options[0].value);
|
||||
});
|
||||
|
||||
it('should select the current option when enter is pressed', () => {
|
||||
|
@ -99,7 +99,7 @@ describe('SelectComponent', () => {
|
|||
fixture.detectChanges();
|
||||
expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 });
|
||||
expect(getButton().textContent).toContain(options[0].title);
|
||||
expect(getButton().querySelector('span').className).toContain(options[0].value);
|
||||
expect(getButton().querySelector('span')!.className).toContain(options[0].value);
|
||||
});
|
||||
|
||||
it('should select the current option when space is pressed', () => {
|
||||
|
@ -108,7 +108,7 @@ describe('SelectComponent', () => {
|
|||
fixture.detectChanges();
|
||||
expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 });
|
||||
expect(getButton().textContent).toContain(options[0].title);
|
||||
expect(getButton().querySelector('span').className).toContain(options[0].value);
|
||||
expect(getButton().querySelector('span')!.className).toContain(options[0].value);
|
||||
});
|
||||
|
||||
it('should hide when an option is clicked', () => {
|
||||
|
@ -155,7 +155,7 @@ function getButton(): HTMLButtonElement {
|
|||
return element.query(By.css('button')).nativeElement;
|
||||
}
|
||||
|
||||
function getOptionContainer(): HTMLUListElement {
|
||||
function getOptionContainer(): HTMLUListElement|null {
|
||||
const de = element.query(By.css('ul'));
|
||||
return de && de.nativeElement;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ describe('TocService', () => {
|
|||
it('should emit the latest value to new subscribers', () => {
|
||||
const expectedValue1 = tocItem('Heading A');
|
||||
const expectedValue2 = tocItem('Heading B');
|
||||
let value1: TocItem[];
|
||||
let value2: TocItem[];
|
||||
let value1: TocItem[]|undefined;
|
||||
let value2: TocItem[]|undefined;
|
||||
|
||||
tocService.tocList.next([]);
|
||||
tocService.tocList.subscribe(v => value1 = v);
|
||||
|
@ -235,22 +235,22 @@ describe('TocService', () => {
|
|||
});
|
||||
|
||||
it('should have href with docId and heading\'s id', () => {
|
||||
const tocItem = lastTocList.find(item => item.title === 'Heading one');
|
||||
const tocItem = lastTocList.find(item => item.title === 'Heading one')!;
|
||||
expect(tocItem.href).toEqual(`${docId}#heading-one-special-id`);
|
||||
});
|
||||
|
||||
it('should have level "h1" for an <h1>', () => {
|
||||
const tocItem = lastTocList.find(item => item.title === 'Fun with TOC');
|
||||
const tocItem = lastTocList.find(item => item.title === 'Fun with TOC')!;
|
||||
expect(tocItem.level).toEqual('h1');
|
||||
});
|
||||
|
||||
it('should have level "h2" for an <h2>', () => {
|
||||
const tocItem = lastTocList.find(item => item.title === 'Heading one');
|
||||
const tocItem = lastTocList.find(item => item.title === 'Heading one')!;
|
||||
expect(tocItem.level).toEqual('h2');
|
||||
});
|
||||
|
||||
it('should have level "h3" for an <h3>', () => {
|
||||
const tocItem = lastTocList.find(item => item.title === 'H3 3a');
|
||||
const tocItem = lastTocList.find(item => item.title === 'H3 3a')!;
|
||||
expect(tocItem.level).toEqual('h3');
|
||||
});
|
||||
|
||||
|
@ -273,7 +273,7 @@ describe('TocService', () => {
|
|||
});
|
||||
|
||||
it('should have href with docId and calculated heading id', () => {
|
||||
const tocItem = lastTocList.find(item => item.title === 'H2 Two');
|
||||
const tocItem = lastTocList.find(item => item.title === 'H2 Two')!;
|
||||
expect(tocItem.href).toEqual(`${docId}#h2-two`);
|
||||
});
|
||||
|
||||
|
@ -343,7 +343,7 @@ interface TestSafeHtml extends SafeHtml {
|
|||
|
||||
class TestDomSanitizer {
|
||||
bypassSecurityTrustHtml = jasmine.createSpy('bypassSecurityTrustHtml')
|
||||
.and.callFake(html => {
|
||||
.and.callFake((html: string) => {
|
||||
return {
|
||||
changingThisBreaksApplicationSecurity: html,
|
||||
getTypeName: () => 'HTML',
|
||||
|
|
|
@ -37,7 +37,7 @@ export class TocService {
|
|||
content: this.extractHeadingSafeHtml(heading),
|
||||
href: `${docId}#${this.getId(heading, idMap)}`,
|
||||
level: heading.tagName.toLowerCase(),
|
||||
title: heading.textContent.trim(),
|
||||
title: (heading.textContent || '').trim(),
|
||||
}));
|
||||
|
||||
this.tocList.next(tocList);
|
||||
|
@ -87,7 +87,7 @@ export class TocService {
|
|||
if (id) {
|
||||
addToMap(id);
|
||||
} else {
|
||||
id = h.textContent.trim().toLowerCase().replace(/\W+/g, '-');
|
||||
id = (h.textContent || '').trim().toLowerCase().replace(/\W+/g, '-');
|
||||
id = addToMap(id);
|
||||
h.id = id;
|
||||
}
|
||||
|
@ -95,7 +95,9 @@ export class TocService {
|
|||
|
||||
// Map guards against duplicate id creation.
|
||||
function addToMap(key: string) {
|
||||
const count = idMap[key] = idMap[key] ? idMap[key] + 1 : 1;
|
||||
const oldCount = idMap.get(key) || 0;
|
||||
const count = oldCount + 1;
|
||||
idMap.set(key, count);
|
||||
return count === 1 ? key : `${key}-${count}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('SwUpdatesService', () => {
|
|||
checkInterval = (service as any).checkInterval;
|
||||
};
|
||||
const tearDown = () => service.ngOnDestroy();
|
||||
const run = specFn => () => {
|
||||
const run = (specFn: VoidFunction) => () => {
|
||||
setup();
|
||||
specFn();
|
||||
tearDown();
|
||||
|
@ -90,7 +90,7 @@ describe('SwUpdatesService', () => {
|
|||
})));
|
||||
|
||||
it('should emit on `updateActivated` when an update has been activated', run(() => {
|
||||
const activatedVersions: string[] = [];
|
||||
const activatedVersions: (string|undefined)[] = [];
|
||||
service.updateActivated.subscribe(v => activatedVersions.push(v));
|
||||
|
||||
sw.$$updatesSubj.next({type: 'pending', version: 'foo'});
|
||||
|
@ -126,7 +126,7 @@ describe('SwUpdatesService', () => {
|
|||
})));
|
||||
|
||||
it('should stop emitting on `updateActivated`', run(() => {
|
||||
const activatedVersions: string[] = [];
|
||||
const activatedVersions: (string|undefined)[] = [];
|
||||
service.updateActivated.subscribe(v => activatedVersions.push(v));
|
||||
|
||||
sw.$$updatesSubj.next({type: 'pending', version: 'foo'});
|
||||
|
|
|
@ -51,7 +51,7 @@ export class SwUpdatesService implements OnDestroy {
|
|||
|
||||
private activateUpdate() {
|
||||
this.log('Activating update...');
|
||||
this.sw.activateUpdate(null)
|
||||
this.sw.activateUpdate(null as any) // expects a non-null string
|
||||
.subscribe(() => this.scheduleCheckForUpdate());
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ export class TestDocViewerComponent extends DocViewerComponent {
|
|||
template: '<aio-doc-viewer [doc]="currentDoc">Test Component</aio-doc-viewer>',
|
||||
})
|
||||
export class TestParentComponent {
|
||||
currentDoc: DocumentContents;
|
||||
currentDoc?: DocumentContents|null;
|
||||
@ViewChild(DocViewerComponent) docViewer: DocViewerComponent;
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ export class TestModule { }
|
|||
|
||||
export class ObservableWithSubscriptionSpies<T = void> extends Observable<T> {
|
||||
unsubscribeSpies: jasmine.Spy[] = [];
|
||||
subscribeSpy = spyOn(this, 'subscribe').and.callFake((...args) => {
|
||||
subscribeSpy = spyOn(this, 'subscribe').and.callFake((...args: any[]) => {
|
||||
const subscription = super.subscribe(...args);
|
||||
const unsubscribeSpy = spyOn(subscription, 'unsubscribe').and.callThrough();
|
||||
this.unsubscribeSpies.push(unsubscribeSpy);
|
||||
|
|
|
@ -113,7 +113,7 @@ export class MockNgModuleFactoryLoader implements NgModuleFactoryLoader {
|
|||
this.loadedPaths.push(path);
|
||||
|
||||
const platformRef = getPlatform();
|
||||
const compilerFactory = platformRef.injector.get(CompilerFactory) as CompilerFactory;
|
||||
const compilerFactory = platformRef!.injector.get(CompilerFactory) as CompilerFactory;
|
||||
const compiler = compilerFactory.createCompiler([]);
|
||||
|
||||
return compiler.compileModuleAsync(MockEmbeddedModule);
|
||||
|
|
|
@ -4,7 +4,7 @@ export class MockLocationService {
|
|||
urlSubject = new BehaviorSubject<string>(this.initialUrl);
|
||||
currentUrl = this.urlSubject.asObservable().map(url => this.stripSlashes(url));
|
||||
// strip off query and hash
|
||||
currentPath = this.currentUrl.map(url => url.match(/[^?#]*/)[0]);
|
||||
currentPath = this.currentUrl.map(url => url.match(/[^?#]*/)![0]);
|
||||
search = jasmine.createSpy('search').and.returnValue({});
|
||||
setSearch = jasmine.createSpy('setSearch');
|
||||
go = jasmine.createSpy('Location.go').and
|
||||
|
@ -14,7 +14,7 @@ export class MockLocationService {
|
|||
handleAnchorClick = jasmine.createSpy('Location.handleAnchorClick')
|
||||
.and.returnValue(false); // prevent click from causing a browser navigation
|
||||
|
||||
constructor(private initialUrl) {}
|
||||
constructor(private initialUrl: string) {}
|
||||
|
||||
private stripSlashes(url: string) {
|
||||
return url.replace(/^\/+/, '').replace(/\/+(\?|#|$)/, '$1');
|
||||
|
|
|
@ -3,21 +3,21 @@ import { Injectable } from '@angular/core';
|
|||
@Injectable()
|
||||
export class MockLogger {
|
||||
|
||||
output = {
|
||||
output: { log: any[], error: any[], warn: any[] } = {
|
||||
log: [],
|
||||
error: [],
|
||||
warn: []
|
||||
};
|
||||
|
||||
log(value: any, ...rest) {
|
||||
log(value: any, ...rest: any[]) {
|
||||
this.output.log.push([value, ...rest]);
|
||||
}
|
||||
|
||||
error(value: any, ...rest) {
|
||||
error(value: any, ...rest: any[]) {
|
||||
this.output.error.push([value, ...rest]);
|
||||
}
|
||||
|
||||
warn(value: any, ...rest) {
|
||||
warn(value: any, ...rest: any[]) {
|
||||
this.output.warn.push([value, ...rest]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"outDir": "./dist/out-tsc",
|
||||
"baseUrl": "src",
|
||||
"sourceMap": true,
|
||||
|
|
Loading…
Reference in New Issue